HTML5 Zone is brought to you in partnership with:

I was born in 1981 in one little city. Since I was 10y/o I programmed in different languages. My first languages were basic, then C++/MFC, after .Net (C#, VB.Net, J#, ASP.Net), XSL+XML processing). In the last 5 years I worked with web languages (HTML, CSS, PHP, SQL, XML, XSL, JavaScript). After university I worked in several different companies, eventually becoming a blogger. This is my hobby too. Andrey is a DZone MVB and is not an employee of DZone and has posted 109 posts at DZone. You can read more from them at their website. View Full User Profile

HTML5 Image Effects – Emboss

03.20.2012
| 6413 views |
  • submit to reddit
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 a pretty difficult method, but I am sure that you can repeat it. In our demo we can play with different images by adding an emboss effect to them, and we can ‘export’ our result on the image element (<img>).

Here are our demo and downloadable packages:

Live Demo

download in package

Ok, download the example files and let's start coding !

Step 1. HTML Markup

This is the markup of our demo page:

index.html
<!DOCTYPE html>
<html lang="en" >
    <head>
        <meta charset="utf-8" />
        <title>HTML5 Image Effects - Emboss | Script Tutorials</title>
        <link href="css/main.css" rel="stylesheet" type="text/css" />
        <script src="https://www.google.com/jsapi"></script>
        <script>
            google.load("jquery", "1.7.1");
        </script>
        <script src="js/script.js"></script>
    </head>
    <body>
        <header>
            <h2>HTML5 Image Effects - Emboss</h2>
            <a href="http://www.script-tutorials.com/html5-image-effects-emboss/" class="stuts">Back to original tutorial on <span>Script Tutorials</span></a>
        </header>
        <div id="container" class="container">
            <table cellspacing=0>
                <tr>
                    <td><p>Canvas Object <CANVAS></p></td>
                    <td><p>Image Object <IMG></p></td>
                </tr>
                <tr>
                    <td><canvas id="source" width="500" height="500"></canvas><div id="next" class="button">Next image</div></td>
                    <td><img id="img" src="images/button.png" /></td>
                </tr>
                <tr>
                    <td><div id="emboss" class="button">Apply Emboss Effect</div></td>
                    <td><div id="toImage" class="button">To Image</div></td>
                </tr>
            </table>
        </div>
    </body>
</html>

Basically – it contains 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
*{
    margin:0;
    padding:0;
}
body {
    background-image:url(../images/bg.png);
    color:#fff;
    font:14px/1.3 Arial,sans-serif;
}
header {
    background-color:#212121;
    box-shadow: 0 -1px 2px #111111;
    display:block;
    height:70px;
    position:relative;
    width:100%;
    z-index:100;
}
header h2{
    font-size:22px;
    font-weight:normal;
    left:50%;
    margin-left:-400px;
    padding:22px 0;
    position:absolute;
    width:540px;
}
header a.stuts,a.stuts:visited {
    border:none;
    text-decoration:none;
    color:#fcfcfc;
    font-size:14px;
    left:50%;
    line-height:31px;
    margin:23px 0 0 110px;
    position:absolute;
    top:0;
}
header .stuts span {
    font-size:22px;
    font-weight:bold;
    margin-left:5px;
}
.container {
    color: #000000;
    margin: 20px auto;
    overflow: hidden;
    position: relative;
    width: 1005px;
}
table {
    background-color: rgba(255, 255, 255, 0.7);
}
table td {
    border: 1px inset #888888;
    position: relative;
    text-align: center;
}
table td p {
    display: block;
    padding: 10px 0;
}
.button {
    cursor: pointer;
    height: 20px;
    padding: 15px 0;
    position: relative;
    text-align: center;
    width: 500px;

   -moz-user-select: none;
   -khtml-user-select: none;
   user-select: none;
}

Step 3. JS

Finally – our JavaScript code for the Emboss effect:

js/script.js
// variables
var canvas, ctx;
var imgObj;

// filter strength
var strength = 0.5;

// shifting matrix
var matrix = [-2, -1, 0, -1, 1, 1, 0, 1, 2];

// normalize matrix
function normalizeMatrix(m) {
    var j = 0;
    for (var i = 0; i < m.length; i++) {
        j += m[i];
    }
    for (var i = 0; i < m.length; i++) {
        m[i] /= j;
    }
    return m;
}

// convert x-y coordinates into pixel position
function convertCoordinates(x, y, w) {
    return x + (y * w);
}

// find a specified distance between two colours
function findColorDiff(dif, dest, src) {
    return dif * dest + (1 - dif) * src;
}

// transform matrix
function transformMatrix(img, pixels) {

    // create a second canvas and context to keep temp results
    var canvas2 = document.createElement('canvas');
    var ctx2 = canvas2.getContext('2d');
    ctx2.width = canvas2.width = img.width;
    ctx2.height = canvas2.height = img.height;

    // draw image
    ctx2.drawImage(img, 0, 0, img.width , img.height);
    var buffImageData = ctx2.getImageData(0, 0, canvas.width, canvas.height);

    var data = pixels.data;
    var bufferedData = buffImageData.data;

    // normalize matrix
    matrix = normalizeMatrix(matrix);
    var mSize = Math.sqrt(matrix.length);

    for (var i = 1; i < img.width - 1; i++) {
        for (var j = 1; j < img.height - 1; j++) {

            var sumR = sumG = sumB = 0;

            // loop through the matrix
            for (var h = 0; h < mSize; h++) {
                for (var w = 0; w < mSize; w++) {
                    var r = convertCoordinates(i + h - 1, j + w - 1, img.width) << 2;

                    // RGB for current pixel
                    var currentPixel = {
                        r: bufferedData[r],
                        g: bufferedData[r + 1],
                        b: bufferedData[r + 2]
                    };

                    sumR += currentPixel.r * matrix[w + h * mSize];
                    sumG += currentPixel.g * matrix[w + h * mSize];
                    sumB += currentPixel.b * matrix[w + h * mSize];
                }
            }

            var rf = convertCoordinates(i, j, img.width) << 2;
            data[rf] = findColorDiff(strength, sumR, data[rf]);
            data[rf + 1] = findColorDiff(strength, sumG, data[rf + 1]);
            data[rf + 2] = findColorDiff(strength, sumB, data[rf + 2]);
        }
    }
    return pixels;
}

// process emboss function
function processEmboss() {

    // clear context
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    // draw image
    ctx.drawImage(imgObj, 0, 0, imgObj.width , imgObj.height);

    // get image data
    var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);

    // transform image data
    imageData = transformMatrix(imgObj, imageData);

    // draw data back
    ctx.putImageData(imageData, 0, 0);
};

$(function () {

    // create canvas and context objects
    canvas = document.getElementById('source');
    ctx = canvas.getContext('2d');

    // load source image
    imgObj = new Image();
    imgObj.onload = function () {

        // draw image
        ctx.drawImage(this, 0, 0, this.width, this.height, 0, 0, canvas.width, canvas.height);
    }
    imgObj.src="images/pic1.jpg";

    // different onclick handlers
    var iCur = 1;
    $('#next').click(function () {
        iCur++;
        if (iCur > 6) iCur = 1;
        imgObj.src="images/pic" + iCur + '.jpg';
    });
    $('#emboss').click(function () {
        processEmboss();
    });
    $('#toImage').click(function () {
        $('#img').attr('src', canvas.toDataURL('image/jpeg'));
    });
});

This effect requires 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 the pixels of the original image, and then will apply some transformations.

Live Demo

download in package

Conclusion

I hope that our demo looks fine. Today we have added a new interesting effect to our html5 application – Emboss. I will be glad to see your thanks and comments. Good luck!

Published at DZone with permission of Andrey Prikaznov, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)