Skip to content

Commit eb39fb9

Browse files
committed
stop wasting bytes decoding PLTE, support indexed transparency
(cherry picked from commit a38fca5)
1 parent f1e5535 commit eb39fb9

1 file changed

Lines changed: 20 additions & 6 deletions

File tree

‎utils/png.js‎

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,19 +85,26 @@ export async function decode(array) {
8585
let c_offset = 33;
8686
const chunks = [];
8787

88-
let palette;
89-
if (array[25] === 3)
90-
palette = new Uint32Array(2 ** bpc);
88+
let palette, alphaPalette;
9189
let type;
9290
while (type !== 1229278788) {
9391
type = view.getUint32(4 + c_offset);
9492

9593
// IDAT
9694
if (type === 1229209940)
9795
chunks.push(array.subarray(8 + c_offset, 8 + c_offset + view.getUint32(c_offset)));
98-
else if (type === 1347179589) {
96+
else if (type === 1347179589) { // PLTE
97+
if (palette)
98+
throw new Error('PLTE can only occur once in an image');
99+
palette = new Uint32Array(view.getUint32(c_offset));
99100
for (let pxlOffset = 0; pxlOffset < palette.length * 8; pxlOffset += 3)
100101
palette[pxlOffset / 3] = array[8 + c_offset + pxlOffset] << 24 | array[8 + c_offset + pxlOffset + 1] << 16 | array[8 + c_offset + pxlOffset + 2] << 8 | 0xff;
102+
} else if (type === 1951551059) { // tRNS
103+
if (alphaPalette)
104+
throw new Error('tRNS can only occur once in an image');
105+
alphaPalette = new Uint8Array(view.getUint32(c_offset));
106+
for (let i = 0; i < alphaPalette.length; i++)
107+
alphaPalette[i] = array[8 + c_offset + i];
101108
}
102109

103110
c_offset += 4 + 4 + 4 + view.getUint32(c_offset);
@@ -118,7 +125,14 @@ export async function decode(array) {
118125
p_offset += row_length;
119126
}
120127

121-
if (channels === 1 && palette) {
128+
if (pixel_type === 3) {
129+
if (!palette)
130+
throw new Error('Indexed color PNG has no PLTE');
131+
132+
if (alphaPalette)
133+
for (let i = 0; i < alphaPalette.length; i++)
134+
palette[i] &= 0xffffff00 | alphaPalette[i];
135+
122136
channels = 4;
123137
const newPixels = new Uint8Array(width * height * 4);
124138
const pixelView = new DataView(newPixels.buffer, newPixels.byteOffset, newPixels.byteLength);
@@ -206,4 +220,4 @@ function filter_4(slice, pixels, p_offset, bytespp, row_length) {
206220
pixels[i + p_offset] = slice[i++] + ((pa <= pb && pa <= pc) ? a : ((pb <= pc) ? b : c));
207221
}
208222
}
209-
}
223+
}

0 commit comments

Comments
 (0)