feat(image-uploader): improve background removal handling and streamline image data processing

Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
This commit is contained in:
Balázs Szücs 2025-12-10 11:17:45 +01:00
parent 7c6bcdfe7a
commit a6fd3f0939
3 changed files with 20 additions and 29 deletions

View File

@ -12,7 +12,6 @@ interface ImageUploaderProps {
hint?: string;
allowBackgroundRemoval?: boolean;
onProcessedImageData?: (dataUrl: string | null) => void;
currentImageData?: string;
}
export const ImageUploader: React.FC<ImageUploaderProps> = ({
@ -22,8 +21,7 @@ export const ImageUploader: React.FC<ImageUploaderProps> = ({
placeholder,
hint,
allowBackgroundRemoval = false,
onProcessedImageData,
currentImageData
onProcessedImageData
}) => {
const { t } = useTranslation();
const [removeBackground, setRemoveBackground] = useState(false);
@ -31,7 +29,7 @@ export const ImageUploader: React.FC<ImageUploaderProps> = ({
const [originalImageData, setOriginalImageData] = useState<string | null>(null);
const [isProcessing, setIsProcessing] = useState(false);
const processImage = async (imageSource: File | string, shouldRemoveBackground: boolean) => {
const processImage = async (imageSource: File | string, shouldRemoveBackground: boolean): Promise<void> => {
if (shouldRemoveBackground && allowBackgroundRemoval) {
setIsProcessing(true);
try {
@ -40,7 +38,6 @@ export const ImageUploader: React.FC<ImageUploaderProps> = ({
tolerance: 15
});
onProcessedImageData?.(transparentImageDataUrl);
return transparentImageDataUrl;
} catch (error) {
console.error('Error removing background:', error);
onProcessedImageData?.(null);
@ -48,12 +45,18 @@ export const ImageUploader: React.FC<ImageUploaderProps> = ({
setIsProcessing(false);
}
} else {
if (originalImageData) {
onProcessedImageData?.(originalImageData);
// When background removal is disabled, return the original image data
if (typeof imageSource === 'string') {
onProcessedImageData?.(imageSource);
} else {
// Convert File to data URL if needed
const reader = new FileReader();
reader.onload = (e) => {
onProcessedImageData?.(e.target?.result as string);
};
reader.readAsDataURL(imageSource);
}
setIsProcessing(false);
}
return null;
};
const handleImageChange = async (file: File | null) => {
@ -90,11 +93,10 @@ export const ImageUploader: React.FC<ImageUploaderProps> = ({
};
const handleBackgroundRemovalChange = async (checked: boolean) => {
if (isProcessing) return; // Prevent race conditions
setRemoveBackground(checked);
if (originalImageData) {
await processImage(originalImageData, checked);
} else if (currentFile) {
await processImage(currentFile, checked);
}
};

View File

@ -461,24 +461,13 @@ const SignSettings = ({
const handleImageChange = async (file: File | null) => {
if (file && !disabled) {
try {
const result = await new Promise<string>((resolve, reject) => {
const reader = new FileReader();
reader.onload = (e) => {
if (e.target?.result) {
resolve(e.target.result as string);
} else {
reject(new Error('Failed to read file'));
}
};
reader.onerror = () => reject(reader.error);
reader.readAsDataURL(file);
});
// Reset pause state and directly activate placement
setPlacementManuallyPaused(false);
lastAppliedPlacementKey.current = null;
setImageSignatureData(result);
// Image data will be set by onProcessedImageData callback in ImageUploader
// This avoids the race condition where both handleImageChange and onProcessedImageData
// try to set the image data, potentially with the wrong version
// Directly activate placement on image upload
if (typeof window !== 'undefined') {

View File

@ -105,10 +105,10 @@ function detectCornerColor(imageData: ImageData): { r: number; g: number; b: num
const sampleSize = 5;
const corners = [
{ x: sampleSize, y: sampleSize }, // top-left
{ x: width - sampleSize - 1, y: sampleSize }, // top-right
{ x: sampleSize, y: height - sampleSize - 1 }, // bottom-left
{ x: width - sampleSize - 1, y: height - sampleSize - 1 } // bottom-right
{ x: 0, y: 0 }, // top-left
{ x: width - sampleSize, y: 0 }, // top-right
{ x: 0, y: height - sampleSize }, // bottom-left
{ x: width - sampleSize, y: height - sampleSize } // bottom-right
];
let totalR = 0, totalG = 0, totalB = 0;