使用 Uint32Array 的画布:正在呈现错误的颜色 [英] Canvas using Uint32Array: Wrong colors are being rendered

查看:19
本文介绍了使用 Uint32Array 的画布:正在呈现错误的颜色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在创建一个 JS 画布,我想在其中显示一个不同颜色的框.

我使用 uint32 来提高速度,但我的颜色永远无法正确显示!我主要在这里查看了示例:

但小提琴显示黄色:

其他颜色也一样,先谢谢了!

感谢@Oriol 的快速回答!我使用以下函数来反转我的颜色(以防有人感兴趣):

function reverseUint32 (uint32) {var s32 = new Uint32Array(4);var s8 = new Uint8Array(s32.buffer);var t32 = new Uint32Array(4);var t8 = new Uint8Array(t32.buffer);reverseUint32 = 函数 (x) {s32[0] = x;t8[0] = s8[3];t8[1] = s8[2];t8[2] = s8[1];t8[3] = s8[0];返回 t32[0];}返回 reverseUint32(uint32);};

像这样使用:reverseUint32(0xfc66feff)

解决方案

当您将 Uint8Array 缓冲区视为小端中的 Uint32 时会发生这种情况:

var buf = new Uint8Array([0x12, 0x34, 0x56, 0x78]).buffer;console.log(new Uint32Array(buf)[0].toString(16));//"78563412" 小端,"12345678" 大端

所以在小端中,顺序变成了 AABBGGRR 而不是 AARRGGBB.

您可以将 0x80d7ffff 反转为 0xffffd780,但这样就无法在大端机器上运行了.

为了避免这些问题,您可以使用 DataView,它允许指定字节序,默认为大字节序:

view.setUint32(offset, 0xffffd780, true);//#80d7ff,小端view.setUint32(offset, 0x80d7ffff, false);//#80d7ff,大端

var canvas = document.getElementById('canvas'),canvasWidth = canvas.width,canvasHeight = canvas.height,ctx = canvas.getContext('2d'),imageData = ctx.getImageData(0, 0, canvasWidth, canvasHeight),view = new DataView(imageData.data.buffer);for (var y = 0; y < canvasHeight; ++y) {for (var x = 0; x 

<canvas id="canvas" height="256" width="256"></canvas>

但是好像浏览器对DataView的优化不多,所以很慢.那么最好在Uint8ClampedArray中单独设置颜色分量:

var canvas = document.getElementById('canvas'),canvasWidth = canvas.width,canvasHeight = canvas.height,ctx = canvas.getContext('2d'),imageData = ctx.getImageData(0, 0, canvasWidth, canvasHeight),数据 = imageData.data;for (var y = 0; y < canvasHeight; ++y) {for (var x = 0; x 

<canvas id="canvas" height="256" width="256"></canvas>

I'm currently creating a JS canvas where I want to display a box of different colors.

I'm using uint32 for extra speed, and my colors never display correctly! I've looked at the examples mainly over here: https://stackoverflow.com/a/19502117 where someone said in the comments:

(small I or JS will throw an error). Tip for OP: colors for Uint32 can also be given simply be using hex - no need to do shifting: 0xff00000 = black + alpha set to 255; for little-endian/LSB CPUs, opposite on big-endian/MSB CPUs."

I'm certain my laptop is little-endian.

I have a demo of my issue here: http://jsfiddle.net/GhwUC/357/

var canvas = document.getElementById('canvas');
var canvasWidth  = canvas.width;
var canvasHeight = canvas.height;
var ctx = canvas.getContext('2d');
var imageData = ctx.getImageData(0, 0, canvasWidth, canvasHeight);

var buf = new ArrayBuffer(imageData.data.length);
var buf8 = new Uint8ClampedArray(buf);
var data = new Uint32Array(buf);

for (var y = 0; y < canvasHeight; ++y) {
    for (var x = 0; x < canvasWidth; ++x) {
        data[y * canvasWidth + x] = 0xff80d7ff // Should be light blue (#80d7ff)
    }
}

imageData.data.set(buf8);

ctx.putImageData(imageData, 0, 0);

The color in question here is:

But the fiddle displays a yellow-ish color:

It's the same on other colors, thanks a lot in advance!

EDIT: thanks @Oriol for quick answer! I used the following function to reverse my colors (in case anyone was interested):

function reverseUint32 (uint32) {
    var s32 = new Uint32Array(4);
    var s8 = new Uint8Array(s32.buffer);
    var t32 = new Uint32Array(4);
    var t8 = new Uint8Array(t32.buffer);        
    reverseUint32 = function (x) {
        s32[0] = x;
        t8[0] = s8[3];
        t8[1] = s8[2];
        t8[2] = s8[1];
        t8[3] = s8[0];
        return t32[0];
    }
    return reverseUint32(uint32);
};

Use it like: reverseUint32(0xfc66feff)

解决方案

This happens when you treat a Uint8Array buffer as a Uint32 in little endian:

var buf = new Uint8Array([0x12, 0x34, 0x56, 0x78]).buffer;
console.log(new Uint32Array(buf)[0].toString(16));
// "78563412" in little endian, "12345678" in big endian

So in little endian, the order becomes AABBGGRR instead of AARRGGBB.

You could reverse 0x80d7ffff to 0xffffd780, but then it wouldn't work on big endian machines.

To avoid these problems you can use a DataView, which allows to specify the endianness, defaulting to big endian:

view.setUint32(offset, 0xffffd780, true);  // #80d7ff, in little endian
view.setUint32(offset, 0x80d7ffff, false); // #80d7ff, in big endian

var canvas = document.getElementById('canvas'),
    canvasWidth  = canvas.width,
    canvasHeight = canvas.height,
    ctx = canvas.getContext('2d'),
    imageData = ctx.getImageData(0, 0, canvasWidth, canvasHeight),
    view = new DataView(imageData.data.buffer);
for (var y = 0; y < canvasHeight; ++y) {
  for (var x = 0; x < canvasWidth; ++x) {
    var offset = 4 * (y * canvasWidth + x);
    view.setUint32(offset, 0x80d7ffff); // light blue (#80d7ff)
  }
}
ctx.putImageData(imageData, 0, 0);

<canvas id="canvas" height="256" width="256"></canvas>

But it seems that browsers haven't optimized much DataView, so it's slow. Then it might be better to set the color components separately in the Uint8ClampedArray:

var canvas = document.getElementById('canvas'),
    canvasWidth  = canvas.width,
    canvasHeight = canvas.height,
    ctx = canvas.getContext('2d'),
    imageData = ctx.getImageData(0, 0, canvasWidth, canvasHeight),
    data = imageData.data;
for (var y = 0; y < canvasHeight; ++y) {
  for (var x = 0; x < canvasWidth; ++x) {
    var offset = 4 * (y * canvasWidth + x);
    // light blue (#80d7ff)
    data[offset+0] = 0x80; // red
    data[offset+1] = 0xd7; // green
    data[offset+2] = 0xff; // blue
    data[offset+3] = 0xff; // alpha
  }
}
ctx.putImageData(imageData, 0, 0);

<canvas id="canvas" height="256" width="256"></canvas>

这篇关于使用 Uint32Array 的画布:正在呈现错误的颜色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