From 6694846c58bc43d6b32fa7b4a6c7cc4667190f22 Mon Sep 17 00:00:00 2001 From: 134 Date: Mon, 6 Jul 2026 03:00:28 +0800 Subject: [PATCH] fix: harden scale adjust person occlusion masks --- app/api/canvas/local-edit/route.ts | 58 +++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/app/api/canvas/local-edit/route.ts b/app/api/canvas/local-edit/route.ts index a76b245da..cc187948a 100644 --- a/app/api/canvas/local-edit/route.ts +++ b/app/api/canvas/local-edit/route.ts @@ -1726,6 +1726,34 @@ function buildScaleAdjustProtectedPersonSeedMask(params: { }); } +function buildScaleAdjustProtectedPersonGeometryMask(params: { + box: { width: number; height: number }; + side: ScaleAdjustProtectedPersonSide | null; +}) { + const { box, side } = params; + if (!side) return null; + const mask = new Uint8Array(box.width * box.height); + for (let y = 0; y < box.height; y += 1) { + for (let x = 0; x < box.width; x += 1) { + const xr = x / Math.max(1, box.width); + const yr = y / Math.max(1, box.height); + const protect = + side === "right" + ? (xr >= 0.72 && yr >= 0.26) || + (xr >= 0.58 && yr >= 0.56) || + (xr >= 0.48 && yr >= 0.7) + : side === "left" + ? (xr <= 0.28 && yr >= 0.26) || + (xr <= 0.42 && yr >= 0.56) || + (xr <= 0.52 && yr >= 0.7) + : (yr >= 0.62 && (xr <= 0.2 || xr >= 0.8)) || + (yr >= 0.72 && (xr <= 0.34 || xr >= 0.66)); + if (protect) mask[y * box.width + x] = 255; + } + } + return mask; +} + function filterScaleAdjustStructureComponents(params: { box: { width: number; height: number }; mask: Uint8Array; @@ -1821,13 +1849,15 @@ function filterScaleAdjustStructureComponents(params: { if (protectedPersonSide === "right") { return ( (pixelX >= width * 0.7 && pixelY >= height * 0.38) || - (pixelX >= width * 0.62 && pixelY >= height * 0.56) + (pixelX >= width * 0.62 && pixelY >= height * 0.56) || + (pixelX >= width * 0.48 && pixelY >= height * 0.7) ); } if (protectedPersonSide === "left") { return ( (pixelX <= width * 0.3 && pixelY >= height * 0.38) || - (pixelX <= width * 0.38 && pixelY >= height * 0.56) + (pixelX <= width * 0.38 && pixelY >= height * 0.56) || + (pixelX <= width * 0.52 && pixelY >= height * 0.7) ); } if (protectedPersonSide === "auto") { @@ -2110,7 +2140,7 @@ async function buildScaleAdjustMaskWashPatch(params: { rgba[offset] = Math.round(background.r); rgba[offset + 1] = Math.round(background.g); rgba[offset + 2] = Math.round(background.b); - rgba[offset + 3] = Math.round((alpha[index] || 0) * 0.9); + rgba[offset + 3] = Math.min(255, Math.round((alpha[index] || 0) * 0.985)); } return sharp(rgba, { raw: { channels: 4, height: box.height, width: box.width }, @@ -2714,12 +2744,20 @@ async function buildScaleAdjustRmbgStructureLockedComposite(params: { .toBuffer(); const targetClipMaskPatch = await buildScaleAdjustOverlayClipMaskPatch(structureOverlay); - const productLockProtectMaskPatch = protectedPersonMask + const productLockProtectMask = + protectedPersonMask || + (protectedPersonSide + ? buildScaleAdjustProtectedPersonGeometryMask({ + box: placement.sourceBox, + side: protectedPersonSide, + }) + : null); + const productLockProtectMaskPatch = productLockProtectMask ? await buildScaleAdjustCompositeClipMaskPatch({ box: placement.sourceBox, maskBuffer: dilateScaleAdjustStructureMask({ height: placement.sourceBox.height, - mask: protectedPersonMask, + mask: productLockProtectMask, radius: Math.max( 2, Math.round( @@ -2742,6 +2780,8 @@ async function buildScaleAdjustRmbgStructureLockedComposite(params: { placedHeight, placedWidth, protectedPersonSide, + protectedPersonGeometryMaskApplied: + Boolean(productLockProtectMask) && !protectedPersonMask, protectedPersonMaskApplied: Boolean(protectedPersonMask), sameSizeCutout, alphaBandingStats, @@ -2874,6 +2914,10 @@ function suppressScaleAdjustProtectedFurnitureDarkAlpha(params: { return ( (sourceX >= sourceBox.width * 0.69 && sourceY >= sourceBox.height * 0.54) || (sourceX >= sourceBox.width * 0.58 && sourceY >= sourceBox.height * 0.7) || + (sourceX >= sourceBox.width * 0.5 && sourceY >= sourceBox.height * 0.74) || + (sourceX >= sourceBox.width * 0.56 && + sourceY >= sourceBox.height * 0.58 && + sourceY <= sourceBox.height * 0.78) || (sourceX >= sourceBox.width * 0.78 && sourceY >= sourceBox.height * 0.4) || (sourceX >= sourceBox.width * 0.91 && sourceY >= sourceBox.height * 0.26) ); @@ -2882,6 +2926,10 @@ function suppressScaleAdjustProtectedFurnitureDarkAlpha(params: { return ( (sourceX <= sourceBox.width * 0.31 && sourceY >= sourceBox.height * 0.54) || (sourceX <= sourceBox.width * 0.42 && sourceY >= sourceBox.height * 0.7) || + (sourceX <= sourceBox.width * 0.5 && sourceY >= sourceBox.height * 0.74) || + (sourceX <= sourceBox.width * 0.44 && + sourceY >= sourceBox.height * 0.58 && + sourceY <= sourceBox.height * 0.78) || (sourceX <= sourceBox.width * 0.22 && sourceY >= sourceBox.height * 0.4) || (sourceX <= sourceBox.width * 0.09 && sourceY >= sourceBox.height * 0.26) );