Javascript:将存储为Uint8Array的PNG呈现到画布元素上,而不使用数据URI

Javascript:将存储为Uint8Array的PNG呈现到画布元素上,而不使用数据URI,javascript,html5-canvas,Javascript,Html5 Canvas,我正在尝试渲染存储在javascriptUint8Array中的PNG图像。我最初尝试的代码如下: var imgByteStr = String.fromCharCode.apply(null, this.imgBytes); var pageImg = new Image(); pageImg.onload = function(e) { // Draw onto the canvas canvasContext.drawImage(pageImg, 0, 0); };

我正在尝试渲染存储在javascript
Uint8Array
中的PNG图像。我最初尝试的代码如下:

var imgByteStr = String.fromCharCode.apply(null, this.imgBytes);

var pageImg = new Image();
pageImg.onload = function(e) {

    // Draw onto the canvas
    canvasContext.drawImage(pageImg, 0, 0);

};

// Attempt to generate the Data URI from the binary
// 3rd-party library adds toBase64() as a string function
pageImg.src="data:image/png;base64,"+encodeURIComponent(imgByteStr.toBase64());
然而,我发现出于某种原因,onload函数从未运行过(我在chrome中设置了断点,它根本就没有运行)。我发现,如果我将src设置为URL而不是数据URI,那么它工作正常。但是,由于一些限制,我无法直接引用图像的URL,即必须从
UInt8Array
加载图像

此外,更复杂的是,这些图像的大小可能是兆字节。从我所读到的内容来看,尝试对非常大的图像使用数据URI存在兼容性问题。因此,我非常犹豫是否要利用它们

因此,问题是如何在不使用数据URI或直接引用图像URL的情况下,将此字节数组作为PNG呈现到画布上下文中


我还尝试使用以下类似的方法直接使用
putImageData
函数操作图像数据。请记住,我不是100%理解这个函数是如何工作的

var imgdata = canvasContext.createImageData(this.baseHeight, this.baseWidth);
var imgdatalen = imgdata.data.length;
for(var i=0; i<imgdatalen; i++) {
    imgdata.data[i] = _this.imgBytes[i];
}
canvasContext.putImageData(imgdata, 0, 0);
var imgdata=canvasContext.createImageData(this.baseHeight,this.baseWidth);
var imgdatalen=imgdata.data.length;

对于(var i=0;i如果您在内存中有PNG数据(我想这就是您所描述的),那么您可以从中创建一个图像。在HTML中,它看起来像:

 <img src="data:image/png;base64,KSjs9JdldhAlisflAkshf==" />
请注意,如果没有PNG数据,可以更改MIME类型

然后,您可以使用
context.drawImage(image,0,0)
或类似工具将
图像
绘制到画布上

因此,谜题的剩余部分是将
Uint8Array
的内容编码到Base 64数据中

var array = new Uint8Array(),
    base64Data = btoa(String.fromCharCode.apply(null, array));
btoa的功能
btoa
不是标准的,所以一些浏览器可能不支持它。但是看起来是这样的。否则你可能会觉得有用


我自己没有测试过这篇文章!

如果你已经有一个UIT8数组,你应该考虑使用<代码> BLB< <代码>和<代码> CurraseObjuturl ;分配一个特殊的URL,允许浏览器访问内部创建的二进制数据块,就好像它是一个被外部加载的文件。
createObjectURL
是巨大数据URI的一个很好的替代品。您可能仍然需要在Opera中使用数据URI,即完整的工作示例:(另存为.html文件并打开)

1:创建Uint8Array

2:用调试模式填充它

3:将其粘贴到页面上的画布元素

输出应如下所示:


U8A_至_画布
var com=4;/:4个组件(RGBA)
var-wid=512;
var-hig=512;
var tot_com=wid*hig*com;/:总成分
var u8a=新的UINT8阵列(tot_com);
拉伸模式(u8a、wid、hig);
Uint8ArrayToCanvas(u8a、wid、hig,“画布ID”);
函数Uint8ArrayToCanvas(
u8a,/:uint8阵列
wid,//:u8a数据的宽度(以像素为单位)
hig,/:u8a数据的高度(以像素为单位)
nam,//:dom上画布的名称\u id\u
){
//:获取画布:
var can=document.getElementById(nam);
如果(!can){抛出“[FailedToGetCanvas]”;}
//:获取画布的二维上下文:
var ctx=can.getContext(“2d”);
如果(!ctx){抛出“[FailedToGetContext]”;}
//:使用U8A创建图像数据对象:
var UAC=新的Uint8ClampedArray(u8a、wid、hig);
var DAT=新图像数据(UAC、wid、hig);
//:将数据粘贴到画布中:
var ORG_X=0;
var组织Y=0;
ctx.putImageData(数据、组织X、组织Y);
}
函数模式(u8a、wid、hig){
var com=4;/:RGBA==4组件。
var tot_pix=wid*hig;/:总像素
//:计算画布中心的点:
var cen_x=wid/2;
var cen_y=高/2;
//:定义圆的半径:
var rad_c=数学最小值(宽、高)/2;
//:在阵列上制作图案:
变量d=0;/:d_表示_距离
var ci=0;/:组件索引
var pi=0;/:像素索引
var px=0;/:像素X坐标
var py=0;/:像素Y坐标
对于(pi=0;pi
您是否查看了
putImageData()
?出于好奇:图像数据是如何进入数组的?@David:我已经研究了一点,但我的理解是,这是原始图像数据,而不是PNG编码的图像数据。我会给它一个解释shot@raghaw:通过异步HTTP GET请求下载。无法在此处直接引用URL的原因是因为下一个step(一旦我开始工作)是加密get请求的结果,然后在JS中解密。因此,从长远来看,图像URL根本不会返回图像,而是一个加密的二进制文件。说来话长,但我一直坚持;)我知道这可能超出了您的控制,但是重新实现浏览器对加密的现有支持似乎。。。令人沮丧的。你不能只使用HTTPS?FWIW我在浏览器中对图像数据做了一些工作,我不确定如何将编码的PNG字节转换为32位的ARGB数据。也许你
var array = new Uint8Array(),
    base64Data = btoa(String.fromCharCode.apply(null, array));
var myArray; //= your data in a UInt8Array
var blob = new Blob([myArray], {'type': 'image/png'});
var url = URL.createObjectURL(blob); //possibly `webkitURL` or another vendor prefix for old browsers.
<!DOCTYPE HTML >
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title> U8A_TO_CANVAS </title>
    <meta name   ="author" 
          content="John Mark Isaac Madison">
    <!-- EMAIL: J4M4I5M7@HOTMAIL.com           -->
</head>
<body>
<canvas id="CANVAS_ID" 
         width ="512" 
         height="512">
</canvas>
<script>

var com     =  4 ; //:4 components( RGBA )
var wid     = 512;
var hig     = 512;
var tot_com = wid*hig*com;//:total#components
var u8a     = new Uint8Array( tot_com );

DrawDebugPattern  ( u8a , wid, hig              );
Uint8ArrayToCanvas( u8a , wid, hig, "CANVAS_ID" );

function Uint8ArrayToCanvas( 
    u8a, //:uint8Array
    wid, //:width__of_u8a_data_in_pixels
    hig, //:height_of_u8a_data_in_pixels
    nam, //:name_id_of_canvas_on_dom
){

    //:Get Canvas:
    var can = document.getElementById( nam );
    if(!can){ throw "[FailedToGetCanvas]"; }

    //:Get Canvas's 2D Context:
    var ctx = can.getContext("2d");
    if(!ctx){ throw "[FailedToGetContext]"; }

    //:Use U8A to create image data object:    
    var UAC = new Uint8ClampedArray( u8a,wid,hig);
    var DAT = new ImageData(UAC, wid, hig);

    //:Paste Data Into Canvas:     
    var ORG_X = 0;                         
    var ORG_Y = 0;                         
    ctx.putImageData( DAT, ORG_X, ORG_Y );  
}

function DrawDebugPattern(u8a,wid,hig){

    var com     = 4      ; //:RGBA==4components.
    var tot_pix = wid*hig;//:total#pixels

    //:Calculate point in center of canvas:
    var cen_x = wid/2;
    var cen_y = hig/2;

    //:Define a circle's radius:
    var rad_c = Math.min(wid,hig) / 2;

    //:Make a pattern on array:
    var d   = 0; //:d_is_for_distance
    var ci  = 0; //:Component_Index
    var pi  = 0; //:Pixel_Index
    var px  = 0; //:Pixel_X_Coord
    var py  = 0; //:Pixel_Y_Coord
    for( pi = 0; pi < tot_pix; pi++ ){

        //:Calculate index of first component
        //:of current pixel:
        ci = pi * com;

        //:Index_To_XY_Formula:
        px =  pi    % wid ;
        py = (pi-px)/ wid ;

        //:Decide if pixel is inside circle:
        var dx = (cen_x-px); //:delta_x
        var dy = (cen_y-py); //:delta_y
        d=Math.sqrt( (dx*dx)+(dy*dy) );
        if( d < rad_c ){
            //:INSIDE_CIRCLE:
            u8a[ ci + 0 ] = 0  ; //:Red
            u8a[ ci + 1 ] = 255; //:Green
            u8a[ ci + 2 ] = 0  ; //:Blue
            u8a[ ci + 3 ] = 255; //:Alpha
        }else{
            //:OUTSIDE_CIRCLE:
            u8a[ ci + 0 ] = 0  ; //:Red
            u8a[ ci + 1 ] = 0  ; //:Green
            u8a[ ci + 2 ] = 64 ; //:Blue
            u8a[ ci + 3 ] = 255; //:Alpha
        }

    }
}
</script>
</body>
<!-- In IE: Script cannot be outside of body.  -->
</html>