Openstatus
www.openstatus.dev
1import { readFileSync } from "node:fs";
2import { join } from "node:path";
3
4interface ImageDimensions {
5 width: number;
6 height: number;
7}
8
9/**
10 * Get image dimensions from PNG file
11 * PNG spec: width and height are stored at bytes 16-23 as 4-byte integers
12 */
13function getPngDimensions(buffer: Buffer): ImageDimensions {
14 const width = buffer.readUInt32BE(16);
15 const height = buffer.readUInt32BE(20);
16 return { width, height };
17}
18
19/**
20 * Get image dimensions from JPEG file
21 */
22function getJpegDimensions(buffer: Buffer): ImageDimensions {
23 let offset = 2; // Skip SOI marker
24
25 while (offset < buffer.length) {
26 // Check for marker
27 if (buffer[offset] !== 0xff) break;
28
29 const marker = buffer[offset + 1];
30 offset += 2;
31
32 // SOF markers (Start of Frame)
33 if (
34 marker >= 0xc0 &&
35 marker <= 0xcf &&
36 marker !== 0xc4 &&
37 marker !== 0xc8 &&
38 marker !== 0xcc
39 ) {
40 const height = buffer.readUInt16BE(offset + 3);
41 const width = buffer.readUInt16BE(offset + 5);
42 return { width, height };
43 }
44
45 // Skip to next marker
46 const segmentLength = buffer.readUInt16BE(offset);
47 offset += segmentLength;
48 }
49
50 throw new Error("Could not find JPEG dimensions");
51}
52
53/**
54 * Get dimensions for an image in the public directory
55 */
56export function getImageDimensions(publicPath: string): ImageDimensions | null {
57 try {
58 const fullPath = join(process.cwd(), "public", publicPath);
59 const buffer = readFileSync(fullPath);
60
61 // Check file signature
62 if (buffer[0] === 0x89 && buffer.toString("ascii", 1, 4) === "PNG") {
63 return getPngDimensions(buffer);
64 }
65
66 if (buffer[0] === 0xff && buffer[1] === 0xd8) {
67 return getJpegDimensions(buffer);
68 }
69
70 return null;
71 } catch (error) {
72 console.warn(`Failed to get dimensions for ${publicPath}:`, error);
73 return null;
74 }
75}