1
0
Fork 0
mirror of https://github.com/codedread/bitjs synced 2025-10-04 01:59:15 +02:00

PngParser: Add support for tIME chunk.

This commit is contained in:
Jeff Schiller 2024-01-18 19:48:18 -08:00
parent 9f5b3a4882
commit 1869cd7bfa
3 changed files with 65 additions and 3 deletions

View file

@ -14,7 +14,7 @@ import { ByteStream } from '../../io/bytestream.js';
// https://www.w3.org/TR/png-3/ // https://www.w3.org/TR/png-3/
// https://en.wikipedia.org/wiki/PNG#File_format // https://en.wikipedia.org/wiki/PNG#File_format
// TODO: Ancillary chunks eXIf, hIST, pHYs, sPLT, tIME. // TODO: Ancillary chunks eXIf, hIST, pHYs, sPLT.
// let DEBUG = true; // let DEBUG = true;
let DEBUG = false; let DEBUG = false;
@ -34,6 +34,7 @@ export const PngParseEventType = {
iTXt: 'intl_text_data', iTXt: 'intl_text_data',
sBIT: 'significant_bits', sBIT: 'significant_bits',
tEXt: 'textual_data', tEXt: 'textual_data',
tIME: 'last_mod_time',
tRNS: 'transparency', tRNS: 'transparency',
zTXt: 'compressed_textual_data', zTXt: 'compressed_textual_data',
}; };
@ -242,6 +243,25 @@ export class PngBackgroundColorEvent extends Event {
} }
} }
/**
* @typedef PngLastModTime
* @property {number} year Four-digit year.
* @property {number} month One-based. Value from 1-12.
* @property {number} day One-based. Value from 1-31.
* @property {number} hour Zero-based. Value from 0-23.
* @property {number} minute Zero-based. Value from 0-59.
* @property {number} second Zero-based. Value from 0-60 to allow for leap-seconds.
*/
export class PngLastModTimeEvent extends Event {
/** @param {PngLastModTime} lastModTime */
constructor(lastModTime) {
super(PngParseEventType.tIME);
/** @type {PngLastModTime} */
this.lastModTime = lastModTime;
}
}
/** /**
* @typedef PngChunk Internal use only. * @typedef PngChunk Internal use only.
* @property {number} length * @property {number} length
@ -347,6 +367,16 @@ export class PngParser extends EventTarget {
return this; return this;
} }
/**
* Type-safe way to bind a listener for a PngLastModTime.
* @param {function(PngLastModTime): void} listener
* @returns {PngParser} for chaining
*/
onLastModTime(listener) {
super.addEventListener(PngParseEventType.tIME, listener);
return this;
}
/** /**
* Type-safe way to bind a listener for a PngPaletteEvent. * Type-safe way to bind a listener for a PngPaletteEvent.
* @param {function(PngPaletteEvent): void} listener * @param {function(PngPaletteEvent): void} listener
@ -553,6 +583,20 @@ export class PngParser extends EventTarget {
this.dispatchEvent(new PngTextualDataEvent(textualData)); this.dispatchEvent(new PngTextualDataEvent(textualData));
break; break;
// https://www.w3.org/TR/png-3/#11tIME
case 'tIME':
/** @type {PngLastModTime} */
const lastModTime = {
year: chStream.readNumber(2),
month: chStream.readNumber(1),
day: chStream.readNumber(1),
hour: chStream.readNumber(1),
minute: chStream.readNumber(1),
second: chStream.readNumber(1),
};
this.dispatchEvent(new PngLastModTimeEvent(lastModTime));
break;
// https://www.w3.org/TR/png-3/#11tRNS // https://www.w3.org/TR/png-3/#11tRNS
case 'tRNS': case 'tRNS':
if (this.colorType === undefined) throw `tRNS before IHDR`; if (this.colorType === undefined) throw `tRNS before IHDR`;
@ -704,7 +748,10 @@ async function main() {
}); });
parser.onBackgroundColor(evt => { parser.onBackgroundColor(evt => {
// console.dir(evt.backgroundColor); // console.dir(evt.backgroundColor);
}) });
parser.onLastModTime(evt => {
console.dir(evt.lastModTime);
});
try { try {
await parser.start(); await parser.start();
@ -714,4 +761,4 @@ async function main() {
} }
} }
// main(); // main();

View file

@ -10,6 +10,7 @@ import { PngColorType, PngInterlaceMethod, PngParser } from '../image/parsers/pn
/** @typedef {import('../image/parsers/png.js').PngImageGamma} PngImageGamma */ /** @typedef {import('../image/parsers/png.js').PngImageGamma} PngImageGamma */
/** @typedef {import('../image/parsers/png.js').PngImageHeader} PngImageHeader */ /** @typedef {import('../image/parsers/png.js').PngImageHeader} PngImageHeader */
/** @typedef {import('../image/parsers/png.js').PngIntlTextualData} PngIntlTextualData */ /** @typedef {import('../image/parsers/png.js').PngIntlTextualData} PngIntlTextualData */
/** @typedef {import('../image/parsers/png.js').PngLastModTime} PngLastModTime */
/** @typedef {import('../image/parsers/png.js').PngPalette} PngPalette */ /** @typedef {import('../image/parsers/png.js').PngPalette} PngPalette */
/** @typedef {import('../image/parsers/png.js').PngSignificantBits} PngSignificantBits */ /** @typedef {import('../image/parsers/png.js').PngSignificantBits} PngSignificantBits */
/** @typedef {import('../image/parsers/png.js').PngTextualData} PngTextualData */ /** @typedef {import('../image/parsers/png.js').PngTextualData} PngTextualData */
@ -233,4 +234,18 @@ describe('bitjs.image.parsers.PngParser', () => {
expect(bc.paletteIndex).equals(245); expect(bc.paletteIndex).equals(245);
}); });
}); });
it('extracts tIME', async () => {
/** @type {PngLastModTime} */
let lastModTime;
await getPngParser('tests/image-testfiles/cm9n0g04.png')
.onLastModTime(evt => { lastModTime = evt.lastModTime })
.start();
expect(lastModTime.year).equals(1999);
expect(lastModTime.month).equals(12);
expect(lastModTime.day).equals(31);
expect(lastModTime.hour).equals(23);
expect(lastModTime.minute).equals(59);
expect(lastModTime.second).equals(59);
});
}); });

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B