我需要从 HTML5 Canvas 中获取 1 位位图。
画布是黑白的。 但是,我只能将 toUrlData() 与 png/jpeg 输出一起使用,但找不到任何方法来生成位图(并将颜色深度更改为 1 位)。
对于这种类型的转换有任何可用的解决方案吗? 或者也许是一个可以编写位图图像的 JavaScript 库?
Canvas 没有内置机制允许您保存 1 位图像。 Canvas 是 32 位(24 位颜色,8 位 alpha),这需要标准使用通用算法来降级图像(这可能是为什么你不能从中保存 GIF 文件,而只能保存支持 24 位的格式)位或更多)。
为此,您需要深入底层并使用 Typed Arrays 自行构建文件格式。
如果 1 位文件格式不是绝对要求,即您希望图像出现就像 1 位一样,您可以简单地自行转换内容。
您可以使用此方法通过将 RGB 转换为亮度值来将图像转换为“1 位”,并使用阈值来确定它是否应该“打开”或“关闭”:
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>
将其另存为 BMP 文件(虽然是 24 位,但并非所有浏览器都支持):
var bmp = canvas.toDataURL("image/bmp");
另请参阅这个答案,了解如何自己构建和编写 BMP 格式。
您也可以将此方法与低级方法一起使用,通过使用此结果来打包位(每 8 个“位”需要打包为一个字节,对于 BMP 格式为小尾数)。
可以选择查看更简单的 TrueVision TGA 文件格式,或 TIFF 文件格式,它也允许您使用大端字节(顺便说一句,大多数 TIFF 格式都可以由浏览器读取。)。
您可以使用像 FileSaver.js 这样的库。并按照BMP文件格式规范手动写出位图文件。
您可以对结果数据执行类似的操作:
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");
}
如果您要这样做,您可能需要查找有关 ArrayBuffer 和 DataView 的一些信息。
如果您确实需要 1 位图像(例如 POS 打印机):
// Function to convert a bitmap image to ESC/POS byte array
function convertBitmapToESCPOS(imageData, width) {
const threshold = 128; // Pixel intensity threshold for monochrome conversion
const bytesPerLine = Math.ceil(width / 8);
const escposArray = [];
// Resize the image to the specified width and convert to monochrome
// You need to implement this part based on your chosen image processing library
// For example: https://github.com/jimp-dev/jimp/
// Iterate through each pixel and convert to ESC/POS commands
for (let y = 0; y < imageData.height; y++) {
let lineData = [];
for (let x = 0; x < imageData.width; x++) {
const pixelIndex = (y * imageData.width + x) * 4;
const grayscaleValue = (imageData.data[pixelIndex] + imageData.data[pixelIndex + 1] + imageData.data[pixelIndex + 2]) / 3;
const isBlack = grayscaleValue < threshold;
const pixelBit = isBlack ? 0 : 1;
lineData.push(pixelBit);
// Once we have 8 pixels (1 byte), convert to a byte and push to the ESC/POS array
if (lineData.length === 8) {
const byteValue = lineData.reduce((byte, bit, index) => byte | (bit << (7 - index)), 0);
escposArray.push(byteValue);
lineData = [];
}
}
// If there are remaining bits in the line, pad with zeros and convert to a byte
if (lineData.length > 0) {
while (lineData.length < 8) {
lineData.push(0);
}
const byteValue = lineData.reduce((byte, bit, index) => byte | (bit << (7 - index)), 0);
escposArray.push(byteValue);
}
}
return escposArray;
}
// Example usage
const imageWidth = 384; // Width of the ESC/POS paper
const imageData = {
// Replace with actual image data or load from a source
width: /* image width */,
height: /* image height */,
data: /* image pixel data */,
};
const escposByteArray = convertBitmapToESCPOS(imageData, imageWidth);
console.log(escposByteArray);