From 1d0abcaee8eb7843b696ecc025ad1de3446a1681 Mon Sep 17 00:00:00 2001 From: Jeff Schiller Date: Tue, 16 Jan 2024 08:19:58 -0800 Subject: [PATCH] PngParser: Handle gAMA chunk --- image/parsers/png.js | 32 ++++++++++++++++++++++++++++- tests/image-parsers-png.spec.js | 10 +++++++++ tests/image-testfiles/g05n3p04.png | Bin 0 -> 206 bytes 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 tests/image-testfiles/g05n3p04.png diff --git a/image/parsers/png.js b/image/parsers/png.js index 36883b7..453b398 100644 --- a/image/parsers/png.js +++ b/image/parsers/png.js @@ -14,12 +14,14 @@ import { ByteStream } from '../../io/bytestream.js'; // https://en.wikipedia.org/wiki/PNG#File_format // https://www.w3.org/TR/2003/REC-PNG-20031110 +// let DEBUG = true; let DEBUG = false; const SIG = new Uint8Array([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]); /** @enum {string} */ export const PngParseEventType = { IHDR: 'image_header', + gAMA: 'image_gamma', PLTE: 'palette', IDAT: 'image_data', }; @@ -59,6 +61,15 @@ export class PngImageHeaderEvent extends Event { } } +export class PngImageGammaEvent extends Event { + /** @param {number} */ + constructor(gamma) { + super(PngParseEventType.gAMA); + /** @type {number} */ + this.gamma = gamma; + } +} + /** * @typedef PngColor * @property {number} red @@ -132,6 +143,16 @@ export class PngParser extends EventTarget { return this; } + /** + * Type-safe way to bind a listener for a PngImageGammaEvent. + * @param {function(PngImageGammaEvent): void} listener + * @returns {PngParser} for chaining + */ + onGamma(listener) { + super.addEventListener(PngParseEventType.gAMA, listener); + return this; + } + /** * Type-safe way to bind a listener for a PngPaletteEvent. * @param {function(PngPaletteEvent): void} listener @@ -204,6 +225,12 @@ export class PngParser extends EventTarget { this.dispatchEvent(new PngImageHeaderEvent(header)); break; + // https://www.w3.org/TR/2003/REC-PNG-20031110/#11gAMA + case 'gAMA': + if (length !== 4) throw `Bad length for gAMA: ${length}`; + this.dispatchEvent(new PngImageGammaEvent(chStream.readNumber(4))); + break; + // https://www.w3.org/TR/2003/REC-PNG-20031110/#11PLTE case 'PLTE': if (this.colorType === undefined) throw `PLTE before IHDR`; @@ -282,8 +309,11 @@ async function main() { parser.onImageHeader(evt => { // console.dir(evt.imageHeader); }); + parser.onGamma(evt => { + // console.dir(evt.imageGamma); + }); parser.onPalette(evt => { - console.dir(evt.palette); + // console.dir(evt.palette); }); parser.onImageData(evt => { // console.dir(evt); diff --git a/tests/image-parsers-png.spec.js b/tests/image-parsers-png.spec.js index 68714c4..ca2cd55 100644 --- a/tests/image-parsers-png.spec.js +++ b/tests/image-parsers-png.spec.js @@ -5,6 +5,7 @@ import { PngColorType, PngInterlaceMethod, PngParser } from '../image/parsers/pn /** @typedef {import('../image/parsers/png.js').PngImageHeader} PngImageHeader */ /** @typedef {import('../image/parsers/png.js').PngImageData} PngImageData */ +/** @typedef {import('../image/parsers/png.js').PngImageGamma} PngImageGamma */ /** @typedef {import('../image/parsers/png.js').PngPalette} PngPalette */ function getPngParser(fileName) { @@ -47,6 +48,15 @@ describe('bitjs.image.parsers.PngParser', () => { }); }); + it('extracts gAMA', async () => { + /** @type {number} */ + let gamma; + await getPngParser('tests/image-testfiles/g05n3p04.png') + .onGamma(evt => gamma = evt.gamma) + .start(); + expect(gamma).equals(55000); + }); + it('extracts PLTE', async () => { /** @type {PngPalette} */ let palette; diff --git a/tests/image-testfiles/g05n3p04.png b/tests/image-testfiles/g05n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..9619930585eb3798db54058d41c09f6cd195c723 GIT binary patch literal 206 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvmUKs7M+Sy#H?H_c7y&7nsP&a50$ri)KG u9IC*rureVboiWQXC@_w%oP86+Of7~h92M4HZx@7u9OCKf=d#Wzp$PyhYDC`v literal 0 HcmV?d00001