From 59a2d0759116e38866554b4015a76dde4c5c1ae4 Mon Sep 17 00:00:00 2001 From: JrMasterModelBuilder Date: Sun, 24 Sep 2023 03:35:05 -0400 Subject: [PATCH] Custom optimized packbits encoder --- package-lock.json | 9 --------- package.json | 1 - src/icon/icns.ts | 12 ++---------- src/util.ts | 44 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 46 insertions(+), 20 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8948225..50a0996 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,6 @@ "version": "2.1.3", "license": "MPL-2.0", "dependencies": { - "@fiahfy/packbits": "0.0.6", "upng-js": "^2.1.0" }, "bin": { @@ -1880,14 +1879,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@fiahfy/packbits": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/@fiahfy/packbits/-/packbits-0.0.6.tgz", - "integrity": "sha512-XuhF/edg+iIvXjkCWgfj6fWtRi/KrEPg2ILXj1l86EN4EssuOiPcLKgkMDr9cL8jTGtVd/MKUWW6Y0/ZVf1PGA==", - "engines": { - "node": ">=8" - } - }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.11", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", diff --git a/package.json b/package.json index c474b1b..3539047 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,6 @@ "copyright": "Copyright (c) 2019-2023 JrMasterModelBuilder", "license": "MPL-2.0", "dependencies": { - "@fiahfy/packbits": "0.0.6", "upng-js": "^2.1.0" }, "devDependencies": { diff --git a/src/icon/icns.ts b/src/icon/icns.ts index 6549141..ab97527 100644 --- a/src/icon/icns.ts +++ b/src/icon/icns.ts @@ -1,8 +1,6 @@ -import {encode as packbitsEncode} from '@fiahfy/packbits'; - import {IImageData} from '../types'; import {Icon} from '../icon'; -import {concatUint8Arrays} from '../util'; +import {concatUint8Arrays, packBitsIcns} from '../util'; const typeArgb = ['ic04', 'ic05']; @@ -343,12 +341,6 @@ export class IconIcns extends Icon { * @returns Compressed data. */ protected _encodePackBitsIcns(data: Readonly) { - const b = packbitsEncode( - Buffer.from(data.buffer, data.byteOffset, data.byteLength), - { - format: 'icns' - } - ); - return new Uint8Array(b.buffer, b.byteOffset, b.byteLength); + return packBitsIcns(data); } } diff --git a/src/util.ts b/src/util.ts index a9c1cc8..d268e46 100644 --- a/src/util.ts +++ b/src/util.ts @@ -67,3 +67,47 @@ export function pngIhdr(data: Readonly): IPngIhdr { throw new Error('Missing PNG IHDR tag'); } + +/** + * Encode data using PackBits ICNS compression. + * + * @param data Data to be compressed. + * @returns Compressed data. + */ +export function packBitsIcns(data: Readonly) { + const chunks = []; + const l = data.length; + for (let i = 0; i < l; ) { + const b = data[i]; + if (i + 2 >= l) { + // Not enough left for anything but literal data. + chunks.push(new Uint8Array([l - i - 1]), data.subarray(i, l)); + break; + } + if (b === data[i + 1] && b === data[i + 2]) { + // 3+ bytes repeat RLE. + i += 2; + let c = 3; + for (; ++i < l && b === data[i] && c < 130; c++); + chunks.push(new Uint8Array([c + 125, b])); + } else { + // Literal until next 3 bytes repeat. + let e = i + 2; + let c = 3; + for (let r = 1, p = data[e]; ++e < l && c < 128; c++) { + const b = data[e]; + if (p !== b) { + p = b; + r = 1; + } else if (++r > 2) { + e -= 2; + c -= 2; + break; + } + } + chunks.push(new Uint8Array([c - 1]), data.subarray(i, e)); + i = e; + } + } + return concatUint8Arrays(chunks); +}