



























@@ -61,9 +61,7 @@ type ExternalImageTool =
6161export const IMAGE_REDUCE_QUALITY_STEPS = [85, 75, 65, 55, 45, 35] as const;
6262export const MAX_IMAGE_INPUT_PIXELS = 25_000_000;
6363const IMAGE_PROCESS_TIMEOUT_MS = 20_000;
64-const IMAGE_METADATA_TIMEOUT_MS = 10_000;
6564const IMAGE_TOOL_MAX_BUFFER = 1024 * 1024;
66-const IMAGE_METADATA_MAX_BUFFER = 512 * 1024;
6765const MEDIA_UNDERSTANDING_CORE_PLUGIN_ID = "media-understanding-core";
6866const MEDIA_UNDERSTANDING_CORE_IMAGE_OPS_ARTIFACT = "image-ops.js";
6967@@ -207,6 +205,7 @@ function isImageBackendUnavailableCause(error: unknown): boolean {
207205detail.includes('cannot find package "sharp"') ||
208206detail.includes("cannot find module 'sharp'") ||
209207detail.includes('cannot find module "sharp"') ||
208+detail.includes("support for this compression format has not been built in") ||
210209detail.includes("is not available") ||
211210detail.includes("command not found") ||
212211detail.includes("enoent")
@@ -223,12 +222,11 @@ async function runWithImageBackends<T>(
223222return await fn(backend);
224223} catch (error) {
225224errors.push(error);
225+if (!isImageBackendUnavailableCause(error)) {
226+throw error;
227+}
226228}
227229}
228-const processingError = errors.find((error) => !isImageBackendUnavailableCause(error));
229-if (processingError) {
230-throw processingError;
231-}
232230throw createImageProcessorUnavailableError(operation, errors);
233231}
234232@@ -768,18 +766,6 @@ async function runPowerShellImageScript(
768766});
769767}
770768771-const WINDOWS_NATIVE_METADATA_SCRIPT = `
772-param([string]$InputPath)
773-$ErrorActionPreference = 'Stop'
774-Add-Type -AssemblyName System.Drawing
775-$image = [System.Drawing.Image]::FromFile($InputPath)
776-try {
777- [Console]::Out.WriteLine(('{0} {1}' -f $image.Width, $image.Height))
778-} finally {
779- $image.Dispose()
780-}
781-`;
782-783769const WINDOWS_NATIVE_RESIZE_SCRIPT = `
784770param(
785771 [string]$InputPath,
@@ -858,22 +844,6 @@ try {
858844}
859845`;
860846861-async function windowsNativeMetadataFromBuffer(buffer: Buffer): Promise<ImageMetadata | null> {
862-return await withImageTemp(async (workspace) => {
863-const input = await workspace.write("in.img", buffer);
864-const { stdout } = await runPowerShellImageScript(
865-"metadata.ps1",
866-WINDOWS_NATIVE_METADATA_SCRIPT,
867-[input],
868-);
869-const [widthRaw, heightRaw] = stdout.trim().split(/\s+/, 2);
870-return buildImageMetadata(
871-Number.parseInt(widthRaw ?? "", 10),
872-Number.parseInt(heightRaw ?? "", 10),
873-);
874-});
875-}
876-877847async function windowsNativeResize(
878848params: ResizeToJpegParams | ResizeToPngParams,
879849format: "jpeg" | "png",
@@ -904,51 +874,6 @@ async function runConvertTool(
904874});
905875}
906876907-async function metadataFromIdentifyTool(
908-tool: Extract<ExternalImageTool, { flavor: "magick" | "convert" | "gm" }>,
909-buffer: Buffer,
910-): Promise<ImageMetadata | null> {
911-return await withImageTemp(async (workspace) => {
912-const input = await workspace.write("in.img", buffer);
913-const command =
914-tool.flavor === "convert"
915- ? resolveSystemBin("identify", { trust: "standard" })
916- : tool.command;
917-if (!command) {
918-return null;
919-}
920-const args = tool.flavor === "magick" ? ["identify"] : tool.flavor === "gm" ? ["identify"] : [];
921-const { stdout } = await runExec(command, [...args, "-format", "%w %h", input], {
922-timeoutMs: IMAGE_METADATA_TIMEOUT_MS,
923-maxBuffer: IMAGE_METADATA_MAX_BUFFER,
924-});
925-const [widthRaw, heightRaw] = stdout.trim().split(/\s+/, 2);
926-const width = Number.parseInt(widthRaw ?? "", 10);
927-const height = Number.parseInt(heightRaw ?? "", 10);
928-return buildImageMetadata(width, height);
929-});
930-}
931-932-async function externalMetadataFromBuffer(
933-backend: Exclude<ImageBackend, "sharp">,
934-buffer: Buffer,
935-): Promise<ImageMetadata | null> {
936-const tool = resolveImageTool(backend);
937-if (!tool) {
938-throw new Error(`Image backend ${backend} is not available`);
939-}
940-if (tool.flavor === "sips") {
941-return await sipsMetadataFromBuffer(buffer);
942-}
943-if (tool.flavor === "powershell") {
944-return await windowsNativeMetadataFromBuffer(buffer);
945-}
946-if (tool.flavor === "ffmpeg") {
947-return null;
948-}
949-return await metadataFromIdentifyTool(tool, buffer);
950-}
951-952877function buildResizeGeometry(maxSide: number, withoutEnlargement?: boolean): string {
953878const side = clampInteger(maxSide, 1, Number.MAX_SAFE_INTEGER);
954879return `${side}x${side}${withoutEnlargement === false ? "" : ">"}`;
@@ -1114,34 +1039,6 @@ async function externalResizeToPng(
11141039});
11151040}
111610411117-async function sipsMetadataFromBuffer(buffer: Buffer): Promise<ImageMetadata | null> {
1118-return await withImageTemp(async (workspace) => {
1119-const input = await workspace.write("in.img", buffer);
1120-const { stdout } = await runExec(
1121-"/usr/bin/sips",
1122-["-g", "pixelWidth", "-g", "pixelHeight", input],
1123-{
1124-timeoutMs: IMAGE_METADATA_TIMEOUT_MS,
1125-maxBuffer: IMAGE_METADATA_MAX_BUFFER,
1126-},
1127-);
1128-const w = stdout.match(/pixelWidth:\s*([0-9]+)/);
1129-const h = stdout.match(/pixelHeight:\s*([0-9]+)/);
1130-if (!w?.[1] || !h?.[1]) {
1131-return null;
1132-}
1133-const width = Number.parseInt(w[1], 10);
1134-const height = Number.parseInt(h[1], 10);
1135-if (!Number.isFinite(width) || !Number.isFinite(height)) {
1136-return null;
1137-}
1138-if (width <= 0 || height <= 0) {
1139-return null;
1140-}
1141-return { width, height };
1142-});
1143-}
1144-11451042async function sipsResizeToJpeg(params: {
11461043buffer: Buffer;
11471044maxSide: number;
@@ -1193,13 +1090,15 @@ export async function getImageMetadata(buffer: Buffer): Promise<ImageMetadata |
11931090}
11941091}
119510921196-return await runWithImageBackends("metadata", async (backend) => {
1197-const meta =
1198-backend === "sharp"
1199- ? await (await loadMediaAttachmentImageOps()).getImageMetadata(buffer)
1200- : await externalMetadataFromBuffer(backend, buffer);
1093+const preference = getImageBackendPreference();
1094+if (preference !== "auto" && preference !== "sharp") {
1095+return null;
1096+}
1097+1098+return await (async () => {
1099+const meta = await (await loadMediaAttachmentImageOps()).getImageMetadata(buffer);
12011100return meta ? validateImagePixelLimit(meta) : null;
1202-}).catch(() => null);
1101+})().catch(() => null);
12031102}
1204110312051104/**
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。