Blending & Mask Composites

Composites can be used to blend or mask one or more images and/or one or more text with each other on a canvas.

We use the globalCompositeOperation to blend or mask new content with what is already drawn on a canvas. There are 12 composite operations, as shown below:

source-atop
Where source and destination overlaps, the source is displayed. Where no overlaps exists, or where the source is transparent, the destination is displayed.
source-in
Where source and destination overlaps and both are opaque, the source is displayed. Everywhere else transparency is displayed.
source-out
Where the source and destination do not overlap, the source is displayed. Everwhere else transparency is displayed.
source-over
Where the source is opaque, the source is displayed. The destination is displayed everywhere else.
destination-atop
Where the source and destination overlap, and both are opaque, the destination is displayed. Where the destination is transparent, the source is displayed.
destination-in
Where the source and destination overlaps, and both are opaque, the destination is displayed. The source is not displayed where no overlaps exists.
destination-out
Displays the destination everywhere the source and destination do not overlap. Everywhere else, transparency is displayed.
destination-over
Where source and destination overlaps, the destination is displayed. Where no overlap exists, the source is displayed.
lighter
The source and destination colors are added to each other, resulting in brighter colors, moving towards colour values of 1 (maximum brightness for that color).
darker
The source and destination colors are subtacted from each other, resulting in brighter colors, moving towards colour values of 0 (minimum brightness for that color).
xor
Shapes are made transparent where both overlap and drawn normal everywhere else.
copy
Where source and destination overlaps, the source is displayed.

Perhaps the most useful alpha composite is the 'source-in composite. It can be used to show part of one image on top of another image.

Example of a source-in alpha composite region (Run Example)

<!DOCTYPE html>
<html>
    <head>
        <title>Course notes example code</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">

        <style>
            img,
            canvas
            {
                width:500px;
                height:500px;
                border:thin solid black;
            }

            #loadingMessage
            {
                position:absolute;
                top:100px;
                left:100px;
                z-index:100;
                font-size:50px;
            }
        </style>

        <script>
            let canvas = null
            let ctx = null
            let width = null
            let height = null
            let originalImage = null

            window.onload = onAllAssetsLoaded
            document.write("<div id='loadingMessage'>Loading...</div>")
            function onAllAssetsLoaded()
            {
                // hide the webpage loading message
                document.getElementById('loadingMessage').style.visibility = "hidden"

                originalImage = document.getElementById('originalImage')
                canvas = document.getElementById('canvas')
                ctx = canvas.getContext('2d')
                width = originalImage.clientWidth
                height = originalImage.clientHeight
                canvas.width = width
                canvas.height = height

                renderCanvas()
            }


            function renderCanvas()
            {
                // 1) define the alpha area  
                ctx.beginPath()
                ctx.fillStyle = "red" // any colour can be used
                ctx.fillRect(100, 100, 200, 100)
                ctx.closePath()

                // 2) select the alpha composite
                ctx.globalCompositeOperation = 'source-in'

                // 3) draw the original image
                // only the part that overlaps the alpha area will be visible
                ctx.drawImage(originalImage, 0, 0, width, height)
            }
        </script>
    </head>

    <body>
        <img id = 'originalImage' src = 'images/dancing.png'>
        <canvas id = 'canvas'></canvas>
    </body>
</html>

Write code to display a circular (spotlight) image on a full-sized, faded, background image, as shown at this link.

Expand your code so that the user can drag the spotlight around the canvas, as shown at this link.

Expand your code so that the user can drag a magnified spotlight around the canvas, as shown at this link.

List a use for each of the 12 various alpha composites.

Modify the code above so that the user can select any of the 12 alpha composites, as shown at, this link.

Example of a source-in alpha composite image (Run Example)

