Handle edge cases with image outline (semi-transparency, tiny pieces and errors)
This commit is contained in:
parent
5e69ffcef8
commit
bfc9c4fba3
@ -189,41 +189,64 @@ export async function createThumbnail(image, type, size = 300, quality = 0.5) {
|
|||||||
* @returns {Outline}
|
* @returns {Outline}
|
||||||
*/
|
*/
|
||||||
export function getImageOutline(image, maxPoints = 100) {
|
export function getImageOutline(image, maxPoints = 100) {
|
||||||
let baseOutline = imageOutline(image);
|
// Basic rect outline for fail conditions
|
||||||
|
const defaultOutline = {
|
||||||
|
type: "rect",
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: image.width,
|
||||||
|
height: image.height,
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
let outlinePoints = imageOutline(image, {
|
||||||
|
opacityThreshold: 1, // Allow everything except full transparency
|
||||||
|
});
|
||||||
|
|
||||||
if (baseOutline) {
|
if (outlinePoints) {
|
||||||
if (baseOutline.length > maxPoints) {
|
if (outlinePoints.length > maxPoints) {
|
||||||
baseOutline = Vector2.resample(baseOutline, maxPoints);
|
outlinePoints = Vector2.resample(outlinePoints, maxPoints);
|
||||||
}
|
}
|
||||||
const bounds = Vector2.getBoundingBox(baseOutline);
|
const bounds = Vector2.getBoundingBox(outlinePoints);
|
||||||
if (Vector2.rectangular(baseOutline)) {
|
|
||||||
return {
|
// Reject outline if it's area is less than 5% of the image
|
||||||
type: "rect",
|
const imageArea = image.width * image.height;
|
||||||
x: Math.round(bounds.min.x),
|
const area = bounds.width * bounds.height;
|
||||||
y: Math.round(bounds.min.y),
|
if (area < imageArea * 0.05) {
|
||||||
width: Math.round(bounds.width),
|
return defaultOutline;
|
||||||
height: Math.round(bounds.height),
|
}
|
||||||
};
|
|
||||||
} else if (
|
// Detect if the outline is a rectangle or circle
|
||||||
Vector2.circular(
|
if (Vector2.rectangular(outlinePoints)) {
|
||||||
baseOutline,
|
return {
|
||||||
Math.max(bounds.width / 10, bounds.height / 10)
|
type: "rect",
|
||||||
)
|
x: Math.round(bounds.min.x),
|
||||||
) {
|
y: Math.round(bounds.min.y),
|
||||||
return {
|
width: Math.round(bounds.width),
|
||||||
type: "circle",
|
height: Math.round(bounds.height),
|
||||||
x: Math.round(bounds.center.x),
|
};
|
||||||
y: Math.round(bounds.center.y),
|
} else if (
|
||||||
radius: Math.round(Math.min(bounds.width, bounds.height) / 2),
|
Vector2.circular(
|
||||||
};
|
outlinePoints,
|
||||||
|
Math.max(bounds.width / 10, bounds.height / 10)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
type: "circle",
|
||||||
|
x: Math.round(bounds.center.x),
|
||||||
|
y: Math.round(bounds.center.y),
|
||||||
|
radius: Math.round(Math.min(bounds.width, bounds.height) / 2),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// Flatten and round outline to save on storage size
|
||||||
|
const points = outlinePoints
|
||||||
|
.map(({ x, y }) => [Math.round(x), Math.round(y)])
|
||||||
|
.flat();
|
||||||
|
return { type: "path", points };
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Flatten and round outline to save on storage size
|
return defaultOutline;
|
||||||
const points = baseOutline
|
|
||||||
.map(({ x, y }) => [Math.round(x), Math.round(y)])
|
|
||||||
.flat();
|
|
||||||
return { type: "path", points };
|
|
||||||
}
|
}
|
||||||
} else {
|
} catch {
|
||||||
return { type: "rect", x: 0, y: 0, width: 1, height: 1 };
|
return defaultOutline;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user