fix: soften scale adjust composite edges

This commit is contained in:
134 2026-06-21 19:34:23 +08:00
parent 317593a72d
commit 2fbcd45035
2 changed files with 34 additions and 7 deletions

View File

@ -729,6 +729,7 @@ function buildScaleAdjustPrompt(
`4. 放大时,目标主体应围绕原位置视觉中心自然变大到约 ${targetLabel};宽度和高度都要同步变大,不能出现“高度变高但宽度变窄”的非等比变形;主体边缘与遮挡关系要合理,不能产生突兀裁切。`,
"5. 如果主体靠近画布边界导致目标尺寸空间不足,请用能完整放入画面的最大统一倍率整体缩放;绝不能为了塞进画面而只压缩宽度或只拉伸高度。",
"6. 框选区域内非目标主体的背景、墙面、桌面、植物、文字和其它物体应保持原场景逻辑,不要跟着主体一起缩放。",
"6.1 比例调整后的主体边缘必须和周围环境自然融合,选区边界不能被肉眼看出;不得出现一整块矩形区域清晰度、颜色、光照、纹理或透视突然变化。",
"7. 未受比例调整影响的其它画面区域必须保持原图不变,尤其是框选区域外的文字、Logo、标题、尺寸标注、装饰条和页面排版不得被清理、改写、模糊或重绘。",
"8. 最终输出必须是一张完整、干净、无缝的照片,不得出现任何选区框、说明文字、对比线、比例数字或 UI 元素。",
"9. 输出前自检:如果目标主体大小与原图相比没有明显变化,或者主体宽高比发生非等比变形,必须重新生成;禁止返回看起来和原图相同或被拉伸的结果。",

View File

@ -112,8 +112,8 @@ class ScaleAdjustOutputRejectedError extends Error {
const LOCAL_EDIT_COMPOSITE_PADDING_RATIO = 0.14;
const LOCAL_EDIT_COMPOSITE_MIN_PADDING_RATIO = 0.012;
const LOCAL_EDIT_COMPOSITE_MAX_PADDING_RATIO = 0.06;
const LOCAL_EDIT_COMPOSITE_FEATHER_MIN_PX = 10;
const LOCAL_EDIT_COMPOSITE_FEATHER_MAX_PX = 44;
const LOCAL_EDIT_COMPOSITE_FEATHER_MIN_PX = 18;
const LOCAL_EDIT_COMPOSITE_FEATHER_MAX_PX = 72;
const SCALE_ADJUST_VISUAL_DIFF_THRESHOLD = 14;
const SCALE_ADJUST_OUTSIDE_DIFF_THRESHOLD = 18;
const SCALE_ADJUST_OUTSIDE_DIFF_MIN_CHANGED_RATIO = 0.28;
@ -678,10 +678,10 @@ function buildLocalEditCompositeMaskSvg(params: {
LOCAL_EDIT_COMPOSITE_FEATHER_MIN_PX,
Math.min(
LOCAL_EDIT_COMPOSITE_FEATHER_MAX_PX,
Math.round(Math.min(width, height) * 0.012)
Math.round(Math.min(width, height) * 0.018)
)
);
const rects = regions
const rectEntries = regions
.map((region) => {
const left = Math.max(0, Math.round(region.x * width));
const top = Math.max(0, Math.round(region.y * height));
@ -693,7 +693,33 @@ function buildLocalEditCompositeMaskSvg(params: {
height - top,
Math.max(1, Math.round(region.height * height))
);
return `<rect x="${left}" y="${top}" width="${rectWidth}" height="${rectHeight}" rx="${Math.round(blur * 0.9)}" fill="#ffffff" />`;
return { left, top, rectHeight, rectWidth };
})
.filter(({ rectHeight, rectWidth }) => rectWidth > 0 && rectHeight > 0);
const softRects = rectEntries
.map(
({ left, top, rectHeight, rectWidth }) =>
`<rect x="${left}" y="${top}" width="${rectWidth}" height="${rectHeight}" rx="${Math.round(
blur * 0.9
)}" fill="#ffffff" />`
)
.join("");
const coreRects = rectEntries
.map(({ left, top, rectHeight, rectWidth }) => {
const inset = Math.max(
0,
Math.min(
Math.round(blur * 1.35),
Math.floor(rectWidth / 3),
Math.floor(rectHeight / 3)
)
);
const coreWidth = rectWidth - inset * 2;
const coreHeight = rectHeight - inset * 2;
if (coreWidth <= 0 || coreHeight <= 0) return "";
return `<rect x="${left + inset}" y="${top + inset}" width="${coreWidth}" height="${coreHeight}" rx="${Math.round(
blur * 0.45
)}" fill="#ffffff" />`;
})
.join("");
@ -706,9 +732,9 @@ function buildLocalEditCompositeMaskSvg(params: {
</defs>
<rect x="0" y="0" width="${width}" height="${height}" fill="rgba(0,0,0,0)" />
<g filter="url(#local-edit-soft-mask)">
${rects}
${softRects}
</g>
${rects}
${coreRects}
</svg>
`);
}