UNPKG

@tldraw/utils

Version:

tldraw infinite canvas SDK (private utilities).

8 lines (7 loc) • 19.2 kB
{ "version": 3, "sources": ["../../../src/lib/media/png.ts"], "sourcesContent": ["/*!\n * MIT License: https://github.com/alexgorbatchev/crc/blob/master/LICENSE\n * Copyright: 2014 Alex Gorbatchev\n * Code: crc32, https://github.com/alexgorbatchev/crc/blob/master/src/calculators/crc32.ts\n */\n\ntype BufferInput = string | ArrayBuffer | Buffer\n\ninterface CRCCalculator<T = BufferInput | Uint8Array> {\n\t(value: T, previous?: number): number\n}\n\nlet TABLE: Array<number> | Int32Array = [\n\t0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,\n\t0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,\n\t0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,\n\t0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,\n\t0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,\n\t0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,\n\t0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,\n\t0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,\n\t0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,\n\t0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,\n\t0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,\n\t0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,\n\t0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,\n\t0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,\n\t0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,\n\t0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,\n\t0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,\n\t0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,\n\t0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,\n\t0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,\n\t0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,\n\t0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,\n\t0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,\n\t0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,\n\t0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,\n\t0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,\n\t0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,\n\t0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,\n\t0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,\n\t0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,\n\t0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,\n\t0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,\n]\n\nif (typeof Int32Array !== 'undefined') {\n\tTABLE = new Int32Array(TABLE)\n}\n\nconst crc: CRCCalculator<Uint8Array> = (current, previous) => {\n\tlet crc = previous === 0 ? 0 : ~~previous! ^ -1\n\n\tfor (let index = 0; index < current.length; index++) {\n\t\tcrc = TABLE[(crc ^ current[index]) & 0xff] ^ (crc >>> 8)\n\t}\n\n\treturn crc ^ -1\n}\n\nconst LEN_SIZE = 4\nconst CRC_SIZE = 4\n\n/**\n * Utility class for reading and manipulating PNG image files.\n * Provides methods for parsing PNG chunks, validating PNG format, and modifying PNG metadata.\n *\n * @example\n * ```ts\n * // Validate PNG file from blob\n * const blob = new Blob([pngData], { type: 'image/png' })\n * const view = new DataView(await blob.arrayBuffer())\n * const isPng = PngHelpers.isPng(view, 0)\n *\n * // Parse PNG metadata for image processing\n * const chunks = PngHelpers.readChunks(view)\n * const physChunk = PngHelpers.findChunk(view, 'pHYs')\n *\n * // Create high-DPI PNG for export\n * const highDpiBlob = PngHelpers.setPhysChunk(view, 2, { type: 'image/png' })\n * ```\n *\n * @public\n */\nexport class PngHelpers {\n\t/**\n\t * Checks if binary data at the specified offset contains a valid PNG file signature.\n\t * Validates the 8-byte PNG signature: 89 50 4E 47 0D 0A 1A 0A.\n\t *\n\t * @param view - DataView containing the binary data to check\n\t * @param offset - Byte offset where the PNG signature should start\n\t * @returns True if the data contains a valid PNG signature, false otherwise\n\t *\n\t * @example\n\t * ```ts\n\t * // Validate PNG from file upload\n\t * const file = event.target.files[0]\n\t * const buffer = await file.arrayBuffer()\n\t * const view = new DataView(buffer)\n\t *\n\t * if (PngHelpers.isPng(view, 0)) {\n\t * console.log('Valid PNG file detected')\n\t * // Process PNG file...\n\t * } else {\n\t * console.error('Not a valid PNG file')\n\t * }\n\t * ```\n\t */\n\tstatic isPng(view: DataView, offset: number) {\n\t\tif (\n\t\t\tview.getUint8(offset + 0) === 0x89 &&\n\t\t\tview.getUint8(offset + 1) === 0x50 &&\n\t\t\tview.getUint8(offset + 2) === 0x4e &&\n\t\t\tview.getUint8(offset + 3) === 0x47 &&\n\t\t\tview.getUint8(offset + 4) === 0x0d &&\n\t\t\tview.getUint8(offset + 5) === 0x0a &&\n\t\t\tview.getUint8(offset + 6) === 0x1a &&\n\t\t\tview.getUint8(offset + 7) === 0x0a\n\t\t) {\n\t\t\treturn true\n\t\t}\n\t\treturn false\n\t}\n\n\t/**\n\t * Reads the 4-character chunk type identifier from a PNG chunk header.\n\t *\n\t * @param view - DataView containing the PNG data\n\t * @param offset - Byte offset of the chunk type field (after length field)\n\t * @returns 4-character string representing the chunk type (e.g., 'IHDR', 'IDAT', 'IEND')\n\t *\n\t * @example\n\t * ```ts\n\t * // Read chunk type from PNG header (after 8-byte signature)\n\t * const chunkType = PngHelpers.getChunkType(dataView, 8)\n\t * console.log(chunkType) // 'IHDR' (Image Header)\n\t *\n\t * // Read chunk type at a specific position during parsing\n\t * let offset = 8 // Skip PNG signature\n\t * const chunkLength = dataView.getUint32(offset)\n\t * const type = PngHelpers.getChunkType(dataView, offset + 4)\n\t * ```\n\t */\n\tstatic getChunkType(view: DataView, offset: number) {\n\t\treturn [\n\t\t\tString.fromCharCode(view.getUint8(offset)),\n\t\t\tString.fromCharCode(view.getUint8(offset + 1)),\n\t\t\tString.fromCharCode(view.getUint8(offset + 2)),\n\t\t\tString.fromCharCode(view.getUint8(offset + 3)),\n\t\t].join('')\n\t}\n\n\t/**\n\t * Parses all chunks in a PNG file and returns their metadata.\n\t * Skips duplicate IDAT chunks but includes all other chunk types.\n\t *\n\t * @param view - DataView containing the complete PNG file data\n\t * @param offset - Starting byte offset (defaults to 0)\n\t * @returns Record mapping chunk types to their metadata (start position, data offset, and size)\n\t * @throws Error if the data is not a valid PNG file\n\t *\n\t * @example\n\t * ```ts\n\t * // Parse PNG structure for metadata extraction\n\t * const view = new DataView(await blob.arrayBuffer())\n\t * const chunks = PngHelpers.readChunks(view)\n\t *\n\t * // Check for specific chunks\n\t * const ihdrChunk = chunks['IHDR']\n\t * const physChunk = chunks['pHYs']\n\t *\n\t * if (physChunk) {\n\t * console.log(`Found pixel density info at byte ${physChunk.start}`)\n\t * } else {\n\t * console.log('No pixel density information found')\n\t * }\n\t * ```\n\t */\n\tstatic readChunks(view: DataView, offset = 0) {\n\t\tconst chunks: Record<string, { dataOffset: number; size: number; start: number }> = {}\n\t\tif (!PngHelpers.isPng(view, offset)) {\n\t\t\tthrow new Error('Not a PNG')\n\t\t}\n\t\toffset += 8\n\n\t\twhile (offset <= view.buffer.byteLength) {\n\t\t\tconst start = offset\n\t\t\tconst len = view.getInt32(offset)\n\t\t\toffset += 4\n\t\t\tconst chunkType = PngHelpers.getChunkType(view, offset)\n\n\t\t\tif (chunkType === 'IDAT' && chunks[chunkType]) {\n\t\t\t\toffset += len + LEN_SIZE + CRC_SIZE\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif (chunkType === 'IEND') {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tchunks[chunkType] = {\n\t\t\t\tstart,\n\t\t\t\tdataOffset: offset + 4,\n\t\t\t\tsize: len,\n\t\t\t}\n\t\t\toffset += len + LEN_SIZE + CRC_SIZE\n\t\t}\n\n\t\treturn chunks\n\t}\n\n\t/**\n\t * Parses the pHYs (physical pixel dimensions) chunk data.\n\t * Reads pixels per unit for X and Y axes, and the unit specifier.\n\t *\n\t * @param view - DataView containing the PNG data\n\t * @param offset - Byte offset of the pHYs chunk data\n\t * @returns Object with ppux (pixels per unit X), ppuy (pixels per unit Y), and unit specifier\n\t *\n\t * @example\n\t * ```ts\n\t * // Extract pixel density information for DPI calculation\n\t * const physChunk = PngHelpers.findChunk(dataView, 'pHYs')\n\t * if (physChunk) {\n\t * const physData = PngHelpers.parsePhys(dataView, physChunk.dataOffset)\n\t *\n\t * if (physData.unit === 1) { // meters\n\t * const dpiX = Math.round(physData.ppux * 0.0254)\n\t * const dpiY = Math.round(physData.ppuy * 0.0254)\n\t * console.log(`DPI: ${dpiX} x ${dpiY}`)\n\t * }\n\t * }\n\t * ```\n\t */\n\tstatic parsePhys(view: DataView, offset: number) {\n\t\treturn {\n\t\t\tppux: view.getUint32(offset),\n\t\t\tppuy: view.getUint32(offset + 4),\n\t\t\tunit: view.getUint8(offset + 8),\n\t\t}\n\t}\n\n\t/**\n\t * Finds a specific chunk type in the PNG file and returns its metadata.\n\t *\n\t * @param view - DataView containing the PNG file data\n\t * @param type - 4-character chunk type to search for (e.g., 'pHYs', 'IDAT')\n\t * @returns Chunk metadata object if found, undefined otherwise\n\t *\n\t * @example\n\t * ```ts\n\t * // Look for pixel density information in PNG\n\t * const physChunk = PngHelpers.findChunk(dataView, 'pHYs')\n\t * if (physChunk) {\n\t * const physData = PngHelpers.parsePhys(dataView, physChunk.dataOffset)\n\t * console.log(`Found pHYs chunk with ${physData.ppux} x ${physData.ppuy} pixels per unit`)\n\t * }\n\t *\n\t * // Check for text metadata\n\t * const textChunk = PngHelpers.findChunk(dataView, 'tEXt')\n\t * if (textChunk) {\n\t * console.log(`Found text metadata at byte ${textChunk.start}`)\n\t * }\n\t * ```\n\t */\n\tstatic findChunk(view: DataView, type: string) {\n\t\tconst chunks = PngHelpers.readChunks(view)\n\t\treturn chunks[type]\n\t}\n\n\t/**\n\t * Adds or replaces a pHYs chunk in a PNG file to set pixel density for high-DPI displays.\n\t * The method determines insertion point by prioritizing IDAT chunk position over existing pHYs,\n\t * creates a properly formatted pHYs chunk with CRC validation, and returns a new Blob.\n\t *\n\t * @param view - DataView containing the original PNG file data\n\t * @param dpr - Device pixel ratio multiplier (defaults to 1)\n\t * @param options - Optional Blob constructor options for MIME type and other properties\n\t * @returns New Blob containing the PNG with updated pixel density information\n\t *\n\t * @example\n\t * ```ts\n\t * // Export PNG with proper pixel density for high-DPI displays\n\t * const canvas = document.createElement('canvas')\n\t * const ctx = canvas.getContext('2d')\n\t * // ... draw content to canvas ...\n\t *\n\t * canvas.toBlob(async (blob) => {\n\t * if (blob) {\n\t * const view = new DataView(await blob.arrayBuffer())\n\t * // Create 2x DPI version for Retina displays\n\t * const highDpiBlob = PngHelpers.setPhysChunk(view, 2, { type: 'image/png' })\n\t * // Download or use the blob...\n\t * }\n\t * }, 'image/png')\n\t * ```\n\t */\n\tstatic setPhysChunk(view: DataView, dpr = 1, options?: BlobPropertyBag) {\n\t\tlet offset = 46\n\t\tlet size = 0\n\t\tconst res1 = PngHelpers.findChunk(view, 'pHYs')\n\t\tif (res1) {\n\t\t\toffset = res1.start\n\t\t\tsize = res1.size\n\t\t}\n\n\t\tconst res2 = PngHelpers.findChunk(view, 'IDAT')\n\t\tif (res2) {\n\t\t\toffset = res2.start\n\t\t\tsize = 0\n\t\t}\n\n\t\tconst pHYsData = new ArrayBuffer(21)\n\t\tconst pHYsDataView = new DataView(pHYsData)\n\n\t\tpHYsDataView.setUint32(0, 9)\n\n\t\tpHYsDataView.setUint8(4, 'p'.charCodeAt(0))\n\t\tpHYsDataView.setUint8(5, 'H'.charCodeAt(0))\n\t\tpHYsDataView.setUint8(6, 'Y'.charCodeAt(0))\n\t\tpHYsDataView.setUint8(7, 's'.charCodeAt(0))\n\n\t\tconst DPI_72 = 2835.5\n\n\t\tpHYsDataView.setInt32(8, DPI_72 * dpr)\n\t\tpHYsDataView.setInt32(12, DPI_72 * dpr)\n\t\tpHYsDataView.setInt8(16, 1)\n\n\t\tconst crcBit = new Uint8Array(pHYsData.slice(4, 17))\n\t\tpHYsDataView.setInt32(17, crc(crcBit))\n\n\t\tconst startBuf = view.buffer.slice(0, offset)\n\t\tconst endBuf = view.buffer.slice(offset + size)\n\n\t\treturn new Blob([startBuf as ArrayBuffer, pHYsData, endBuf as ArrayBuffer], options)\n\t}\n}\n"], "mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAYA,IAAI,QAAoC;AAAA,EACvC;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EACpF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", "names": ["crc"] }