【问题标题】:Uint8Array to image in JavaScriptUint8Array 到 JavaScript 中的图像
【发布时间】:2020-12-08 00:10:13
【问题描述】:

我有一个名为 frameBytes 的 Uint8Array。我已经用这段代码从这个字节数组中创建了 RGBA 值。

    for (var i = 0; i < frameBytes.length; i++) {
        imgData.data[4 * i] = frameBytes[i];// red
        imgData.data[4 * i + 1] = frameBytes[i]; // green
        imgData.data[4 * i + 2] = frameBytes[i];// blue
        imgData.data[4 * i + 3] = 255; // alpha 
    }

然后我使用以下代码将这个 GRBA 值显示到画布上。

var ctx = fingerFrame.getContext('2d');
var imgData = ctx.createImageData(fingerFrame.width, fingerFrame.height);
ctx.putImageData(imgData, 0, 0, 0, 0, fingerFrame.width, fingerFrame.height);

在画布之后,我使用以下代码在图像标签中成像:

 const img = document.getElementById('i');  
 img.src = fingerFrame.toDataURL(); 

但我不想使用画布。我想直接在 Uint8Array 的图像标签中显示图像。我怎样才能做到这一点?任何帮助将不胜感激。

【问题讨论】:

  • 你为什么不想使用画布呢?这是最直接的方法。其他方式都涉及您使用能够从您的 RGBA 值编码为图像格式的外部脚本,即它必须完全构建图像文件。
  • 你能给我举个例子吗?
  • “那个”是什么?构建自己的 PNG 编码器?哼,不。 Specs for png are herepako.js 可能也会帮助你,但我能为你做的就是这些了。如果你的意思是用画布做的例子,那么jsfiddle.net/9ggpqzL0
  • 我知道这是一篇旧帖子,但对任何人都可能有所帮助:看看这个很好的utility。这是一个可以复制的简单代码块。你可以这样使用它:var base64image = "data:image/png;base64,"+ bytesToBase64(data) 确保 mimetype image/png 是正确的(你必须弄清楚)。

标签: javascript image canvas base64


【解决方案1】:

我想直接在 Uint8Array 的图像标签中显示图像

使用 Blob 非常简单:

// Small red dot image
const content = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 5, 0, 0, 0, 5, 8, 6, 0, 0, 0, 141, 111, 38, 229, 0, 0, 0, 28, 73, 68, 65, 84, 8, 215, 99, 248, 255, 255, 63, 195, 127, 6, 32, 5, 195, 32, 18, 132, 208, 49, 241, 130, 88, 205, 4, 0, 14, 245, 53, 203, 209, 142, 14, 31, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130]);

document.getElementById('my-img').src = URL.createObjectURL(
  new Blob([content.buffer], { type: 'image/png' } /* (1) */)
);
Should display a small red dot: &lt;img id="my-img"&gt;

(1) 它也可以在不指定 Blob MIME 类型的情况下工作。

