Skip to content
Source
Sign inSign up

icns.ts

27 lines1.3 KB

1import { readImageDimensions } from "@t3tools/shared/imageDimensions";
2​
3const ICNS_HEADER_BYTES = 8;
4const ICNS_MAGIC = 0x69636e73;
5const PNG_MAGIC = 0x89504e47;
6​
7/** Returns a copy to avoid retaining the whole .icns buffer. */
8export function extractIcnsPng(bytes: Uint8Array, minSize: number): Uint8Array | null {
9 const data = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
10 if (bytes.length < ICNS_HEADER_BYTES || data.getUint32(0) !== ICNS_MAGIC) return null;
11 const end = Math.min(data.getUint32(4), bytes.length);
12 let best: { readonly png: Uint8Array; readonly width: number } | null = null;
13 for (let offset = ICNS_HEADER_BYTES; offset + ICNS_HEADER_BYTES <= end;) {
14 const length = data.getUint32(offset + 4);
15 if (length < ICNS_HEADER_BYTES || offset + length > end) break;
16 const entry = bytes.subarray(offset + ICNS_HEADER_BYTES, offset + length);
17 const isPng = entry.length >= 4 && data.getUint32(offset + ICNS_HEADER_BYTES) === PNG_MAGIC;
18 offset += length;
19 const width = isPng ? readImageDimensions(entry)?.width : undefined;
20 if (width === undefined) continue;
21 const isBetter =
22 best === null ||
23 (best.width < minSize ? width > best.width : width >= minSize && width < best.width);
24 if (isBetter) best = { png: entry, width };
25 }
26 return best?.png.slice() ?? null;