Skip to content

Commit 1869cd7

Browse files
committed
PngParser: Add support for tIME chunk.
1 parent 9f5b3a4 commit 1869cd7

File tree

3 files changed

+65
-3
lines changed

3 files changed

+65
-3
lines changed

image/parsers/png.js

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { ByteStream } from '../../io/bytestream.js';
1414
// https://www.w3.org/TR/png-3/
1515
// https://en.wikipedia.org/wiki/PNG#File_format
1616

17-
// TODO: Ancillary chunks eXIf, hIST, pHYs, sPLT, tIME.
17+
// TODO: Ancillary chunks eXIf, hIST, pHYs, sPLT.
1818

1919
// let DEBUG = true;
2020
let DEBUG = false;
@@ -34,6 +34,7 @@ export const PngParseEventType = {
3434
iTXt: 'intl_text_data',
3535
sBIT: 'significant_bits',
3636
tEXt: 'textual_data',
37+
tIME: 'last_mod_time',
3738
tRNS: 'transparency',
3839
zTXt: 'compressed_textual_data',
3940
};
@@ -242,6 +243,25 @@ export class PngBackgroundColorEvent extends Event {
242243
}
243244
}
244245

246+
/**
247+
* @typedef PngLastModTime
248+
* @property {number} year Four-digit year.
249+
* @property {number} month One-based. Value from 1-12.
250+
* @property {number} day One-based. Value from 1-31.
251+
* @property {number} hour Zero-based. Value from 0-23.
252+
* @property {number} minute Zero-based. Value from 0-59.
253+
* @property {number} second Zero-based. Value from 0-60 to allow for leap-seconds.
254+
*/
255+
256+
export class PngLastModTimeEvent extends Event {
257+
/** @param {PngLastModTime} lastModTime */
258+
constructor(lastModTime) {
259+
super(PngParseEventType.tIME);
260+
/** @type {PngLastModTime} */
261+
this.lastModTime = lastModTime;
262+
}
263+
}
264+
245265
/**
246266
* @typedef PngChunk Internal use only.
247267
* @property {number} length
@@ -347,6 +367,16 @@ export class PngParser extends EventTarget {
347367
return this;
348368
}
349369

370+
/**
371+
* Type-safe way to bind a listener for a PngLastModTime.
372+
* @param {function(PngLastModTime): void} listener
373+
* @returns {PngParser} for chaining
374+
*/
375+
onLastModTime(listener) {
376+
super.addEventListener(PngParseEventType.tIME, listener);
377+
return this;
378+
}
379+
350380
/**
351381
* Type-safe way to bind a listener for a PngPaletteEvent.
352382
* @param {function(PngPaletteEvent): void} listener
@@ -553,6 +583,20 @@ export class PngParser extends EventTarget {
553583
this.dispatchEvent(new PngTextualDataEvent(textualData));
554584
break;
555585

586+
// https://www.w3.org/TR/png-3/#11tIME
587+
case 'tIME':
588+
/** @type {PngLastModTime} */
589+
const lastModTime = {
590+
year: chStream.readNumber(2),
591+
month: chStream.readNumber(1),
592+
day: chStream.readNumber(1),
593+
hour: chStream.readNumber(1),
594+
minute: chStream.readNumber(1),
595+
second: chStream.readNumber(1),
596+
};
597+
this.dispatchEvent(new PngLastModTimeEvent(lastModTime));
598+
break;
599+
556600
// https://www.w3.org/TR/png-3/#11tRNS
557601
case 'tRNS':
558602
if (this.colorType === undefined) throw `tRNS before IHDR`;
@@ -704,7 +748,10 @@ async function main() {
704748
});
705749
parser.onBackgroundColor(evt => {
706750
// console.dir(evt.backgroundColor);
707-
})
751+
});
752+
parser.onLastModTime(evt => {
753+
console.dir(evt.lastModTime);
754+
});
708755

709756
try {
710757
await parser.start();
@@ -714,4 +761,4 @@ async function main() {
714761
}
715762
}
716763

717-
// main();
764+
// main();

tests/image-parsers-png.spec.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { PngColorType, PngInterlaceMethod, PngParser } from '../image/parsers/pn
1010
/** @typedef {import('../image/parsers/png.js').PngImageGamma} PngImageGamma */
1111
/** @typedef {import('../image/parsers/png.js').PngImageHeader} PngImageHeader */
1212
/** @typedef {import('../image/parsers/png.js').PngIntlTextualData} PngIntlTextualData */
13+
/** @typedef {import('../image/parsers/png.js').PngLastModTime} PngLastModTime */
1314
/** @typedef {import('../image/parsers/png.js').PngPalette} PngPalette */
1415
/** @typedef {import('../image/parsers/png.js').PngSignificantBits} PngSignificantBits */
1516
/** @typedef {import('../image/parsers/png.js').PngTextualData} PngTextualData */
@@ -233,4 +234,18 @@ describe('bitjs.image.parsers.PngParser', () => {
233234
expect(bc.paletteIndex).equals(245);
234235
});
235236
});
237+
238+
it('extracts tIME', async () => {
239+
/** @type {PngLastModTime} */
240+
let lastModTime;
241+
await getPngParser('tests/image-testfiles/cm9n0g04.png')
242+
.onLastModTime(evt => { lastModTime = evt.lastModTime })
243+
.start();
244+
expect(lastModTime.year).equals(1999);
245+
expect(lastModTime.month).equals(12);
246+
expect(lastModTime.day).equals(31);
247+
expect(lastModTime.hour).equals(23);
248+
expect(lastModTime.minute).equals(59);
249+
expect(lastModTime.second).equals(59);
250+
});
236251
});

tests/image-testfiles/cm9n0g04.png

292 Bytes
Loading

0 commit comments

Comments
 (0)