fix(image-engine): support sharp 0.35 types

This commit is contained in:
SnapOtter
2026-06-29 16:04:17 +08:00
parent 744bd482c8
commit 2137be479e
5 changed files with 22 additions and 17 deletions
+2 -1
View File
@@ -34,6 +34,7 @@ import type {
Sharp, Sharp,
SharpenAdvancedOptions, SharpenAdvancedOptions,
SharpenOptions, SharpenOptions,
SharpFormat,
StripMetadataOptions, StripMetadataOptions,
} from "./types.js"; } from "./types.js";
import { getImageInfo } from "./utils/metadata.js"; import { getImageInfo } from "./utils/metadata.js";
@@ -109,7 +110,7 @@ export async function processImage(
if (!sharpFormat) { if (!sharpFormat) {
throw new Error(`Unsupported output format: ${outputFormat}`); throw new Error(`Unsupported output format: ${outputFormat}`);
} }
image = image.toFormat(sharpFormat as keyof sharp.FormatEnum); image = image.toFormat(sharpFormat as SharpFormat);
} }
const buffer = await image.toBuffer(); const buffer = await image.toBuffer();
@@ -5,6 +5,8 @@ import type {
CorrectionParams, CorrectionParams,
EnhancementMode, EnhancementMode,
Sharp, Sharp,
SharpChannelStats,
SharpMetadata,
} from "../types.js"; } from "../types.js";
/** /**
@@ -123,9 +125,9 @@ export async function analyzeImage(buffer: Buffer): Promise<AnalysisResult> {
} }
function computeScores( function computeScores(
rCh: sharp.ChannelStats, rCh: SharpChannelStats,
gCh: sharp.ChannelStats, gCh: SharpChannelStats,
bCh: sharp.ChannelStats, bCh: SharpChannelStats,
meanLum: number, meanLum: number,
stdevLum: number, stdevLum: number,
isGrayscale: boolean, isGrayscale: boolean,
@@ -200,7 +202,7 @@ function detectIssues(scores: AnalysisScores): string[] {
return issues; return issues;
} }
function suggestMode(scores: AnalysisScores, _meta: sharp.Metadata): EnhancementMode { function suggestMode(scores: AnalysisScores, _meta: SharpMetadata): EnhancementMode {
if (scores.exposure < 30) return "low-light"; if (scores.exposure < 30) return "low-light";
if (scores.contrast > 60 && scores.saturation < 30) return "document"; if (scores.contrast > 60 && scores.saturation < 30) return "document";
return "auto"; return "auto";
@@ -1,7 +1,7 @@
import sharp from "sharp"; import sharp from "sharp";
import type { CompressOptions, Sharp } from "../types.js"; import type { CompressOptions, Sharp, SharpFormat } from "../types.js";
const FORMAT_MAP: Record<string, string> = { const FORMAT_MAP: Record<string, SharpFormat> = {
jpg: "jpeg", jpg: "jpeg",
jpeg: "jpeg", jpeg: "jpeg",
png: "png", png: "png",
@@ -16,7 +16,7 @@ const FORMAT_MAP: Record<string, string> = {
/** Formats that Sharp cannot encode — fall back to PNG for output. */ /** Formats that Sharp cannot encode — fall back to PNG for output. */
const NO_ENCODER = new Set(["svg", "raw", "tga", "psd", "exr", "hdr"]); const NO_ENCODER = new Set(["svg", "raw", "tga", "psd", "exr", "hdr"]);
function formatOpts(format: string, quality: number): Record<string, unknown> { function formatOpts(format: SharpFormat, quality: number): Record<string, unknown> {
const opts: Record<string, unknown> = { quality }; const opts: Record<string, unknown> = { quality };
if (format === "avif") opts.effort = 4; if (format === "avif") opts.effort = 4;
return opts; return opts;
@@ -31,7 +31,7 @@ export async function compress(image: Sharp, options: CompressOptions): Promise<
const safeDetected = NO_ENCODER.has(detected) ? "png" : detected; const safeDetected = NO_ENCODER.has(detected) ? "png" : detected;
const outputFormat = (FORMAT_MAP[format ?? ""] ?? const outputFormat = (FORMAT_MAP[format ?? ""] ??
FORMAT_MAP[safeDetected] ?? FORMAT_MAP[safeDetected] ??
safeDetected) as keyof sharp.FormatEnum; safeDetected) as SharpFormat;
if (targetSizeBytes !== undefined) { if (targetSizeBytes !== undefined) {
if (targetSizeBytes <= 0) { if (targetSizeBytes <= 0) {
@@ -52,7 +52,7 @@ export async function compress(image: Sharp, options: CompressOptions): Promise<
async function findBestQuality( async function findBestQuality(
inputBuffer: Buffer, inputBuffer: Buffer,
resize: { width: number; height: number } | null, resize: { width: number; height: number } | null,
format: keyof sharp.FormatEnum, format: SharpFormat,
targetBytes: number, targetBytes: number,
): Promise<number | null> { ): Promise<number | null> {
let low = 1; let low = 1;
@@ -82,7 +82,7 @@ async function findBestQuality(
async function compressToTargetSize( async function compressToTargetSize(
inputBuffer: Buffer, inputBuffer: Buffer,
format: keyof sharp.FormatEnum, format: SharpFormat,
targetBytes: number, targetBytes: number,
): Promise<Sharp> { ): Promise<Sharp> {
const quality = await findBestQuality(inputBuffer, null, format, targetBytes); const quality = await findBestQuality(inputBuffer, null, format, targetBytes);
@@ -1,12 +1,11 @@
import type sharp from "sharp"; import type { ConvertOptions, Sharp, SharpFormat } from "../types.js";
import type { ConvertOptions, Sharp } from "../types.js";
/** /**
* Maps user-facing format names to Sharp format strings. * Maps user-facing format names to Sharp format strings.
* Note: HEIC is excluded because Sharp cannot encode HEVC. * Note: HEIC is excluded because Sharp cannot encode HEVC.
* HEIC encoding is handled at the API route level via heif-enc. * HEIC encoding is handled at the API route level via heif-enc.
*/ */
const FORMAT_MAP: Record<string, string> = { const FORMAT_MAP: Partial<Record<ConvertOptions["format"], SharpFormat>> = {
jpg: "jpeg", jpg: "jpeg",
png: "png", png: "png",
webp: "webp", webp: "webp",
@@ -32,5 +31,5 @@ export async function convert(image: Sharp, options: ConvertOptions): Promise<Sh
formatOptions.quality = quality; formatOptions.quality = quality;
} }
return image.toFormat(sharpFormat as keyof sharp.FormatEnum, formatOptions); return image.toFormat(sharpFormat, formatOptions);
} }
+5 -2
View File
@@ -1,6 +1,9 @@
import type sharp from "sharp"; import type { ChannelStats, FormatEnum, Metadata, Sharp as SharpInstance } from "sharp";
export type Sharp = sharp.Sharp; export type Sharp = SharpInstance;
export type SharpFormat = Extract<keyof FormatEnum, string> | "avif";
export type SharpChannelStats = ChannelStats;
export type SharpMetadata = Metadata;
export interface ImageInfo { export interface ImageInfo {
width: number; width: number;