<!DOCTYPE html>
<html>
    <head>
        <title>Course notes example code</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">

        <style>
            img,
            canvas
            {
                width:500px;
                height:500px;
                border:thin solid black;
            }

            #loadingMessage
            {
                position:absolute;
                top:100px;
                left:100px;
                z-index:100;
                font-size:50px;
            }
        </style>

        <script>
            let canvas = null
            let ctx = null
            let originalImage = null
            let width = null
            let height = null
            let alphaImage = new Image()
            alphaImage.src = 'images/four_leaf_clover.png'

            window.onload = onAllAssetsLoaded
            document.write("<div id='loadingMessage'>Loading...</div>")
            function onAllAssetsLoaded()
            {
                // hide the webpage loading message
                document.getElementById('loadingMessage').style.visibility = "hidden"

                originalImage = document.getElementById('originalImage')
                canvas = document.getElementById('canvas')
                ctx = canvas.getContext('2d')
                width = originalImage.clientWidth
                height = originalImage.clientHeight
                canvas.width = width
                canvas.height = height

                renderCanvas()
            }


            function renderCanvas()
            {
                // 1) define the alpha area   
                ctx.drawImage(alphaImage, 100, 50, 200, 200)

                // 2) select the alpha composite
                ctx.globalCompositeOperation = 'source-in'

                // 3) draw the original image
                // only the part that overlaps the alpha area will be visible
                ctx.drawImage(originalImage, 0, 0, width, height)
            }
        </script>
    </head>

    <body>
        <img id = 'originalImage' src = 'images/dancing.png'>
        <canvas id = 'canvas'></canvas>
    </body>
</html>

Modify the above code to use a different image.

Example of a source-in alpha composite text (Run Example)

<!DOCTYPE html>
<html>
    <head>
        <title>Course notes example code</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">

        <style>
            img,
            canvas
            {
                width:500px;
                height:500px;
                border:thin solid black;
            }

            #loadingMessage
            {
                position:absolute;
                top:100px;
                left:100px;
                z-index:100;
                font-size:50px;
            }
        </style>

        <script>
            let canvas = null
            let ctx = null
            let width = null
            let height = null
            let originalImage = null

            window.onload = onAllAssetsLoaded
            document.write("<div id='loadingMessage'>Loading...</div>")
            function onAllAssetsLoaded()
            {
                // hide the webpage loading message
                document.getElementById('loadingMessage').style.visibility = "hidden"

                originalImage = document.getElementById('originalImage')
                canvas = document.getElementById('canvas')
                ctx = canvas.getContext('2d')
                width = originalImage.clientWidth
                height = originalImage.clientHeight
                canvas.width = width
                canvas.height = height

                renderCanvas()
            }


            function renderCanvas()
            {
                // 1) define the alpha area   
                ctx.beginPath()
                ctx.fillStyle = "red"
                ctx.font = "170px Times Roman"
                ctx.fillText("DkIT", 25, 200)
                ctx.closePath()

                // 2) select the alpha composite
                ctx.globalCompositeOperation = 'source-in'

                // 3) draw the original image
                // only the part that overlaps the alpha area will be visible
                ctx.drawImage(originalImage, 0, 0, width, height)
            }
        </script>
    </head>

    <body>
        <img id = 'originalImage' src = 'images/dancing.png'>
        <canvas id = 'canvas'></canvas>
    </body>
</html>

Change the text font and position in the code above.

Allow the user to type in the text that will be used as the alpha composite.

Use the global alpha to fade your modified code.

Complex global Composite Operations

Example of a drop shadow on an image (Run Example)

