Spaces:
Running
Running
Download imageinfo.js from MegaPotatoAI/Photo-Enhancer: direct link, hf CLI and curl.
- Browser
- Download file 3.5 kB
-
https://huggingface.co/spaces/MegaPotatoAI/Photo-Enhancer/resolve/main/imageinfo.js
- Command line
-
hf download hf://spaces/MegaPotatoAI/Photo-Enhancer/imageinfo.js
-
curl -L -o imageinfo.js https://huggingface.co/spaces/MegaPotatoAI/Photo-Enhancer/resolve/main/imageinfo.js
3.5 kB
| // Image size from the file header, without decoding: PNG, JPEG (with EXIF orientation) and WebP. | |
| // Anything else (GIF, BMP, HEIC, AVIF, …) returns null and is refused before any decoding. | |
| // Returns { width, height, format, rotated } with width/height as displayed (after EXIF rotation), or null. | |
| const HEAD_BYTES = 512 * 1024; | |
| export async function readImageInfo(file) { | |
| const buf = new Uint8Array(await file.slice(0, HEAD_BYTES).arrayBuffer()); | |
| return png(buf) ?? jpeg(buf) ?? webp(buf); | |
| } | |
| const u16be = (b, i) => (b[i] << 8) | b[i + 1]; | |
| const u16le = (b, i) => b[i] | (b[i + 1] << 8); | |
| const u32be = (b, i) => ((b[i] << 24) | (b[i + 1] << 16) | (b[i + 2] << 8) | b[i + 3]) >>> 0; | |
| const u32le = (b, i) => (b[i] | (b[i + 1] << 8) | (b[i + 2] << 16) | (b[i + 3] << 24)) >>> 0; | |
| const ascii = (b, i, n) => String.fromCharCode(...b.subarray(i, i + n)); | |
| function result(width, height, format, orientation = 1) { | |
| if (!width || !height) return null; | |
| const rotated = orientation >= 5 && orientation <= 8; | |
| return { width: rotated ? height : width, height: rotated ? width : height, format, rotated }; | |
| } | |
| function png(b) { | |
| if (b.length < 24 || u32be(b, 0) !== 0x89504e47 || ascii(b, 12, 4) !== "IHDR") return null; | |
| let at = 8; | |
| while (at + 8 <= b.length) { | |
| const len = u32be(b, at); | |
| const type = ascii(b, at + 4, 4); | |
| if (type === "acTL") return { ...result(u32be(b, 16), u32be(b, 20), "png"), animated: true }; | |
| if (type === "IDAT") return result(u32be(b, 16), u32be(b, 20), "png"); | |
| at += 12 + len; | |
| } | |
| return null; | |
| } | |
| function exifOrientation(b, start, len) { | |
| if (ascii(b, start, 4) !== "Exif") return 1; | |
| const tiff = start + 6; | |
| if (tiff + 8 > b.length) return 1; | |
| const little = ascii(b, tiff, 2) === "II"; | |
| const r16 = (i) => (little ? u16le(b, i) : u16be(b, i)); | |
| const r32 = (i) => (little ? u32le(b, i) : u32be(b, i)); | |
| const ifd = tiff + r32(tiff + 4); | |
| if (ifd + 2 > Math.min(b.length, start + len)) return 1; | |
| const count = r16(ifd); | |
| for (let k = 0; k < count; k++) { | |
| const e = ifd + 2 + k * 12; | |
| if (e + 12 > b.length) break; | |
| if (r16(e) === 0x0112) return r16(e + 8) || 1; | |
| } | |
| return 1; | |
| } | |
| function jpeg(b) { | |
| if (b.length < 4 || b[0] !== 0xff || b[1] !== 0xd8) return null; | |
| let at = 2; | |
| let orientation = 1; | |
| while (at + 4 <= b.length) { | |
| if (b[at] !== 0xff) return null; | |
| const marker = b[at + 1]; | |
| if (marker === 0xd8 || (marker >= 0xd0 && marker <= 0xd7) || marker === 0x01) { | |
| at += 2; | |
| continue; | |
| } | |
| const len = u16be(b, at + 2); | |
| if (marker === 0xe1) orientation = exifOrientation(b, at + 4, len - 2); | |
| const isSof = marker >= 0xc0 && marker <= 0xcf && marker !== 0xc4 && marker !== 0xc8 && marker !== 0xcc; | |
| if (isSof && at + 9 <= b.length) return result(u16be(b, at + 7), u16be(b, at + 5), "jpeg", orientation); | |
| at += 2 + len; | |
| } | |
| return null; | |
| } | |
| function webp(b) { | |
| if (b.length < 30 || ascii(b, 0, 4) !== "RIFF" || ascii(b, 8, 4) !== "WEBP") return null; | |
| const kind = ascii(b, 12, 4); | |
| if (kind === "VP8 ") return result(u16le(b, 26) & 0x3fff, u16le(b, 28) & 0x3fff, "webp"); | |
| if (kind === "VP8L") { | |
| const bits = u32le(b, 21); | |
| return result((bits & 0x3fff) + 1, ((bits >> 14) & 0x3fff) + 1, "webp"); | |
| } | |
| if (kind === "VP8X") { | |
| const animated = (b[20] & 0x02) !== 0; | |
| const w = 1 + (b[24] | (b[25] << 8) | (b[26] << 16)); | |
| const h = 1 + (b[27] | (b[28] << 8) | (b[29] << 16)); | |
| return { ...result(w, h, "webp"), animated }; | |
| } | |
| return null; | |
| } | |