Use uint32 bit-shifting for rgb->rgba interleaving
This commit is contained in:
@@ -632,18 +632,43 @@ export class KittyGraphicsHandler implements IApcHandler, IResetHandler, IDispos
|
||||
}
|
||||
|
||||
const pixelCount = width * height;
|
||||
|
||||
if (image.format === KittyFormat.RGBA) {
|
||||
// RGBA: use bytes directly — no copy needed
|
||||
return createImageBitmap(new ImageData(new Uint8ClampedArray(bytes.buffer as ArrayBuffer, bytes.byteOffset, pixelCount * BYTES_PER_PIXEL_RGBA), width, height));
|
||||
}
|
||||
|
||||
// RGB→RGBA: interleave alpha using uint32 block processing (4 pixels per iteration).
|
||||
// 3 uint32 reads + 4 uint32 writes per 4 pixels vs 28 byte reads/writes — ~6x faster.
|
||||
// Assumes little-endian (all modern browsers/Node.js).
|
||||
const data = new Uint8ClampedArray(pixelCount * BYTES_PER_PIXEL_RGBA);
|
||||
const isRgba = image.format === KittyFormat.RGBA;
|
||||
const src32 = new Uint32Array(bytes.buffer, bytes.byteOffset, Math.floor(bytes.byteLength / 4));
|
||||
const dst32 = new Uint32Array(data.buffer);
|
||||
const alignedPixels = pixelCount & ~3; // round down to multiple of 4
|
||||
|
||||
let srcOffset = 0;
|
||||
let dstOffset = 0;
|
||||
for (let i = 0; i < pixelCount; i++) {
|
||||
data[dstOffset] = bytes[srcOffset];
|
||||
data[dstOffset + 1] = bytes[srcOffset + 1];
|
||||
data[dstOffset + 2] = bytes[srcOffset + 2];
|
||||
data[dstOffset + 3] = isRgba ? bytes[srcOffset + 3] : ALPHA_OPAQUE;
|
||||
srcOffset += bytesPerPixel;
|
||||
dstOffset += BYTES_PER_PIXEL_RGBA;
|
||||
for (let i = 0; i < alignedPixels; i += 4) {
|
||||
const b0 = src32[srcOffset++];
|
||||
const b1 = src32[srcOffset++];
|
||||
const b2 = src32[srcOffset++];
|
||||
// Little-endian: pixel bytes are [R,G,B] → uint32 ABGR layout
|
||||
dst32[dstOffset++] = (b0 & 0x00FFFFFF) | 0xFF000000;
|
||||
dst32[dstOffset++] = ((b0 >>> 24) | (b1 << 8)) & 0x00FFFFFF | 0xFF000000;
|
||||
dst32[dstOffset++] = ((b1 >>> 16) | (b2 << 16)) & 0x00FFFFFF | 0xFF000000;
|
||||
dst32[dstOffset++] = (b2 >>> 8) | 0xFF000000;
|
||||
}
|
||||
|
||||
// Handle remaining 1–3 pixels
|
||||
let srcByte = alignedPixels * BYTES_PER_PIXEL_RGB;
|
||||
let dstByte = alignedPixels * BYTES_PER_PIXEL_RGBA;
|
||||
for (let i = alignedPixels; i < pixelCount; i++) {
|
||||
data[dstByte] = bytes[srcByte];
|
||||
data[dstByte + 1] = bytes[srcByte + 1];
|
||||
data[dstByte + 2] = bytes[srcByte + 2];
|
||||
data[dstByte + 3] = ALPHA_OPAQUE;
|
||||
srcByte += BYTES_PER_PIXEL_RGB;
|
||||
dstByte += BYTES_PER_PIXEL_RGBA;
|
||||
}
|
||||
|
||||
return createImageBitmap(new ImageData(data, width, height));
|
||||
|
||||
Reference in New Issue
Block a user