diff --git a/public/common/bytes.js b/public/common/bytes.js
new file mode 100644
index 0000000..7337a73
--- /dev/null
+++ b/public/common/bytes.js
@@ -0,0 +1,28 @@
+// @ts-check
+
+/**
+ * @param {Uint8Array} a
+ * @param {Uint8Array} b
+ * @returns {boolean}
+ */
+export const areBytesEqual = (a, b) => {
+ if (a.length !== b.length) return false;
+ for (let i = 0; i < a.length; i++) {
+ if (a[i] !== b[i]) return false;
+ }
+ return true;
+};
+
+/**
+ * @param {Uint8Array} bytes
+ * @param {number} size
+ * @returns {Uint8Array[]}
+ */
+export const chunkBytes = (bytes, size) => {
+ /** @type {Uint8Array[]} */
+ const result = [];
+ for (let i = 0; i < bytes.byteLength; i += size) {
+ result.push(bytes.subarray(i, i + size));
+ }
+ return result;
+};
diff --git a/public/png/constants.js b/public/png/constants.js
new file mode 100644
index 0000000..5f4ce5a
--- /dev/null
+++ b/public/png/constants.js
@@ -0,0 +1,99 @@
+// @ts-check
+
+/** @enum {string} */
+export const PngNodeType = [
+ "root",
+ "signature",
+
+ "unknownChunk",
+ "chunkLength",
+ "chunkType",
+ "chunkData",
+ "chunkCrc",
+
+ "ihdr",
+ "ihdrChunkData",
+ "ihdrWidth",
+ "ihdrHeight",
+ "ihdrBitDepth",
+ "ihdrColourType",
+ "ihdrCompressionMethod",
+ "ihdrFilterMethod",
+ "ihdrInterlaceMethod",
+
+ "plte",
+ "plteChunkData",
+ "plteColor",
+
+ "idat",
+ "idatChunkData",
+
+ "iend",
+ "iendChunkLength",
+
+ "trns",
+
+ "chrm",
+
+ "gama",
+
+ "iccp",
+
+ "sbit",
+
+ "srgb",
+
+ "cicp",
+
+ "text",
+ "textData",
+ "textKeyword",
+ "textNullSeparator",
+ "textString",
+
+ "ztxt",
+ "ztxtData",
+ "ztxtCompressionMethod",
+ "ztxtString",
+
+ "itxt",
+
+ "bkgd",
+
+ "hist",
+
+ "phys",
+
+ "splt",
+
+ "exif",
+
+ "time",
+
+ "actl",
+
+ "fctl",
+
+ "fdat",
+
+ "offs",
+
+ "pcal",
+
+ "scal",
+
+ "gifg",
+
+ "gifx",
+
+ "gift",
+
+ "ster",
+
+ "dsig",
+
+ "idot",
+].reduce((result, id) => {
+ result[id] = id;
+ return result;
+}, Object.create(null));
diff --git a/public/png/crc32.js b/public/png/crc32.js
new file mode 100644
index 0000000..37028be
--- /dev/null
+++ b/public/png/crc32.js
@@ -0,0 +1,28 @@
+// @ts-check
+
+/** * @type {number[]} */
+const crcTable = [];
+for (let i = 0; i < 256; i++) {
+ let b = i;
+ for (let j = 0; j < 8; j++) {
+ b = b & 1 ? 0xedb88320 ^ (b >>> 1) : b >>> 1;
+ }
+ crcTable[i] = b >>> 0;
+}
+
+/**
+ * Compute the CRC32 checksum of some `Uint8Array`s.
+ * @param {Uint8Array[]} uint8arrays
+ * @returns {number}
+ */
+export default (...uint8arrays) => {
+ let crc = -1;
+
+ for (const bytes of uint8arrays) {
+ for (let i = 0; i < bytes.length; i++) {
+ crc = crcTable[(crc ^ bytes[i]) & 0xff] ^ (crc >>> 8);
+ }
+ }
+
+ return (crc ^ -1) >>> 0;
+};
diff --git a/public/png/index.html b/public/png/index.html
index 786effd..a83c846 100644
--- a/public/png/index.html
+++ b/public/png/index.html
@@ -11,7 +11,7 @@
-
+ Failed to parse PNG
diff --git a/public/png/parsePng.js b/public/png/parsePng.js
new file mode 100644
index 0000000..d7dda03
--- /dev/null
+++ b/public/png/parsePng.js
@@ -0,0 +1,305 @@
+// @ts-check
+
+import { PngNodeType } from "./constants.js";
+import { areBytesEqual, chunkBytes } from "../common/bytes.js";
+import crc32 from "./crc32.js";
+
+/** @typedef {import("../../types/png.d.ts").Node
} PngNode */
+
+const PNG_SIGNATURE = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]);
+
+const textDecoder = new TextDecoder();
+
+/**
+ * @param {Uint8Array} bytes
+ * @returns {null | PngNode} The root node of the PNG tree, or null if the PNG is invalid.
+ */
+export default (bytes) => {
+ if (!isSignatureValid(bytes)) {
+ console.warn("Invalid PNG signature");
+ return null;
+ }
+
+ /** @type {PngNode[]} */
+ const children = [{ type: PngNodeType.signature, bytes: PNG_SIGNATURE }];
+
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
+
+ for (let i = PNG_SIGNATURE.length; i < bytes.length;) {
+ const lengthBytes = bytes.subarray(i, i + 4);
+ if (lengthBytes.byteLength !== 4) {
+ console.warn("Invalid data. Did the file end too early?");
+ return null;
+ }
+ const length = view.getUint32(i);
+ i += 4;
+
+ const typeBytes = bytes.subarray(i, i + 4);
+ const type = parseType(typeBytes);
+ if (!type) {
+ console.warn("Invalid chunk type)");
+ return null;
+ }
+ i += 4;
+
+ const data = bytes.subarray(i, i + length);
+ if (data.length !== length) {
+ console.warn("Invalid data. Did the file end too early?");
+ return null;
+ }
+ i += length;
+
+ const actualCrcBytes = bytes.subarray(i, i + 4);
+ if (actualCrcBytes.length !== 4) {
+ console.warn("Not enough bytes for the CRC. Did the file end too early?");
+ return null;
+ }
+ const actualCrc = view.getUint32(i);
+ const expectedCrc = crc32(typeBytes, data);
+ if (actualCrc !== expectedCrc) {
+ console.warn("Invalid chunk CRC");
+ return null;
+ }
+ i += 4;
+
+ const allBytes = bytes.subarray(i - length - 12, i);
+
+ children.push(
+ formatChunk(allBytes, lengthBytes, typeBytes, data, actualCrcBytes),
+ );
+ }
+
+ return { type: PngNodeType.root, bytes, children };
+};
+
+/**
+ * @param {Uint8Array} bytes
+ * @returns {boolean}
+ */
+const isSignatureValid = (bytes) =>
+ areBytesEqual(bytes.subarray(0, 8), PNG_SIGNATURE);
+
+/**
+ * @param {Uint8Array} bytes
+ * @returns {null | string} The chunk type, or null if the chunk type is invalid.
+ */
+const parseType = (bytes) => {
+ if (bytes.length !== 4) return null;
+ const result = textDecoder.decode(bytes);
+ if (!/^[A-Za-z]{4}$/.test(result)) return null;
+ return result;
+};
+
+/**
+ * @param {Uint8Array} allBytes All the bytes in the chunk.
+ * @param {Uint8Array} lengthBytes
+ * @param {Uint8Array} typeBytes
+ * @param {Uint8Array} data
+ * @param {Uint8Array} crcBytes
+ * @returns {PngNode}
+ */
+const formatChunk = (allBytes, lengthBytes, typeBytes, data, crcBytes) => {
+ /** @type {PngNodeType} */
+ let type = PngNodeType.unknownChunk;
+
+ /** @type {PngNode} */
+ let chunkLengthNode = { type: PngNodeType.chunkLength, bytes: lengthBytes };
+ /** @type {PngNode} */
+ const chunkTypeNode = { type: PngNodeType.chunkType, bytes: typeBytes };
+ /** @type {PngNode} */
+ let chunkDataNode = { type: PngNodeType.chunkData, bytes: data };
+ /** @type {PngNode} */
+ const chunkCrcNode = { type: PngNodeType.chunkCrc, bytes: crcBytes };
+
+ switch (textDecoder.decode(typeBytes)) {
+ case "IHDR":
+ type = PngNodeType.ihdr;
+ chunkDataNode = {
+ ...chunkDataNode,
+ type: PngNodeType.ihdrChunkData,
+ children: [
+ { type: PngNodeType.ihdrWidth, bytes: data.subarray(0, 4) },
+ { type: PngNodeType.ihdrHeight, bytes: data.subarray(4, 8) },
+ { type: PngNodeType.ihdrBitDepth, bytes: data.subarray(8, 9) },
+ { type: PngNodeType.ihdrColourType, bytes: data.subarray(9, 10) },
+ {
+ type: PngNodeType.ihdrCompressionMethod,
+ bytes: data.subarray(10, 11),
+ },
+ { type: PngNodeType.ihdrFilterMethod, bytes: data.subarray(11, 12) },
+ {
+ type: PngNodeType.ihdrInterlaceMethod,
+ bytes: data.subarray(12, 13),
+ },
+ ],
+ };
+ break;
+ case "PLTE":
+ type = PngNodeType.plte;
+ chunkDataNode = {
+ ...chunkDataNode,
+ type: PngNodeType.plteChunkData,
+ children: chunkBytes(data, 3).map((bytes) => ({
+ type: PngNodeType.plteColor,
+ bytes,
+ })),
+ };
+ break;
+ case "IDAT":
+ type = PngNodeType.idat;
+ chunkDataNode = { ...chunkDataNode, type: PngNodeType.idatChunkData };
+ break;
+ case "IEND":
+ type = PngNodeType.iend;
+ chunkLengthNode = {
+ ...chunkLengthNode,
+ type: PngNodeType.iendChunkLength,
+ };
+ break;
+ case "tRNS":
+ type = PngNodeType.trns;
+ break;
+ case "cHRM":
+ type = PngNodeType.chrm;
+ break;
+ case "gAMA":
+ type = PngNodeType.gama;
+ break;
+ case "iCCP":
+ type = PngNodeType.iccp;
+ break;
+ case "sBIT":
+ type = PngNodeType.sbit;
+ break;
+ case "sRGB":
+ type = PngNodeType.srgb;
+ break;
+ case "cICP":
+ type = PngNodeType.cicp;
+ break;
+ case "tEXt": {
+ type = PngNodeType.text;
+ const nullSeparatorIndex = data.indexOf(0);
+ if (nullSeparatorIndex === -1) break;
+ chunkDataNode = {
+ ...chunkDataNode,
+ type: PngNodeType.textData,
+ children: [
+ {
+ type: PngNodeType.textKeyword,
+ bytes: data.subarray(0, nullSeparatorIndex),
+ },
+ {
+ type: PngNodeType.textNullSeparator,
+ bytes: data.subarray(nullSeparatorIndex, nullSeparatorIndex + 1),
+ },
+ {
+ type: PngNodeType.textString,
+ bytes: data.subarray(nullSeparatorIndex + 1),
+ },
+ ],
+ };
+ break;
+ }
+ case "zTXt": {
+ type = PngNodeType.ztxt;
+ const nullSeparatorIndex = data.indexOf(0);
+ if (nullSeparatorIndex === -1) break;
+ chunkDataNode = {
+ ...chunkDataNode,
+ type: PngNodeType.ztxtData,
+ children: [
+ {
+ type: PngNodeType.textKeyword,
+ bytes: data.subarray(0, nullSeparatorIndex),
+ },
+ {
+ type: PngNodeType.textNullSeparator,
+ bytes: data.subarray(nullSeparatorIndex, nullSeparatorIndex + 1),
+ },
+ {
+ type: PngNodeType.ztxtCompressionMethod,
+ bytes: data.subarray(
+ nullSeparatorIndex + 1,
+ nullSeparatorIndex + 2,
+ ),
+ },
+ {
+ type: PngNodeType.ztxtString,
+ bytes: data.subarray(nullSeparatorIndex + 2),
+ },
+ ],
+ };
+ break;
+ }
+ case "iTXt":
+ type = PngNodeType.itxt;
+ break;
+ case "bKGD":
+ type = PngNodeType.bkgd;
+ break;
+ case "hIST":
+ type = PngNodeType.hist;
+ break;
+ case "pHYs":
+ type = PngNodeType.phys;
+ break;
+ case "sPLT":
+ type = PngNodeType.splt;
+ break;
+ case "eXIf":
+ type = PngNodeType.exif;
+ break;
+ case "tIME":
+ type = PngNodeType.time;
+ break;
+ case "acTL":
+ type = PngNodeType.actl;
+ break;
+ case "fcTL":
+ type = PngNodeType.fctl;
+ break;
+ case "fdAT":
+ type = PngNodeType.fdat;
+ break;
+ case "oFFs":
+ type = PngNodeType.offs;
+ break;
+ case "pCAL":
+ type = PngNodeType.pcal;
+ break;
+ case "sCAL":
+ type = PngNodeType.scal;
+ break;
+ case "gIFg":
+ type = PngNodeType.gifg;
+ break;
+ case "gIFx":
+ type = PngNodeType.gifx;
+ break;
+ case "gIFt":
+ type = PngNodeType.gift;
+ break;
+ case "sTER":
+ type = PngNodeType.ster;
+ break;
+ case "dSIG":
+ type = PngNodeType.dsig;
+ break;
+ case "iDOT":
+ type = PngNodeType.idot;
+ break;
+ default:
+ console.warn(`Unknown chunk type ${type}`);
+ break;
+ }
+
+ /** @type {PngNode[]} */
+ const children = [];
+ children.push(chunkLengthNode);
+ children.push(chunkTypeNode);
+ if (data.byteLength) children.push(chunkDataNode);
+ children.push(chunkCrcNode);
+
+ return { type, bytes: allBytes, children };
+};
diff --git a/public/png/png.js b/public/png/png.js
index 05eb284..e771cf4 100644
--- a/public/png/png.js
+++ b/public/png/png.js
@@ -1,5 +1,7 @@
// @ts-check
+import parsePng from "./parsePng.js";
+
import parseHash from "./parseHash.js";
const errorEl = document.getElementById("error");
@@ -14,8 +16,17 @@ const main = () => {
return;
}
+ const { bytes } = parsedHash;
+
+ const rootNode = parsePng(bytes);
+ if (!rootNode) {
+ // TODO: Is there better UI than this?
+ errorEl.removeAttribute("hidden");
+ return;
+ }
+
// TODO: Actually do something!
- console.log(parsedHash);
+ console.log(rootNode);
};
main();
diff --git a/test/common/base64url.test.ts b/test/common/base64url.test.ts
index d881f53..c4dcf90 100644
--- a/test/common/base64url.test.ts
+++ b/test/common/base64url.test.ts
@@ -1,11 +1,7 @@
import { assertEquals } from "assert";
+import { b } from "../helpers.ts";
import * as base64url from "../../public/common/base64url.js";
-/**
- * A shorthand for `new Uint8Array()`.
- */
-const b = (...bytes: number[]) => new Uint8Array(bytes);
-
Deno.test('encodes no bytes as ""', () => {
assertEquals(base64url.stringify(b()), "");
});
diff --git a/test/common/bytes.test.ts b/test/common/bytes.test.ts
new file mode 100644
index 0000000..01d1a99
--- /dev/null
+++ b/test/common/bytes.test.ts
@@ -0,0 +1,20 @@
+import { assert, assertEquals } from "assert";
+import { b } from "../helpers.ts";
+import { areBytesEqual, chunkBytes } from "../../public/common/bytes.js";
+
+Deno.test("areBytesEqual", () => {
+ const x = b(1, 2);
+ const y = b(1, 2, 3);
+ const z = b(1, 2, 3);
+
+ assert(areBytesEqual(x, x));
+ assert(areBytesEqual(y, z));
+ assert(!areBytesEqual(x, y));
+});
+
+Deno.test("chunkBytes", () => {
+ assertEquals(
+ chunkBytes(b(1, 2, 3, 4, 5, 6, 7, 8), 3),
+ [b(1, 2, 3), b(4, 5, 6), b(7, 8)],
+ );
+});
diff --git a/test/helpers.ts b/test/helpers.ts
new file mode 100644
index 0000000..a30eb38
--- /dev/null
+++ b/test/helpers.ts
@@ -0,0 +1,25 @@
+import { stub } from "mock";
+
+/**
+ * A shorthand for `new Uint8Array()`.
+ */
+export const b = (...bytes: number[]) => new Uint8Array(bytes);
+
+/**
+ * @example
+ * Deno.test("works", stubbingWarn(() => {
+ * // ...
+ * }));
+ */
+export const stubbingWarn = (
+ fn: (t: Deno.TestContext) => void | Promise,
+): (t: Deno.TestContext) => Promise => (
+ async (t) => {
+ const warnStub = stub(console, "warn");
+ try {
+ return await fn(t);
+ } finally {
+ warnStub.restore();
+ }
+ }
+);
diff --git a/test/png/crc32.test.ts b/test/png/crc32.test.ts
new file mode 100644
index 0000000..07f2aa5
--- /dev/null
+++ b/test/png/crc32.test.ts
@@ -0,0 +1,21 @@
+import { assertEquals } from "assert";
+import { b } from "../helpers.ts";
+import crc32 from "../../public/png/crc32.js";
+
+Deno.test("computes CRC32s", () => {
+ // These tests are lifted from the following Go 1.19.3 code:
+ //
+ // ```
+ // crc := crc32.NewIEEE()
+ // fmt.Println(crc.Sum32())
+ // crc.Write([]byte{})
+ // fmt.Println(crc.Sum32())
+ // crc.Write([]byte{1, 2, 3})
+ // fmt.Println(crc.Sum32())
+ // crc.Write([]byte{4, 5, 6})
+ // fmt.Println(crc.Sum32())
+ // ```
+ assertEquals(crc32(), 0);
+ assertEquals(crc32(b(1, 2, 3)), 1438416925);
+ assertEquals(crc32(b(1, 2, 3, 4, 5, 6)), 2180413220);
+});
diff --git a/test/png/fixtures/basi0g01.png b/test/png/fixtures/basi0g01.png
new file mode 100644
index 0000000..556fa72
Binary files /dev/null and b/test/png/fixtures/basi0g01.png differ
diff --git a/test/png/fixtures/basi0g02.png b/test/png/fixtures/basi0g02.png
new file mode 100644
index 0000000..ce09821
Binary files /dev/null and b/test/png/fixtures/basi0g02.png differ
diff --git a/test/png/fixtures/basi0g04.png b/test/png/fixtures/basi0g04.png
new file mode 100644
index 0000000..3853273
Binary files /dev/null and b/test/png/fixtures/basi0g04.png differ
diff --git a/test/png/fixtures/basi0g08.png b/test/png/fixtures/basi0g08.png
new file mode 100644
index 0000000..faed8be
Binary files /dev/null and b/test/png/fixtures/basi0g08.png differ
diff --git a/test/png/fixtures/basi0g16.png b/test/png/fixtures/basi0g16.png
new file mode 100644
index 0000000..a9f2816
Binary files /dev/null and b/test/png/fixtures/basi0g16.png differ
diff --git a/test/png/fixtures/basi2c08.png b/test/png/fixtures/basi2c08.png
new file mode 100644
index 0000000..2aab44d
Binary files /dev/null and b/test/png/fixtures/basi2c08.png differ
diff --git a/test/png/fixtures/basi2c16.png b/test/png/fixtures/basi2c16.png
new file mode 100644
index 0000000..cd7e50f
Binary files /dev/null and b/test/png/fixtures/basi2c16.png differ
diff --git a/test/png/fixtures/basi3p01.png b/test/png/fixtures/basi3p01.png
new file mode 100644
index 0000000..00a7cea
Binary files /dev/null and b/test/png/fixtures/basi3p01.png differ
diff --git a/test/png/fixtures/basi3p02.png b/test/png/fixtures/basi3p02.png
new file mode 100644
index 0000000..bb16b44
Binary files /dev/null and b/test/png/fixtures/basi3p02.png differ
diff --git a/test/png/fixtures/basi3p04.png b/test/png/fixtures/basi3p04.png
new file mode 100644
index 0000000..b4e888e
Binary files /dev/null and b/test/png/fixtures/basi3p04.png differ
diff --git a/test/png/fixtures/basi3p08.png b/test/png/fixtures/basi3p08.png
new file mode 100644
index 0000000..50a6d1c
Binary files /dev/null and b/test/png/fixtures/basi3p08.png differ
diff --git a/test/png/fixtures/basi4a08.png b/test/png/fixtures/basi4a08.png
new file mode 100644
index 0000000..398132b
Binary files /dev/null and b/test/png/fixtures/basi4a08.png differ
diff --git a/test/png/fixtures/basi4a16.png b/test/png/fixtures/basi4a16.png
new file mode 100644
index 0000000..51192e7
Binary files /dev/null and b/test/png/fixtures/basi4a16.png differ
diff --git a/test/png/fixtures/basi6a08.png b/test/png/fixtures/basi6a08.png
new file mode 100644
index 0000000..aecb32e
Binary files /dev/null and b/test/png/fixtures/basi6a08.png differ
diff --git a/test/png/fixtures/basi6a16.png b/test/png/fixtures/basi6a16.png
new file mode 100644
index 0000000..4181533
Binary files /dev/null and b/test/png/fixtures/basi6a16.png differ
diff --git a/test/png/fixtures/basn0g01.png b/test/png/fixtures/basn0g01.png
new file mode 100644
index 0000000..1d72242
Binary files /dev/null and b/test/png/fixtures/basn0g01.png differ
diff --git a/test/png/fixtures/basn0g02.png b/test/png/fixtures/basn0g02.png
new file mode 100644
index 0000000..5083324
Binary files /dev/null and b/test/png/fixtures/basn0g02.png differ
diff --git a/test/png/fixtures/basn0g04.png b/test/png/fixtures/basn0g04.png
new file mode 100644
index 0000000..0bf3687
Binary files /dev/null and b/test/png/fixtures/basn0g04.png differ
diff --git a/test/png/fixtures/basn0g08.png b/test/png/fixtures/basn0g08.png
new file mode 100644
index 0000000..23c8237
Binary files /dev/null and b/test/png/fixtures/basn0g08.png differ
diff --git a/test/png/fixtures/basn0g16.png b/test/png/fixtures/basn0g16.png
new file mode 100644
index 0000000..e7c82f7
Binary files /dev/null and b/test/png/fixtures/basn0g16.png differ
diff --git a/test/png/fixtures/basn2c08.png b/test/png/fixtures/basn2c08.png
new file mode 100644
index 0000000..db5ad15
Binary files /dev/null and b/test/png/fixtures/basn2c08.png differ
diff --git a/test/png/fixtures/basn2c16.png b/test/png/fixtures/basn2c16.png
new file mode 100644
index 0000000..50c1cb9
Binary files /dev/null and b/test/png/fixtures/basn2c16.png differ
diff --git a/test/png/fixtures/basn3p01.png b/test/png/fixtures/basn3p01.png
new file mode 100644
index 0000000..b145c2b
Binary files /dev/null and b/test/png/fixtures/basn3p01.png differ
diff --git a/test/png/fixtures/basn3p02.png b/test/png/fixtures/basn3p02.png
new file mode 100644
index 0000000..8985b3d
Binary files /dev/null and b/test/png/fixtures/basn3p02.png differ
diff --git a/test/png/fixtures/basn3p04.png b/test/png/fixtures/basn3p04.png
new file mode 100644
index 0000000..0fbf9e8
Binary files /dev/null and b/test/png/fixtures/basn3p04.png differ
diff --git a/test/png/fixtures/basn3p08.png b/test/png/fixtures/basn3p08.png
new file mode 100644
index 0000000..0ddad07
Binary files /dev/null and b/test/png/fixtures/basn3p08.png differ
diff --git a/test/png/fixtures/basn4a08.png b/test/png/fixtures/basn4a08.png
new file mode 100644
index 0000000..3e13052
Binary files /dev/null and b/test/png/fixtures/basn4a08.png differ
diff --git a/test/png/fixtures/basn4a16.png b/test/png/fixtures/basn4a16.png
new file mode 100644
index 0000000..8243644
Binary files /dev/null and b/test/png/fixtures/basn4a16.png differ
diff --git a/test/png/fixtures/basn6a08.png b/test/png/fixtures/basn6a08.png
new file mode 100644
index 0000000..e608738
Binary files /dev/null and b/test/png/fixtures/basn6a08.png differ
diff --git a/test/png/fixtures/basn6a16.png b/test/png/fixtures/basn6a16.png
new file mode 100644
index 0000000..984a995
Binary files /dev/null and b/test/png/fixtures/basn6a16.png differ
diff --git a/test/png/fixtures/bgai4a08.png b/test/png/fixtures/bgai4a08.png
new file mode 100644
index 0000000..398132b
Binary files /dev/null and b/test/png/fixtures/bgai4a08.png differ
diff --git a/test/png/fixtures/bgai4a16.png b/test/png/fixtures/bgai4a16.png
new file mode 100644
index 0000000..51192e7
Binary files /dev/null and b/test/png/fixtures/bgai4a16.png differ
diff --git a/test/png/fixtures/bgan6a08.png b/test/png/fixtures/bgan6a08.png
new file mode 100644
index 0000000..e608738
Binary files /dev/null and b/test/png/fixtures/bgan6a08.png differ
diff --git a/test/png/fixtures/bgan6a16.png b/test/png/fixtures/bgan6a16.png
new file mode 100644
index 0000000..984a995
Binary files /dev/null and b/test/png/fixtures/bgan6a16.png differ
diff --git a/test/png/fixtures/bgbn4a08.png b/test/png/fixtures/bgbn4a08.png
new file mode 100644
index 0000000..7cbefc3
Binary files /dev/null and b/test/png/fixtures/bgbn4a08.png differ
diff --git a/test/png/fixtures/bggn4a16.png b/test/png/fixtures/bggn4a16.png
new file mode 100644
index 0000000..13fd85b
Binary files /dev/null and b/test/png/fixtures/bggn4a16.png differ
diff --git a/test/png/fixtures/bgwn6a08.png b/test/png/fixtures/bgwn6a08.png
new file mode 100644
index 0000000..a67ff20
Binary files /dev/null and b/test/png/fixtures/bgwn6a08.png differ
diff --git a/test/png/fixtures/bgyn6a16.png b/test/png/fixtures/bgyn6a16.png
new file mode 100644
index 0000000..ae3e9be
Binary files /dev/null and b/test/png/fixtures/bgyn6a16.png differ
diff --git a/test/png/fixtures/ccwn2c08.png b/test/png/fixtures/ccwn2c08.png
new file mode 100644
index 0000000..47c2481
Binary files /dev/null and b/test/png/fixtures/ccwn2c08.png differ
diff --git a/test/png/fixtures/ccwn3p08.png b/test/png/fixtures/ccwn3p08.png
new file mode 100644
index 0000000..8bb2c10
Binary files /dev/null and b/test/png/fixtures/ccwn3p08.png differ
diff --git a/test/png/fixtures/cdfn2c08.png b/test/png/fixtures/cdfn2c08.png
new file mode 100644
index 0000000..559e526
Binary files /dev/null and b/test/png/fixtures/cdfn2c08.png differ
diff --git a/test/png/fixtures/cdhn2c08.png b/test/png/fixtures/cdhn2c08.png
new file mode 100644
index 0000000..3e07e8e
Binary files /dev/null and b/test/png/fixtures/cdhn2c08.png differ
diff --git a/test/png/fixtures/cdsn2c08.png b/test/png/fixtures/cdsn2c08.png
new file mode 100644
index 0000000..076c32c
Binary files /dev/null and b/test/png/fixtures/cdsn2c08.png differ
diff --git a/test/png/fixtures/cdun2c08.png b/test/png/fixtures/cdun2c08.png
new file mode 100644
index 0000000..846033b
Binary files /dev/null and b/test/png/fixtures/cdun2c08.png differ
diff --git a/test/png/fixtures/ch1n3p04.png b/test/png/fixtures/ch1n3p04.png
new file mode 100644
index 0000000..17cd12d
Binary files /dev/null and b/test/png/fixtures/ch1n3p04.png differ
diff --git a/test/png/fixtures/ch2n3p08.png b/test/png/fixtures/ch2n3p08.png
new file mode 100644
index 0000000..25c1798
Binary files /dev/null and b/test/png/fixtures/ch2n3p08.png differ
diff --git a/test/png/fixtures/cm0n0g04.png b/test/png/fixtures/cm0n0g04.png
new file mode 100644
index 0000000..9fba5db
Binary files /dev/null and b/test/png/fixtures/cm0n0g04.png differ
diff --git a/test/png/fixtures/cm7n0g04.png b/test/png/fixtures/cm7n0g04.png
new file mode 100644
index 0000000..f7dc46e
Binary files /dev/null and b/test/png/fixtures/cm7n0g04.png differ
diff --git a/test/png/fixtures/cm9n0g04.png b/test/png/fixtures/cm9n0g04.png
new file mode 100644
index 0000000..dd70911
Binary files /dev/null and b/test/png/fixtures/cm9n0g04.png differ
diff --git a/test/png/fixtures/cs3n2c16.png b/test/png/fixtures/cs3n2c16.png
new file mode 100644
index 0000000..bf5fd20
Binary files /dev/null and b/test/png/fixtures/cs3n2c16.png differ
diff --git a/test/png/fixtures/cs3n3p08.png b/test/png/fixtures/cs3n3p08.png
new file mode 100644
index 0000000..f4a6623
Binary files /dev/null and b/test/png/fixtures/cs3n3p08.png differ
diff --git a/test/png/fixtures/cs5n2c08.png b/test/png/fixtures/cs5n2c08.png
new file mode 100644
index 0000000..40f947c
Binary files /dev/null and b/test/png/fixtures/cs5n2c08.png differ
diff --git a/test/png/fixtures/cs5n3p08.png b/test/png/fixtures/cs5n3p08.png
new file mode 100644
index 0000000..dfd6e6e
Binary files /dev/null and b/test/png/fixtures/cs5n3p08.png differ
diff --git a/test/png/fixtures/cs8n2c08.png b/test/png/fixtures/cs8n2c08.png
new file mode 100644
index 0000000..8e01d32
Binary files /dev/null and b/test/png/fixtures/cs8n2c08.png differ
diff --git a/test/png/fixtures/cs8n3p08.png b/test/png/fixtures/cs8n3p08.png
new file mode 100644
index 0000000..a44066e
Binary files /dev/null and b/test/png/fixtures/cs8n3p08.png differ
diff --git a/test/png/fixtures/ct0n0g04.png b/test/png/fixtures/ct0n0g04.png
new file mode 100644
index 0000000..40d1e06
Binary files /dev/null and b/test/png/fixtures/ct0n0g04.png differ
diff --git a/test/png/fixtures/ct1n0g04.png b/test/png/fixtures/ct1n0g04.png
new file mode 100644
index 0000000..3ba110a
Binary files /dev/null and b/test/png/fixtures/ct1n0g04.png differ
diff --git a/test/png/fixtures/cten0g04.png b/test/png/fixtures/cten0g04.png
new file mode 100644
index 0000000..a6a56fa
Binary files /dev/null and b/test/png/fixtures/cten0g04.png differ
diff --git a/test/png/fixtures/ctfn0g04.png b/test/png/fixtures/ctfn0g04.png
new file mode 100644
index 0000000..353873e
Binary files /dev/null and b/test/png/fixtures/ctfn0g04.png differ
diff --git a/test/png/fixtures/ctgn0g04.png b/test/png/fixtures/ctgn0g04.png
new file mode 100644
index 0000000..453f2b0
Binary files /dev/null and b/test/png/fixtures/ctgn0g04.png differ
diff --git a/test/png/fixtures/cthn0g04.png b/test/png/fixtures/cthn0g04.png
new file mode 100644
index 0000000..8fce253
Binary files /dev/null and b/test/png/fixtures/cthn0g04.png differ
diff --git a/test/png/fixtures/ctjn0g04.png b/test/png/fixtures/ctjn0g04.png
new file mode 100644
index 0000000..a77b8d2
Binary files /dev/null and b/test/png/fixtures/ctjn0g04.png differ
diff --git a/test/png/fixtures/ctzn0g04.png b/test/png/fixtures/ctzn0g04.png
new file mode 100644
index 0000000..b4401c9
Binary files /dev/null and b/test/png/fixtures/ctzn0g04.png differ
diff --git a/test/png/fixtures/exif2c08.png b/test/png/fixtures/exif2c08.png
new file mode 100644
index 0000000..56eb734
Binary files /dev/null and b/test/png/fixtures/exif2c08.png differ
diff --git a/test/png/fixtures/f00n0g08.png b/test/png/fixtures/f00n0g08.png
new file mode 100644
index 0000000..45a0075
Binary files /dev/null and b/test/png/fixtures/f00n0g08.png differ
diff --git a/test/png/fixtures/f00n2c08.png b/test/png/fixtures/f00n2c08.png
new file mode 100644
index 0000000..d6a1fff
Binary files /dev/null and b/test/png/fixtures/f00n2c08.png differ
diff --git a/test/png/fixtures/f01n0g08.png b/test/png/fixtures/f01n0g08.png
new file mode 100644
index 0000000..4a1107b
Binary files /dev/null and b/test/png/fixtures/f01n0g08.png differ
diff --git a/test/png/fixtures/f01n2c08.png b/test/png/fixtures/f01n2c08.png
new file mode 100644
index 0000000..26fee95
Binary files /dev/null and b/test/png/fixtures/f01n2c08.png differ
diff --git a/test/png/fixtures/f02n0g08.png b/test/png/fixtures/f02n0g08.png
new file mode 100644
index 0000000..bfe410c
Binary files /dev/null and b/test/png/fixtures/f02n0g08.png differ
diff --git a/test/png/fixtures/f02n2c08.png b/test/png/fixtures/f02n2c08.png
new file mode 100644
index 0000000..e590f12
Binary files /dev/null and b/test/png/fixtures/f02n2c08.png differ
diff --git a/test/png/fixtures/f03n0g08.png b/test/png/fixtures/f03n0g08.png
new file mode 100644
index 0000000..ed01e29
Binary files /dev/null and b/test/png/fixtures/f03n0g08.png differ
diff --git a/test/png/fixtures/f03n2c08.png b/test/png/fixtures/f03n2c08.png
new file mode 100644
index 0000000..7581150
Binary files /dev/null and b/test/png/fixtures/f03n2c08.png differ
diff --git a/test/png/fixtures/f04n0g08.png b/test/png/fixtures/f04n0g08.png
new file mode 100644
index 0000000..663fdae
Binary files /dev/null and b/test/png/fixtures/f04n0g08.png differ
diff --git a/test/png/fixtures/f04n2c08.png b/test/png/fixtures/f04n2c08.png
new file mode 100644
index 0000000..3c8b511
Binary files /dev/null and b/test/png/fixtures/f04n2c08.png differ
diff --git a/test/png/fixtures/f99n0g04.png b/test/png/fixtures/f99n0g04.png
new file mode 100644
index 0000000..0b521c1
Binary files /dev/null and b/test/png/fixtures/f99n0g04.png differ
diff --git a/test/png/fixtures/g03n0g16.png b/test/png/fixtures/g03n0g16.png
new file mode 100644
index 0000000..41083ca
Binary files /dev/null and b/test/png/fixtures/g03n0g16.png differ
diff --git a/test/png/fixtures/g03n2c08.png b/test/png/fixtures/g03n2c08.png
new file mode 100644
index 0000000..a9354db
Binary files /dev/null and b/test/png/fixtures/g03n2c08.png differ
diff --git a/test/png/fixtures/g03n3p04.png b/test/png/fixtures/g03n3p04.png
new file mode 100644
index 0000000..60396c9
Binary files /dev/null and b/test/png/fixtures/g03n3p04.png differ
diff --git a/test/png/fixtures/g04n0g16.png b/test/png/fixtures/g04n0g16.png
new file mode 100644
index 0000000..32395b7
Binary files /dev/null and b/test/png/fixtures/g04n0g16.png differ
diff --git a/test/png/fixtures/g04n2c08.png b/test/png/fixtures/g04n2c08.png
new file mode 100644
index 0000000..a652b0c
Binary files /dev/null and b/test/png/fixtures/g04n2c08.png differ
diff --git a/test/png/fixtures/g04n3p04.png b/test/png/fixtures/g04n3p04.png
new file mode 100644
index 0000000..5661cc3
Binary files /dev/null and b/test/png/fixtures/g04n3p04.png differ
diff --git a/test/png/fixtures/g05n0g16.png b/test/png/fixtures/g05n0g16.png
new file mode 100644
index 0000000..70b37f0
Binary files /dev/null and b/test/png/fixtures/g05n0g16.png differ
diff --git a/test/png/fixtures/g05n2c08.png b/test/png/fixtures/g05n2c08.png
new file mode 100644
index 0000000..932c136
Binary files /dev/null and b/test/png/fixtures/g05n2c08.png differ
diff --git a/test/png/fixtures/g05n3p04.png b/test/png/fixtures/g05n3p04.png
new file mode 100644
index 0000000..9619930
Binary files /dev/null and b/test/png/fixtures/g05n3p04.png differ
diff --git a/test/png/fixtures/g07n0g16.png b/test/png/fixtures/g07n0g16.png
new file mode 100644
index 0000000..d6a47c2
Binary files /dev/null and b/test/png/fixtures/g07n0g16.png differ
diff --git a/test/png/fixtures/g07n2c08.png b/test/png/fixtures/g07n2c08.png
new file mode 100644
index 0000000..5973464
Binary files /dev/null and b/test/png/fixtures/g07n2c08.png differ
diff --git a/test/png/fixtures/g07n3p04.png b/test/png/fixtures/g07n3p04.png
new file mode 100644
index 0000000..c73fb61
Binary files /dev/null and b/test/png/fixtures/g07n3p04.png differ
diff --git a/test/png/fixtures/g10n0g16.png b/test/png/fixtures/g10n0g16.png
new file mode 100644
index 0000000..85f2c95
Binary files /dev/null and b/test/png/fixtures/g10n0g16.png differ
diff --git a/test/png/fixtures/g10n2c08.png b/test/png/fixtures/g10n2c08.png
new file mode 100644
index 0000000..b303997
Binary files /dev/null and b/test/png/fixtures/g10n2c08.png differ
diff --git a/test/png/fixtures/g10n3p04.png b/test/png/fixtures/g10n3p04.png
new file mode 100644
index 0000000..1b6a6be
Binary files /dev/null and b/test/png/fixtures/g10n3p04.png differ
diff --git a/test/png/fixtures/g25n0g16.png b/test/png/fixtures/g25n0g16.png
new file mode 100644
index 0000000..a9f6787
Binary files /dev/null and b/test/png/fixtures/g25n0g16.png differ
diff --git a/test/png/fixtures/g25n2c08.png b/test/png/fixtures/g25n2c08.png
new file mode 100644
index 0000000..03f505a
Binary files /dev/null and b/test/png/fixtures/g25n2c08.png differ
diff --git a/test/png/fixtures/g25n3p04.png b/test/png/fixtures/g25n3p04.png
new file mode 100644
index 0000000..4f943c6
Binary files /dev/null and b/test/png/fixtures/g25n3p04.png differ
diff --git a/test/png/fixtures/oi1n0g16.png b/test/png/fixtures/oi1n0g16.png
new file mode 100644
index 0000000..e7c82f7
Binary files /dev/null and b/test/png/fixtures/oi1n0g16.png differ
diff --git a/test/png/fixtures/oi1n2c16.png b/test/png/fixtures/oi1n2c16.png
new file mode 100644
index 0000000..50c1cb9
Binary files /dev/null and b/test/png/fixtures/oi1n2c16.png differ
diff --git a/test/png/fixtures/oi2n0g16.png b/test/png/fixtures/oi2n0g16.png
new file mode 100644
index 0000000..14d64c5
Binary files /dev/null and b/test/png/fixtures/oi2n0g16.png differ
diff --git a/test/png/fixtures/oi2n2c16.png b/test/png/fixtures/oi2n2c16.png
new file mode 100644
index 0000000..4c2e3e3
Binary files /dev/null and b/test/png/fixtures/oi2n2c16.png differ
diff --git a/test/png/fixtures/oi4n0g16.png b/test/png/fixtures/oi4n0g16.png
new file mode 100644
index 0000000..69e73ed
Binary files /dev/null and b/test/png/fixtures/oi4n0g16.png differ
diff --git a/test/png/fixtures/oi4n2c16.png b/test/png/fixtures/oi4n2c16.png
new file mode 100644
index 0000000..93691e3
Binary files /dev/null and b/test/png/fixtures/oi4n2c16.png differ
diff --git a/test/png/fixtures/oi9n0g16.png b/test/png/fixtures/oi9n0g16.png
new file mode 100644
index 0000000..9248413
Binary files /dev/null and b/test/png/fixtures/oi9n0g16.png differ
diff --git a/test/png/fixtures/oi9n2c16.png b/test/png/fixtures/oi9n2c16.png
new file mode 100644
index 0000000..f0512e4
Binary files /dev/null and b/test/png/fixtures/oi9n2c16.png differ
diff --git a/test/png/fixtures/pp0n2c16.png b/test/png/fixtures/pp0n2c16.png
new file mode 100644
index 0000000..8f2aad7
Binary files /dev/null and b/test/png/fixtures/pp0n2c16.png differ
diff --git a/test/png/fixtures/pp0n6a08.png b/test/png/fixtures/pp0n6a08.png
new file mode 100644
index 0000000..4ed7a30
Binary files /dev/null and b/test/png/fixtures/pp0n6a08.png differ
diff --git a/test/png/fixtures/ps1n0g08.png b/test/png/fixtures/ps1n0g08.png
new file mode 100644
index 0000000..99625fa
Binary files /dev/null and b/test/png/fixtures/ps1n0g08.png differ
diff --git a/test/png/fixtures/ps1n2c16.png b/test/png/fixtures/ps1n2c16.png
new file mode 100644
index 0000000..0c7a6b3
Binary files /dev/null and b/test/png/fixtures/ps1n2c16.png differ
diff --git a/test/png/fixtures/ps2n0g08.png b/test/png/fixtures/ps2n0g08.png
new file mode 100644
index 0000000..90b2979
Binary files /dev/null and b/test/png/fixtures/ps2n0g08.png differ
diff --git a/test/png/fixtures/ps2n2c16.png b/test/png/fixtures/ps2n2c16.png
new file mode 100644
index 0000000..a4a181e
Binary files /dev/null and b/test/png/fixtures/ps2n2c16.png differ
diff --git a/test/png/fixtures/s01i3p01.png b/test/png/fixtures/s01i3p01.png
new file mode 100644
index 0000000..6c0fad1
Binary files /dev/null and b/test/png/fixtures/s01i3p01.png differ
diff --git a/test/png/fixtures/s01n3p01.png b/test/png/fixtures/s01n3p01.png
new file mode 100644
index 0000000..cb2c8c7
Binary files /dev/null and b/test/png/fixtures/s01n3p01.png differ
diff --git a/test/png/fixtures/s02i3p01.png b/test/png/fixtures/s02i3p01.png
new file mode 100644
index 0000000..2defaed
Binary files /dev/null and b/test/png/fixtures/s02i3p01.png differ
diff --git a/test/png/fixtures/s02n3p01.png b/test/png/fixtures/s02n3p01.png
new file mode 100644
index 0000000..2b1b669
Binary files /dev/null and b/test/png/fixtures/s02n3p01.png differ
diff --git a/test/png/fixtures/s03i3p01.png b/test/png/fixtures/s03i3p01.png
new file mode 100644
index 0000000..c23fdc4
Binary files /dev/null and b/test/png/fixtures/s03i3p01.png differ
diff --git a/test/png/fixtures/s03n3p01.png b/test/png/fixtures/s03n3p01.png
new file mode 100644
index 0000000..6d96ee4
Binary files /dev/null and b/test/png/fixtures/s03n3p01.png differ
diff --git a/test/png/fixtures/s04i3p01.png b/test/png/fixtures/s04i3p01.png
new file mode 100644
index 0000000..0e710c2
Binary files /dev/null and b/test/png/fixtures/s04i3p01.png differ
diff --git a/test/png/fixtures/s04n3p01.png b/test/png/fixtures/s04n3p01.png
new file mode 100644
index 0000000..956396c
Binary files /dev/null and b/test/png/fixtures/s04n3p01.png differ
diff --git a/test/png/fixtures/s05i3p02.png b/test/png/fixtures/s05i3p02.png
new file mode 100644
index 0000000..d14cbd3
Binary files /dev/null and b/test/png/fixtures/s05i3p02.png differ
diff --git a/test/png/fixtures/s05n3p02.png b/test/png/fixtures/s05n3p02.png
new file mode 100644
index 0000000..bf940f0
Binary files /dev/null and b/test/png/fixtures/s05n3p02.png differ
diff --git a/test/png/fixtures/s06i3p02.png b/test/png/fixtures/s06i3p02.png
new file mode 100644
index 0000000..456ada3
Binary files /dev/null and b/test/png/fixtures/s06i3p02.png differ
diff --git a/test/png/fixtures/s06n3p02.png b/test/png/fixtures/s06n3p02.png
new file mode 100644
index 0000000..501064d
Binary files /dev/null and b/test/png/fixtures/s06n3p02.png differ
diff --git a/test/png/fixtures/s07i3p02.png b/test/png/fixtures/s07i3p02.png
new file mode 100644
index 0000000..44b66ba
Binary files /dev/null and b/test/png/fixtures/s07i3p02.png differ
diff --git a/test/png/fixtures/s07n3p02.png b/test/png/fixtures/s07n3p02.png
new file mode 100644
index 0000000..6a58259
Binary files /dev/null and b/test/png/fixtures/s07n3p02.png differ
diff --git a/test/png/fixtures/s08i3p02.png b/test/png/fixtures/s08i3p02.png
new file mode 100644
index 0000000..acf74f3
Binary files /dev/null and b/test/png/fixtures/s08i3p02.png differ
diff --git a/test/png/fixtures/s08n3p02.png b/test/png/fixtures/s08n3p02.png
new file mode 100644
index 0000000..b7094e1
Binary files /dev/null and b/test/png/fixtures/s08n3p02.png differ
diff --git a/test/png/fixtures/s09i3p02.png b/test/png/fixtures/s09i3p02.png
new file mode 100644
index 0000000..0bfae8e
Binary files /dev/null and b/test/png/fixtures/s09i3p02.png differ
diff --git a/test/png/fixtures/s09n3p02.png b/test/png/fixtures/s09n3p02.png
new file mode 100644
index 0000000..711ab82
Binary files /dev/null and b/test/png/fixtures/s09n3p02.png differ
diff --git a/test/png/fixtures/s32i3p04.png b/test/png/fixtures/s32i3p04.png
new file mode 100644
index 0000000..0841910
Binary files /dev/null and b/test/png/fixtures/s32i3p04.png differ
diff --git a/test/png/fixtures/s32n3p04.png b/test/png/fixtures/s32n3p04.png
new file mode 100644
index 0000000..fa58e3e
Binary files /dev/null and b/test/png/fixtures/s32n3p04.png differ
diff --git a/test/png/fixtures/s33i3p04.png b/test/png/fixtures/s33i3p04.png
new file mode 100644
index 0000000..ab0dc14
Binary files /dev/null and b/test/png/fixtures/s33i3p04.png differ
diff --git a/test/png/fixtures/s33n3p04.png b/test/png/fixtures/s33n3p04.png
new file mode 100644
index 0000000..764f1a3
Binary files /dev/null and b/test/png/fixtures/s33n3p04.png differ
diff --git a/test/png/fixtures/s34i3p04.png b/test/png/fixtures/s34i3p04.png
new file mode 100644
index 0000000..bd99039
Binary files /dev/null and b/test/png/fixtures/s34i3p04.png differ
diff --git a/test/png/fixtures/s34n3p04.png b/test/png/fixtures/s34n3p04.png
new file mode 100644
index 0000000..9cbc68b
Binary files /dev/null and b/test/png/fixtures/s34n3p04.png differ
diff --git a/test/png/fixtures/s35i3p04.png b/test/png/fixtures/s35i3p04.png
new file mode 100644
index 0000000..e2a5e0a
Binary files /dev/null and b/test/png/fixtures/s35i3p04.png differ
diff --git a/test/png/fixtures/s35n3p04.png b/test/png/fixtures/s35n3p04.png
new file mode 100644
index 0000000..90b892e
Binary files /dev/null and b/test/png/fixtures/s35n3p04.png differ
diff --git a/test/png/fixtures/s36i3p04.png b/test/png/fixtures/s36i3p04.png
new file mode 100644
index 0000000..eb61b6f
Binary files /dev/null and b/test/png/fixtures/s36i3p04.png differ
diff --git a/test/png/fixtures/s36n3p04.png b/test/png/fixtures/s36n3p04.png
new file mode 100644
index 0000000..b38d179
Binary files /dev/null and b/test/png/fixtures/s36n3p04.png differ
diff --git a/test/png/fixtures/s37i3p04.png b/test/png/fixtures/s37i3p04.png
new file mode 100644
index 0000000..6e2b1e9
Binary files /dev/null and b/test/png/fixtures/s37i3p04.png differ
diff --git a/test/png/fixtures/s37n3p04.png b/test/png/fixtures/s37n3p04.png
new file mode 100644
index 0000000..4d3054d
Binary files /dev/null and b/test/png/fixtures/s37n3p04.png differ
diff --git a/test/png/fixtures/s38i3p04.png b/test/png/fixtures/s38i3p04.png
new file mode 100644
index 0000000..a0a8a14
Binary files /dev/null and b/test/png/fixtures/s38i3p04.png differ
diff --git a/test/png/fixtures/s38n3p04.png b/test/png/fixtures/s38n3p04.png
new file mode 100644
index 0000000..1233ed0
Binary files /dev/null and b/test/png/fixtures/s38n3p04.png differ
diff --git a/test/png/fixtures/s39i3p04.png b/test/png/fixtures/s39i3p04.png
new file mode 100644
index 0000000..04fee93
Binary files /dev/null and b/test/png/fixtures/s39i3p04.png differ
diff --git a/test/png/fixtures/s39n3p04.png b/test/png/fixtures/s39n3p04.png
new file mode 100644
index 0000000..c750100
Binary files /dev/null and b/test/png/fixtures/s39n3p04.png differ
diff --git a/test/png/fixtures/s40i3p04.png b/test/png/fixtures/s40i3p04.png
new file mode 100644
index 0000000..68f358b
Binary files /dev/null and b/test/png/fixtures/s40i3p04.png differ
diff --git a/test/png/fixtures/s40n3p04.png b/test/png/fixtures/s40n3p04.png
new file mode 100644
index 0000000..864b6b9
Binary files /dev/null and b/test/png/fixtures/s40n3p04.png differ
diff --git a/test/png/fixtures/tbbn0g04.png b/test/png/fixtures/tbbn0g04.png
new file mode 100644
index 0000000..39a7050
Binary files /dev/null and b/test/png/fixtures/tbbn0g04.png differ
diff --git a/test/png/fixtures/tbbn2c16.png b/test/png/fixtures/tbbn2c16.png
new file mode 100644
index 0000000..dd3168e
Binary files /dev/null and b/test/png/fixtures/tbbn2c16.png differ
diff --git a/test/png/fixtures/tbbn3p08.png b/test/png/fixtures/tbbn3p08.png
new file mode 100644
index 0000000..0ede357
Binary files /dev/null and b/test/png/fixtures/tbbn3p08.png differ
diff --git a/test/png/fixtures/tbgn2c16.png b/test/png/fixtures/tbgn2c16.png
new file mode 100644
index 0000000..85cec39
Binary files /dev/null and b/test/png/fixtures/tbgn2c16.png differ
diff --git a/test/png/fixtures/tbgn3p08.png b/test/png/fixtures/tbgn3p08.png
new file mode 100644
index 0000000..8cf2e6f
Binary files /dev/null and b/test/png/fixtures/tbgn3p08.png differ
diff --git a/test/png/fixtures/tbrn2c08.png b/test/png/fixtures/tbrn2c08.png
new file mode 100644
index 0000000..5cca0d6
Binary files /dev/null and b/test/png/fixtures/tbrn2c08.png differ
diff --git a/test/png/fixtures/tbwn0g16.png b/test/png/fixtures/tbwn0g16.png
new file mode 100644
index 0000000..99bdeed
Binary files /dev/null and b/test/png/fixtures/tbwn0g16.png differ
diff --git a/test/png/fixtures/tbwn3p08.png b/test/png/fixtures/tbwn3p08.png
new file mode 100644
index 0000000..eacab7a
Binary files /dev/null and b/test/png/fixtures/tbwn3p08.png differ
diff --git a/test/png/fixtures/tbyn3p08.png b/test/png/fixtures/tbyn3p08.png
new file mode 100644
index 0000000..656db09
Binary files /dev/null and b/test/png/fixtures/tbyn3p08.png differ
diff --git a/test/png/fixtures/tm3n3p02.png b/test/png/fixtures/tm3n3p02.png
new file mode 100644
index 0000000..fb3ef1d
Binary files /dev/null and b/test/png/fixtures/tm3n3p02.png differ
diff --git a/test/png/fixtures/tp0n0g08.png b/test/png/fixtures/tp0n0g08.png
new file mode 100644
index 0000000..333465f
Binary files /dev/null and b/test/png/fixtures/tp0n0g08.png differ
diff --git a/test/png/fixtures/tp0n2c08.png b/test/png/fixtures/tp0n2c08.png
new file mode 100644
index 0000000..fc6e42c
Binary files /dev/null and b/test/png/fixtures/tp0n2c08.png differ
diff --git a/test/png/fixtures/tp0n3p08.png b/test/png/fixtures/tp0n3p08.png
new file mode 100644
index 0000000..69a69e5
Binary files /dev/null and b/test/png/fixtures/tp0n3p08.png differ
diff --git a/test/png/fixtures/tp1n3p08.png b/test/png/fixtures/tp1n3p08.png
new file mode 100644
index 0000000..a6c9f35
Binary files /dev/null and b/test/png/fixtures/tp1n3p08.png differ
diff --git a/test/png/fixtures/xc1n0g08.png b/test/png/fixtures/xc1n0g08.png
new file mode 100644
index 0000000..9404227
Binary files /dev/null and b/test/png/fixtures/xc1n0g08.png differ
diff --git a/test/png/fixtures/xc9n2c08.png b/test/png/fixtures/xc9n2c08.png
new file mode 100644
index 0000000..b11c2a7
Binary files /dev/null and b/test/png/fixtures/xc9n2c08.png differ
diff --git a/test/png/fixtures/xcrn0g04.png b/test/png/fixtures/xcrn0g04.png
new file mode 100644
index 0000000..48abba1
Binary files /dev/null and b/test/png/fixtures/xcrn0g04.png differ
diff --git a/test/png/fixtures/xcsn0g01.png b/test/png/fixtures/xcsn0g01.png
new file mode 100644
index 0000000..9863a26
Binary files /dev/null and b/test/png/fixtures/xcsn0g01.png differ
diff --git a/test/png/fixtures/xd0n2c08.png b/test/png/fixtures/xd0n2c08.png
new file mode 100644
index 0000000..2f00161
Binary files /dev/null and b/test/png/fixtures/xd0n2c08.png differ
diff --git a/test/png/fixtures/xd3n2c08.png b/test/png/fixtures/xd3n2c08.png
new file mode 100644
index 0000000..9e4a3ff
Binary files /dev/null and b/test/png/fixtures/xd3n2c08.png differ
diff --git a/test/png/fixtures/xd9n2c08.png b/test/png/fixtures/xd9n2c08.png
new file mode 100644
index 0000000..2c3b91a
Binary files /dev/null and b/test/png/fixtures/xd9n2c08.png differ
diff --git a/test/png/fixtures/xdtn0g01.png b/test/png/fixtures/xdtn0g01.png
new file mode 100644
index 0000000..1a81abe
Binary files /dev/null and b/test/png/fixtures/xdtn0g01.png differ
diff --git a/test/png/fixtures/xhdn0g08.png b/test/png/fixtures/xhdn0g08.png
new file mode 100644
index 0000000..fcb8737
Binary files /dev/null and b/test/png/fixtures/xhdn0g08.png differ
diff --git a/test/png/fixtures/xlfn0g04.png b/test/png/fixtures/xlfn0g04.png
new file mode 100644
index 0000000..d9ec53e
Binary files /dev/null and b/test/png/fixtures/xlfn0g04.png differ
diff --git a/test/png/fixtures/xs1n0g01.png b/test/png/fixtures/xs1n0g01.png
new file mode 100644
index 0000000..1817c51
Binary files /dev/null and b/test/png/fixtures/xs1n0g01.png differ
diff --git a/test/png/fixtures/xs2n0g01.png b/test/png/fixtures/xs2n0g01.png
new file mode 100644
index 0000000..b8147f2
Binary files /dev/null and b/test/png/fixtures/xs2n0g01.png differ
diff --git a/test/png/fixtures/xs4n0g01.png b/test/png/fixtures/xs4n0g01.png
new file mode 100644
index 0000000..45237a1
Binary files /dev/null and b/test/png/fixtures/xs4n0g01.png differ
diff --git a/test/png/fixtures/xs7n0g01.png b/test/png/fixtures/xs7n0g01.png
new file mode 100644
index 0000000..3f307f1
Binary files /dev/null and b/test/png/fixtures/xs7n0g01.png differ
diff --git a/test/png/fixtures/z00n2c08.png b/test/png/fixtures/z00n2c08.png
new file mode 100644
index 0000000..7669eb8
Binary files /dev/null and b/test/png/fixtures/z00n2c08.png differ
diff --git a/test/png/fixtures/z03n2c08.png b/test/png/fixtures/z03n2c08.png
new file mode 100644
index 0000000..bfb10de
Binary files /dev/null and b/test/png/fixtures/z03n2c08.png differ
diff --git a/test/png/fixtures/z06n2c08.png b/test/png/fixtures/z06n2c08.png
new file mode 100644
index 0000000..b90ebc1
Binary files /dev/null and b/test/png/fixtures/z06n2c08.png differ
diff --git a/test/png/fixtures/z09n2c08.png b/test/png/fixtures/z09n2c08.png
new file mode 100644
index 0000000..5f191a7
Binary files /dev/null and b/test/png/fixtures/z09n2c08.png differ
diff --git a/test/png/parseHash.test.ts b/test/png/parseHash.test.ts
index 953754f..de67f47 100644
--- a/test/png/parseHash.test.ts
+++ b/test/png/parseHash.test.ts
@@ -1,22 +1,21 @@
import { assertEquals } from "assert";
-import { stub } from "mock";
+import { stubbingWarn } from "../helpers.ts";
import parseHash from "../../public/png/parseHash.js";
-Deno.test("returns null if hash cannot be parsed", () => {
- const testCases = [
- // Missing fields
- "#null",
- "#{}",
- "#{%22name%22:%22image.png%22}",
- "#{%22bytes%22:%22AQID%22}",
- // Invalid JSON
- "",
- "#{%22name%22:%22small.png%22,%22bytes%22:%22iAQID",
- ];
+Deno.test(
+ "returns null if hash cannot be parsed",
+ stubbingWarn(() => {
+ const testCases = [
+ // Missing fields
+ "#null",
+ "#{}",
+ "#{%22name%22:%22image.png%22}",
+ "#{%22bytes%22:%22AQID%22}",
+ // Invalid JSON
+ "",
+ "#{%22name%22:%22small.png%22,%22bytes%22:%22iAQID",
+ ];
- const warnStub = stub(console, "warn");
-
- try {
for (const testCase of testCases) {
assertEquals(
parseHash(testCase),
@@ -24,10 +23,8 @@ Deno.test("returns null if hash cannot be parsed", () => {
`Parsing ${testCase} should fail`,
);
}
- } finally {
- warnStub.restore();
- }
-});
+ }),
+);
Deno.test("parses hashes", () => {
const hash = "#{%22name%22:%22small.png%22,%22bytes%22:%22AQID%22}";
diff --git a/test/png/parsePng.test.ts b/test/png/parsePng.test.ts
new file mode 100644
index 0000000..00172c7
--- /dev/null
+++ b/test/png/parsePng.test.ts
@@ -0,0 +1,124 @@
+import { assert, assertEquals } from "assert";
+import { b, stubbingWarn } from "../helpers.ts";
+import { PngNodeType } from "../../public/png/constants.js";
+import parsePng from "../../public/png/parsePng.js";
+
+const FIXTURES_URL = new URL("./fixtures/", import.meta.url);
+
+const getFixture = (name: string): Promise =>
+ Deno.readFile(new URL(name, FIXTURES_URL));
+
+async function* getFixtureNames(): AsyncIterable {
+ for await (const dirEntry of Deno.readDir(FIXTURES_URL)) {
+ if (!dirEntry.isFile) continue;
+ const { name } = dirEntry;
+ if (name.endsWith(".png")) yield name;
+ }
+}
+
+const t = (type: string) => new TextEncoder().encode(type);
+
+Deno.test(
+ "parses PNG test suite reasonably",
+ stubbingWarn(async () => {
+ const fixturesToSkip = new Set([
+ // Incorrect bit depths, which we don't detect.
+ "xd0n2c08.png",
+ "xd3n2c08.png",
+ "xd9n2c08.png",
+ // Incorrect color types, which we don't detect.
+ "xc1n0g08.png",
+ "xc9n2c08.png",
+ // Missing an IDAT chunk, which we don't detect.
+ "xdtn0g01.png",
+ ]);
+
+ for await (const fixtureName of getFixtureNames()) {
+ const fixture = await getFixture(fixtureName);
+
+ if (fixturesToSkip.has(fixtureName)) continue;
+
+ if (fixtureName.startsWith("x")) {
+ assertEquals(
+ parsePng(fixture),
+ null,
+ `${fixtureName} should fail to parse`,
+ );
+ } else {
+ try {
+ parsePng(fixture);
+ } catch {
+ assert(false, `${fixtureName} should parse`);
+ }
+ }
+ }
+ }),
+);
+
+Deno.test("parses a basic PNG", async () => {
+ const fixture = await getFixture("basn2c16.png");
+ assertEquals(parsePng(fixture), {
+ type: PngNodeType.root,
+ bytes: fixture,
+ children: [
+ {
+ type: PngNodeType.signature,
+ bytes: fixture.subarray(0, 8),
+ },
+ {
+ type: PngNodeType.ihdr,
+ bytes: fixture.subarray(8, 8 + 25),
+ children: [
+ { type: PngNodeType.chunkLength, bytes: b(0, 0, 0, 13) },
+ { type: PngNodeType.chunkType, bytes: t("IHDR") },
+ {
+ type: PngNodeType.ihdrChunkData,
+ bytes: fixture.subarray(16, 16 + 13),
+ children: [
+ { type: PngNodeType.ihdrWidth, bytes: b(0, 0, 0, 32) },
+ { type: PngNodeType.ihdrHeight, bytes: b(0, 0, 0, 32) },
+ { type: PngNodeType.ihdrBitDepth, bytes: b(16) },
+ { type: PngNodeType.ihdrColourType, bytes: b(2) },
+ { type: PngNodeType.ihdrCompressionMethod, bytes: b(0) },
+ { type: PngNodeType.ihdrFilterMethod, bytes: b(0) },
+ { type: PngNodeType.ihdrInterlaceMethod, bytes: b(0) },
+ ],
+ },
+ { type: PngNodeType.chunkCrc, bytes: b(172, 136, 49, 224) },
+ ],
+ },
+ {
+ type: PngNodeType.gama,
+ bytes: fixture.subarray(33, 33 + 16),
+ children: [
+ { type: PngNodeType.chunkLength, bytes: b(0, 0, 0, 4) },
+ { type: PngNodeType.chunkType, bytes: t("gAMA") },
+ { type: PngNodeType.chunkData, bytes: b(0, 1, 134, 160) },
+ { type: PngNodeType.chunkCrc, bytes: b(49, 232, 150, 95) },
+ ],
+ },
+ {
+ type: PngNodeType.idat,
+ bytes: fixture.subarray(49, 49 + 241),
+ children: [
+ { type: PngNodeType.chunkLength, bytes: b(0, 0, 0, 229) },
+ { type: PngNodeType.chunkType, bytes: t("IDAT") },
+ {
+ type: PngNodeType.idatChunkData,
+ bytes: fixture.subarray(57, 57 + 229),
+ },
+ { type: PngNodeType.chunkCrc, bytes: b(7, 187, 196, 236) },
+ ],
+ },
+ {
+ type: PngNodeType.iend,
+ bytes: fixture.subarray(290, 290 + 12),
+ children: [
+ { type: PngNodeType.iendChunkLength, bytes: b(0, 0, 0, 0) },
+ { type: PngNodeType.chunkType, bytes: t("IEND") },
+ { type: PngNodeType.chunkCrc, bytes: b(0xae, 0x42, 0x60, 0x82) },
+ ],
+ },
+ ],
+ });
+});
diff --git a/types/png.d.ts b/types/png.d.ts
new file mode 100644
index 0000000..e36223c
--- /dev/null
+++ b/types/png.d.ts
@@ -0,0 +1,19 @@
+export type Node = {
+ /**
+ * The type of this node. Typically an enum specific to the format.
+ */
+ type: T;
+
+ /**
+ * The bytes that make up this node.
+ *
+ * It is highly encouraged to use `Uint8Array.prototype.subarray`,
+ * not `.slice`, to avoid copying the data.
+ */
+ bytes: Uint8Array;
+
+ /**
+ * Child nodes.
+ */
+ children?: ReadonlyArray>;
+};