Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create 1-bit bitmap from HTML Canvas in javascript

I need to get a 1-bit bitmap out of an HTML5 Canvas.

The canvas is black-and-white. However, I can only use toUrlData() with png/jpeg outputs, but can't find any way to generate a bitmap (and change the color depth to 1-bit).

Are there any available solutions for this type of conversion? Or maybe a javascript library that can write a bitmap image?

like image 885
Gilad Avatar asked Jun 12 '26 13:06

Gilad


2 Answers

Converting to 1-bit

There is no built-in mechanism for Canvas that allow you to save 1-bit images. Canvas is 32-bit (24 bit color, 8 bit alpha) and this would require the standard to use a common algorithm to degrade the image (which I likely why you can't save GIF files from it but only formats that support 24-bits or more).

For that you need to go low-level and build up the file format your self with Typed Arrays.

If 1-bit file format is not an absolute requirement, i.e. you want the image to appear as if it is 1-bit you can simply convert the content yourself.

You can use this method to convert an image to "1-bit" by converting RGB to luma values and use a threshold to determine if it should be "on" or "off":

var ctx = c.getContext("2d"), img = new Image();
img.onload = function() {
  ctx.drawImage(img, 0, 0, c.width, c.height);

  // Main code
  var idata = ctx.getImageData(0, 0, c.width, c.height),
      buffer = idata.data,
      len = buffer.length,
      threshold = 127,
      i, luma;

  for (i = 0; i < len; i += 4) {
    // get approx. luma value from RGB
    luma = buffer[i] * 0.3 + buffer[i + 1] * 0.59 + buffer[i + 2] * 0.11;

    // test against some threshold
    luma = luma < threshold ? 0 : 255;

    // write result back to all components
    buffer[i] = luma;
    buffer[i + 1] = luma;
    buffer[i + 2] = luma;
  }
  
  // update canvas with the resulting bitmap data
  ctx.putImageData(idata, 0, 0);
};

img.crossOrigin = "";
img.src = "//i.imgur.com/BrNTgRFl.jpg";
<canvas id=c width=500 height=400></canvas>

To 1-bit

To save it as a BMP file (24-bits though and not supported by all browsers):

var bmp = canvas.toDataURL("image/bmp");

Also see this answer for how you can build and write a BMP format yourself.

You can use this method also with a low-level approach by using the result from this to pack the bits (every 8 "bits" needs to be packed into a single byte, little-endian for BMP format).

Optionally look into the TrueVision TGA file format which is simpler, or the TIFF file format which also allow you to use big-endian bytes (most TIFF formats can be read by browsers btw.).

You could use a library like FileSaver.js. And write out the bitmap file manually by following the BMP File Format specification.

You'd do something like this with the resulting data:

function saveData() {
    var arrayBuffer = new ArrayBuffer(data.length);
    var dataView = new DataView(arrayBuffer);
    for(var i = 0; i < data.length; i ++) {
        dataView.setUint8(i, data.charCodeAt(i));
    }
    var blob = new Blob([dataView], {type: "application/octet-stream"});
    saveAs(blob, "test.bmp");
}

You'd probably need to look up some info on ArrayBuffer and DataView if you were to do it this way.

like image 39
Lyndon Armitage Avatar answered Jun 15 '26 01:06

Lyndon Armitage



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!