From 0cc9dd8d2df0094067293018370b896214c5e10b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Sat, 10 Feb 2024 16:42:44 +0100 Subject: [PATCH] feat: add hasPngSignature method Closes: https://github.com/image-js/fast-png/issues/30 --- src/PngDecoder.ts | 22 ++++++---------------- src/PngEncoder.ts | 14 +++++--------- src/__tests__/decode.test.ts | 11 +++++++---- src/common.ts | 2 -- src/helpers/signature.ts | 27 +++++++++++++++++++++++++++ src/index.ts | 1 + 6 files changed, 46 insertions(+), 31 deletions(-) create mode 100644 src/helpers/signature.ts diff --git a/src/PngDecoder.ts b/src/PngDecoder.ts index 6dab44a..db353a0 100644 --- a/src/PngDecoder.ts +++ b/src/PngDecoder.ts @@ -1,7 +1,8 @@ import { IOBuffer } from 'iobuffer'; import { inflate, Inflate as Inflator } from 'pako'; -import { pngSignature, crc } from './common'; +import { crc } from './common'; +import { checkSignature } from './helpers/signature'; import { ColorType, CompressionMethod, @@ -25,9 +26,9 @@ const uint8 = new Uint8Array(uint16.buffer); const osIsLittleEndian = uint8[0] === 0xff; export default class PngDecoder extends IOBuffer { - private _checkCrc: boolean; - private _inflator: Inflator; - private _png: DecodedPng; + private readonly _checkCrc: boolean; + private readonly _inflator: Inflator; + private readonly _png: DecodedPng; private _end: boolean; private _hasPalette: boolean; private _palette: IndexedColors; @@ -66,7 +67,7 @@ export default class PngDecoder extends IOBuffer { } public decode(): DecodedPng { - this.decodeSignature(); + checkSignature(this); while (!this._end) { this.decodeChunk(); } @@ -74,17 +75,6 @@ export default class PngDecoder extends IOBuffer { return this._png; } - // https://www.w3.org/TR/PNG/#5PNG-file-signature - private decodeSignature(): void { - for (let i = 0; i < pngSignature.length; i++) { - if (this.readUint8() !== pngSignature[i]) { - throw new Error( - `wrong PNG signature. Byte at ${i} should be ${pngSignature[i]}.`, - ); - } - } - } - // https://www.w3.org/TR/PNG/#5Chunk-layout private decodeChunk(): void { const length = this.readUint32(); diff --git a/src/PngEncoder.ts b/src/PngEncoder.ts index fc1c7ec..1f19202 100644 --- a/src/PngEncoder.ts +++ b/src/PngEncoder.ts @@ -1,7 +1,8 @@ import { IOBuffer } from 'iobuffer'; import { deflate } from 'pako'; -import { pngSignature, crc } from './common'; +import { crc } from './common'; +import { writeSignature } from './helpers/signature'; import { ColorType, CompressionMethod, @@ -22,8 +23,8 @@ const defaultZlibOptions: DeflateFunctionOptions = { }; export default class PngEncoder extends IOBuffer { - private _png: DecodedPng; - private _zlibOptions: DeflateFunctionOptions; + private readonly _png: DecodedPng; + private readonly _zlibOptions: DeflateFunctionOptions; private _colorType: ColorType; public constructor(data: ImageData, options: PngEncoderOptions = {}) { @@ -35,18 +36,13 @@ export default class PngEncoder extends IOBuffer { } public encode(): Uint8Array { - this.encodeSignature(); + writeSignature(this); this.encodeIHDR(); this.encodeData(); this.encodeIEND(); return this.toArray(); } - // https://www.w3.org/TR/PNG/#5PNG-file-signature - private encodeSignature(): void { - this.writeBytes(pngSignature); - } - // https://www.w3.org/TR/PNG/#11IHDR private encodeIHDR(): void { this.writeUint32(13); diff --git a/src/__tests__/decode.test.ts b/src/__tests__/decode.test.ts index 57ae673..3882272 100644 --- a/src/__tests__/decode.test.ts +++ b/src/__tests__/decode.test.ts @@ -88,10 +88,13 @@ describe('decode', () => { loadAndDecode('palette.png', { checkCrc: true }); }); - it('should throw with a non-png', () => { - expect(() => decode(new Uint8Array(20))).toThrow( - 'wrong PNG signature. Byte at 0 should be 137.', - ); + it.each([ + // Enough values, last one is wrong. + Uint8Array.of(137, 80, 78, 71, 13, 10, 26, 9, 0, 0, 0), + // Not enough values. + Uint8Array.of(137, 80), + ])('should throw with a non-png', (value) => { + expect(() => decode(value)).toThrow('wrong PNG signature'); }); it('ICC Embeded Profile', () => { diff --git a/src/common.ts b/src/common.ts index 2f54fdf..8e28166 100644 --- a/src/common.ts +++ b/src/common.ts @@ -1,5 +1,3 @@ -export const pngSignature = [137, 80, 78, 71, 13, 10, 26, 10]; - const crcTable: number[] = []; for (let n = 0; n < 256; n++) { let c = n; diff --git a/src/helpers/signature.ts b/src/helpers/signature.ts new file mode 100644 index 0000000..319fc66 --- /dev/null +++ b/src/helpers/signature.ts @@ -0,0 +1,27 @@ +import type { IOBuffer } from 'iobuffer'; + +// https://www.w3.org/TR/PNG/#5PNG-file-signature + +const pngSignature = Uint8Array.of(137, 80, 78, 71, 13, 10, 26, 10); + +export function writeSignature(buffer: IOBuffer) { + buffer.writeBytes(pngSignature); +} + +export function checkSignature(buffer: IOBuffer) { + if (!hasPngSignature(buffer.readBytes(pngSignature.length))) { + throw new Error('wrong PNG signature'); + } +} + +export function hasPngSignature(array: ArrayLike) { + if (array.length < pngSignature.length) { + return false; + } + for (let i = 0; i < pngSignature.length; i++) { + if (array[i] !== pngSignature[i]) { + return false; + } + } + return true; +} diff --git a/src/index.ts b/src/index.ts index 580c0f3..99c4c33 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,6 +8,7 @@ import { PngEncoderOptions, } from './types'; +export { hasPngSignature } from './helpers/signature'; export * from './types'; function decodePng(