@@ -14,21 +14,25 @@ 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, tEXt, tIME, zTXt.
17+ // TODO: Ancillary chunks bKGD, eXIf, hIST, iTXt, pHYs, sPLT, tIME, zTXt.
1818
1919// let DEBUG = true;
2020let DEBUG = false ;
2121const SIG = new Uint8Array ( [ 0x89 , 0x50 , 0x4E , 0x47 , 0x0D , 0x0A , 0x1A , 0x0A ] ) ;
2222
2323/** @enum {string} */
2424export const PngParseEventType = {
25+ // Critical chunks.
26+ IDAT : 'image_data' ,
2527 IHDR : 'image_header' ,
28+ PLTE : 'palette' ,
29+
30+ // Ancillary chunks.
31+ cHRM : 'chromaticities_white_point' ,
2632 gAMA : 'image_gamma' ,
2733 sBIT : 'significant_bits' ,
28- cHRM : 'chromaticities_white_point' ,
29- PLTE : 'palette' ,
34+ tEXt : 'textual_data' ,
3035 tRNS : 'transparency' ,
31- IDAT : 'image_data' ,
3236} ;
3337
3438/** @enum {number} */
@@ -167,6 +171,21 @@ export class PngImageDataEvent extends Event {
167171 }
168172}
169173
174+ /**
175+ * @typedef PngTextualData
176+ * @property {string } keyword
177+ * @property {string= } textString
178+ */
179+
180+ export class PngTextualDataEvent extends Event {
181+ /** @param {PngTextualData } textualData */
182+ constructor ( textualData ) {
183+ super ( PngParseEventType . tEXt ) ;
184+ /** @type {PngTextualData } */
185+ this . textualData = textualData ;
186+ }
187+ }
188+
170189/**
171190 * @typedef PngChunk Internal use only.
172191 * @property {number } length
@@ -203,12 +222,12 @@ export class PngParser extends EventTarget {
203222 }
204223
205224 /**
206- * Type-safe way to bind a listener for a PngImageHeaderEvent .
207- * @param {function(PngImageHeaderEvent ): void } listener
225+ * Type-safe way to bind a listener for a PngChromaticiesEvent .
226+ * @param {function(PngChromaticiesEvent ): void } listener
208227 * @returns {PngParser } for chaining
209228 */
210- onImageHeader ( listener ) {
211- super . addEventListener ( PngParseEventType . IHDR , listener ) ;
229+ onChromaticities ( listener ) {
230+ super . addEventListener ( PngParseEventType . cHRM , listener ) ;
212231 return this ;
213232 }
214233
@@ -223,22 +242,22 @@ export class PngParser extends EventTarget {
223242 }
224243
225244 /**
226- * Type-safe way to bind a listener for a PngSignificantBitsEvent .
227- * @param {function(PngSignificantBitsEvent ): void } listener
245+ * Type-safe way to bind a listener for a PngImageDataEvent .
246+ * @param {function(PngImageDataEvent ): void } listener
228247 * @returns {PngParser } for chaining
229248 */
230- onSignificantBits ( listener ) {
231- super . addEventListener ( PngParseEventType . sBIT , listener ) ;
249+ onImageData ( listener ) {
250+ super . addEventListener ( PngParseEventType . IDAT , listener ) ;
232251 return this ;
233252 }
234253
235254 /**
236- * Type-safe way to bind a listener for a PngChromaticiesEvent .
237- * @param {function(PngChromaticiesEvent ): void } listener
255+ * Type-safe way to bind a listener for a PngImageHeaderEvent .
256+ * @param {function(PngImageHeaderEvent ): void } listener
238257 * @returns {PngParser } for chaining
239258 */
240- onChromaticities ( listener ) {
241- super . addEventListener ( PngParseEventType . cHRM , listener ) ;
259+ onImageHeader ( listener ) {
260+ super . addEventListener ( PngParseEventType . IHDR , listener ) ;
242261 return this ;
243262 }
244263
@@ -253,22 +272,32 @@ export class PngParser extends EventTarget {
253272 }
254273
255274 /**
256- * Type-safe way to bind a listener for a PngTransparencyEvent .
257- * @param {function(PngTransparencyEvent ): void } listener
275+ * Type-safe way to bind a listener for a PngSignificantBitsEvent .
276+ * @param {function(PngSignificantBitsEvent ): void } listener
258277 * @returns {PngParser } for chaining
259278 */
260- onTransparency ( listener ) {
261- super . addEventListener ( PngParseEventType . tRNS , listener ) ;
279+ onSignificantBits ( listener ) {
280+ super . addEventListener ( PngParseEventType . sBIT , listener ) ;
262281 return this ;
263282 }
264283
265284 /**
266- * Type-safe way to bind a listener for a PngImageDataEvent .
267- * @param {function(PngImageDataEvent ): void } listener
285+ * Type-safe way to bind a listener for a PngTextualDataEvent .
286+ * @param {function(PngTextualDataEvent ): void } listener
268287 * @returns {PngParser } for chaining
269288 */
270- onImageData ( listener ) {
271- super . addEventListener ( PngParseEventType . IDAT , listener ) ;
289+ onTextualData ( listener ) {
290+ super . addEventListener ( PngParseEventType . tEXt , listener ) ;
291+ return this ;
292+ }
293+
294+ /**
295+ * Type-safe way to bind a listener for a PngTransparencyEvent.
296+ * @param {function(PngTransparencyEvent): void } listener
297+ * @returns {PngParser } for chaining
298+ */
299+ onTransparency ( listener ) {
300+ super . addEventListener ( PngParseEventType . tRNS , listener ) ;
272301 return this ;
273302 }
274303
@@ -404,6 +433,18 @@ export class PngParser extends EventTarget {
404433 this . dispatchEvent ( new PngPaletteEvent ( this . palette ) ) ;
405434 break ;
406435
436+ // https://www.w3.org/TR/png-3/#11tEXt
437+ case 'tEXt' :
438+ const byteArr = chStream . peekBytes ( length ) ;
439+ const nullIndex = byteArr . indexOf ( 0 ) ;
440+ /** @type {PngTextualData } */
441+ const textualData = {
442+ keyword : chStream . readString ( nullIndex ) ,
443+ textString : chStream . skip ( 1 ) . readString ( length - nullIndex - 1 ) ,
444+ } ;
445+ this . dispatchEvent ( new PngTextualDataEvent ( textualData ) ) ;
446+ break ;
447+
407448 // https://www.w3.org/TR/png-3/#11tRNS
408449 case 'tRNS' :
409450 if ( this . colorType === undefined ) throw `tRNS before IHDR` ;
@@ -507,6 +548,9 @@ async function main() {
507548 parser . onImageData ( evt => {
508549 // console.dir(evt);
509550 } ) ;
551+ parser . onTextualData ( evt => {
552+ // console.dir(evt.textualData);
553+ } ) ;
510554
511555 try {
512556 await parser . start ( ) ;
0 commit comments