Page 1 of 3 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
Contents
- JavaScript Graphics
- Getting Started With Canvas
- Drawing Paths
Extract: Basic Paths Extract: SVG Paths Extract: Bezier Curves
- Stroke and Fill
Extract: Stroke Properties Extract: Fill and Holes Extract: Gradient & Pattern Fills
- Transformations
Extract: Transformations Extract: Custom Coordinates Extract Graphics State
- Text
Extract: Text, Typography & SVG Extract: Unicode
- Clipping, Compositing and Effects
Extract: Clipping & Basic Compositing
- Generating Bitmaps
Extract: Introduction To Bitmaps Extract : Animation
- WebWorkers & OffscreenCanvas
Extract: Web Workers Extract: OffscreenCanvas
- Bit Manipulation In JavaScript
Extract: Bit Manipulation
- Typed Arrays
Extract: Typed Arrays
- Files, blobs, URLs & Fetch
Extract: Blobs & Files Extract: Read/Writing Local Files Extract: Fetch API **NEW!
- Image Processing
Extract: ImageData Extract:The Filter API
- 3D WebGL
Extract: WebGL 3D
- 2D WebGL
Extract: WebGL Convolutions
<ASIN:B07XJQDS4Z>
<ASIN:1871962579>
<ASIN:1871962560>
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);
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);
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);
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.
|