71 lines
2.1 KiB
TypeScript
71 lines
2.1 KiB
TypeScript
import "server-only";
|
|
|
|
import { fetchImageBufferFromUrl } from "@/lib/ai/rmbg/service";
|
|
|
|
export type CanvasLayoutReplaceSourceProfile = {
|
|
boundingHeight: number;
|
|
boundingWidth: number;
|
|
silhouetteAspectRatio: number;
|
|
sourceHeight: number;
|
|
sourceWidth: number;
|
|
transparentPixelRatio: number;
|
|
};
|
|
|
|
export async function resolveCanvasLayoutReplaceSourceProfile(
|
|
sourceImageUrl: string,
|
|
): Promise<CanvasLayoutReplaceSourceProfile | null> {
|
|
try {
|
|
const sharp = (await import("sharp")).default;
|
|
const sourceBuffer = await fetchImageBufferFromUrl(sourceImageUrl);
|
|
const { data, info } = await sharp(sourceBuffer, { failOn: "none" })
|
|
.rotate()
|
|
.ensureAlpha()
|
|
.raw()
|
|
.toBuffer({ resolveWithObject: true });
|
|
const pixelCount = info.width * info.height;
|
|
if (pixelCount <= 0 || info.channels < 4) return null;
|
|
|
|
let transparentPixelCount = 0;
|
|
let minX = info.width;
|
|
let minY = info.height;
|
|
let maxX = -1;
|
|
let maxY = -1;
|
|
|
|
for (let pixelIndex = 0; pixelIndex < pixelCount; pixelIndex += 1) {
|
|
const alpha = data[pixelIndex * info.channels + 3] || 0;
|
|
if (alpha < 250) transparentPixelCount += 1;
|
|
if (alpha < 24) continue;
|
|
|
|
const x = pixelIndex % info.width;
|
|
const y = Math.floor(pixelIndex / info.width);
|
|
if (x < minX) minX = x;
|
|
if (x > maxX) maxX = x;
|
|
if (y < minY) minY = y;
|
|
if (y > maxY) maxY = y;
|
|
}
|
|
|
|
const transparentPixelRatio = transparentPixelCount / pixelCount;
|
|
if (transparentPixelRatio < 0.01 || maxX < minX || maxY < minY) {
|
|
return null;
|
|
}
|
|
|
|
const boundingWidth = maxX - minX + 1;
|
|
const boundingHeight = maxY - minY + 1;
|
|
if (boundingWidth < 2 || boundingHeight < 2) return null;
|
|
|
|
return {
|
|
boundingHeight,
|
|
boundingWidth,
|
|
silhouetteAspectRatio: boundingWidth / boundingHeight,
|
|
sourceHeight: info.height,
|
|
sourceWidth: info.width,
|
|
transparentPixelRatio,
|
|
};
|
|
} catch (error) {
|
|
console.warn("[Canvas Layout Replace] Failed to resolve source profile:", {
|
|
error: error instanceof Error ? error.message : String(error),
|
|
});
|
|
return null;
|
|
}
|
|
}
|