【讨论】:

    【解决方案2】:

    我认为您可以直接从该页面上的示例中创建ImageData

    const arr = new Uint8ClampedArray(40000);
    
    // Iterate through every pixel
    for (let i = 0; i < arr.length; i += 4) {
      arr[i + 0] = 0;    // R value
      arr[i + 1] = 190;  // G value
      arr[i + 2] = 0;    // B value
      arr[i + 3] = 255;  // A value
    }
    
    // Initialize a new ImageData object
    let imageData = new ImageData(arr, 200);
    

    不幸的是,似乎没有任何方法可以在&lt;img&gt; 元素中显示ImageData,只能在&lt;canvas&gt; 中显示。 &lt;img&gt; 需要一个实际的图像文件。

    幸运的是,BMP 格式得到广泛支持,并支持原始 RGBA 数据。您只需要预先添加一个适当的 BMP 标头。完成后,您可以使用 Ben Fortune 概述的技术将您的数据传递给&lt;img&gt;。我会使用data: URL,即使您发现网络上的人都在使用它。这是不必要的低效。

    这是一些示例代码。它将像素数据附加到单个缓冲区中的位图标头,因为这样会更有效。如果您已经拥有数据,您可以为标题创建一个单独的Uint8Array,并将它们连接到Blob 构造函数中,即new Blob([header, pixels])。我没试过。

    const header_size = 70;
    
    const width = 255;
    const height = 255;
    const image_size = width * height * 4;
    
    const arr = new Uint8Array(header_size + image_size);
    const view = new DataView(arr.buffer);
    
    // File Header
    
    // BM magic number.
    view.setUint16(0, 0x424D, false);
    // File size.
    view.setUint32(2, arr.length, true);
    // Offset to image data.
    view.setUint32(10, header_size, true);
    
    // BITMAPINFOHEADER
    
    // Size of BITMAPINFOHEADER
    view.setUint32(14, 40, true);
    // Width
    view.setInt32(18, width, true);
    // Height (signed because negative values flip
    // the image vertically).
    view.setInt32(22, height, true);
    // Number of colour planes (colours stored as
    // separate images; must be 1).
    view.setUint16(26, 1, true);
    // Bits per pixel.
    view.setUint16(28, 32, true);
    // Compression method, 6 = BI_ALPHABITFIELDS
    view.setUint32(30, 6, true);
    // Image size in bytes.
    view.setUint32(34, image_size, true);
    // Horizontal resolution, pixels per metre.
    // This will be unused in this situation.
    view.setInt32(38, 10000, true);
    // Vertical resolution, pixels per metre.
    view.setInt32(42, 10000, true);
    // Number of colours. 0 = all
    view.setUint32(46, 0, true);
    // Number of important colours. 0 = all
    view.setUint32(50, 0, true);
    
    // Colour table. Because we used BI_ALPHABITFIELDS
    // this specifies the R, G, B and A bitmasks.
    
    // Red
    view.setUint32(54, 0x000000FF, true);
    // Green
    view.setUint32(58, 0x0000FF00, true);
    // Blue
    view.setUint32(62, 0x00FF0000, true);
    // Alpha
    view.setUint32(66, 0xFF000000, true);
    
    // Pixel data.
    for (let w = 0; w < width; ++w) {
      for (let h = 0; h < height; ++h) {
        const offset = header_size + (h * width + w) * 4;
        arr[offset + 0] = w;     // R value
        arr[offset + 1] = h;     // G value
        arr[offset + 2] = 255-w; // B value
        arr[offset + 3] = 255-h; // A value
      }
    }
    
    const blob = new Blob([arr], { type: "image/bmp" });
    const url = window.URL.createObjectURL(blob);
    
    const img = document.getElementById('i');
    img.src = url;
    &lt;img id="i"&gt;

    一个重要的警告是,这种 BMP 的 RGBA 变体根本没有得到广泛支持。 Chrome似乎支持它。 Firefox 没有,Apple 的 finder 也没有。如果您正在编写一个 Electron 应用程序,那应该没问题,但我不会在网络上使用它。

    但是,由于您已将 alpha 设置为 255,我猜您甚至不需要 alpha 通道。在这种情况下,您可以改用BI_RGB

        const header_size = 54;
    
        const width = 255;
        const height = 255;
           
        const image_size = width * height * 4;
    
        const arr = new Uint8Array(header_size + image_size);
        const view = new DataView(arr.buffer);
    
        // File Header
    
        // BM magic number.
        view.setUint16(0, 0x424D, false);
        // File size.
        view.setUint32(2, arr.length, true);
        // Offset to image data.
        view.setUint32(10, header_size, true);
    
        // BITMAPINFOHEADER
    
        // Size of BITMAPINFOHEADER
        view.setUint32(14, 40, true);
        // Width
        view.setInt32(18, width, true);
        // Height (signed because negative values flip
        // the image vertically).
        view.setInt32(22, height, true);
        // Number of colour planes (colours stored as
        // separate images; must be 1).
        view.setUint16(26, 1, true);
        // Bits per pixel.
        view.setUint16(28, 32, true);
        // Compression method, 0 = BI_RGB
        view.setUint32(30, 0, true);
        // Image size in bytes.
        view.setUint32(34, image_size, true);
        // Horizontal resolution, pixels per metre.
        // This will be unused in this situation.
        view.setInt32(38, 10000, true);
        // Vertical resolution, pixels per metre.
        view.setInt32(42, 10000, true);
        // Number of colours. 0 = all
        view.setUint32(46, 0, true);
        // Number of important colours. 0 = all
        view.setUint32(50, 0, true);
    
        // Pixel data.
        for (let w = 0; w < width; ++w) {
          for (let h = 0; h < height; ++h) {
            const offset = header_size + (h * width + w) * 4;
            arr[offset + 0] = w;     // R value
            arr[offset + 1] = h;     // G value
            arr[offset + 2] = 255-w; // B value
            // arr[offset + 3] is ignored but must still be present because we specified 32 BPP
          }
        }
    
        const blob = new Blob([arr], { type: "image/bmp" });
        const url = window.URL.createObjectURL(blob);
    
        const img = document.getElementById('i');
        img.src = url;
    &lt;img id="i"&gt;

    在上面的示例中,我仍然使用 32 BPP,但是因为我将压缩设置为BI_RGB,所以忽略了 alpha 通道。这有点浪费内存。您可以将其设置为 24 BPP ,然后每个像素只使用 3 个字节,但需要注意的是每行必须填充到最多 4 个字节的倍数,我在这里懒得做。

    【讨论】:

      【解决方案3】:

      我相信你可以使用 btoa 函数,它会创建图像数据的 base64 ASCII 表示。

       const img = document.getElementById('i');  
      
       //ImageDataArrayBuffer is your uint8 Array Buffer
       img.src =  "data:image/png;base64,"+ btoa(String.fromCharCode.apply(null, ImageDataArrayBuffer));
      

      【讨论】:

      • 您需要预先添加数据 URL data:image/png;base64,
      • uint8Array OP 仅包含 RGBA 值,它不是 png 文件(没有标题、未压缩数据等)。您的解决方案将不起作用。
      猜你喜欢
      • 2019-01-22
      • 2017-09-15
      • 2021-08-30
      • 2012-02-14
      • 1970-01-01
      • 1970-01-01
      • 2021-06-19
      • 1970-01-01
      • 2021-05-10
      相关资源
      最近更新 更多