@@ -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 bKGD, eXIf, hIST, iTXt, pHYs, sPLT, tIME, zTXt .
17+ // TODO: Ancillary chunks bKGD, eXIf, hIST, iTXt, pHYs, sPLT, tIME.
1818
1919// let DEBUG = true;
2020let DEBUG = false ;
@@ -33,6 +33,7 @@ export const PngParseEventType = {
3333 sBIT : 'significant_bits' ,
3434 tEXt : 'textual_data' ,
3535 tRNS : 'transparency' ,
36+ zTXt : 'compressed_textual_data' ,
3637} ;
3738
3839/** @enum {number} */
@@ -186,6 +187,22 @@ export class PngTextualDataEvent extends Event {
186187 }
187188}
188189
190+ /**
191+ * @typedef PngCompressedTextualData
192+ * @property {string } keyword
193+ * @property {number } compressionMethod Only value supported is 0 for deflate compression.
194+ * @property {Uint8Array= } compressedText
195+ */
196+
197+ export class PngCompressedTextualDataEvent extends Event {
198+ /** @param {PngCompressedTextualData } compressedTextualData */
199+ constructor ( compressedTextualData ) {
200+ super ( PngParseEventType . zTXt ) ;
201+ /** @type {PngCompressedTextualData } */
202+ this . compressedTextualData = compressedTextualData ;
203+ }
204+ }
205+
189206/**
190207 * @typedef PngChunk Internal use only.
191208 * @property {number } length
@@ -231,6 +248,16 @@ export class PngParser extends EventTarget {
231248 return this ;
232249 }
233250
251+ /**
252+ * Type-safe way to bind a listener for a PngCompressedTextualDataEvent.
253+ * @param {function(PngCompressedTextualDataEvent): void } listener
254+ * @returns {PngParser } for chaining
255+ */
256+ onCompressedTextualData ( listener ) {
257+ super . addEventListener ( PngParseEventType . zTXt , listener ) ;
258+ return this ;
259+ }
260+
234261 /**
235262 * Type-safe way to bind a listener for a PngImageGammaEvent.
236263 * @param {function(PngImageGammaEvent): void } listener
@@ -479,6 +506,20 @@ export class PngParser extends EventTarget {
479506 this . dispatchEvent ( new PngTransparencyEvent ( transparency ) ) ;
480507 break ;
481508
509+ // https://www.w3.org/TR/png-3/#11zTXt
510+ case 'zTXt' :
511+ const compressedByteArr = chStream . peekBytes ( length ) ;
512+ const compressedNullIndex = compressedByteArr . indexOf ( 0 ) ;
513+
514+ /** @type {PngCompressedTextualData } */
515+ const compressedTextualData = {
516+ keyword : chStream . readString ( compressedNullIndex ) ,
517+ compressionMethod : chStream . skip ( 1 ) . readNumber ( 1 ) ,
518+ compressedText : chStream . readBytes ( length - compressedNullIndex - 2 ) ,
519+ } ;
520+ this . dispatchEvent ( new PngCompressedTextualDataEvent ( compressedTextualData ) ) ;
521+ break ;
522+
482523 // https://www.w3.org/TR/png-3/#11IDAT
483524 case 'IDAT' :
484525 /** @type {PngImageData } */
@@ -551,6 +592,9 @@ async function main() {
551592 parser . onTextualData ( evt => {
552593 // console.dir(evt.textualData);
553594 } ) ;
595+ parser . onCompressedTextualData ( evt => {
596+ // console.dir(evt.compressedTextualData);
597+ } ) ;
554598
555599 try {
556600 await parser . start ( ) ;
0 commit comments