Forked from vadimfedenko/analyze-images
Forked from vadimfedenko/analyze-images
src / compatibleImage.ts
import type { FileHandle, LMStudioClient } from "@lmstudio/sdk";
import { IMAGE_LIMIT } from "./attachmentIdentity";
import { inlineImage } from "./inlineImage";
// Raw inline WebP can fail even when the same bytes work through a normal SDK upload.
// Normalize this inline path to PNG; preserve native JPEG/PNG bytes.
export async function compatibleImage(client: LMStudioClient, name: string, bytes: Buffer): Promise<FileHandle> {
if (!bytes.length || bytes.length > IMAGE_LIMIT) throw new Error("Image exceeds attachment size limit.");
const png = bytes.subarray(0, 8).equals(Buffer.from("89504e470d0a1a0a", "hex"));
const jpeg = bytes.length >= 3 && bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff;
let prepared = bytes;
if (!png && !jpeg) {
const { default: sharp } = await import("sharp");
// Decode a single frame, preserving dimensions. Reject excessive decoded image sizes.
prepared = await sharp(bytes, { limitInputPixels: 40_000_000, animated: false })
.rotate().png().toBuffer();
}
const extension = jpeg ? "jpg" : "png";
const fileName = `${name.replace(/\.[^./\\]*$/, "")}.${extension}`;
// Output size is checked again: lossless PNG can be larger than the source WebP.
return inlineImage(client, fileName, prepared);
}
src / compatibleImage.ts
import type { FileHandle, LMStudioClient } from "@lmstudio/sdk";
import { IMAGE_LIMIT } from "./attachmentIdentity";
import { inlineImage } from "./inlineImage";
// Raw inline WebP can fail even when the same bytes work through a normal SDK upload.
// Normalize this inline path to PNG; preserve native JPEG/PNG bytes.
export async function compatibleImage(client: LMStudioClient, name: string, bytes: Buffer): Promise<FileHandle> {
if (!bytes.length || bytes.length > IMAGE_LIMIT) throw new Error("Image exceeds attachment size limit.");
const png = bytes.subarray(0, 8).equals(Buffer.from("89504e470d0a1a0a", "hex"));
const jpeg = bytes.length >= 3 && bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff;
let prepared = bytes;
if (!png && !jpeg) {
const { default: sharp } = await import("sharp");
// Decode a single frame, preserving dimensions. Reject excessive decoded image sizes.
prepared = await sharp(bytes, { limitInputPixels: 40_000_000, animated: false })
.rotate().png().toBuffer();
}
const extension = jpeg ? "jpg" : "png";
const fileName = `${name.replace(/\.[^./\\]*$/, "")}.${extension}`;
// Output size is checked again: lossless PNG can be larger than the source WebP.
return inlineImage(client, fileName, prepared);
}