@@ -14,7 +14,7 @@ import { ByteStream } from '../../io/bytestream.js';
14
14
// https://www.w3.org/TR/png-3/
15
15
// https://en.wikipedia.org/wiki/PNG#File_format
16
16
17
- // TODO: Ancillary chunks eXIf, hIST, pHYs, sPLT.
17
+ // TODO: Ancillary chunks eXIf, hIST, sPLT.
18
18
19
19
// let DEBUG = true;
20
20
let DEBUG = false ;
@@ -32,6 +32,7 @@ export const PngParseEventType = {
32
32
cHRM : 'chromaticities_white_point' ,
33
33
gAMA : 'image_gamma' ,
34
34
iTXt : 'intl_text_data' ,
35
+ pHYs : 'physical_pixel_dims' ,
35
36
sBIT : 'significant_bits' ,
36
37
tEXt : 'textual_data' ,
37
38
tIME : 'last_mod_time' ,
@@ -262,6 +263,27 @@ export class PngLastModTimeEvent extends Event {
262
263
}
263
264
}
264
265
266
+ export const PngUnitSpecifier = {
267
+ UNKNOWN : 0 ,
268
+ METRE : 1 ,
269
+ } ;
270
+
271
+ /**
272
+ * @typedef PngPhysicalPixelDimensions
273
+ * @property {number } pixelPerUnitX
274
+ * @property {number } pixelPerUnitY
275
+ * @property {PngUnitSpecifier } unitSpecifier
276
+ */
277
+
278
+ export class PngPhysicalPixelDimensionsEvent extends Event {
279
+ /** @param {PngPhysicalPixelDimensions } physicalPixelDimensions */
280
+ constructor ( physicalPixelDimensions ) {
281
+ super ( PngParseEventType . pHYs ) ;
282
+ /** @type {PngPhysicalPixelDimensions } */
283
+ this . physicalPixelDimensions = physicalPixelDimensions ;
284
+ }
285
+ }
286
+
265
287
/**
266
288
* @typedef PngChunk Internal use only.
267
289
* @property {number } length
@@ -368,8 +390,8 @@ export class PngParser extends EventTarget {
368
390
}
369
391
370
392
/**
371
- * Type-safe way to bind a listener for a PngLastModTime .
372
- * @param {function(PngLastModTime ): void } listener
393
+ * Type-safe way to bind a listener for a PngLastModTimeEvent .
394
+ * @param {function(PngLastModTimeEvent ): void } listener
373
395
* @returns {PngParser } for chaining
374
396
*/
375
397
onLastModTime ( listener ) {
@@ -387,6 +409,16 @@ export class PngParser extends EventTarget {
387
409
return this ;
388
410
}
389
411
412
+ /**
413
+ * Type-safe way to bind a listener for a PngPhysicalPixelDimensionsEvent.
414
+ * @param {function(PngPhysicalPixelDimensionsEvent): void } listener
415
+ * @returns {PngParser } for chaining
416
+ */
417
+ onPhysicalPixelDimensions ( listener ) {
418
+ super . addEventListener ( PngParseEventType . pHYs , listener ) ;
419
+ return this ;
420
+ }
421
+
390
422
/**
391
423
* Type-safe way to bind a listener for a PngSignificantBitsEvent.
392
424
* @param {function(PngSignificantBitsEvent): void } listener
@@ -571,6 +603,21 @@ export class PngParser extends EventTarget {
571
603
this . dispatchEvent ( new PngPaletteEvent ( this . palette ) ) ;
572
604
break ;
573
605
606
+ // https://www.w3.org/TR/png-3/#11pHYs
607
+ case 'pHYs' :
608
+ /** @type {physicalPixelDimensions } */
609
+ const pixelDims = {
610
+ pixelPerUnitX : chStream . readNumber ( 4 ) ,
611
+ pixelPerUnitY : chStream . readNumber ( 4 ) ,
612
+ unitSpecifier : chStream . readNumber ( 1 ) ,
613
+ } ;
614
+ if ( ! Object . values ( PngUnitSpecifier ) . includes ( pixelDims . unitSpecifier ) ) {
615
+ throw `Bad pHYs unit specifier: ${ pixelDims . unitSpecifier } ` ;
616
+ }
617
+
618
+ this . dispatchEvent ( new PngPhysicalPixelDimensionsEvent ( pixelDims ) ) ;
619
+ break ;
620
+
574
621
// https://www.w3.org/TR/png-3/#11tEXt
575
622
case 'tEXt' :
576
623
const byteArr = chStream . peekBytes ( length ) ;
@@ -750,7 +797,10 @@ async function main() {
750
797
// console.dir(evt.backgroundColor);
751
798
} ) ;
752
799
parser . onLastModTime ( evt => {
753
- console . dir ( evt . lastModTime ) ;
800
+ // console.dir(evt.lastModTime);
801
+ } ) ;
802
+ parser . onPhysicalPixelDimensions ( evt => {
803
+ // console.dir(evt.physicalPixelDimensions);
754
804
} ) ;
755
805
756
806
try {
0 commit comments