Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add hasPngSignature method #36

Merged
merged 1 commit into from
Feb 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 6 additions & 16 deletions src/PngDecoder.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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;
Expand Down Expand Up @@ -66,25 +67,14 @@ export default class PngDecoder extends IOBuffer {
}

public decode(): DecodedPng {
this.decodeSignature();
checkSignature(this);
while (!this._end) {
this.decodeChunk();
}
this.decodeImage();
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();
Expand Down
14 changes: 5 additions & 9 deletions src/PngEncoder.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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 = {}) {
Expand All @@ -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);
Expand Down
11 changes: 7 additions & 4 deletions src/__tests__/decode.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down
2 changes: 0 additions & 2 deletions src/common.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
27 changes: 27 additions & 0 deletions src/helpers/signature.ts
Original file line number Diff line number Diff line change
@@ -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<number>) {
if (array.length < pngSignature.length) {
return false;
}
for (let i = 0; i < pngSignature.length; i++) {
if (array[i] !== pngSignature[i]) {
return false;
}
}
return true;
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
PngEncoderOptions,
} from './types';

export { hasPngSignature } from './helpers/signature';
export * from './types';

function decodePng(
Expand Down
Loading