Page 1 of 2 Blobs and files, sounds useful if you want to load or save graphics files or create them dynamically. In this extract from my new book on JavaScript Graphics, we look at the basics of what makes a blob a file.
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>
When working with bitmaps and many other similar resources there is a common problem of how do we actually load or save the resource? In simple cases the standard method is to use a URL within an HTML tag. For example, setting the src property of an img tag to a URL causes the browser to request the file, the server to send it and the browser to display it. If you want to do the same in JavaScript, so that you can process the file before it is displayed, then you need to know how to work with files and their precursor, the blob. If you want to create files within JavaScript you also need to know how to create URLs that reference data within the program.
This chapter looks at the problem of working with files, specifically image files from JavaScript. Although the emphasis is on image files, the ideas are general and are applicable to any type of file with slight modifications.
The Blob
The most basic type of file in JavaScript is the “blob”. Its name, which derives from “binary large object”, correctly suggests a collection of bits with no predefined structure. However, it is important to realize and keep in mind that a blob, despite its name, is just a file. To be more accurate, a blob is more a file-like reference to some data which is stored elsewhere. To get at the data you have to read it, which is what the FileReader object, see later, is for.
To create a blob you use the constructor:
var myBlob=new Blob([data],options);
The first parameter is an array of data sources for the blob. These can include strings, ArrayBuffer, ArrayBufferView and other blobs. They are each treated as binary and combined to make the final blob. After you have created the blob the data sources remain unaltered.
The second parameter, options is optional and can have the properties:
-
type – a MIME type for the content
-
endings – specifies how to deal with \n character in strings. The default transparent is to write them out unchanged but native will convert them to whatever the local file system uses.
What can you do with a blob? The answer is not much as it has just one method:
slice(start,end, type)
This creates a new blob by extracting the bytes from start to end and assigns the specified type. All parameters are optional and negative index values start from the end of the blob. The new blob has only two properties:
Given these limited resources there isn’t much you can do with a blob. What makes it useful is the URL object and its createObjectURL static method. This can be used to create a URL that references a blob, file or media source. Once you have a URL it can be used anywhere a “normal” URL can be used. Of course, the blob has to be correctly formatted for the type of file that the MIME type suggests it is and that the target expects.
There is one potential problem with an object URL. When you create an object URL referencing an object, that object is never garbage collected or disposed of, even when it goes out of scope and should be destroyed. Creating an object URL and not disposing of it using the revokeObjectURL static method when you have finished using it, will result in a memory leak.
For example:
var myBlob=new Blob(["<p>Hello World</p>"], {type : 'text/html'});
var myURL=URL.createObjectURL(myBlob);
myIframe.src=myURL;
URL.revokeObjectURL(myURL);
Assuming that there is an <iframe> with id myIframe on the page this will display the HTML in the string which is exactly what would happen if the URL references a file with the same content. This isn’t particularly useful because iframes have an srcdoc property which can be set to a string but it illustrates the general idea.
A more realistic example is to use the canvas.toBlob method which will convert the contents of the canvas to a blob in the desired format:
canvas.toBlob(callback, type, quality);
The callback is a function that is used to receive the blob once it has been constructed. The optional second parameter sets the MIME type of the blob, png by default. Most browsers only support png and jpg. The optional final parameter sets the quality, 0.0 to 1.0, for formats that use lossy compression.
For example:
var ctx = document.body.appendChild( createCanvas(600, 600)).getContext("2d");
var myPath = new Path2D();
myPath.moveTo(50, 50);
myPath.lineTo(100, 100);
myPath.lineTo(0, 100);
myPath.lineTo(50, 50);
myPath.moveTo(50, 110);
myPath.lineTo(0, 60);
myPath.lineTo(100, 60);
myPath.lineTo(50, 110);
ctx.stroke(myPath);
ctx.canvas.toBlob(doBlob);
The doBlob function is:
function doBlob(myBlob){
var url=URL.createObjectURL(myBlob);
myImg.src=url;
}
This draws the star in the example given in Chapter 3, converts it to a blob and display it in an <img> tag with id myImg. The format for the blob is the default png. Remember to revoke the URL object after the image has loaded.
You can create other formats using the appropriate MIME types but the only formats you can reasonably rely on are png and jpeg. Chrome also support webp. If the browser doesn’t support a MIME type you ask for, it simply creates a png format blob.
If you try to create a jpeg you might be surprised to find that all you seem to have is a black image:
ctx.canvas.toBlob(doBlob,"image/jpeg",0.8);
The reason is simply that jpeg doesn’t support transparency and so the background pixels that are black transparent show as black. One solution is to clear the canvas to white opaque:
ctx.fillStyle = '#fff';
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
Instead of using a callback you can convert the toBlob method into a function that returns a Promise:
function canvasToBlob(ctx, type) {
return new Promise(function (resolve, reject) {
ctx.canvas.toBlob(function (blob) {
resolve(blob);
}, type);
});
}
This is a function that you can use with await to simplify your code. For example:
var blob=await canvasToBlob(ctx, “image/png”);
but, of course, this only works in a function as you cannot use await in the main program.
|