简体   繁体   English

Uint8Array 到 JavaScript 中的图像

[英]Uint8Array to image in JavaScript

I have Uint8Array named frameBytes.我有名为 frameBytes 的 Uint8Array。 I have created RGBA values from this byte array with this code.我已经用这段代码从这个字节数组中创建了 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 
    }

Then I have shown this GRBA values to canvas using the following code .然后我使用以下代码将此 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);

After that from canvas I used to image in image tag using the following code:在那之后,我曾经使用以下代码在画布中对图像标记进行图像处理:

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

But I do not want to use canvas.但我不想使用画布。 I want to show image in image tag from Uint8Array directly.我想直接在 Uint8Array 的图像标签中显示图像。 How can I do that?我怎样才能做到这一点? Any help will be highly appreciated.任何帮助将不胜感激。

I want to show image in image tag from Uint8Array directly我想直接在 Uint8Array 的图像标签中显示图像

This is very simple using a Blob:使用 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: <img id="my-img">

(1) It also works without specifying the Blob MIME type. (1) 它也可以在不指定 Blob MIME 类型的情况下工作。

I think you can make an ImageData directly, from the example on that page:我认为您可以从该页面上的示例中直接制作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);

Unfortunately there does not seem to be any way to display an ImageData in an <img> element, only in a <canvas> .不幸的是,似乎没有任何方法可以在<img>元素中显示ImageData ,只能在<canvas> <img> requires an actual image file. <img>需要一个实际的图像文件。

Fortunately the BMP format is widely supported and supports raw RGBA data.幸运的是,BMP 格式得到了广泛的支持,并且支持原始 RGBA 数据。 You just need to prepend an appropriate BMP header.您只需要在前面添加一个适当的 BMP 标头。 Once that is done you can pass your data to the <img> using the technique outlined by Ben Fortune.完成后,您可以使用 Ben Fortune 概述的技术将数据传递到<img> I would NOT use a data: URL even though you find people all over the web using it.不会使用data: URL,即使你发现网上到处都有人在使用它。 It is needlessly inefficient.这是不必要的低效。

Here's some example code.这是一些示例代码。 It appends the pixel data to the bitmap header in a single buffer since that will be more efficient.它将像素数据附加到单个缓冲区中的位图标头,因为这样会更有效率。 If you already have the data you could create a separate Uint8Array just for the header and concatenate them in the Blob constructor, ie new Blob([header, pixels]) .如果您已经拥有数据,您可以为标头创建一个单独的Uint8Array并将它们连接到Blob构造函数中,即new Blob([header, pixels]) I haven't tried that.我没试过。

 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;
 <img id="i">

A big caveat is that this RGBA variant of BMP is not widely supported at all.一个很大的警告是,这种 BMP 的 RGBA 变体根本没有得到广泛支持。 Chrome seems to support it. Chrome 似乎支持它。 Firefox doesn't, nor does Apple's finder. Firefox 没有,Apple 的 finder 也没有。 If you're writing an Electron app it should be fine but I wouldn't use it on the web.如果您正在编写 Electron 应用程序,那应该没问题,但我不会在网络上使用它。

However, since you have set alpha to 255 I'm guessing you don't even need the alpha channel.但是,由于您已将 alpha 设置为 255,我猜您甚至不需要 alpha 通道。 In that case you can use BI_RGB instead:在这种情况下,您可以改用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;
 <img id="i">

In the above example I still use 32 BPP, but because I set the compression to BI_RGB the alpha channel is ignored.在上面的示例中,我仍然使用 32 BPP,但是因为我将压缩设置为BI_RGB ,所以忽略了 alpha 通道。 This is a bit wasteful of memory.这有点浪费内存。 You can set it to 24 BPP instead and then only use 3 bytes per pixel, but the caveat is each row has to be padded to up to a multiple of 4 bytes, which I couldn't be bothered to do here.您可以将其设置为24 BPP ,然后每个像素只使用 3 个字节,但需要注意的是,每一行都必须填充到最多 4 个字节的倍数,我不能在这里费心去做。

You can create a Blob if you know the mimetype. 如果您知道模仿类型,则可以创建一个Blob

const blob = new Blob(imgData.data, 'image/png');
const url = window.URL.createObjectURL(blob);

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

I belive you can use the btoa function, which would create a base64 ASCII representation of the image data..我相信您可以使用 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));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM