使用 Uint32Array 的画布:正在呈现错误的颜色 [英] Canvas using Uint32Array: Wrong colors are being rendered
问题描述
我目前正在创建一个 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屋!