fix: guide fal scale adjust with marked photo
This commit is contained in:
parent
291597a69f
commit
2cccac34ff
@ -1371,6 +1371,84 @@ function buildScaleAdjustZoomedCoordinateSvg(params: {
|
||||
`);
|
||||
}
|
||||
|
||||
function buildScaleAdjustFalPhotoGuideSvg(params: {
|
||||
width: number;
|
||||
height: number;
|
||||
regions: NormalizedLocalEditRegion[];
|
||||
scalePercent?: ScaleAdjustPercent | null;
|
||||
}) {
|
||||
const { width, height, regions, scalePercent } = params;
|
||||
const minSide = Math.max(1, Math.min(width, height));
|
||||
const strokeWidth = Math.max(3, Math.round(minSide * 0.005));
|
||||
const fontSize = Math.max(16, Math.round(minSide * 0.022));
|
||||
const labelPadX = Math.round(fontSize * 0.48);
|
||||
const labelHeight = Math.round(fontSize * 1.35);
|
||||
const currentColor = "#00b8d4";
|
||||
const finalColor = "#2563eb";
|
||||
const label = (text: string, x: number, y: number, color: string) => {
|
||||
const labelWidth = Math.round(text.length * fontSize * 0.74 + labelPadX * 2);
|
||||
const left = clamp(x, 6, Math.max(6, width - labelWidth - 6));
|
||||
const top = clamp(y, 6, Math.max(6, height - labelHeight - 6));
|
||||
return `
|
||||
<rect x="${left}" y="${top}" width="${labelWidth}" height="${labelHeight}" rx="${Math.round(labelHeight * 0.22)}" fill="${color}" opacity="0.92" />
|
||||
<text x="${left + labelPadX}" y="${top + Math.round(labelHeight * 0.68)}" fill="#ffffff" font-size="${fontSize}" font-family="Arial, Helvetica, sans-serif" font-weight="800">${escapeXml(text)}</text>
|
||||
`;
|
||||
};
|
||||
|
||||
const regionSvg = regions
|
||||
.map((region) => {
|
||||
const source = region.pixelRect;
|
||||
const targetRect = getScaleAdjustTargetRect(region, scalePercent);
|
||||
const target =
|
||||
region.targetPixelRect || rectToPixels(targetRect, width, height);
|
||||
const radius = Math.max(8, Math.round(strokeWidth * 2));
|
||||
return `
|
||||
<rect x="${source.left}" y="${source.top}" width="${source.width}" height="${source.height}" rx="${radius}" fill="${currentColor}" opacity="0.08" />
|
||||
<rect x="${target.left}" y="${target.top}" width="${target.width}" height="${target.height}" rx="${radius}" fill="${finalColor}" opacity="0.14" />
|
||||
<rect x="${source.left}" y="${source.top}" width="${source.width}" height="${source.height}" rx="${radius}" fill="none" stroke="${currentColor}" stroke-width="${strokeWidth}" stroke-dasharray="${strokeWidth * 2} ${strokeWidth * 1.4}" opacity="0.95" />
|
||||
<rect x="${target.left}" y="${target.top}" width="${target.width}" height="${target.height}" rx="${radius}" fill="none" stroke="${finalColor}" stroke-width="${Math.max(3, Math.round(strokeWidth * 1.25))}" opacity="0.98" />
|
||||
${label(`CURRENT ${region.index}`, source.left + strokeWidth, source.top + strokeWidth, currentColor)}
|
||||
${label(`FINAL ${region.index}`, target.left + strokeWidth, target.top + strokeWidth, finalColor)}
|
||||
`;
|
||||
})
|
||||
.join("");
|
||||
|
||||
return Buffer.from(`
|
||||
<svg width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="0" y="0" width="${width}" height="${height}" fill="#f8fafc" opacity="0.24" />
|
||||
${regionSvg}
|
||||
</svg>
|
||||
`);
|
||||
}
|
||||
|
||||
async function buildScaleAdjustFalPhotoGuideBuffer(params: {
|
||||
sourceBuffer: Buffer;
|
||||
width: number;
|
||||
height: number;
|
||||
regions: NormalizedLocalEditRegion[];
|
||||
scalePercent?: ScaleAdjustPercent | null;
|
||||
}) {
|
||||
const { sourceBuffer, width, height, regions, scalePercent } = params;
|
||||
return sharp(sourceBuffer, { failOn: "none" })
|
||||
.rotate()
|
||||
.resize(width, height, { fit: "cover", position: "center" })
|
||||
.modulate({ brightness: 1.04, saturation: 0.45 })
|
||||
.composite([
|
||||
{
|
||||
input: buildScaleAdjustFalPhotoGuideSvg({
|
||||
height,
|
||||
regions,
|
||||
scalePercent,
|
||||
width,
|
||||
}),
|
||||
left: 0,
|
||||
top: 0,
|
||||
},
|
||||
])
|
||||
.png({ compressionLevel: 6 })
|
||||
.toBuffer();
|
||||
}
|
||||
|
||||
function buildLocalEditPrompt(regions: NormalizedLocalEditRegion[]) {
|
||||
const regionLines = regions
|
||||
.map((region) => {
|
||||
@ -1576,8 +1654,8 @@ function buildScaleAdjustCoordinatePrompt(
|
||||
return [
|
||||
"Interior furniture photo edit.",
|
||||
`Return one realistic photo with the same camera frame and pixel size as input image 1: ${sourceSize.width} x ${sourceSize.height} px.`,
|
||||
"Input image 1 is the source photo. Input image 2 is a coordinate guide only and should not appear in the final photo.",
|
||||
"The guide labels OLD as the current furniture box and TARGET as the requested final footprint.",
|
||||
"Input image 1 is the source photo. Input image 2 is a marked copy of the source photo for location guidance only and should not appear in the final photo.",
|
||||
"The guide labels CURRENT as the existing furniture box and FINAL as the requested final footprint.",
|
||||
"Resize only the furniture subject indicated by each current box. Keep the camera, room layout, walls, windows, floor, rug, sofa, lamp, text, and background stable.",
|
||||
"Preserve the furniture identity, material, perspective, objects on top, and natural aspect ratio.",
|
||||
"For a smaller final footprint, show the furniture smaller and blend newly visible floor, rug, wall, window area, shadow, and background around it naturally. For a larger final footprint, scale the same furniture proportionally with natural edges and contact shadows.",
|
||||
@ -1799,17 +1877,25 @@ export async function POST(request: NextRequest) {
|
||||
resolvedScaleAdjustModelEntry?.provider?.type === "fal-image";
|
||||
const annotatedBuffer = isScaleAdjustOperation
|
||||
? useScaleAdjustCoordinateGuide
|
||||
? await sharp(
|
||||
buildScaleAdjustZoomedCoordinateSvg({
|
||||
? useFalScaleAdjustCoordinatePrompt
|
||||
? await buildScaleAdjustFalPhotoGuideBuffer({
|
||||
height: sourceHeight,
|
||||
regions,
|
||||
scalePercent,
|
||||
sourceBuffer,
|
||||
width: sourceWidth,
|
||||
}),
|
||||
{ failOn: "none" }
|
||||
)
|
||||
.png({ compressionLevel: 6 })
|
||||
.toBuffer()
|
||||
})
|
||||
: await sharp(
|
||||
buildScaleAdjustZoomedCoordinateSvg({
|
||||
height: sourceHeight,
|
||||
regions,
|
||||
scalePercent,
|
||||
width: sourceWidth,
|
||||
}),
|
||||
{ failOn: "none" }
|
||||
)
|
||||
.png({ compressionLevel: 6 })
|
||||
.toBuffer()
|
||||
: await buildScaleAdjustVisualLayoutGuideBuffer({
|
||||
regions,
|
||||
scalePercent,
|
||||
@ -1915,7 +2001,9 @@ export async function POST(request: NextRequest) {
|
||||
annotatedReferenceSentToModel: isScaleAdjustOperation,
|
||||
annotatedReferenceType: isScaleAdjustOperation
|
||||
? useScaleAdjustCoordinateGuide
|
||||
? "scale-adjust-neutral-coordinate-map"
|
||||
? useFalScaleAdjustCoordinatePrompt
|
||||
? "scale-adjust-fal-marked-photo-guide"
|
||||
: "scale-adjust-neutral-coordinate-map"
|
||||
: "scale-adjust-full-frame-semantic-edit-map"
|
||||
: "source-overlay",
|
||||
cleanSourceReferenceIndex: 1,
|
||||
@ -1932,7 +2020,10 @@ export async function POST(request: NextRequest) {
|
||||
scaleAdjustModelFamily: scaleAdjustModelFamily || null,
|
||||
scaleAdjustCoordinateGuideApplied: useScaleAdjustCoordinateGuide,
|
||||
scaleAdjustNeutralCoordinateMapApplied:
|
||||
isScaleAdjustOperation && useScaleAdjustCoordinateGuide,
|
||||
isScaleAdjustOperation &&
|
||||
useScaleAdjustCoordinateGuide &&
|
||||
!useFalScaleAdjustCoordinatePrompt,
|
||||
scaleAdjustFalMarkedPhotoGuideApplied: useFalScaleAdjustCoordinatePrompt,
|
||||
scaleAdjustVisualLayoutGuideApplied:
|
||||
isScaleAdjustOperation && !useScaleAdjustCoordinateGuide,
|
||||
falScaleAdjustCoordinateGuideApplied:
|
||||
@ -1963,7 +2054,7 @@ export async function POST(request: NextRequest) {
|
||||
scaleAdjustPromptStrategy: isScaleAdjustOperation
|
||||
? useScaleAdjustCoordinateGuide
|
||||
? useFalScaleAdjustCoordinatePrompt
|
||||
? "fal-safe-zoomed-coordinate-map-no-old-crop-v42-one-shot"
|
||||
? "fal-safe-marked-photo-guide-no-old-crop-v43-one-shot"
|
||||
: "same-name-zoomed-coordinate-map-no-old-crop-v42-one-shot"
|
||||
: "locked-plate-semantic-target-map-no-old-crop-v15"
|
||||
: undefined,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user