mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
fix(svg-to-raster): use encodeHeic for HEIF output, fix preview decoding
Sharp cannot encode HEVC directly. Use encodeHeic() (same as convert tool) to go through heif-enc. Also decode HEIF before Sharp for preview generation. Hoist NON_PREVIEWABLE set to module scope.
This commit is contained in:
@@ -4,9 +4,12 @@ import { basename, join } from "node:path";
|
|||||||
import type { FastifyInstance } from "fastify";
|
import type { FastifyInstance } from "fastify";
|
||||||
import sharp from "sharp";
|
import sharp from "sharp";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
import { decodeHeic, encodeHeic } from "../../lib/heic-converter.js";
|
||||||
import { sanitizeSvg } from "../../lib/svg-sanitize.js";
|
import { sanitizeSvg } from "../../lib/svg-sanitize.js";
|
||||||
import { createWorkspace } from "../../lib/workspace.js";
|
import { createWorkspace } from "../../lib/workspace.js";
|
||||||
|
|
||||||
|
const NON_PREVIEWABLE = new Set(["tiff", "heif"]);
|
||||||
|
|
||||||
const settingsSchema = z.object({
|
const settingsSchema = z.object({
|
||||||
width: z.number().min(1).max(16384).optional(),
|
width: z.number().min(1).max(16384).optional(),
|
||||||
height: z.number().min(1).max(16384).optional(),
|
height: z.number().min(1).max(16384).optional(),
|
||||||
@@ -113,10 +116,13 @@ export function registerSvgToRaster(app: FastifyInstance) {
|
|||||||
buffer = await image.gif().toBuffer();
|
buffer = await image.gif().toBuffer();
|
||||||
ext = "gif";
|
ext = "gif";
|
||||||
break;
|
break;
|
||||||
case "heif":
|
case "heif": {
|
||||||
buffer = await image.heif({ quality: settings.quality }).toBuffer();
|
// Sharp cannot encode HEVC. Convert to PNG first, then use heif-enc.
|
||||||
|
const pngBuffer = await image.png().toBuffer();
|
||||||
|
buffer = await encodeHeic(pngBuffer, settings.quality);
|
||||||
ext = "heif";
|
ext = "heif";
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
buffer = await image.png().toBuffer();
|
buffer = await image.png().toBuffer();
|
||||||
ext = "png";
|
ext = "png";
|
||||||
@@ -129,12 +135,12 @@ export function registerSvgToRaster(app: FastifyInstance) {
|
|||||||
const outputPath = join(workspacePath, "output", outFilename);
|
const outputPath = join(workspacePath, "output", outFilename);
|
||||||
await writeFile(outputPath, buffer);
|
await writeFile(outputPath, buffer);
|
||||||
|
|
||||||
// Generate browser-previewable thumbnail for non-browser formats
|
|
||||||
const NON_PREVIEWABLE = new Set(["tiff", "heif"]);
|
|
||||||
let previewUrl: string | undefined;
|
let previewUrl: string | undefined;
|
||||||
if (NON_PREVIEWABLE.has(ext)) {
|
if (NON_PREVIEWABLE.has(ext)) {
|
||||||
try {
|
try {
|
||||||
const previewBuffer = await sharp(buffer)
|
// Sharp can't decode HEVC-encoded HEIF; decode first
|
||||||
|
const previewInput = ext === "heif" ? await decodeHeic(buffer) : buffer;
|
||||||
|
const previewBuffer = await sharp(previewInput)
|
||||||
.resize(1200, 1200, { fit: "inside" })
|
.resize(1200, 1200, { fit: "inside" })
|
||||||
.webp({ quality: 80 })
|
.webp({ quality: 80 })
|
||||||
.toBuffer();
|
.toBuffer();
|
||||||
|
|||||||
Reference in New Issue
Block a user