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?
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 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With