<!DOCTYPE html>
<html>
    <head>
        <title>Course notes example code</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">

        <style>
            img,
            canvas
            {
                width:500px;
                height:500px;
                border:thin solid black;
            }

            #loadingMessage
            {
                position:absolute;
                top:100px;
                left:100px;
                z-index:100;
                font-size:50px;
            }
        </style>

        <script>
            let canvas = null
            let ctx = null
            let width = null
            let height = null
            let originalImage = null

            let alphaImage = new Image()
            alphaImage.src = 'images/four_leaf_clover.png'

            window.onload = onAllAssetsLoaded
            document.write("<div id='loadingMessage'>Loading...</div>")
            function onAllAssetsLoaded()
            {
                // hide the webpage loading message
                document.getElementById('loadingMessage').style.visibility = "hidden"

                originalImage = document.getElementById('originalImage')
                canvas = document.getElementById('canvas')
                ctx = canvas.getContext('2d')
                width = originalImage.clientWidth
                height = originalImage.clientHeight
                canvas.width = width
                canvas.height = height

                renderCanvas()
            }


            function renderCanvas()
            {
                // set up a double-buffer
                let doubleBuffer = document.createElement('canvas')
                let doubleBufferCtx = doubleBuffer.getContext('2d')
                doubleBuffer.width = width
                doubleBuffer.height = height

                // define the shadow offset and colour
                let offset = 10
                let shadowColour = '#ff0'

                // 1) define the alpha area    
                doubleBufferCtx.drawImage(alphaImage, 10, 10, 350, 350)

                // 2) select the alpha composite   
                doubleBufferCtx.globalCompositeOperation = 'source-in'

                // 3) draw the original image
                // only the part that overlaps the alpha area will be visible
                doubleBufferCtx.beginPath()
                doubleBufferCtx.fillStyle = shadowColour
                doubleBufferCtx.fillRect(0, 0, width, height)
                doubleBufferCtx.closePath()

                // draw the saved shadow image onto the canvas slightly below and to the right 
                // of where the actual image will be drawn
                ctx.drawImage(doubleBuffer, 0, 0, width + offset, height + offset)

                // draw the image slightly above and to the left of the shadow
                // this is similar to the code above, except now we draw the
                // original image rather than its shadow
                doubleBufferCtx.globalCompositeOperation = 'source-over'

                // 1) define the alpha area
                doubleBufferCtx.drawImage(alphaImage, 10, 10, 350, 350)

                // 2) select the alpha operation    
                doubleBufferCtx.globalCompositeOperation = 'source-in'

                // 3) draw the original image
                // only the part that overlaps the alpha area will be visible
                doubleBufferCtx.drawImage(originalImage, 0, 0, width, height)

                // draw the saved image onto the canvas slightly below and to the right 
                // of where the actual image will be drawn   
                ctx.drawImage(doubleBuffer, 0, 0, width, height)
            }



        </script>
    </head>

    <body>
        <img id = 'originalImage' src = 'images/dancing.png'>
        <canvas id = 'canvas'></canvas>
    </body>
</html>

Change the shadow colour to grey in the example above.

In real shadows, the shadow colour fades out as it moves away from the object. Modify the code above, so that the shadow has ten different shades of grey, as shown at this link.

Replace the overlay image with text in the above example.

Example of a multi-layered image (Run Example)

<!DOCTYPE html>
<html>
    <head>
        <title>Course notes example code</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">

        <style>
            img,
            canvas
            {
                width:500px;
                height:500px;
                border:thin solid black;
            }

            #loadingMessage
            {
                position:absolute;
                top:100px;
                left:100px;
                z-index:100;
                font-size:50px;
            }
        </style>

        <script>
            let canvas = null
            let ctx = null
            let width = null
            let height = null
            let originalImage = null

            let alphaImage = new Image()
            alphaImage.src = 'images/overlay.png'

            let pictureFrame = new Image()
            pictureFrame.src = 'images/frame.png'

            window.onload = onAllAssetsLoaded
            document.write("<div id='loadingMessage'>Loading...</div>")
            function onAllAssetsLoaded()
            {
                // hide the webpage loading message
                document.getElementById('loadingMessage').style.visibility = "hidden"

                originalImage = document.getElementById('originalImage')
                canvas = document.getElementById('canvas')
                ctx = canvas.getContext('2d')
                width = originalImage.clientWidth
                height = originalImage.clientHeight
                canvas.width = width
                canvas.height = height

                renderCanvas()
            }


            function renderCanvas()
            {
                // 1) define the alpha area   
                ctx.drawImage(alphaImage, 0, 0, width, height)

                // 2) select the alpha composite
                ctx.globalCompositeOperation = 'source-in'

                // 3) draw the original image
                // only the part that overlaps the alpha area will be visible
                ctx.drawImage(originalImage, 0, 0, width, height)

                // draw the picture frame on top of the picture
                ctx.globalCompositeOperation = 'source-over'
                ctx.drawImage(pictureFrame, 0, 0, width, height)
            }
        </script>
    </head>

    <body>
        <img id = 'originalImage' src = 'images/dancing.png'>
        <canvas id = 'canvas'></canvas>
    </body>
</html>

Modify the above code to display a different photo frame.

 
<div align="center"><a href="../versionC/index.html" title="DKIT Lecture notes homepage for Derek O&#39; Reilly, Dundalk Institute of Technology (DKIT), Dundalk, County Louth, Ireland. Copyright Derek O&#39; Reilly, DKIT." target="_parent" style='font-size:0;color:white;background-color:white'>&nbsp;</a></div>