【问题标题】:How to convert the raw image byte array to PNG image using Javascript如何使用 Javascript 将原始图像字节数组转换为 PNG 图像
【发布时间】:2019-11-08 03:47:09
【问题描述】:

我有一个原始图像(.raw 格式,没有任何图像标题),我想将其转换为 PNG 格式以显示在画布上。我尝试将原始图像转换为 RGBA 并且它成功(通过操作字节并在画布中使用 ImageData API)。现在我需要将原始图像转换为 PNG。

我试过了,

  1. 从响应中获取图像并创建数组缓冲区
  2. 创建图像arraybuffer 的UInt8Array。
  3. 将其转换为base64:png 内容

谁能帮帮我?

我尝试了在互联网上找到的多种解决方案,但没有一个适合我。

  1. 创建一个 blob 并使用它构造一个对象 URL 并在画布上显示 - 无效
  2. 将 PNG 图像标题添加到字节数组并显示在画布上。

    fetch(image.src).then(resp => {  // load from original source
      return resp.arrayBuffer();
      //return resp.blob();      // obtain a blob
    }).then(arrayBuffer => {
      let int8array = new Uint8Array(arrayBuffer);
      let base64content = this.arrayBufferToBase64(int8array.buffer);
      let newImg = document.createElement('img');
      newImg.src = 'data:image/png;base64,' + base64content;
      this.context.drawImage(newImg, 0, 0);
    });
    
    arrayBufferToBase64( buffer ) {
    let binary = '';
    let bytes = new Uint8Array( buffer );
    var len = bytes.byteLength;
    for (let i = 0; i < len; i++) {
        binary += String.fromCharCode( bytes[ i ] );
    }
    return window.btoa( binary );
    }
    

    我希望结果是在画布上绘制 png 图像,但我看到的是空画布。

  3. 我还尝试将PNG图像标题直接添加到图像的bytearray内容

    fetch(image.src).then(resp => {
          return resp.arrayBuffer();
        }).then(arrayBuffer => {
          let int8array = new Uint8Array(arrayBuffer);
          let signature = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]);
          let newArray = new Uint8Array(int8array.length + signature.length);
          newArray.set(signature);
          newArray.set(int8array, signature.length);
          const imgData = this.uint8ToImageData(newArray, 500, 500);
          this.context.putImageData(imgData, 0, 0);
     });
     uint8ToImageData(uint8, width, height) {
          let iData = this.context.createImageData(width, height);
          for (let i = 0; i < uint8.length; i++) {
            iData.data[i] = uint8[i];
          }
          return iData;
      }

我至少可以看到画布上显示的图像,但与原始图像不同。

【问题讨论】:

  • 图片与原图有何不同?
  • 像素好像有不同的值,所以外观看起来有不同的颜色,但有相同的原始图像痕迹。
  • 好的,但是如果您使用我发布的代码,是否会为您提供 PNG 数据 url,即使它不起作用?如果是这样,问题只是调试代码的问题。如果您编辑以包含原始版本和画布版本的屏幕截图,这可能会更容易。
  • 是的,我可以看到带有您的代码的 PNG 数据 URL。关于截图,我不能在这里发布,因为它是我公司内部的。
  • 好的,很公平。不过,在#3 的代码中,我发现在使用 putImageData 之前将 PNG 签名添加到原始图像数据中很奇怪,因为您实际上在做的是绘制 2 个像素(4 个字节/像素)的PNG 签名到画布上,然后未对齐图像的其余部分。我将从删除签名开始,因为您不是在写入实际的 PNG 文件,而是在画布上。

标签: javascript angular html5-canvas


【解决方案1】:

如果您有 RGBA 数组格式的图像并且可以将其打印到画布上,您可以简单地使用 canvas.toDataURL() 来获取像 "data:image/png;base64,ABCDEFG..." 这样的 PNG 字符串

我知道canvas.toDataURL 的唯一限制是,如果您从另一个站点直接在画布上加载图像(即通过ctx.drawImage),它会将画布置于“损坏”状态,因此您无法访问图像(这可能只适用于访问ImageData API)。但是,如果您远程加载原始图像数据并使用ImageData API,我认为它不会被触发,因此以下示例应该可以工作:

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

canvas.width = 200;
canvas.height = 150;

ctx.fillStyle = 'lightblue';
ctx.fillRect(0, 0, canvas.width, canvas.height)

ctx.fillStyle = 'blue';
ctx.fillText('Testing', canvas.width/2 - 20, canvas.height/2);

document.getElementById('dump').innerText = canvas.toDataURL();
#canvas {
  border: 1px solid black;
}
<canvas id='canvas'></canvas>
<p>As you can see the textarea has the PNG data url of the canvas</p>
<textarea id='dump'></textarea>

【讨论】:

  • 但是我在本地有原始格式的图像。我尝试使用原始问题代码中的函数将其转换为base64content。此外,在使用图像数据创建 blob 并将其绘制在画布上之后,我已经尝试过使用 URL.createObjectURL() 方法。但是这两种方法都没有给出输出。
  • @Arun,抱歉,我阅读了"I tried to convert the raw image to RGBA and it was successful(by manipulating the bytes and using ImageData API in canvas). Now I need to convert the raw image to PNG",并认为您的意思是您已经设法使用 ImageData 将图像绘制到画布上,只需将画布转换为 PNG。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多