mirror of
https://github.com/codedread/bitjs
synced 2025-10-03 09:39:16 +02:00
PngParser: Add support for zTXt chunk
This commit is contained in:
parent
afb1a67f2d
commit
ade8f1a9ab
2 changed files with 59 additions and 1 deletions
|
@ -14,7 +14,7 @@ import { ByteStream } from '../../io/bytestream.js';
|
||||||
// https://www.w3.org/TR/png-3/
|
// https://www.w3.org/TR/png-3/
|
||||||
// https://en.wikipedia.org/wiki/PNG#File_format
|
// https://en.wikipedia.org/wiki/PNG#File_format
|
||||||
|
|
||||||
// TODO: Ancillary chunks bKGD, eXIf, hIST, iTXt, pHYs, sPLT, tIME, zTXt.
|
// TODO: Ancillary chunks bKGD, eXIf, hIST, iTXt, pHYs, sPLT, tIME.
|
||||||
|
|
||||||
// let DEBUG = true;
|
// let DEBUG = true;
|
||||||
let DEBUG = false;
|
let DEBUG = false;
|
||||||
|
@ -33,6 +33,7 @@ export const PngParseEventType = {
|
||||||
sBIT: 'significant_bits',
|
sBIT: 'significant_bits',
|
||||||
tEXt: 'textual_data',
|
tEXt: 'textual_data',
|
||||||
tRNS: 'transparency',
|
tRNS: 'transparency',
|
||||||
|
zTXt: 'compressed_textual_data',
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @enum {number} */
|
/** @enum {number} */
|
||||||
|
@ -186,6 +187,22 @@ export class PngTextualDataEvent extends Event {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef PngCompressedTextualData
|
||||||
|
* @property {string} keyword
|
||||||
|
* @property {number} compressionMethod Only value supported is 0 for deflate compression.
|
||||||
|
* @property {Uint8Array=} compressedText
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class PngCompressedTextualDataEvent extends Event {
|
||||||
|
/** @param {PngCompressedTextualData} compressedTextualData */
|
||||||
|
constructor(compressedTextualData) {
|
||||||
|
super(PngParseEventType.zTXt);
|
||||||
|
/** @type {PngCompressedTextualData} */
|
||||||
|
this.compressedTextualData = compressedTextualData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef PngChunk Internal use only.
|
* @typedef PngChunk Internal use only.
|
||||||
* @property {number} length
|
* @property {number} length
|
||||||
|
@ -231,6 +248,16 @@ export class PngParser extends EventTarget {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type-safe way to bind a listener for a PngCompressedTextualDataEvent.
|
||||||
|
* @param {function(PngCompressedTextualDataEvent): void} listener
|
||||||
|
* @returns {PngParser} for chaining
|
||||||
|
*/
|
||||||
|
onCompressedTextualData(listener) {
|
||||||
|
super.addEventListener(PngParseEventType.zTXt, listener);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type-safe way to bind a listener for a PngImageGammaEvent.
|
* Type-safe way to bind a listener for a PngImageGammaEvent.
|
||||||
* @param {function(PngImageGammaEvent): void} listener
|
* @param {function(PngImageGammaEvent): void} listener
|
||||||
|
@ -479,6 +506,20 @@ export class PngParser extends EventTarget {
|
||||||
this.dispatchEvent(new PngTransparencyEvent(transparency));
|
this.dispatchEvent(new PngTransparencyEvent(transparency));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/png-3/#11zTXt
|
||||||
|
case 'zTXt':
|
||||||
|
const compressedByteArr = chStream.peekBytes(length);
|
||||||
|
const compressedNullIndex = compressedByteArr.indexOf(0);
|
||||||
|
|
||||||
|
/** @type {PngCompressedTextualData} */
|
||||||
|
const compressedTextualData = {
|
||||||
|
keyword: chStream.readString(compressedNullIndex),
|
||||||
|
compressionMethod: chStream.skip(1).readNumber(1),
|
||||||
|
compressedText: chStream.readBytes(length - compressedNullIndex - 2),
|
||||||
|
};
|
||||||
|
this.dispatchEvent(new PngCompressedTextualDataEvent(compressedTextualData));
|
||||||
|
break;
|
||||||
|
|
||||||
// https://www.w3.org/TR/png-3/#11IDAT
|
// https://www.w3.org/TR/png-3/#11IDAT
|
||||||
case 'IDAT':
|
case 'IDAT':
|
||||||
/** @type {PngImageData} */
|
/** @type {PngImageData} */
|
||||||
|
@ -551,6 +592,9 @@ async function main() {
|
||||||
parser.onTextualData(evt => {
|
parser.onTextualData(evt => {
|
||||||
// console.dir(evt.textualData);
|
// console.dir(evt.textualData);
|
||||||
});
|
});
|
||||||
|
parser.onCompressedTextualData(evt => {
|
||||||
|
// console.dir(evt.compressedTextualData);
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await parser.start();
|
await parser.start();
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { expect } from 'chai';
|
||||||
import { PngColorType, PngInterlaceMethod, PngParser } from '../image/parsers/png.js';
|
import { PngColorType, PngInterlaceMethod, PngParser } from '../image/parsers/png.js';
|
||||||
|
|
||||||
/** @typedef {import('../image/parsers/png.js').PngChromaticies} PngChromaticies */
|
/** @typedef {import('../image/parsers/png.js').PngChromaticies} PngChromaticies */
|
||||||
|
/** @typedef {import('../image/parsers/png.js').PngCompressedTextualData} PngCompressedTextualData */
|
||||||
/** @typedef {import('../image/parsers/png.js').PngImageData} PngImageData */
|
/** @typedef {import('../image/parsers/png.js').PngImageData} PngImageData */
|
||||||
/** @typedef {import('../image/parsers/png.js').PngImageGamma} PngImageGamma */
|
/** @typedef {import('../image/parsers/png.js').PngImageGamma} PngImageGamma */
|
||||||
/** @typedef {import('../image/parsers/png.js').PngImageHeader} PngImageHeader */
|
/** @typedef {import('../image/parsers/png.js').PngImageHeader} PngImageHeader */
|
||||||
|
@ -166,4 +167,17 @@ describe('bitjs.image.parsers.PngParser', () => {
|
||||||
expect(textualDataArr[1].keyword).equals('Author');
|
expect(textualDataArr[1].keyword).equals('Author');
|
||||||
expect(textualDataArr[1].textString).equals('Willem A.J. van Schaik\n(willem@schaik.com)');
|
expect(textualDataArr[1].textString).equals('Willem A.J. van Schaik\n(willem@schaik.com)');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('extracts zTXt', async () => {
|
||||||
|
/** @type {PngCompressedTextualData} */
|
||||||
|
let data;
|
||||||
|
|
||||||
|
await getPngParser('tests/image-testfiles/ctzn0g04.png')
|
||||||
|
.onCompressedTextualData(evt => { data = evt.compressedTextualData })
|
||||||
|
.start();
|
||||||
|
|
||||||
|
expect(data.keyword).equals('Disclaimer');
|
||||||
|
expect(data.compressionMethod).equals(0);
|
||||||
|
expect(data.compressedText.byteLength).equals(17);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue