mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
fix(image-engine): support sharp 0.35 types
This commit is contained in:
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user