Project Files
src / image.ts
import fs from "fs";
import path from "path";
import Jimp from "jimp";
export function toIsoLikeTimestamp(d: Date): string {
// Compact form: 20251028T164247509Z (no dashes/colons)
const iso = d.toISOString(); // 2025-10-28T16:42:47.509Z
// yyyy-mm-ddThh:MM:ss.sssZ -> yyyymmddThhMMsssssZ
const [datePart, timePartWithZ] = iso.split("T");
const date = datePart.replace(/-/g, ""); // yyyymmdd
const timePart = timePartWithZ.replace("Z", ""); // hh:MM:ss.sss
const time = timePart.replace(/:/g, "").replace(".", ""); // hhMMssssss
return `${date}T${time}Z`;
}
export async function encodeJpegFromBuffer(buf: Buffer, quality = 85): Promise<Buffer> {
const img = await Jimp.read(buf);
img.quality(quality);
return await img.getBufferAsync(Jimp.MIME_JPEG);
}
export async function resizeMaxDimJpegFromBuffer(buf: Buffer, maxDim = 1024, quality = 85): Promise<Buffer> {
const img = await Jimp.read(buf);
const w = img.bitmap.width;
const h = img.bitmap.height;
const maxSide = Math.max(w, h);
if (maxSide > maxDim) {
const scale = maxDim / maxSide;
const newW = Math.max(1, Math.round(w * scale));
const newH = Math.max(1, Math.round(h * scale));
img.resize(newW, newH);
}
img.quality(quality);
return await img.getBufferAsync(Jimp.MIME_JPEG);
}
export async function encodeJpegFromFile(srcAbs: string, quality = 85): Promise<Buffer> {
const img = await Jimp.read(srcAbs);
img.quality(quality);
return await img.getBufferAsync(Jimp.MIME_JPEG);
}
export async function resizeMaxDimJpegFromFile(srcAbs: string, maxDim = 1024, quality = 85): Promise<Buffer> {
const img = await Jimp.read(srcAbs);
const w = img.bitmap.width;
const h = img.bitmap.height;
const maxSide = Math.max(w, h);
if (maxSide > maxDim) {
const scale = maxDim / maxSide;
const newW = Math.max(1, Math.round(w * scale));
const newH = Math.max(1, Math.round(h * scale));
img.resize(newW, newH);
}
img.quality(quality);
return await img.getBufferAsync(Jimp.MIME_JPEG);
}
export async function copyFile(srcAbs: string, dstAbs: string) {
await fs.promises.mkdir(path.dirname(dstAbs), { recursive: true });
await fs.promises.copyFile(srcAbs, dstAbs);
}
export function fileUriToPath(uri: string): string | null {
try {
const p = decodeURIComponent(uri.replace(/^file:\/\//i, "").replace(/^(?!\/)/, "/"));
return p;
} catch { return null; }
}
export function replacePrefixGeneratedToAnalysis(fileName: string): string {
if (fileName.startsWith("generated-image-") && fileName.endsWith(".png")) {
const stem = fileName.slice("generated-image-".length, -".png".length);
return `analysis-generated-image-${stem}.jpg`;
}
// Fallback: add analysis- prefix and .jpg
const base = fileName.replace(/\.[^.]+$/, "");
return `analysis-${base}.jpg`;
}