ai-chatbot/lib/image-delivery.ts
Your Name dba2460c43
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
feat(canvas): add resolution label and bottom action rails
2026-03-03 23:50:09 +08:00

57 lines
1.5 KiB
TypeScript

const IMAGE_PROXY_PATH = "/api/image-proxy";
type ImageProxyFormat = "webp" | "avif" | "jpeg" | "png";
export type ImageProxyOptions = {
width?: number;
quality?: number;
format?: ImageProxyFormat;
};
function clamp(value: number, min: number, max: number): number {
return Math.max(min, Math.min(max, value));
}
function normalizeWidth(width?: number): number | undefined {
if (!Number.isFinite(width) || !width) return undefined;
return clamp(Math.round(width), 64, 4096);
}
function normalizeQuality(quality?: number): number | undefined {
if (!Number.isFinite(quality) || !quality) return undefined;
return clamp(Math.round(quality), 40, 100);
}
function isAbsoluteHttpUrl(url: string): boolean {
return /^https?:\/\//i.test(url);
}
function isBypassUrl(url: string): boolean {
return (
!url ||
url.startsWith("data:") ||
url.startsWith("blob:") ||
url.startsWith(IMAGE_PROXY_PATH) ||
!isAbsoluteHttpUrl(url)
);
}
export function buildImageProxyUrl(url: string, options: ImageProxyOptions = {}): string {
const source = String(url || "").trim();
if (isBypassUrl(source)) {
return source;
}
const width = normalizeWidth(options.width);
const quality = normalizeQuality(options.quality);
const format = options.format;
const params = new URLSearchParams();
params.set("url", source);
if (width) params.set("w", String(width));
if (quality) params.set("q", String(quality));
if (format) params.set("f", format);
return `${IMAGE_PROXY_PATH}?${params.toString()}`;
}