From 88878c33074cb6d582c45e1a22191967f841ac6b Mon Sep 17 00:00:00 2001 From: 134 Date: Fri, 3 Jul 2026 21:57:26 +0800 Subject: [PATCH] fix: refine rmbg alpha for scale drafts --- app/api/canvas/local-edit/route.ts | 44 ++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/app/api/canvas/local-edit/route.ts b/app/api/canvas/local-edit/route.ts index 4461bcccd..174851ba8 100644 --- a/app/api/canvas/local-edit/route.ts +++ b/app/api/canvas/local-edit/route.ts @@ -1721,6 +1721,28 @@ function thresholdScaleAdjustAlphaMask(params: { return output; } +async function applyScaleAdjustAlphaMaskToRgba(params: { + alphaMask: Uint8Array; + height: number; + rawRgba: Buffer; + width: number; +}) { + const { alphaMask, height, rawRgba, width } = params; + const blur = Math.max(0.45, Math.min(width, height) * 0.0035); + const softenedAlpha = await sharp(Buffer.from(alphaMask), { + raw: { channels: 1, height, width }, + }) + .blur(blur) + .raw() + .toBuffer(); + const output = Buffer.from(rawRgba); + const pixelCount = Math.min(alphaMask.length, Math.floor(output.length / 4)); + for (let index = 0; index < pixelCount; index += 1) { + output[index * 4 + 3] = softenedAlpha[index] || 0; + } + return output; +} + function getScaleAdjustAlphaBandingStats(params: { height: number; maskBuffer: Buffer | Uint8Array; @@ -1927,14 +1949,30 @@ async function buildScaleAdjustRmbgStructureLockedComposite(params: { rawRgba: cutoutRaw, width: cutoutWidth, }); - const cleanedCutout = await sharp(cleanedRaw, { + const highConfidenceCutoutMask = thresholdScaleAdjustAlphaMask({ + maskBuffer: cleanedAlpha, + threshold: 96, + }); + const highConfidenceCutoutBbox = getScaleAdjustMaskBoundingBox({ + height: cutoutHeight, + mask: highConfidenceCutoutMask, + width: cutoutWidth, + }); + if (!highConfidenceCutoutBbox) return null; + const refinedCutoutRaw = await applyScaleAdjustAlphaMaskToRgba({ + alphaMask: highConfidenceCutoutMask, + height: cutoutHeight, + rawRgba: cleanedRaw, + width: cutoutWidth, + }); + const cleanedCutout = await sharp(refinedCutoutRaw, { raw: { channels: 4, height: cutoutHeight, width: cutoutWidth }, }) .png({ compressionLevel: 6 }) .toBuffer(); const alphaBbox = getScaleAdjustAlphaBoundingBox({ height: cutoutHeight, - rawRgba: cleanedRaw, + rawRgba: refinedCutoutRaw, width: cutoutWidth, }); if (!alphaBbox) return null; @@ -1950,7 +1988,7 @@ async function buildScaleAdjustRmbgStructureLockedComposite(params: { return null; } - const fullAlphaMask = cleanedAlpha; + const fullAlphaMask = Buffer.from(highConfidenceCutoutMask); const sourceMaskBuffer = sameSizeCutout ? fullAlphaMask : await resizeScaleAdjustAlphaMask({