Skip to content

Commit ee5f451

Browse files
committed
feat: add support for tRNS field on colour types 0 and 2
Closes: #31
1 parent dc4c0e6 commit ee5f451

File tree

4 files changed

+43
-1
lines changed

4 files changed

+43
-1
lines changed

‎img/trns_grey_16bit.png

6.88 KB
Loading

‎src/PngDecoder.ts

+28-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ export default class PngDecoder extends IOBuffer {
3131
private _end: boolean;
3232
private _hasPalette: boolean;
3333
private _palette: IndexedColors;
34+
private _hasTransparency: boolean;
35+
private _transparency: Uint16Array;
3436
private _compressionMethod: CompressionMethod;
3537
private _filterMethod: FilterMethod;
3638
private _interlaceMethod: InterlaceMethod;
@@ -52,6 +54,8 @@ export default class PngDecoder extends IOBuffer {
5254
this._end = false;
5355
this._hasPalette = false;
5456
this._palette = [];
57+
this._hasTransparency = false;
58+
this._transparency = new Uint16Array(0);
5559
this._compressionMethod = CompressionMethod.UNKNOWN;
5660
this._filterMethod = FilterMethod.UNKNOWN;
5761
this._interlaceMethod = InterlaceMethod.UNKNOWN;
@@ -210,7 +214,27 @@ export default class PngDecoder extends IOBuffer {
210214
// https://www.w3.org/TR/PNG/#11tRNS
211215
private decodetRNS(length: number): void {
212216
switch (this._colorType) {
213-
// TODO: support other color types.
217+
case ColorType.GREYSCALE:
218+
case ColorType.TRUECOLOUR: {
219+
if (length % 2 !== 0) {
220+
throw new RangeError(
221+
`tRNS chunk length must be a multiple of 2. Got ${length}`,
222+
);
223+
}
224+
if (length / 2 > this._png.width * this._png.height) {
225+
throw new Error(
226+
`tRNS chunk contains more alpha values than there are pixels (${
227+
length / 2
228+
} vs ${this._png.width * this._png.height})`,
229+
);
230+
}
231+
this._hasTransparency = true;
232+
this._transparency = new Uint16Array(length / 2);
233+
for (let i = 0; i < length / 2; i++) {
234+
this._transparency[i] = this.readUint16();
235+
}
236+
break;
237+
}
214238
case ColorType.INDEXED_COLOUR: {
215239
if (length > this._palette.length) {
216240
throw new Error(
@@ -346,6 +370,9 @@ export default class PngDecoder extends IOBuffer {
346370
if (this._hasPalette) {
347371
this._png.palette = this._palette;
348372
}
373+
if (this._hasTransparency) {
374+
this._png.transparency = this._transparency;
375+
}
349376

350377
if (this._png.depth === 16) {
351378
const uint16Data = new Uint16Array(newData.buffer);

‎src/__tests__/decode.test.ts

+14
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,20 @@ describe('decode', () => {
7070
expect(img.palette[255]).toStrictEqual([98, 185, 201, 255]);
7171
});
7272

73+
it('16-bit grey image with tRNS', () => {
74+
const img = loadAndDecode('trns_grey_16bit.png');
75+
check(img, {
76+
width: 256,
77+
height: 256,
78+
depth: 16,
79+
channels: 1,
80+
});
81+
expect(img.transparency).toBeInstanceOf(Uint16Array);
82+
expect(img.transparency).toHaveLength(1);
83+
// @ts-expect-error Transparency should not be undefined
84+
expect(img.transparency[0]).toBe(0);
85+
});
86+
7387
it('should not throw when CRC is correct', () => {
7488
loadAndDecode('palette.png', { checkCrc: true });
7589
});

‎src/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export interface DecodedPng {
5252
text: { [key: string]: string };
5353
resolution?: PngResolution;
5454
palette?: IndexedColors;
55+
transparency?: Uint16Array;
5556
iccEmbeddedProfile?: IccEmbeddedProfile;
5657
}
5758

0 commit comments

Comments
 (0)