Skip to content

Commit 7b1906a

Browse files
committed
PngParser: Add support for hIST chunk
1 parent aeb5bb2 commit 7b1906a

File tree

3 files changed

+44
-3
lines changed

3 files changed

+44
-3
lines changed

image/parsers/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ General-purpose, event-based parsers for digital images.
22

33
Currently supports GIF, JPEG, and PNG.
44

5-
Some nice implementations of Exif parsing for PNG, HEIF, TIFF here:
5+
Some nice implementations of Exif parsing for HEIF, TIFF here:
66
https://github.com/MikeKovarik/exifr/tree/master/src/file-parsers

image/parsers/png.js

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { getExifProfile } from './exif.js';
1717
// https://www.w3.org/TR/png-3/
1818
// https://en.wikipedia.org/wiki/PNG#File_format
1919

20-
// TODO: Ancillary chunks: hIST, sPLT.
20+
// TODO: Ancillary chunks: sPLT.
2121

2222
// let DEBUG = true;
2323
let DEBUG = false;
@@ -35,6 +35,7 @@ export const PngParseEventType = {
3535
cHRM: 'chromaticities_white_point',
3636
eXIf: 'exif_profile',
3737
gAMA: 'image_gamma',
38+
hIST: 'histogram',
3839
iTXt: 'intl_text_data',
3940
pHYs: 'physical_pixel_dims',
4041
sBIT: 'significant_bits',
@@ -299,6 +300,20 @@ export class PngExifProfileEvent extends Event {
299300
}
300301
}
301302

303+
/**
304+
* @typedef PngHistogram
305+
* @property {number[]} frequencies The # of frequencies matches the # of palette entries.
306+
*/
307+
308+
export class PngHistogramEvent extends Event {
309+
/** @param {PngHistogram} histogram */
310+
constructor(histogram) {
311+
super(PngParseEventType.hIST);
312+
/** @type {PngHistogram} */
313+
this.histogram = histogram;
314+
}
315+
}
316+
302317
/**
303318
* @typedef PngChunk Internal use only.
304319
* @property {number} length
@@ -326,7 +341,6 @@ export class PngParser extends EventTarget {
326341
*/
327342
palette;
328343

329-
330344
/** @param {ArrayBuffer} ab */
331345
constructor(ab) {
332346
super();
@@ -384,6 +398,16 @@ export class PngParser extends EventTarget {
384398
return this;
385399
}
386400

401+
/**
402+
* Type-safe way to bind a listener for a PngHistogramEvent.
403+
* @param {function(PngHistogramEvent): void} listener
404+
* @returns {PngParser} for chaining
405+
*/
406+
onHistogram(listener) {
407+
super.addEventListener(PngParseEventType.hIST, listener);
408+
return this;
409+
}
410+
387411
/**
388412
* Type-safe way to bind a listener for a PngImageDataEvent.
389413
* @param {function(PngImageDataEvent): void} listener
@@ -746,6 +770,20 @@ export class PngParser extends EventTarget {
746770
this.dispatchEvent(new PngExifProfileEvent(exifValueMap));
747771
break;
748772

773+
// https://www.w3.org/TR/png-3/#11hIST
774+
case 'hIST':
775+
if (!this.palette) throw `hIST before PLTE`;
776+
if (length !== this.palette.entries.length * 2) throw `Bad # of hIST frequencies: ${length / 2}`;
777+
778+
/** @type {PngHistogram} */
779+
const hist = { frequencies: [] };
780+
for (let f = 0; f < this.palette.entries.length; ++f) {
781+
hist.frequencies.push(chStream.readNumber(2));
782+
}
783+
784+
this.dispatchEvent(new PngHistogramEvent(hist));
785+
break;
786+
749787
// https://www.w3.org/TR/png-3/#11IDAT
750788
case 'IDAT':
751789
/** @type {PngImageData} */
@@ -836,6 +874,9 @@ async function main() {
836874
parser.onExifProfile(evt => {
837875
// console.dir(evt.exifProfile);
838876
});
877+
parser.onHistogram(evt => {
878+
// console.dir(evt.histogram);
879+
});
839880

840881
try {
841882
await parser.start();

tests/image-testfiles/ch1n3p04.png

258 Bytes
Loading

0 commit comments

Comments
 (0)