sharp by wasm
This commit is contained in:
@@ -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}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user