JavaScript Canvas - Blobs & Files
Written by Ian Elliot   
Monday, 26 October 2020
Article Index
JavaScript Canvas - Blobs & Files
The File

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

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 
  12. Files, blobs, URLs & Fetch
      Extract: Blobs & Files
      Extract: Read/Writing Local Files
      Extract: Fetch API **NEW!
  13. Image Processing
      Extract: ImageData
      Extract:The Filter API
  14. 3D WebGL
      Extract: WebGL 3D
  15. 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: 

  • size – size of the blob in bytes

  • type – the MIME type of the blob. 

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.



Last Updated ( Monday, 09 November 2020 )