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") {
|
if (aspectRatio === "auto") {
|
||||||
// 阿里文档在 auto 下默认接近 1024*1024,这会让 4K 选择失效。
|
// 阿里文档在 auto 下默认接近 1024*1024,这会让 4K 选择失效。
|
||||||
// 这里改为根据参考图比例计算 size,确保 1K/2K/4K 档位真正生效。
|
// 这里改为根据参考图比例计算 size,确保 1K/2K/4K 档位真正生效。
|
||||||
const referenceImageUrl = imageUrls[imageUrls.length - 1];
|
const referenceImageUrl = imageUrls[0];
|
||||||
const inferredAspectRatio = await inferAspectRatioFromImageUrl(referenceImageUrl);
|
const inferredDimensions = await inferImageDimensionsFromImageUrl(referenceImageUrl);
|
||||||
if (inferredAspectRatio) {
|
if (inferredDimensions) {
|
||||||
params.size = calculateAlibabaSizeByAspect(inferredAspectRatio, baseSize);
|
params.size = calculateAlibabaSizeFromDimensions(
|
||||||
|
inferredDimensions.width,
|
||||||
|
inferredDimensions.height,
|
||||||
|
baseSize,
|
||||||
|
);
|
||||||
console.log(
|
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 {
|
} else {
|
||||||
console.log(
|
const inferredAspectRatio = await inferAspectRatioFromImageUrl(referenceImageUrl);
|
||||||
`[Alibaba Image] Auto mode keeps provider default size: imageSize=${imageSize}, inferredAspect=unavailable`
|
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 {
|
} else {
|
||||||
const calculatedSize = calculateSize(aspectRatio, baseSize);
|
const calculatedSize = calculateSize(aspectRatio, baseSize);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user