fix(media): match optimized image filenames to output format (#128902)

This commit is contained in:
Peter Steinberger
2026-08-24 17:04:34 -07:00
committed by GitHub
parent 058a72fe66
commit ee4bb5f85b
2 changed files with 37 additions and 8 deletions
+30 -1
View File
@@ -13,7 +13,7 @@ import { resolvePreferredOpenClawTmpDir } from "../infra/tmp-openclaw-dir.js";
import { createEmptyPluginRegistry } from "../plugins/registry-empty.js";
import { resetPluginRuntimeStateForTest, setActivePluginRegistry } from "../plugins/runtime.js";
import { withEnvAsync } from "../test-utils/env.js";
import { resizeToJpeg } from "./media-services.js";
import { createImageProcessor, resizeToJpeg } from "./media-services.js";
import { encodePngRgba, fillPixel } from "./png-encode.js";
let effectiveImageBytesCap: typeof import("./web-media.js").effectiveImageBytesCap;
@@ -488,6 +488,35 @@ describe("loadWebMedia", () => {
}
});
it("renames transparent WebP images converted to PNG across direct and local image owners", async () => {
const { optimizeImageBufferForWebMedia } = await import("./web-media.js");
const sourcePng = createLargeTransparentColorBlockPng(64);
const sourceWebp = (await createImageProcessor().encode(sourcePng, { format: "webp" })).data;
const imageCompression = { models: [{ maxSidePx: 32, preferredSidePx: 32 }] };
const direct = await optimizeImageBufferForWebMedia({
buffer: sourceWebp,
contentType: "image/webp",
fileName: "portrait.WebP",
maxBytes: 1024 * 1024,
imageCompression,
});
const convertedPath = path.join(fixtureRoot, "portrait.WebP");
await fs.writeFile(convertedPath, sourceWebp);
const loaded = await loadWebMedia(convertedPath, {
maxBytes: 1024 * 1024,
localRoots: [fixtureRoot],
imageCompression,
});
for (const result of [direct, loaded]) {
expect(result.kind).toBe("image");
expect(result.contentType).toBe("image/png");
expect(result.fileName).toBe("portrait.png");
expect(readPngDimensions(result.buffer)).toEqual({ width: 32, height: 32 });
}
});
it("applies model image maxBytes to the effective image cap", async () => {
await expect(
loadWebMediaRaw(tinyPngFile, {
+7 -7
View File
@@ -604,7 +604,7 @@ function assertHostReadMediaAllowed(params: {
);
}
function toJpegFileName(fileName?: string): string | undefined {
function toImageFileName(fileName: string | undefined, mimeType: string): string | undefined {
if (!fileName) {
return undefined;
}
@@ -613,10 +613,10 @@ function toJpegFileName(fileName?: string): string | undefined {
return fileName;
}
const parsed = path.parse(trimmed);
if (!parsed.ext || HEIC_EXT_RE.test(parsed.ext)) {
return path.format({ dir: parsed.dir, name: parsed.name || trimmed, ext: ".jpg" });
}
return path.format({ dir: parsed.dir, name: parsed.name, ext: ".jpg" });
const ext = extensionForMime(mimeType);
return mimeType !== "image/jpeg" && parsed.ext.toLowerCase() === ext
? fileName
: path.format({ dir: parsed.dir, name: parsed.name || trimmed, ext });
}
type OptimizedImage = {
@@ -994,7 +994,7 @@ export async function optimizeImageBufferForWebMedia(params: {
buffer: optimized.buffer,
contentType: optimized.mimeType,
kind: "image",
fileName: optimized.format === "jpeg" ? toJpegFileName(params.fileName) : params.fileName,
fileName: toImageFileName(params.fileName, optimized.mimeType),
};
}
@@ -1054,7 +1054,7 @@ async function loadWebMediaInternal(
throw new Error(formatCapReduce("Media", cap, optimized.buffer.length));
}
const fileName = optimized.format === "jpeg" ? toJpegFileName(meta?.fileName) : meta?.fileName;
const fileName = toImageFileName(meta?.fileName, optimized.mimeType);
return {
buffer: optimized.buffer,