将存储RGBA格式的Uint8Array数组保存为.png文件

4
我目前正在尝试将ThreeJS特定区域的截图保存到文件中。迄今为止,我只尝试将图像显示到新标签页中,并已通过以下方式使其正常工作。
window.open(renderer.domElement.toDataURL("image/png"));

renderer是一个带有preserveDrawingBuffer: true属性的THREE.WebGLRenderer对象。

但是它使用整个场景,所以我已经切换到:

    var gl = renderer.getContext();
    var pixels = new Uint8Array(width * height * 4);
    gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
    window.open("data:image/png;base64," + btoa(String.fromCharCode.apply(null, pixels)));

这样做的话,除了一个带灰色轮廓的方块,没有别的东西被渲染出来。

带有灰色轮廓的方块

2个回答

5
在意识到数据不符合PNG的正确格式之后,找到了一个解决方案。
    var gl = renderer.getContext();
    var pixels = new Uint8Array(width * height * 4);
    gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);

    var canvas = document.createElement('canvas');
    var ctx = canvas.getContext("2d");
    var imageData = ctx.createImageData(width, height);

    for(var i = 0; i < imageData.data.length; i+=4) {
        imageData.data[i + 0] = pixels[i + 0];
        imageData.data[i + 1] = pixels[i + 1];
        imageData.data[i + 2] = pixels[i + 2];
        imageData.data[i + 3] = pixels[i + 3];
    }

    ctx.putImageData(imageData,0,0);
    window.open(canvas.toDataURL("image/png"));
    canvas.remove();

这不是最好的方式,但它起作用了。


3
由于您只是复制整个数组,因此无需逐个复制像素。一个简单的循环 for (var i = 0; i < pixels.length; ++i) { imageData.data[i] = pixels[i]; } 就可以工作。 - gman

0
如果你只想获取它的一个小部分,而不是调用gl.readPixels函数,那么你可以直接使用drawImage函数中的源图像宽度和高度参数。
var gl = renderer.getContext();

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

ctx.canvas.width = width;
ctx.canvas.height = height;

ctx.drawImage(gl.canvas, 0, 0, width, height, 0, 0, width, height);

window.open(ctx.canvas.toDataURL());

drawImage 的 3 个版本:

  1. drawImage(image, dstX, dstY)

  2. drawImage(image, dstX, dstY, dstWidth, dstHeight)

  3. drawImage(image, srcX, srcY, srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接