Canvas Bitmap Operations - bitblt in JavaScript
Written by Ian Elliot   
Thursday, 31 May 2018
Article Index
Canvas Bitmap Operations - bitblt in JavaScript
ImageData object
Security

With Canvas you can now work with bitmaps at the pixel level. It's not difficult but you need to organise things to make it really easy and a good understanding helps.

Now available as a paperback or ebook from Amazon.

JavaScript Bitmap Graphics
With Canvas

largecover360

 

Contents

  1. JavaScript Graphics
  2. Getting Started With Canvas
  3. Drawing Paths
      Extract: Basic Paths
      Extract: SVG Paths
      Extract: Bezier Curves
  4. Stroke and Fill
      Extract: Stroke Properties 
      Extract: Fill and Holes
      Extract: Gradient & Pattern Fills
  5. Transformations
      Extract: Transformations
      Extract: Custom Coordinates 
      Extract  Graphics State
  6. Text
      Extract: Text, Typography & SVG 
      Extract: Unicode
  7. Clipping, Compositing and Effects
      Extract: Clipping & Basic Compositing
  8. Generating Bitmaps
      Extract:  Introduction To Bitmaps
      Extract :  Animation 
  9. WebWorkers & OffscreenCanvas
      Extract: Web Workers
      Extract: OffscreenCanvas
  10. Bit Manipulation In JavaScript
      Extract: Bit Manipulation
  11. Typed Arrays
      Extract: Typed Arrays **NEW!
  12. Files, blobs, URLs & Fetch
      Extract: Blobs & Files
      Extract: Read/Writing Local Files
  13. Image Processing
      Extract: ImageData
      Extract:The Filter API
  14. 3D WebGL
      Extract: WebGL 3D
  15. 2D WebGL
    Extract: WebGL Convolutions

<ASIN:1871962625>

<ASIN:B07XJQDS4Z>

<ASIN:1871962579>

<ASIN:1871962560>

<ASIN:1871962501>

<ASIN:1871962528>

 

One of the operations that low-level APIs tend to give you that higher level graphics systems tend to ignore is the bitblt - bit-block operation (pronounced bit-blit). This is essentially a low-level copy of a group of bits stored in memory to another area of memory.

What has this got to do with graphics?

The answer is that in many cases the bits represented the pixels of a bitmap and the bitblt was one way to update or modify another bitmap by copying another bitmap into it. Bitblt operations are useful when ever you want to perform dynamic updating of an bitmap and the good news is that at long last you can now do this using JavaScript and its is all because of the canvas object.

Until the canvas object was introduced as part of HTML5 JavaScript could be used to load and display images but you couldn't dynamically modify or generate images. Load and display was as far as it went. Now you can get at and modify pixels as much as you like.

It is assumed that you know the basics of using the canvas tag. If not read A Programmer's Guide to Canvas first. For simplicity the browser used is Chrome but you can use Firefox, Edge or any modern browser.

Drawing an image

The first part of the canvas bitmap operations that we need to look at is the drawImage method.

This will draw a bitmap onto a canvas.

What is interesting about this method is not so much that it provides a link between a bitmap and the canvas object but the range of bitmap sources that can be used.

The source for a bitmap can either be a bitmap object, another canvas object or a video object. Notice that if you are using a canvas object as the source of the bitmap you have to have actually drawn something on it first and you have to use the canvas object not the drawing context - see later for an example. If you use a video object then the current frame is rendered to the canvas.

To start with the simplest you can take any standard Image object and draw it to the canvas. You can derive your image object from the DOM or create it directly within JavaScript.

For example suppose the page contains an image:

<img id="myImage" src="/test.jpg"/>

then you can retrieve the image object from the DOM using:

var img1=document.getElementById("myImage");

and you can then display it on the canvas, with the 2D drawing context stored in ctx,  using:

ctx.drawImage(img,10, 10);

The drawImage method takes a number of different parameters but in this simply form drawImage(image,x,y) simply draws as much of the image that fits on the canvas with its top left hand corner at x,y.

The only problem is that you have to make sure that the image has loaded before you try using it. If this is a problem use:

img.addEventListener("load", function(){
                         ctx.drawImage(img1, 0,0);
                    });

Alternatively you could load the image dynamically using JavaScript. The only problem with this approach is that you have to use asynchronous code to allow for the time to download the bitmap. For example:

var img=new Image();
img.onload = function(){
               ctx.drawImage(img,0, 0);
             }
img.src = "test.jpg";

In this case the loading of the bitmap starts as soon as the src property is set. When the bitmap is loaded the onload function is called which draws it to the canvas. (Notice the way closure makes this asynchronous code much easier to write because the callback can still access ctx even though it is out of scope at the point the function is called.)

The complete program is:

<body>
  <canvas id="Canvas"
          width="600" height="600"
          style="height:600px;width:600px;">
 </canvas>
</body>
<script>
 var c = document.getElementById("Canvas");
 var ctx = c.getContext("2d");
 var img=new Image();
 img.onload = function(){
                ctx.drawImage(img, 10, 10);
 
img.src = "test.jpg";
</script>

 

If you want to scale the image then use the alternative form of the drawImage method:

drawImage(image,x,y,w,h);

where w and h specify the width and height that the image is scaled to. For example:

ctx.drawImage(img,10, 10,300,300);

scale1

 

The problem here is that you might well distort the bitmap by scaling it unequally in the x and y directions. The solution is to use the Image object's width and height properties:

ctx.drawImage(img,10,10,img.width/4,img.height/4);

scale2

 

The final form of the drawImage method give you complete control over the way the image is drawn:

drawImage(image,sx,sy,sw,sh,dx,dy,dw,dh)

This looks complicated but it simply specifies the location of a source and a destination rectangle. The source rectangle has its top left hand corner at sx,sy and is sw wide and sh high. The destination rectangle has its top left hand corner at dx,dy and it is dw wide and dh high. The draw copies pixels in the source rectangle to the source rectangle performing any scaling that is needed. For example, to display the area of the bitmap within the rectangle with its top left-hand corner at 700,200 of width 600 and height 800 to the canvas in a square with its top left-hand corner at 0,0 and side 200 you would use:

ctx.drawImage(img,700,200,600,600,0,0,200,200);

scale3

 

Finally you can use all three versions of the drawImage method with another canvas object as the source of the bitmap.

For example:

ctx2.drawImage(canvas,0,0,200,200);

will draw the contents of canvas onto the drawing context ctx2 of another canvas object.

You can also draw a canvas object onto itself.  For example

ctx.drawImage(canvas,0,0,200,200);

will copy the contents of the canvas object back onto itself in a 200 by 200 rectangle if ctx is the drawing context of the canvas object. Notice that the source bitmap is copied before it is drawn back to the canvas.

So to summarize:

There are three drawImage methods

  • drawImage(image,dx,dy)
  • drawImage(image,dx,dy,dw,dh)
  • drawImage(image,sx,sy,sw,sh,dx,dy,dw,dh)

Where image is either a canvas, video or an image object derived either from the DOM or constructed in JavaScript and sx,sy,sw,sh define the source rectangle and dx,dy,dw,dh define the destination rectangle.



Last Updated ( Thursday, 06 September 2018 )