sharp by wasm

This commit is contained in:
seb
2026-10-28 01:46:51 +01:00
parent 1c5385061c
commit e7884c03ef
20 changed files with 530 additions and 364 deletions

View File

@@ -1,6 +1,6 @@
import fs from 'fs';
import path from 'path';
import sharp from 'sharp';
import { optimizeImage } from 'wasm-image-optimization';
import { defineTool, ToolError } from 'libllmorbiter';
import env from '../config/env.js';
import { getImageByHash } from '../db/pic.js';
@@ -201,26 +201,46 @@ async function loadAttachmentBytes(targetPath, vfsRoot, googleAuthId) {
*/
async function processAttachmentToDataUrl(rawBuffer, high) {
const maxEdge = high ? 1536 : 512;
const metadata = await sharp(rawBuffer).metadata();
const hasAlpha = Boolean(metadata.hasAlpha);
const raw = await optimizeImage({ image: rawBuffer, format: 'raw' });
let hasAlpha = false;
for (let i = 3; i < raw.data.length; i += 4) {
if (raw.data[i] < 255) {
hasAlpha = true;
break;
}
}
const srcW = raw.originalWidth || raw.width || 0;
const srcH = raw.originalHeight || raw.height || 0;
const needsResize = srcW > maxEdge || srcH > maxEdge;
const scale = needsResize ? Math.min(maxEdge / srcW, maxEdge / srcH) : 1;
const width = needsResize ? Math.max(1, Math.round(srcW * scale)) : undefined;
const height = needsResize ? Math.max(1, Math.round(srcH * scale)) : undefined;
let mime = 'image/jpeg';
let outputBuffer;
if (hasAlpha) {
mime = 'image/png';
outputBuffer = await sharp(rawBuffer)
.rotate()
.resize(maxEdge, maxEdge, { fit: 'inside', withoutEnlargement: true })
.png({ compressionLevel: high ? 6 : 9 })
.toBuffer();
const res = await optimizeImage({
image: rawBuffer,
width,
height,
fit: 'fill',
format: 'png',
});
outputBuffer = Buffer.from(res.data);
} else {
const quality = high ? 90 : 70;
outputBuffer = await sharp(rawBuffer)
.rotate()
.resize(maxEdge, maxEdge, { fit: 'inside', withoutEnlargement: true })
.jpeg({ quality })
.toBuffer();
const res = await optimizeImage({
image: rawBuffer,
width,
height,
fit: 'fill',
format: 'jpeg',
quality,
});
outputBuffer = Buffer.from(res.data);
}
return `data:${mime};base64,${outputBuffer.toString('base64')}`;
@@ -447,10 +467,12 @@ export function createEditImageTool({ googleAuthId, model: fallbackModel }) {
// ── Convert output to AVIF format ─────────────────────────────
let finalBuffer;
try {
finalBuffer = await sharp(resultBuffer)
.rotate()
.avif({ quality: AVIF_QUALITY })
.toBuffer();
const encoded = await optimizeImage({
image: resultBuffer,
format: 'avif',
quality: AVIF_QUALITY,
});
finalBuffer = Buffer.from(encoded.data);
} catch (convErr) {
throw new ToolError(`edit_image: failed to encode output image to AVIF: ${convErr.message}`);
}