fix: reject banded rmbg scale drafts
This commit is contained in:
parent
01e17361c8
commit
5ec43fa8a3
@ -1709,6 +1709,83 @@ function getScaleAdjustAlphaBoundingBox(params: {
|
||||
};
|
||||
}
|
||||
|
||||
function thresholdScaleAdjustAlphaMask(params: {
|
||||
maskBuffer: Buffer | Uint8Array;
|
||||
threshold?: number;
|
||||
}) {
|
||||
const { maskBuffer, threshold = 96 } = params;
|
||||
const output = new Uint8Array(maskBuffer.length);
|
||||
for (let index = 0; index < maskBuffer.length; index += 1) {
|
||||
output[index] = (maskBuffer[index] || 0) >= threshold ? 255 : 0;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
function getScaleAdjustAlphaBandingStats(params: {
|
||||
height: number;
|
||||
maskBuffer: Buffer | Uint8Array;
|
||||
threshold?: number;
|
||||
width: number;
|
||||
}) {
|
||||
const { height, maskBuffer, threshold = 24, width } = params;
|
||||
const mask = thresholdScaleAdjustAlphaMask({ maskBuffer, threshold });
|
||||
const bbox = getScaleAdjustMaskBoundingBox({ height, mask, width });
|
||||
if (!bbox) {
|
||||
return {
|
||||
activeRowRatio: 0,
|
||||
bboxHeightRatio: 0,
|
||||
bboxWidthRatio: 0,
|
||||
detected: false,
|
||||
transitionRatio: 0,
|
||||
wideRowRatio: 0,
|
||||
};
|
||||
}
|
||||
|
||||
let activeRows = 0;
|
||||
let transitions = 0;
|
||||
let wideRows = 0;
|
||||
let previousCoverage: number | null = null;
|
||||
for (let y = bbox.top; y < bbox.top + bbox.height; y += 1) {
|
||||
let rowCount = 0;
|
||||
for (let x = bbox.left; x < bbox.left + bbox.width; x += 1) {
|
||||
if (mask[y * width + x] !== 0) rowCount += 1;
|
||||
}
|
||||
const coverage = rowCount / Math.max(1, bbox.width);
|
||||
if (coverage >= 0.08) activeRows += 1;
|
||||
if (coverage >= 0.45) wideRows += 1;
|
||||
if (
|
||||
previousCoverage !== null &&
|
||||
Math.abs(coverage - previousCoverage) >= 0.28
|
||||
) {
|
||||
transitions += 1;
|
||||
}
|
||||
previousCoverage = coverage;
|
||||
}
|
||||
|
||||
const bboxHeightRatio = bbox.height / Math.max(1, height);
|
||||
const bboxWidthRatio = bbox.width / Math.max(1, width);
|
||||
const activeRowRatio = activeRows / Math.max(1, bbox.height);
|
||||
const transitionRatio = transitions / Math.max(1, bbox.height - 1);
|
||||
const wideRowRatio = wideRows / Math.max(1, bbox.height);
|
||||
const detected =
|
||||
(bboxWidthRatio >= 0.38 &&
|
||||
bboxHeightRatio >= 0.22 &&
|
||||
wideRowRatio >= 0.18 &&
|
||||
transitionRatio >= 0.12) ||
|
||||
(bboxWidthRatio >= 0.55 &&
|
||||
activeRowRatio >= 0.45 &&
|
||||
transitionRatio >= 0.09);
|
||||
|
||||
return {
|
||||
activeRowRatio: Number(activeRowRatio.toFixed(3)),
|
||||
bboxHeightRatio: Number(bboxHeightRatio.toFixed(3)),
|
||||
bboxWidthRatio: Number(bboxWidthRatio.toFixed(3)),
|
||||
detected,
|
||||
transitionRatio: Number(transitionRatio.toFixed(3)),
|
||||
wideRowRatio: Number(wideRowRatio.toFixed(3)),
|
||||
};
|
||||
}
|
||||
|
||||
async function cleanScaleAdjustAlphaChannel(params: {
|
||||
height: number;
|
||||
referenceRawRgb?: Buffer | null;
|
||||
@ -1883,14 +1960,45 @@ async function buildScaleAdjustRmbgStructureLockedComposite(params: {
|
||||
targetWidth: placement.sourceBox.width,
|
||||
width: cutoutWidth,
|
||||
});
|
||||
const alphaBandingStats = getScaleAdjustAlphaBandingStats({
|
||||
height: placement.sourceBox.height,
|
||||
maskBuffer: sourceMaskBuffer,
|
||||
width: placement.sourceBox.width,
|
||||
});
|
||||
if (alphaBandingStats.detected) {
|
||||
console.warn(
|
||||
"[Canvas Local Edit] Scale adjust RMBG alpha banding detected; fallback to pixel mask:",
|
||||
alphaBandingStats
|
||||
);
|
||||
return null;
|
||||
}
|
||||
const background = estimateScaleAdjustBoxBackground({
|
||||
box: placement.sourceBox,
|
||||
raw,
|
||||
width: sourceWidth,
|
||||
});
|
||||
const highConfidenceSourceMask = thresholdScaleAdjustAlphaMask({
|
||||
maskBuffer: sourceMaskBuffer,
|
||||
threshold: 96,
|
||||
});
|
||||
const filteredSourceMask = filterScaleAdjustStructureComponents({
|
||||
box: placement.sourceBox,
|
||||
mask: highConfidenceSourceMask,
|
||||
});
|
||||
const filteredSourceBbox = getScaleAdjustMaskBoundingBox({
|
||||
height: placement.sourceBox.height,
|
||||
mask: filteredSourceMask,
|
||||
width: placement.sourceBox.width,
|
||||
});
|
||||
const sourceWashBaseMask = filteredSourceBbox
|
||||
? solidifyScaleAdjustStructureMask({
|
||||
box: placement.sourceBox,
|
||||
mask: filteredSourceMask,
|
||||
})
|
||||
: highConfidenceSourceMask;
|
||||
const sourceWashMask = dilateScaleAdjustStructureMask({
|
||||
height: placement.sourceBox.height,
|
||||
mask: new Uint8Array(sourceMaskBuffer),
|
||||
mask: sourceWashBaseMask,
|
||||
radius: Math.max(
|
||||
2,
|
||||
Math.round(
|
||||
@ -1977,6 +2085,7 @@ async function buildScaleAdjustRmbgStructureLockedComposite(params: {
|
||||
placedHeight,
|
||||
placedWidth,
|
||||
sameSizeCutout,
|
||||
alphaBandingStats,
|
||||
sourceHeight: placement.sourceBox.height,
|
||||
sourceWidth: placement.sourceBox.width,
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user