fix: preserve source aspect for alibaba auto size
This commit is contained in:
parent
d6a06e0cd0
commit
5be4d0e9df
@ -120,6 +120,79 @@ async function inferAspectRatioFromImageUrl(imageUrl: string): Promise<number |
|
||||
}
|
||||
}
|
||||
|
||||
async function inferImageDimensionsFromImageUrl(
|
||||
imageUrl: string,
|
||||
): Promise<{ width: number; height: number; aspectRatio: number } | null> {
|
||||
if (!/^https?:\/\//i.test(imageUrl)) return null;
|
||||
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), ALIBABA_IMAGE_FETCH_TIMEOUT_MS);
|
||||
try {
|
||||
const response = await fetch(imageUrl, { signal: controller.signal });
|
||||
if (!response.ok) {
|
||||
console.warn("[Alibaba Image] Failed to fetch reference image dimensions:", response.status);
|
||||
return null;
|
||||
}
|
||||
|
||||
const buffer = Buffer.from(await response.arrayBuffer());
|
||||
if (!buffer.length) return null;
|
||||
|
||||
const metadata = await sharp(buffer).metadata();
|
||||
if (!metadata.width || !metadata.height || metadata.height <= 0) return null;
|
||||
|
||||
return {
|
||||
width: metadata.width,
|
||||
height: metadata.height,
|
||||
aspectRatio: metadata.width / metadata.height,
|
||||
};
|
||||
} catch (error) {
|
||||
console.warn("[Alibaba Image] Failed to infer image dimensions from reference image:", error);
|
||||
return null;
|
||||
} finally {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
}
|
||||
|
||||
function calculateAlibabaSizeFromDimensions(
|
||||
width: number,
|
||||
height: number,
|
||||
baseSize: number,
|
||||
): string {
|
||||
const safeWidth = Math.max(1, Math.round(width));
|
||||
const safeHeight = Math.max(1, Math.round(height));
|
||||
const longestSide = Math.max(safeWidth, safeHeight);
|
||||
const scale = baseSize / longestSide;
|
||||
|
||||
let scaledWidth = Math.round(safeWidth * scale);
|
||||
let scaledHeight = Math.round(safeHeight * scale);
|
||||
|
||||
if (scaledWidth > ALIBABA_MAX_SIZE || scaledHeight > ALIBABA_MAX_SIZE) {
|
||||
const clampScale = Math.min(
|
||||
ALIBABA_MAX_SIZE / scaledWidth,
|
||||
ALIBABA_MAX_SIZE / scaledHeight,
|
||||
);
|
||||
scaledWidth = Math.round(scaledWidth * clampScale);
|
||||
scaledHeight = Math.round(scaledHeight * clampScale);
|
||||
}
|
||||
|
||||
if (scaledWidth < ALIBABA_MIN_SIZE || scaledHeight < ALIBABA_MIN_SIZE) {
|
||||
const boostScale = Math.max(
|
||||
ALIBABA_MIN_SIZE / scaledWidth,
|
||||
ALIBABA_MIN_SIZE / scaledHeight,
|
||||
);
|
||||
scaledWidth = Math.round(scaledWidth * boostScale);
|
||||
scaledHeight = Math.round(scaledHeight * boostScale);
|
||||
}
|
||||
|
||||
scaledWidth = Math.max(ALIBABA_MIN_SIZE, Math.min(ALIBABA_MAX_SIZE, scaledWidth));
|
||||
scaledHeight = Math.max(ALIBABA_MIN_SIZE, Math.min(ALIBABA_MAX_SIZE, scaledHeight));
|
||||
|
||||
scaledWidth = Math.round(scaledWidth / 2) * 2;
|
||||
scaledHeight = Math.round(scaledHeight / 2) * 2;
|
||||
|
||||
return `${scaledWidth}*${scaledHeight}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建缩略图
|
||||
*/
|
||||
@ -501,17 +574,29 @@ export function createAlibabaImage({ apiKey, baseURL }: AlibabaImageConfig) {
|
||||
if (aspectRatio === "auto") {
|
||||
// 阿里文档在 auto 下默认接近 1024*1024,这会让 4K 选择失效。
|
||||
// 这里改为根据参考图比例计算 size,确保 1K/2K/4K 档位真正生效。
|
||||
const referenceImageUrl = imageUrls[imageUrls.length - 1];
|
||||
const inferredAspectRatio = await inferAspectRatioFromImageUrl(referenceImageUrl);
|
||||
if (inferredAspectRatio) {
|
||||
params.size = calculateAlibabaSizeByAspect(inferredAspectRatio, baseSize);
|
||||
const referenceImageUrl = imageUrls[0];
|
||||
const inferredDimensions = await inferImageDimensionsFromImageUrl(referenceImageUrl);
|
||||
if (inferredDimensions) {
|
||||
params.size = calculateAlibabaSizeFromDimensions(
|
||||
inferredDimensions.width,
|
||||
inferredDimensions.height,
|
||||
baseSize,
|
||||
);
|
||||
console.log(
|
||||
`[Alibaba Image] Auto mode resolved size: imageSize=${imageSize}, inferredAspect=${inferredAspectRatio} => size=${params.size}`
|
||||
`[Alibaba Image] Auto mode resolved size: imageSize=${imageSize}, reference=${inferredDimensions.width}x${inferredDimensions.height}, inferredAspect=${inferredDimensions.aspectRatio} => size=${params.size}`
|
||||
);
|
||||
} else {
|
||||
console.log(
|
||||
`[Alibaba Image] Auto mode keeps provider default size: imageSize=${imageSize}, inferredAspect=unavailable`
|
||||
);
|
||||
const inferredAspectRatio = await inferAspectRatioFromImageUrl(referenceImageUrl);
|
||||
if (inferredAspectRatio) {
|
||||
params.size = calculateAlibabaSizeByAspect(inferredAspectRatio, baseSize);
|
||||
console.log(
|
||||
`[Alibaba Image] Auto mode resolved size via aspect fallback: imageSize=${imageSize}, inferredAspect=${inferredAspectRatio} => size=${params.size}`
|
||||
);
|
||||
} else {
|
||||
console.log(
|
||||
`[Alibaba Image] Auto mode keeps provider default size: imageSize=${imageSize}, inferredAspect=unavailable`
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const calculatedSize = calculateSize(aspectRatio, baseSize);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user