如何将 BitmapData 从 Flash 转换为 canvas HTML?

How to convert BitmapData from Flash to canvas HTML?

我遇到了一个相当严重的问题。我正在将 Flash 重写为 JS,运行 导致 SOAP returned 数据处理出现问题。它是关于我以字符串形式获取的图像,并将其转换为 Flash 中使用的 BitmapData。 我尝试了很多不同的方法,但充其量只能得到一张在 canvas 上带有噪点的绿色图像。以下是您可能会觉得有用的所有代码片段

来自 Flash 的代码:

        private function encode(bitmap:Bitmap):ByteArray{
            var encoder:JPGEncoder = new JPGEncoder(QUALITY);
            return encoder.encode(bitmap.bitmapData);
        }

        public function decodeBytes(bm:Bitmap):void{
            _bitmap = bm;
            _bytesData = encode(_bitmap);
            var imgConventer:ArrayDataConventer = new ArrayDataConventer();
            imgConventer.addEventListener(ImageConvertCompleteEvent.IMAGE_CONVERT_COMPLETE, convertCompleteHandler);
            imgConventer.decByteArrToHexStr(bytesData);
        }   

decByteArrToHexStr return 字符串,其中两个十六进制字符表示字节。当我想获取它时,这个字符串被推送到 SOAP 和它的 returned。这是Flash部分。

现在我想把这个字符串转换成我可以放入 canvas 的图像数据。

我有方法将字符串转换为 Uint8Array。

  public hexStrToDecByteArr(str: string): Uint8Array {
    const byteArr: Uint8Array = new Uint8Array(str.length / 2);

    for (let i: number = 0; i < str.length; i = i + 2) {
      const n: number = parseInt('0x' + str.substr(i, 2), 0);

      if (!isNaN(n)) {
        byteArr[i] = n;
      }
    }

    return data;
  }

然后在响应处理程序中我有这样的东西:

const decodes: ArrayDataConverter = new ArrayDataConverter();
        const data = decodes.hexStrToDecByteArr(downloadedImage.sData);
        const encoder: any = new JPGEncoder(100);
        const encoded = encoder.encode({width: 400, height: 300, data});

        const context = this.canvas.nativeElement.getContext('2d');
        context.clearRect(0, 0, 400, 300);

        const image = new Image();
        image.onload = () => {
          context.drawImage(image, 0, 0);
        };
        image.src = encoded;

所以 downloadedImage.sData 包含十六进制字符串。 JPGEncoder 是我找到的包,是 JPGEncoder Flash 版本重写为 JS (https://www.npmjs.com/package/@koba04/jpeg-encoder).

正如我之前提到的,我在 canvas 上得到了带有一些噪点的绿色图像。

提前致谢。

看起来您正在使用 JPEG 压缩来压缩实际像素颜色(原始位图数据),然后尝试将相同的 JPEG 数据加载到 HTML5 canvas?

这种方法行不通,因为 Canvas 需要像素颜色值而不是 JPEG 压缩算法。

可能的修复 #1:将 AS3 像素值用于 Canvas...

在您的 AS3 代码中,不要编码为 JPEG,而是将像素值写为十六进制字符串(来自数组)。

public function decodeBytes(bm:Bitmap):void
{
    //# get pixel values into an array named: _bytesData
    bm.bitmapData.copyPixelsToByteArray( bm.bitmapData.rect, _bytesData );
    
    var imgConventer:ArrayDataConventer = new ArrayDataConventer();
    imgConventer.addEventListener(ImageConvertCompleteEvent.IMAGE_CONVERT_COMPLETE, convertCompleteHandler);
    imgConventer.decByteArrToHexStr( _bytesData );
}

然后在 TypeScript(或 JavaScript)端将接收到的数据读入 array/buffer.

要在 (HTML5) Canvas 中显示图像,您必须使用 for-loop 来读取数组

var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var imgData = ctx.createImageData( canvas.width, canvas.height );

//# notice the order is:
//# JS imagedata = R-G-B-A
//# AS3 bitmap   = A-R-G-B

for (var i=0; i < imgData.data.length; i += 4)
{
    imgData.data[i + 0] = downloadedImage.sData[i + 1]; //put RED
    imgData.data[i + 1] = downloadedImage.sData[i + 2]; //put GREEN
    imgData.data[i + 2] = downloadedImage.sData[i + 3]; //put BLUE
    imgData.data[i + 3] = downloadedImage.sData[i + 0]; //put ALPHA
}

//# Update canvas with the image data
ctx.putImageData(imgData,0,0);

这应该会在您网页的 Canvas 中显示您的图片(其中有 idmyCanvas)。

可能的修复 #2:在数组中使用 JPEG 数据...

由于上述发送原始位图数据的方法可能意味着您正在发送一个大文件,您可以尝试使用 JPEG 压缩,这种方式意味着您可以将 JPEG 数组直接加载到 <Image> 标记中就像加载的文件一样。

无需对 JPEG 进行两次编码(第一次在 AS3 中,然后在 TypeScript 中再次编码,这只会破坏您的图像数据)

(1) 首先像在原始 AS3 代码中一样创建 JPEG,然后 (2) 在 TypeScript 或 HTML 端,检查提供给您的前 3 个值(使用 alertconsole.log 选项)...

downloadedImage.sData[0] //should be: 0xFF (or 255)
downloadedImage.sData[1] //should be: 0xD8 (or 216)
downloadedImage.sData[2] //should be: 0xFF (or 255)

这 3 个值是 JPEG header 的正确和预期的开始字节(它表明您的数据确实是一个有效的 JPEG 图像)。

在你的 HTML 的 <body> 部分,确保你有一个 <image> 标签,等待字节图像被添加为 .src...

<body>

<img id="myPic" src="none.jpg" width="600" height="400">

</body>

然后在JavaScript(我不会TypeScript所以这部分你自己转换)

<script>

//# downloadedImage.sData String must look like "0xFF,0xD8,0xFF" etc (using 0xFF or 0xff is same result)
var myArr = new Uint8Array( [ downloadedImage.sData ] );

var blob = new Blob( [downloadedImage.sData], { type: "image/jpeg" } );
var urlCreator = window.URL || window.webkitURL;
var imageUrl = urlCreator.createObjectURL( blob );
var img = document.getElementById( "myPic" );
img.src = imageUrl;

</script>

希望这对获得工作结果有用。

PS:一些完整的可测试示例代码(仅 HTML/JS,无 TypeScript)...

<!DOCTYPE html>
<html>
<body>

<img id="myPic" src="none.jpg" width="600" height="400">

</body>

<script>

//# fill the array properly & fully, below is just small example of expected values
var myArr = new Uint8Array( [0xFF,0xD8,0xFF,0xE0,0x00 ... 0xFF,0xD9]);

var blob = new Blob( [myArr], { type: "image/jpeg" } );
var urlCreator = window.URL || window.webkitURL;
var imageUrl = urlCreator.createObjectURL( blob );
var img = document.getElementById( "myPic" );
img.src = imageUrl;

</script>

</html>