我想将Uint8Array
包含 ARGB 图像的字节转换为它的 RGBA 表示,但是我想用比我在这里建议的更优化的东西来获得它,例如使用字节移位。
我现在所做的只是在某种意义上交换字节顺序(例如,但长度可以是 4 的任意倍数):
let input = [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 ];
let expected = [0x22, 0x33, 0x44, 0x11, 0x88, 0x55, 0x66, 0x77 ];
所以简单的情况是:
function argbToRgba(src) {
let dest = new Uint8Array(src.length)
for (let i = 0; i < src.length; i += 4) {
let a = src[i]
let r = src[i + 1]
let g = src[i + 2]
let b = src[i + 3]
dest[i] = r;
dest[i + 1] = g;
dest[i + 2] = b;
dest[i + 3] = a;
}
return dest;
}
但是,理想情况下,我想使用字节移位来构建 RGBA 值(这是微不足道的部分),但我的问题是如何将这样的 uint32 数字放入dest
(必须是一个Uint8Array
,理想情况下甚至与 src 相同)进行就地更改)。
我的意思是,在 C 中,一旦我uint32_t rgbaColor
定义好了,我就可以memwrite
将 int 分配给数组索引,然后溢出来完成剩下的工作。但是我如何在 JS 中做到这一点?
编辑:经过一些测试,看起来最初的提案仍然是最快的,实际上
function argbToRgbaDataView(src, inline=false) {
let dest = inline ? src : new Uint8Array(src.length);
let srcView = new DataView(src.buffer);
let destView = new DataView(dest.buffer);
for (let i = 0; i < src.length; i += 4) {
let argb = srcView.getUint32(i);
let rgba = (argb & 0x00FFFFFF) << 8 |
(argb & 0xFF000000) >>> 24;
destView.setUint32(i, rgba);
}
return dest;
}
function argbToRgbaDataViewInline(src) {
return argbToRgbaDataView(src, true);
}
function argbToRgbaSwap(src, inline=false) {
let dest = inline ? src : new Uint8Array(src.length);
for (let i = 0; i < src.length; i += 4) {
let a = src[i]
let r = src[i + 1]
let g = src[i + 2]
let b = src[i + 3]
dest[i] = r;
dest[i + 1] = g;
dest[i + 2] = b;
dest[i + 3] = a;
}
return dest;
}
function argbToRgbaSwapInline(src) {
return argbToRgbaSwap(src, true);
}
function argbToRgbaSwapNoVars(src, inline = false) {
let dest = inline ? src : new Uint8Array(src);
for (let i = 0; i < src.length; i += 4) {
let a = src[i]
dest[i] = src[i + 1];
dest[i + 1] = src[i + 2];
dest[i + 2] = src[i + 3];
dest[i + 3] = a;
}
return dest;
}
function argbToRgbaSwapNoVarsInline(src) {
return argbToRgbaSwapNoVars(src, true);
}
// From https://stackoverflow.com/a/60639510/210151
function argb2rgbaStackOverflow(inArr) {
return inArr.reduce((a, c, i, t) => {
if (i % 4 === 0) {
let [A, R, G, B] = t.slice(i, i + 4)
a.push(R, G, B, A)
}
return a
}, [])
}
function measureFunction(func) {
let preTime = new Date().getTime();
let ret = func.call(...arguments);
console.log(`Calling ${func.name} took ${new Date().getTime() - preTime}ms`);
return ret;
}
function createRandomArray(size) {
return new Uint8Array(size).fill().map((a, i) =>
a = i).sort(() => Math.random() - 0.5);
}
function iconSizeToBytes(iconSize) {
const bytesPerPixel = 4;
return iconSize * iconSize * bytesPerPixel;
}
// This is to add support to console.log to gjs
try {
console;
} catch(e) {
window.console = {
log: function() { print(...arguments) },
};
}
let allSizes = [
iconSizeToBytes(32),
iconSizeToBytes(64),
iconSizeToBytes(512),
iconSizeToBytes(1024),
iconSizeToBytes(2048),
];
for (let size of allSizes) {
console.log(`Creating random array of ${size/(1024 * 1024)}Mbyte...`);
let randomArray = measureFunction(createRandomArray, size);
measureFunction(argbToRgbaDataView, randomArray);
measureFunction(argbToRgbaDataViewInline, randomArray);
measureFunction(argbToRgbaSwap, randomArray);
measureFunction(argbToRgbaSwapInline, randomArray);
measureFunction(argbToRgbaSwapNoVars, randomArray);
measureFunction(argbToRgbaSwapNoVarsInline, randomArray);
measureFunction(argb2rgbaStackOverflow, randomArray);
console.log('------------------------------------------------------');
}
<script src="https://rawgit.com/eu81273/jsfiddle-console/master/console.js"></script>