fix: send opaque scale adjust masks to fal

This commit is contained in:
134 2026-07-06 05:54:52 +08:00
parent aad838a8e0
commit d94f6dea8c
2 changed files with 65 additions and 7 deletions

View File

@ -128,6 +128,7 @@ type ScaleAdjustPatchReference = {
compositeClipMaskUrl?: string | null;
productLockMethod?: string | null;
productLockEditMaskUrl?: string | null;
productLockFalEditMaskUrl?: string | null;
productLockOverlayUrl?: string | null;
productLockProtectMaskUrl?: string | null;
sourceCropUrl: string;
@ -2262,6 +2263,36 @@ async function buildScaleAdjustTransparentEditMaskFromOpacityMask(params: {
.toBuffer();
}
async function buildScaleAdjustOpaqueEditMaskFromOpacityMask(params: {
height: number;
maskBuffer: Buffer;
width: number;
}) {
const { height, maskBuffer, width } = params;
const editAlpha = await sharp(maskBuffer, { failOn: "none" })
.rotate()
.resize(width, height, { fit: "fill" })
.ensureAlpha()
.extractChannel(3)
.greyscale()
.raw()
.toBuffer();
const rgba = Buffer.alloc(width * height * 4);
for (let index = 0; index < width * height; index += 1) {
const offset = index * 4;
const value = editAlpha[index] || 0;
rgba[offset] = value;
rgba[offset + 1] = value;
rgba[offset + 2] = value;
rgba[offset + 3] = 255;
}
return sharp(rgba, {
raw: { channels: 4, height, width },
})
.png({ compressionLevel: 9 })
.toBuffer();
}
function getScaleAdjustAlphaBoundingBox(params: {
height: number;
rawRgba: Buffer;
@ -3738,12 +3769,21 @@ async function buildScaleAdjustVisualLayoutGuideBuffer(params: {
width: sourceWidth,
})
: null;
const productLockFalEditMaskBuffer =
productLockComposites.length && compositeClipMaskBuffer
? await buildScaleAdjustOpaqueEditMaskFromOpacityMask({
height: sourceHeight,
maskBuffer: compositeClipMaskBuffer,
width: sourceWidth,
})
: null;
return {
backgroundPlateBuffer,
buffer,
compositeClipMaskBuffer,
productLockEditMaskBuffer,
productLockFalEditMaskBuffer,
productLockOverlayBuffer,
productLockProtectMaskBuffer,
};
@ -3796,6 +3836,7 @@ async function createScaleAdjustPatchReference(params: {
productLockProtectMaskUpload,
compositeClipMaskUpload,
productLockEditMaskUpload,
productLockFalEditMaskUpload,
] = await Promise.all([
uploadFile(
`canvas-scale-adjust-full-target-draft-${suffix}.png`,
@ -3831,6 +3872,12 @@ async function createScaleAdjustPatchReference(params: {
toArrayBuffer(targetDraftReference.productLockEditMaskBuffer)
)
: Promise.resolve(null),
targetDraftReference.productLockFalEditMaskBuffer
? uploadFile(
`canvas-scale-adjust-product-lock-fal-edit-mask-${suffix}.png`,
toArrayBuffer(targetDraftReference.productLockFalEditMaskBuffer)
)
: Promise.resolve(null),
]);
return {
@ -3838,6 +3885,7 @@ async function createScaleAdjustPatchReference(params: {
compositeClipMaskUrl: compositeClipMaskUpload?.url || null,
productLockMethod: productLockOverlayUpload ? "rmbg-cutout" : null,
productLockEditMaskUrl: productLockEditMaskUpload?.url || null,
productLockFalEditMaskUrl: productLockFalEditMaskUpload?.url || null,
productLockOverlayUrl: productLockOverlayUpload?.url || null,
productLockProtectMaskUrl: productLockProtectMaskUpload?.url || null,
sourceCropUrl: sourceImageUrl || targetDraftFullUpload.url,
@ -3868,6 +3916,7 @@ async function createScaleAdjustPatchReference(params: {
productLockProtectMaskUpload,
compositeClipMaskUpload,
productLockEditMaskUpload,
productLockFalEditMaskUpload,
] = await Promise.all([
uploadFile(
`canvas-scale-adjust-workspace-source-${suffix}.png`,
@ -3911,6 +3960,12 @@ async function createScaleAdjustPatchReference(params: {
toArrayBuffer(targetDraftReference.productLockEditMaskBuffer)
)
: Promise.resolve(null),
targetDraftReference.productLockFalEditMaskBuffer
? uploadFile(
`canvas-scale-adjust-product-lock-fal-edit-mask-${suffix}.png`,
toArrayBuffer(targetDraftReference.productLockFalEditMaskBuffer)
)
: Promise.resolve(null),
]);
return {
@ -3918,6 +3973,7 @@ async function createScaleAdjustPatchReference(params: {
compositeClipMaskUrl: compositeClipMaskUpload?.url || null,
productLockMethod: productLockOverlayUpload ? "rmbg-cutout" : null,
productLockEditMaskUrl: productLockEditMaskUpload?.url || null,
productLockFalEditMaskUrl: productLockFalEditMaskUpload?.url || null,
productLockOverlayUrl: productLockOverlayUpload?.url || null,
productLockProtectMaskUrl: productLockProtectMaskUpload?.url || null,
sourceCropUrl: sourceCropUpload.url,
@ -5316,9 +5372,6 @@ export async function POST(request: NextRequest) {
scalePercent,
{ width: sourceWidth, height: sourceHeight },
{
backgroundReference:
useScaleAdjustProductLockMaskEdit &&
Boolean(scaleAdjustPatchReference?.backgroundPlateFullUrl),
maskEdit: useScaleAdjustProductLockMaskEdit,
}
)
@ -5394,9 +5447,6 @@ export async function POST(request: NextRequest) {
? useScaleAdjustProductLockMaskEdit
? [
sourceImageUrl,
...(scaleAdjustPatchReference.backgroundPlateFullUrl
? [scaleAdjustPatchReference.backgroundPlateFullUrl]
: []),
...scaleAdjustCropReferenceImageUrls,
...manualRegionReferenceImageUrls,
]
@ -5581,6 +5631,8 @@ export async function POST(request: NextRequest) {
useScaleAdjustProductLockMaskEdit,
scaleAdjustProductLockEditMaskUrl:
scaleAdjustPatchReference?.productLockEditMaskUrl || null,
scaleAdjustProductLockFalEditMaskUrl:
scaleAdjustPatchReference?.productLockFalEditMaskUrl || null,
scaleAdjustProductLockOverlayUrl:
scaleAdjustPatchReference?.productLockOverlayUrl || null,
scaleAdjustProductLockProtectMaskUrl:
@ -5706,6 +5758,9 @@ export async function POST(request: NextRequest) {
promptExtend: false,
providerImageParams: useScaleAdjustProductLockMaskEdit
? {
falMaskImageUrl:
scaleAdjustPatchReference?.productLockFalEditMaskUrl ||
(scaleAdjustPatchReference?.productLockEditMaskUrl as string),
maskImageUrl:
scaleAdjustPatchReference?.productLockEditMaskUrl as string,
}

View File

@ -21,6 +21,7 @@ interface FalImageParams {
safetyTolerance?: string | number;
seed?: string | number;
enableWebSearch?: boolean;
falMaskImageUrl?: string;
quality?: string;
maskImageUrl?: string;
openaiApiKey?: string;
@ -690,7 +691,9 @@ function buildFalRequestPayload(params: {
output_format: outputFormat,
};
const maskImageUrl = normalizeOptionalHttpUrl(params.imageParams?.maskImageUrl);
const maskImageUrl =
normalizeOptionalHttpUrl(params.imageParams?.falMaskImageUrl) ||
normalizeOptionalHttpUrl(params.imageParams?.maskImageUrl);
if (maskImageUrl) {
input.mask_url = maskImageUrl;
}