@@ -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;
2020let 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();
0 commit comments