@wordpress/upload-media
Version:
Core media upload logic.
8 lines (7 loc) • 7.3 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../src/get-image-dimensions.ts"],
"sourcesContent": ["/**\n * Image dimensions and encoding details parsed from a file header.\n */\nexport interface ImageDimensions {\n\t/**\n\t * Image width in pixels.\n\t */\n\twidth: number;\n\t/**\n\t * Image height in pixels.\n\t */\n\theight: number;\n\t/**\n\t * Whether the image is interlaced (progressive JPEG or Adam7 PNG).\n\t *\n\t * Interlaced images cannot be decoded with shrink-on-load, so the full\n\t * image must be buffered in memory at once. This matters for deciding\n\t * whether an image is safe to process client-side within the wasm-vips\n\t * memory cap.\n\t */\n\tinterlaced: boolean;\n}\n\n/**\n * Maximum number of bytes to read from the start of a file when probing for\n * dimensions. Generous enough to skip past large EXIF/ICC segments that can\n * precede a JPEG's frame header, while avoiding reading huge files in full.\n */\nconst MAX_HEADER_BYTES = 512 * 1024;\n\n/**\n * Parses dimensions and interlacing from a JPEG file header.\n *\n * Walks the JPEG marker segments until the Start Of Frame (SOFn) marker, which\n * carries the image dimensions. Progressive DCT frames (SOF2/6/10/14) are\n * reported as interlaced.\n *\n * @param view DataView over the file header bytes.\n * @return Parsed dimensions, or null if they could not be determined.\n */\nfunction parseJpeg( view: DataView ): ImageDimensions | null {\n\tlet offset = 2; // Skip the SOI marker (0xFFD8).\n\n\twhile ( offset < view.byteLength ) {\n\t\t// Markers begin with 0xFF; bail if we have lost alignment.\n\t\tif ( view.getUint8( offset ) !== 0xff ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Skip any 0xFF padding bytes preceding the marker code.\n\t\twhile ( offset < view.byteLength && view.getUint8( offset ) === 0xff ) {\n\t\t\toffset++;\n\t\t}\n\n\t\tif ( offset >= view.byteLength ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst marker = view.getUint8( offset );\n\t\toffset++;\n\n\t\t// Standalone markers without a length payload: TEM, RSTn, SOI, EOI.\n\t\tif ( marker === 0x01 || ( marker >= 0xd0 && marker <= 0xd9 ) ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Start Of Scan: pixel data begins, so no frame header was found.\n\t\tif ( marker === 0xda ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif ( offset + 2 > view.byteLength ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst segmentLength = view.getUint16( offset );\n\t\tif ( segmentLength < 2 ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Start Of Frame markers (0xC0-0xCF) carry the dimensions, except\n\t\t// DHT (0xC4), JPG extension (0xC8), and DAC/arithmetic (0xCC).\n\t\tconst isStartOfFrame =\n\t\t\tmarker >= 0xc0 &&\n\t\t\tmarker <= 0xcf &&\n\t\t\tmarker !== 0xc4 &&\n\t\t\tmarker !== 0xc8 &&\n\t\t\tmarker !== 0xcc;\n\n\t\tif ( isStartOfFrame ) {\n\t\t\tif ( offset + 7 > view.byteLength ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t// Segment layout: length(2) precision(1) height(2) width(2).\n\t\t\tconst height = view.getUint16( offset + 3 );\n\t\t\tconst width = view.getUint16( offset + 5 );\n\t\t\t// Progressive DCT frames: SOF2, SOF6, SOF10, SOF14.\n\t\t\tconst interlaced =\n\t\t\t\tmarker === 0xc2 ||\n\t\t\t\tmarker === 0xc6 ||\n\t\t\t\tmarker === 0xca ||\n\t\t\t\tmarker === 0xce;\n\t\t\treturn { width, height, interlaced };\n\t\t}\n\n\t\toffset += segmentLength;\n\t}\n\n\treturn null;\n}\n\n/**\n * Parses dimensions and interlacing from a PNG file header.\n *\n * Reads the IHDR chunk, which is always the first chunk and contains the\n * dimensions and the interlace method (0 = none, 1 = Adam7).\n *\n * @param view DataView over the file header bytes.\n * @return Parsed dimensions, or null if they could not be determined.\n */\nfunction parsePng( view: DataView ): ImageDimensions | null {\n\t// Signature (8 bytes) + IHDR length (4) + \"IHDR\" (4) + 13 bytes of data.\n\tif ( view.byteLength < 29 ) {\n\t\treturn null;\n\t}\n\n\t// The IHDR chunk type must immediately follow the 8-byte signature and\n\t// 4-byte chunk length.\n\tconst isIhdr =\n\t\tview.getUint8( 12 ) === 0x49 && // I\n\t\tview.getUint8( 13 ) === 0x48 && // H\n\t\tview.getUint8( 14 ) === 0x44 && // D\n\t\tview.getUint8( 15 ) === 0x52; // R\n\n\tif ( ! isIhdr ) {\n\t\treturn null;\n\t}\n\n\tconst width = view.getUint32( 16 );\n\tconst height = view.getUint32( 20 );\n\tconst interlaceMethod = view.getUint8( 28 );\n\n\treturn { width, height, interlaced: interlaceMethod !== 0 };\n}\n\n/**\n * Reads an image's dimensions and interlacing from its header bytes.\n *\n * Only the leading bytes of the file are read, so this is cheap even for very\n * large images and never fully decodes the pixel data. Currently supports JPEG\n * and PNG, the formats most commonly affected by client-side memory limits;\n * other formats return null (treated as unknown).\n *\n * @param file The image file to inspect.\n * @return The parsed dimensions, or null if they could not be determined.\n */\nexport async function getImageDimensions(\n\tfile: File\n): Promise< ImageDimensions | null > {\n\ttry {\n\t\tconst headerBytes = Math.min( file.size, MAX_HEADER_BYTES );\n\t\tconst buffer = await file.slice( 0, headerBytes ).arrayBuffer();\n\t\tconst view = new DataView( buffer );\n\n\t\t// JPEG: starts with the SOI marker 0xFFD8.\n\t\tif ( view.byteLength >= 3 && view.getUint16( 0 ) === 0xffd8 ) {\n\t\t\treturn parseJpeg( view );\n\t\t}\n\n\t\t// PNG: 8-byte signature 89 50 4E 47 0D 0A 1A 0A.\n\t\tif (\n\t\t\tview.byteLength >= 8 &&\n\t\t\tview.getUint32( 0 ) === 0x89504e47 &&\n\t\t\tview.getUint32( 4 ) === 0x0d0a1a0a\n\t\t) {\n\t\t\treturn parsePng( view );\n\t\t}\n\n\t\treturn null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n"],
"mappings": ";AA4BA,IAAM,mBAAmB,MAAM;AAY/B,SAAS,UAAW,MAAyC;AAC5D,MAAI,SAAS;AAEb,SAAQ,SAAS,KAAK,YAAa;AAElC,QAAK,KAAK,SAAU,MAAO,MAAM,KAAO;AACvC,aAAO;AAAA,IACR;AAGA,WAAQ,SAAS,KAAK,cAAc,KAAK,SAAU,MAAO,MAAM,KAAO;AACtE;AAAA,IACD;AAEA,QAAK,UAAU,KAAK,YAAa;AAChC,aAAO;AAAA,IACR;AAEA,UAAM,SAAS,KAAK,SAAU,MAAO;AACrC;AAGA,QAAK,WAAW,KAAU,UAAU,OAAQ,UAAU,KAAS;AAC9D;AAAA,IACD;AAGA,QAAK,WAAW,KAAO;AACtB,aAAO;AAAA,IACR;AAEA,QAAK,SAAS,IAAI,KAAK,YAAa;AACnC,aAAO;AAAA,IACR;AAEA,UAAM,gBAAgB,KAAK,UAAW,MAAO;AAC7C,QAAK,gBAAgB,GAAI;AACxB,aAAO;AAAA,IACR;AAIA,UAAM,iBACL,UAAU,OACV,UAAU,OACV,WAAW,OACX,WAAW,OACX,WAAW;AAEZ,QAAK,gBAAiB;AACrB,UAAK,SAAS,IAAI,KAAK,YAAa;AACnC,eAAO;AAAA,MACR;AAEA,YAAM,SAAS,KAAK,UAAW,SAAS,CAAE;AAC1C,YAAM,QAAQ,KAAK,UAAW,SAAS,CAAE;AAEzC,YAAM,aACL,WAAW,OACX,WAAW,OACX,WAAW,OACX,WAAW;AACZ,aAAO,EAAE,OAAO,QAAQ,WAAW;AAAA,IACpC;AAEA,cAAU;AAAA,EACX;AAEA,SAAO;AACR;AAWA,SAAS,SAAU,MAAyC;AAE3D,MAAK,KAAK,aAAa,IAAK;AAC3B,WAAO;AAAA,EACR;AAIA,QAAM,SACL,KAAK,SAAU,EAAG,MAAM;AAAA,EACxB,KAAK,SAAU,EAAG,MAAM;AAAA,EACxB,KAAK,SAAU,EAAG,MAAM;AAAA,EACxB,KAAK,SAAU,EAAG,MAAM;AAEzB,MAAK,CAAE,QAAS;AACf,WAAO;AAAA,EACR;AAEA,QAAM,QAAQ,KAAK,UAAW,EAAG;AACjC,QAAM,SAAS,KAAK,UAAW,EAAG;AAClC,QAAM,kBAAkB,KAAK,SAAU,EAAG;AAE1C,SAAO,EAAE,OAAO,QAAQ,YAAY,oBAAoB,EAAE;AAC3D;AAaA,eAAsB,mBACrB,MACoC;AACpC,MAAI;AACH,UAAM,cAAc,KAAK,IAAK,KAAK,MAAM,gBAAiB;AAC1D,UAAM,SAAS,MAAM,KAAK,MAAO,GAAG,WAAY,EAAE,YAAY;AAC9D,UAAM,OAAO,IAAI,SAAU,MAAO;AAGlC,QAAK,KAAK,cAAc,KAAK,KAAK,UAAW,CAAE,MAAM,OAAS;AAC7D,aAAO,UAAW,IAAK;AAAA,IACxB;AAGA,QACC,KAAK,cAAc,KACnB,KAAK,UAAW,CAAE,MAAM,cACxB,KAAK,UAAW,CAAE,MAAM,WACvB;AACD,aAAO,SAAU,IAAK;AAAA,IACvB;AAEA,WAAO;AAAA,EACR,QAAQ;AACP,WAAO;AAAA,EACR;AACD;",
"names": []
}