mirror of
https://github.com/codedread/bitjs
synced 2025-10-03 09:39:16 +02:00
PngParser: Add support for pHYs chunk
This commit is contained in:
parent
1869cd7bfa
commit
17b3850745
3 changed files with 67 additions and 5 deletions
|
@ -14,7 +14,7 @@ import { ByteStream } from '../../io/bytestream.js';
|
|||
// https://www.w3.org/TR/png-3/
|
||||
// https://en.wikipedia.org/wiki/PNG#File_format
|
||||
|
||||
// TODO: Ancillary chunks eXIf, hIST, pHYs, sPLT.
|
||||
// TODO: Ancillary chunks eXIf, hIST, sPLT.
|
||||
|
||||
// let DEBUG = true;
|
||||
let DEBUG = false;
|
||||
|
@ -32,6 +32,7 @@ export const PngParseEventType = {
|
|||
cHRM: 'chromaticities_white_point',
|
||||
gAMA: 'image_gamma',
|
||||
iTXt: 'intl_text_data',
|
||||
pHYs: 'physical_pixel_dims',
|
||||
sBIT: 'significant_bits',
|
||||
tEXt: 'textual_data',
|
||||
tIME: 'last_mod_time',
|
||||
|
@ -262,6 +263,27 @@ export class PngLastModTimeEvent extends Event {
|
|||
}
|
||||
}
|
||||
|
||||
export const PngUnitSpecifier = {
|
||||
UNKNOWN: 0,
|
||||
METRE: 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef PngPhysicalPixelDimensions
|
||||
* @property {number} pixelPerUnitX
|
||||
* @property {number} pixelPerUnitY
|
||||
* @property {PngUnitSpecifier} unitSpecifier
|
||||
*/
|
||||
|
||||
export class PngPhysicalPixelDimensionsEvent extends Event {
|
||||
/** @param {PngPhysicalPixelDimensions} physicalPixelDimensions */
|
||||
constructor(physicalPixelDimensions) {
|
||||
super(PngParseEventType.pHYs);
|
||||
/** @type {PngPhysicalPixelDimensions} */
|
||||
this.physicalPixelDimensions = physicalPixelDimensions;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef PngChunk Internal use only.
|
||||
* @property {number} length
|
||||
|
@ -368,8 +390,8 @@ export class PngParser extends EventTarget {
|
|||
}
|
||||
|
||||
/**
|
||||
* Type-safe way to bind a listener for a PngLastModTime.
|
||||
* @param {function(PngLastModTime): void} listener
|
||||
* Type-safe way to bind a listener for a PngLastModTimeEvent.
|
||||
* @param {function(PngLastModTimeEvent): void} listener
|
||||
* @returns {PngParser} for chaining
|
||||
*/
|
||||
onLastModTime(listener) {
|
||||
|
@ -387,6 +409,16 @@ export class PngParser extends EventTarget {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type-safe way to bind a listener for a PngPhysicalPixelDimensionsEvent.
|
||||
* @param {function(PngPhysicalPixelDimensionsEvent): void} listener
|
||||
* @returns {PngParser} for chaining
|
||||
*/
|
||||
onPhysicalPixelDimensions(listener) {
|
||||
super.addEventListener(PngParseEventType.pHYs, listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type-safe way to bind a listener for a PngSignificantBitsEvent.
|
||||
* @param {function(PngSignificantBitsEvent): void} listener
|
||||
|
@ -571,6 +603,21 @@ export class PngParser extends EventTarget {
|
|||
this.dispatchEvent(new PngPaletteEvent(this.palette));
|
||||
break;
|
||||
|
||||
// https://www.w3.org/TR/png-3/#11pHYs
|
||||
case 'pHYs':
|
||||
/** @type {physicalPixelDimensions} */
|
||||
const pixelDims = {
|
||||
pixelPerUnitX: chStream.readNumber(4),
|
||||
pixelPerUnitY: chStream.readNumber(4),
|
||||
unitSpecifier: chStream.readNumber(1),
|
||||
};
|
||||
if (!Object.values(PngUnitSpecifier).includes(pixelDims.unitSpecifier)) {
|
||||
throw `Bad pHYs unit specifier: ${pixelDims.unitSpecifier}`;
|
||||
}
|
||||
|
||||
this.dispatchEvent(new PngPhysicalPixelDimensionsEvent(pixelDims));
|
||||
break;
|
||||
|
||||
// https://www.w3.org/TR/png-3/#11tEXt
|
||||
case 'tEXt':
|
||||
const byteArr = chStream.peekBytes(length);
|
||||
|
@ -750,7 +797,10 @@ async function main() {
|
|||
// console.dir(evt.backgroundColor);
|
||||
});
|
||||
parser.onLastModTime(evt => {
|
||||
console.dir(evt.lastModTime);
|
||||
// console.dir(evt.lastModTime);
|
||||
});
|
||||
parser.onPhysicalPixelDimensions(evt => {
|
||||
// console.dir(evt.physicalPixelDimensions);
|
||||
});
|
||||
|
||||
try {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as fs from 'node:fs';
|
||||
import 'mocha';
|
||||
import { expect } from 'chai';
|
||||
import { PngColorType, PngInterlaceMethod, PngParser } from '../image/parsers/png.js';
|
||||
import { PngColorType, PngInterlaceMethod, PngUnitSpecifier, PngParser } from '../image/parsers/png.js';
|
||||
|
||||
/** @typedef {import('../image/parsers/png.js').PngBackgroundColor} PngBackgroundColor */
|
||||
/** @typedef {import('../image/parsers/png.js').PngChromaticies} PngChromaticies */
|
||||
|
@ -12,6 +12,7 @@ import { PngColorType, PngInterlaceMethod, PngParser } from '../image/parsers/pn
|
|||
/** @typedef {import('../image/parsers/png.js').PngIntlTextualData} PngIntlTextualData */
|
||||
/** @typedef {import('../image/parsers/png.js').PngLastModTime} PngLastModTime */
|
||||
/** @typedef {import('../image/parsers/png.js').PngPalette} PngPalette */
|
||||
/** @typedef {import('../image/parsers/png.js').PngPhysicalPixelDimensions} PngPhysicalPixelDimensions */
|
||||
/** @typedef {import('../image/parsers/png.js').PngSignificantBits} PngSignificantBits */
|
||||
/** @typedef {import('../image/parsers/png.js').PngTextualData} PngTextualData */
|
||||
/** @typedef {import('../image/parsers/png.js').PngTransparency} PngTransparency */
|
||||
|
@ -248,4 +249,15 @@ describe('bitjs.image.parsers.PngParser', () => {
|
|||
expect(lastModTime.minute).equals(59);
|
||||
expect(lastModTime.second).equals(59);
|
||||
});
|
||||
|
||||
it('extracts pHYs', async () => {
|
||||
/** @type {PngPhysicalPixelDimensions} */
|
||||
let pixelDims;
|
||||
await getPngParser('tests/image-testfiles/cdun2c08.png')
|
||||
.onPhysicalPixelDimensions(evt => { pixelDims = evt.physicalPixelDimensions })
|
||||
.start();
|
||||
expect(pixelDims.pixelPerUnitX).equals(1000);
|
||||
expect(pixelDims.pixelPerUnitY).equals(1000);
|
||||
expect(pixelDims.unitSpecifier).equals(PngUnitSpecifier.METRE);
|
||||
});
|
||||
});
|
||||
|
|
BIN
tests/image-testfiles/cdun2c08.png
Normal file
BIN
tests/image-testfiles/cdun2c08.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 724 B |
Loading…
Add table
Add a link
Reference in a new issue