Я хочу преобразовать 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
и в идеале даже тот же самый из sr c, чтобы сделать изменения на месте).
Я имею в виду, в 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>