11/**
2- * Minimal intrinsic-dimension reader for the image formats the content
3- * pipeline actually ships as OG covers ( PNG, JPEG, WebP) .
2+ * Minimal intrinsic-dimension reader for the raster formats that are valid as
3+ * social preview images: PNG, JPEG, WebP, and GIF .
44 *
55 * This replaces the `image-size` package, which is archived upstream and
66 * carries unpatched high-severity DoS advisories (GHSA-w3rx-r6r6-pgpr,
77 * GHSA-5p2g-fcmc-qvqq) in its ICNS/JXL/HEIF parsers — formats this app never
88 * reads. Only the JPEG marker scan loops at all, and it advances on every
9- * iteration regardless of the declared lengths (see `readJpeg`); PNG and WebP
10- * are fixed-offset header reads.
9+ * iteration regardless of the declared lengths (see `readJpeg`); the rest are
10+ * fixed-offset header reads.
11+ *
12+ * SVG and ICO are deliberately unsupported: neither is accepted as an
13+ * `og:image` by the major social crawlers, and reading SVG dimensions means
14+ * regex-matching untrusted-shaped XML, which is the failure class that
15+ * motivated removing the dependency in the first place. Callers are expected
16+ * to treat a null return as "fall back to the declared OG default".
1117 */
1218
1319const PNG_SIGNATURE = Buffer . from ( [ 0x89 , 0x50 , 0x4e , 0x47 , 0x0d , 0x0a , 0x1a , 0x0a ] )
1420
21+ const GIF_SIGNATURES = new Set ( [ 'GIF87a' , 'GIF89a' ] )
22+
1523/** JPEG frame markers that carry a size record, excluding DHT/JPG/DAC. */
1624const JPEG_SOF_MARKERS = new Set ( [
1725 0xc0 , 0xc1 , 0xc2 , 0xc3 , 0xc5 , 0xc6 , 0xc7 , 0xc9 , 0xca , 0xcb , 0xcd , 0xce , 0xcf ,
@@ -59,6 +67,11 @@ function readJpeg(buffer: Buffer): ImageDimensions | null {
5967 return null
6068}
6169
70+ function readGif ( buffer : Buffer ) : ImageDimensions | null {
71+ if ( buffer . length < 10 ) return null
72+ return { width : buffer . readUInt16LE ( 6 ) , height : buffer . readUInt16LE ( 8 ) }
73+ }
74+
6275function readWebp ( buffer : Buffer ) : ImageDimensions | null {
6376 const chunkType = buffer . subarray ( 12 , 16 ) . toString ( 'latin1' )
6477
@@ -92,8 +105,9 @@ function readWebp(buffer: Buffer): ImageDimensions | null {
92105}
93106
94107/**
95- * Reads intrinsic pixel dimensions from a PNG, JPEG, or WebP buffer. Returns
96- * null for unrecognized formats, truncated buffers, or zero-valued dimensions.
108+ * Reads intrinsic pixel dimensions from a PNG, JPEG, WebP, or GIF buffer.
109+ * Returns null for unrecognized formats, truncated buffers, or zero-valued
110+ * dimensions.
97111 */
98112export function readImageDimensions ( buffer : Buffer ) : ImageDimensions | null {
99113 if ( buffer . length < 12 ) return null
@@ -108,6 +122,8 @@ export function readImageDimensions(buffer: Buffer): ImageDimensions | null {
108122 buffer . subarray ( 8 , 12 ) . toString ( 'latin1' ) === 'WEBP'
109123 ) {
110124 dimensions = readWebp ( buffer )
125+ } else if ( GIF_SIGNATURES . has ( buffer . subarray ( 0 , 6 ) . toString ( 'latin1' ) ) ) {
126+ dimensions = readGif ( buffer )
111127 }
112128
113129 if ( ! dimensions || dimensions . width <= 0 || dimensions . height <= 0 ) return null
0 commit comments