| 1 | import { readImageDimensions } from "@t3tools/shared/imageDimensions"; |
| 2 | |
| 3 | const ICNS_HEADER_BYTES = 8; |
| 4 | const ICNS_MAGIC = 0x69636e73; // "icns" |
| 5 | const PNG_MAGIC = 0x89504e47; // "\x89PNG" |
| 6 | |
| 7 | /** |
| 8 | * Picks the smallest PNG at least `minSize` wide, else the largest; null when there is none. |
| 9 | * Returns a copy so the response does not pin the whole `.icns` buffer. |
| 10 | */ |
| 11 | export function extractIcnsPng(bytes: Uint8Array, minSize: number): Uint8Array | null { |
| 12 | const data = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength); |
| 13 | if (bytes.length < ICNS_HEADER_BYTES || data.getUint32(0) !== ICNS_MAGIC) return null; |
| 14 | const end = Math.min(data.getUint32(4), bytes.length); |
| 15 | let best: { readonly png: Uint8Array; readonly width: number } | null = null; |
| 16 | for (let offset = ICNS_HEADER_BYTES; offset + ICNS_HEADER_BYTES <= end;) { |
| 17 | const length = data.getUint32(offset + 4); |
| 18 | if (length < ICNS_HEADER_BYTES || offset + length > end) break; |
| 19 | const entry = bytes.subarray(offset + ICNS_HEADER_BYTES, offset + length); |
| 20 | const isPng = entry.length >= 4 && data.getUint32(offset + ICNS_HEADER_BYTES) === PNG_MAGIC; |
| 21 | offset += length; |
| 22 | const width = isPng ? readImageDimensions(entry)?.width : undefined; |
| 23 | if (width === undefined) continue; |
| 24 | const isBetter = |
| 25 | best === null || |
| 26 | (best.width < minSize ? width > best.width : width >= minSize && width < best.width); |
| 27 | if (isBetter) best = { png: entry, width }; |
| 28 | } |
| 29 | return best?.png.slice() ?? null; |
| 30 | } |