Skip to content

Commit 6d9e3ec

Browse files
committed
fix: support tRNS chunk for palette images
1 parent 30c0272 commit 6d9e3ec

File tree

4 files changed

+43
-1
lines changed

4 files changed

+43
-1
lines changed

‎img/palette_trns.png

156 KB
Loading

‎src/PNGDecoder.ts

+26
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export default class PNGDecoder extends IOBuffer {
3434
private _compressionMethod: CompressionMethod;
3535
private _filterMethod: FilterMethod;
3636
private _interlaceMethod: InterlaceMethod;
37+
private _colorType: number;
3738

3839
public constructor(data: DecoderInputType, options: IPNGDecoderOptions = {}) {
3940
super(data);
@@ -54,6 +55,7 @@ export default class PNGDecoder extends IOBuffer {
5455
this._compressionMethod = CompressionMethod.UNKNOWN;
5556
this._filterMethod = FilterMethod.UNKNOWN;
5657
this._interlaceMethod = InterlaceMethod.UNKNOWN;
58+
this._colorType = -1;
5759
// PNG is always big endian
5860
// https://www.w3.org/TR/PNG/#7Integers-and-byte-order
5961
this.setBigEndian();
@@ -99,6 +101,9 @@ export default class PNGDecoder extends IOBuffer {
99101
this._end = true;
100102
break;
101103
// 11.3 Ancillary chunks
104+
case 'tRNS': // 11.3.2.1 tRNS Transparency
105+
this.decodetRNS(length);
106+
break;
102107
case 'tEXt': // 11.3.4.3 tEXt Textual data
103108
this.decodetEXt(length);
104109
break;
@@ -141,6 +146,7 @@ export default class PNGDecoder extends IOBuffer {
141146
image.depth = checkBitDepth(this.readUint8());
142147

143148
const colorType: ColorType = this.readUint8();
149+
this._colorType = colorType;
144150
let channels: number;
145151
switch (colorType) {
146152
case ColorType.GREYSCALE:
@@ -199,6 +205,26 @@ export default class PNGDecoder extends IOBuffer {
199205
this.skip(length);
200206
}
201207

208+
// https://www.w3.org/TR/PNG/#11tRNS
209+
private decodetRNS(length: number): void {
210+
// TODO: support other color types.
211+
if (this._colorType === 3) {
212+
if (length > this._palette.length) {
213+
throw new Error(
214+
`tRNS chunk contains more alpha values than there are palette colors (${length} vs ${this._palette.length})`,
215+
);
216+
}
217+
let i = 0;
218+
for (; i < length; i++) {
219+
const alpha = this.readByte();
220+
this._palette[i].push(alpha);
221+
}
222+
for (; i < this._palette.length; i++) {
223+
this._palette[i].push(255);
224+
}
225+
}
226+
}
227+
202228
// https://www.w3.org/TR/PNG/#11tEXt
203229
private decodetEXt(length: number): void {
204230
let keyword = '';

‎src/__tests__/decode.test.ts

+16
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,22 @@ describe('decode', () => {
4646
expect(img.palette[0]).toStrictEqual([124, 124, 124]);
4747
});
4848

49+
it('palette with tRNS', () => {
50+
const img = loadAndDecode('palette_trns.png');
51+
check(img, {
52+
width: 1300,
53+
height: 1300,
54+
depth: 8,
55+
channels: 1,
56+
});
57+
expect(img.palette).toBeInstanceOf(Array);
58+
expect(img.palette).toHaveLength(256);
59+
// @ts-ignore
60+
expect(img.palette[0]).toStrictEqual([71, 112, 76, 0]);
61+
// @ts-ignore
62+
expect(img.palette[255]).toStrictEqual([98, 185, 201, 255]);
63+
});
64+
4965
it('should not throw when CRC is correct', () => {
5066
loadAndDecode('palette.png', { checkCrc: true });
5167
});

‎src/types.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,4 @@ export interface IPNGEncoderOptions {
6262
zlib?: DeflateFunctionOptions;
6363
}
6464

65-
export type IndexedColors = [number, number, number][];
65+
export type IndexedColors = number[][];

0 commit comments

Comments
 (0)