用JavaScript从HTML画布创建1位图。

5

我需要从HTML5 Canvas中获取一个1位的位图。

该画布是黑白的。 然而,我只能使用png/jpeg输出的toUrlData()函数,但找不到任何生成位图(并将颜色深度更改为1位)的方法。

是否有任何可用的解决方案来进行此类型的转换? 或者,是否有一个javascript库可以写入位图图像?

3个回答

12

转换为1位

Canvas没有内置机制允许您保存1位图像。Canvas是32位(24位颜色,8位 alpha),这将需要使用一种公共算法来降级图像(这很可能是为什么您无法从中保存 GIF 文件,只能使用支持 24 位或更多的格式)。

为此,您需要深入了解并使用Typed 数组构建自己的文件格式。

如果1位文件格式不是绝对要求,即您希望图像看起来像是 1 位,那么您可以简单地自己转换内容。

您可以使用此方法将图像转换为“1位”,通过将 RGB 转换为亮度值并使用阈值确定它是否应该是“on”或“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>

转换成1位

将其保存为BMP文件(24位,不适用于所有浏览器):

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

此外,还可以查看这个答案中介绍的如何构建和编写BMP格式文件。

你也可以使用这种方法来进行低级别的操作,通过使用此结果来打包位(每8个“位”需要打包成一个字节,对于BMP格式是小端)。

如有需要,还可以了解更简单的TrueVision TGA文件格式或者TIFF文件格式,后者还允许您使用大端字节(大多数TIFF格式都可以被浏览器读取)。


这里有一个更新的fiddle,没有破损的依赖。 - Jackson
1
感谢 @Jackson 的付出(以及提醒过时的代码)。我决定改为内联代码,这在原回答编写时不是一种选择,同时也稍微改进了一下整个回答(无意冒犯)。 - user1693593

2
你可以使用像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");
}

如果你选择这种方法,可能需要查找一些 ArrayBufferDataView 相关的信息。


0
如果你真的需要图像为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);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接