Today we continue our HTML5 canvas image filter examples, today I would like to share with you a method of applying a Emboss effect to images. This is pretty difficult method, but I sure that you can repeat it. In our demo we can play with different images by adding a emboss effect to them, as well as we can ‘export’ our result on the image element (<img>).
Here are our demo and downloadable package:
Live Demo
download in package
Ok, download the example files and lets start coding !
Step 1. HTML Markup
This is markup of our demo page. Here it is:
index.html
01 |
<!DOCTYPE html> |
02 |
< html lang = "en" > |
03 |
< head > |
04 |
< meta charset = "utf-8" /> |
05 |
< title >HTML5 Image Effects - Emboss | Script Tutorials</ title > |
06 |
< link href = "css/main.css" rel = "stylesheet" type = "text/css" /> |
07 |
< script src = "https://www.google.com/jsapi" ></ script > |
08 |
< script > |
09 |
google.load("jquery", "1.7.1"); |
10 |
</ script > |
11 |
< script src = "js/script.js" ></ script > |
12 |
</ head > |
13 |
< body > |
14 |
< header > |
15 |
< h2 >HTML5 Image Effects - Emboss</ h2 > |
16 |
< a href = "https://www.script-tutorials.com/html5-image-effects-emboss/" class = "stuts" >Back to original tutorial on < span >Script Tutorials</ span ></ a > |
17 |
</ header > |
18 |
< div id = "container" class = "container" > |
19 |
< table cellspacing = 0 > |
20 |
< tr > |
21 |
< td >< p >Canvas Object <CANVAS></ p ></ td > |
22 |
< td >< p >Image Object <IMG></ p ></ td > |
23 |
</ tr > |
24 |
< tr > |
25 |
< td >< canvas id = "source" width = "500" height = "500" ></ canvas >< div id = "next" class = "button" >Next image</ div ></ td > |
26 |
< td >< img id = "img" src = "images/button.png" /></ td > |
27 |
</ tr > |
28 |
< tr > |
29 |
< td >< div id = "emboss" class = "button" >Apply Emboss Effect</ div ></ td > |
30 |
< td >< div id = "toImage" class = "button" >To Image</ div ></ td > |
31 |
</ tr > |
32 |
</ table > |
33 |
</ div > |
34 |
</ body > |
35 |
</ html > |
Basically – it contain just one canvas object, one image, and three ‘buttons’ (div elements).
Step 2. CSS
Here are our stylesheets (not so important, but anyway):
css/main.css
01 |
*{ |
02 |
margin : 0 ; |
03 |
padding : 0 ; |
04 |
} |
05 |
body { |
06 |
background-image : url (../images/bg.png); |
07 |
color : #fff ; |
08 |
font : 14px / 1.3 Arial , sans-serif ; |
09 |
} |
10 |
header { |
11 |
background-color : #212121 ; |
12 |
box-shadow: 0 -1px 2px #111111 ; |
13 |
display : block ; |
14 |
height : 70px ; |
15 |
position : relative ; |
16 |
width : 100% ; |
17 |
z-index : 100 ; |
18 |
} |
19 |
header h 2 { |
20 |
font-size : 22px ; |
21 |
font-weight : normal ; |
22 |
left : 50% ; |
23 |
margin-left : -400px ; |
24 |
padding : 22px 0 ; |
25 |
position : absolute ; |
26 |
width : 540px ; |
27 |
} |
28 |
header a.stuts,a.stuts:visited { |
29 |
border : none ; |
30 |
text-decoration : none ; |
31 |
color : #fcfcfc ; |
32 |
font-size : 14px ; |
33 |
left : 50% ; |
34 |
line-height : 31px ; |
35 |
margin : 23px 0 0 110px ; |
36 |
position : absolute ; |
37 |
top : 0 ; |
38 |
} |
39 |
header .stuts span { |
40 |
font-size : 22px ; |
41 |
font-weight : bold ; |
42 |
margin-left : 5px ; |
43 |
} |
44 |
.container { |
45 |
color : #000000 ; |
46 |
margin : 20px auto ; |
47 |
overflow : hidden ; |
48 |
position : relative ; |
49 |
width : 1005px ; |
50 |
} |
51 |
table { |
52 |
background-color : rgba( 255 , 255 , 255 , 0.7 ); |
53 |
} |
54 |
table td { |
55 |
border : 1px inset #888888 ; |
56 |
position : relative ; |
57 |
text-align : center ; |
58 |
} |
59 |
table td p { |
60 |
display : block ; |
61 |
padding : 10px 0 ; |
62 |
} |
63 |
.button { |
64 |
cursor : pointer ; |
65 |
height : 20px ; |
66 |
padding : 15px 0 ; |
67 |
position : relative ; |
68 |
text-align : center ; |
69 |
width : 500px ; |
70 |
-moz-user-select: none ; |
71 |
-khtml-user-select: none ; |
72 |
user-select: none ; |
73 |
} |
Step 3. JS
Finally – our javascript code of Emboss effect:
js/script.js
001 |
// variables |
002 |
var canvas, ctx; |
003 |
var imgObj; |
004 |
// filter strength |
005 |
var strength = 0.5; |
006 |
// shifting matrix |
007 |
var matrix = [-2, -1, 0, -1, 1, 1, 0, 1, 2]; |
008 |
// normalize matrix |
009 |
function normalizeMatrix(m) { |
010 |
var j = 0; |
011 |
for ( var i = 0; i < m.length; i++) { |
012 |
j += m[i]; |
013 |
} |
014 |
for ( var i = 0; i < m.length; i++) { |
015 |
m[i] /= j; |
016 |
} |
017 |
return m; |
018 |
} |
019 |
// convert x-y coordinates into pixel position |
020 |
function convertCoordinates(x, y, w) { |
021 |
return x + (y * w); |
022 |
} |
023 |
// find a specified distance between two colours |
024 |
function findColorDiff(dif, dest, src) { |
025 |
return dif * dest + (1 - dif) * src; |
026 |
} |
027 |
// transform matrix |
028 |
function transformMatrix(img, pixels) { |
029 |
// create a second canvas and context to keep temp results |
030 |
var canvas2 = document.createElement( 'canvas' ); |
031 |
var ctx2 = canvas2.getContext( '2d' ); |
032 |
ctx2.width = canvas2.width = img.width; |
033 |
ctx2.height = canvas2.height = img.height; |
034 |
// draw image |
035 |
ctx2.drawImage(img, 0, 0, img.width , img.height); |
036 |
var buffImageData = ctx2.getImageData(0, 0, canvas.width, canvas.height); |
037 |
var data = pixels.data; |
038 |
var bufferedData = buffImageData.data; |
039 |
// normalize matrix |
040 |
matrix = normalizeMatrix(matrix); |
041 |
var mSize = Math.sqrt(matrix.length); |
042 |
for ( var i = 1; i < img.width - 1; i++) { |
043 |
for ( var j = 1; j < img.height - 1; j++) { |
044 |
var sumR = sumG = sumB = 0; |
045 |
// loop through the matrix |
046 |
for ( var h = 0; h < mSize; h++) { |
047 |
for ( var w = 0; w < mSize; w++) { |
048 |
var r = convertCoordinates(i + h - 1, j + w - 1, img.width) << 2; |
049 |
// RGB for current pixel |
050 |
var currentPixel = { |
051 |
r: bufferedData[r], |
052 |
g: bufferedData[r + 1], |
053 |
b: bufferedData[r + 2] |
054 |
}; |
055 |
sumR += currentPixel.r * matrix[w + h * mSize]; |
056 |
sumG += currentPixel.g * matrix[w + h * mSize]; |
057 |
sumB += currentPixel.b * matrix[w + h * mSize]; |
058 |
} |
059 |
} |
060 |
var rf = convertCoordinates(i, j, img.width) << 2; |
061 |
data[rf] = findColorDiff(strength, sumR, data[rf]); |
062 |
data[rf + 1] = findColorDiff(strength, sumG, data[rf + 1]); |
063 |
data[rf + 2] = findColorDiff(strength, sumB, data[rf + 2]); |
064 |
} |
065 |
} |
066 |
return pixels; |
067 |
} |
068 |
// process emboss function |
069 |
function processEmboss() { |
070 |
// clear context |
071 |
ctx.clearRect(0, 0, canvas.width, canvas.height); |
072 |
// draw image |
073 |
ctx.drawImage(imgObj, 0, 0, imgObj.width , imgObj.height); |
074 |
// get image data |
075 |
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); |
076 |
// transform image data |
077 |
imageData = transformMatrix(imgObj, imageData); |
078 |
// draw data back |
079 |
ctx.putImageData(imageData, 0, 0); |
080 |
}; |
081 |
$( function () { |
082 |
// create canvas and context objects |
083 |
canvas = document.getElementById( 'source' ); |
084 |
ctx = canvas.getContext( '2d' ); |
085 |
// load source image |
086 |
imgObj = new Image(); |
087 |
imgObj.onload = function () { |
088 |
// draw image |
089 |
ctx.drawImage( this , 0, 0, this .width, this .height, 0, 0, canvas.width, canvas.height); |
090 |
} |
091 |
imgObj.src = 'images/pic1.jpg' ; |
092 |
// different onclick handlers |
093 |
var iCur = 1; |
094 |
$( '#next' ).click( function () { |
095 |
iCur++; |
096 |
if (iCur > 6) iCur = 1; |
097 |
imgObj.src = 'images/pic' + iCur + '.jpg' ; |
098 |
}); |
099 |
$( '#emboss' ).click( function () { |
100 |
processEmboss(); |
101 |
}); |
102 |
$( '#toImage' ).click( function () { |
103 |
$( '#img' ).attr( 'src' , canvas.toDataURL( 'image/jpeg' )); |
104 |
}); |
105 |
}); |
This effect is required some pretty difficult matrix transformations, so, you can try to understand it, or use it as is. Of course, our script will pass through all pixels of original image, and after – will apply some transformation.
Live Demo
download in package
Conclusion
I hope that our demo looks fine. Today we have added new interesting effect to our html5 application – Emboss. I will be glad to see your thanks and comments. Good luck!