|
|
|
|
|
|
|
|
|
|
|
import { removeBackground as removeBackgroundLib } from '@imgly/background-removal'; |
|
|
|
|
|
interface BackgroundRemovalConfig { |
|
model?: 'small' | 'medium' | 'large'; |
|
output?: { |
|
format?: string; |
|
quality?: number; |
|
}; |
|
debug?: boolean; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
export async function removeBackgroundAI(imageUrl: string): Promise<string> { |
|
try { |
|
|
|
const response = await fetch(imageUrl); |
|
if (!response.ok) { |
|
throw new Error(`Failed to fetch image: ${response.statusText}`); |
|
} |
|
const imageBlob = await response.blob(); |
|
|
|
|
|
const resultBlob = await removeBackgroundLib(imageBlob); |
|
|
|
|
|
return new Promise((resolve, reject) => { |
|
const reader = new FileReader(); |
|
reader.onload = () => resolve(reader.result as string); |
|
reader.onerror = () => reject(new Error('Failed to convert result to data URL')); |
|
reader.readAsDataURL(resultBlob); |
|
}); |
|
|
|
} catch (error) { |
|
console.error('AI background removal failed:', error); |
|
throw new Error(`Background removal failed: ${error instanceof Error ? error.message : 'Unknown error'}`); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
export async function removeWhiteBackgroundSimple(imageUrl: string): Promise<string> { |
|
return new Promise((resolve, reject) => { |
|
const img = new Image(); |
|
img.crossOrigin = 'anonymous'; |
|
|
|
img.onload = () => { |
|
const canvas = document.createElement('canvas'); |
|
const ctx = canvas.getContext('2d'); |
|
|
|
if (!ctx) { |
|
reject(new Error('Failed to get canvas context')); |
|
return; |
|
} |
|
|
|
canvas.width = img.width; |
|
canvas.height = img.height; |
|
ctx.drawImage(img, 0, 0); |
|
|
|
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); |
|
const data = imageData.data; |
|
|
|
|
|
const whiteThreshold = 240; |
|
for (let i = 0; i < data.length; i += 4) { |
|
const r = data[i]; |
|
const g = data[i + 1]; |
|
const b = data[i + 2]; |
|
|
|
|
|
if (r > whiteThreshold && g > whiteThreshold && b > whiteThreshold) { |
|
data[i + 3] = 0; |
|
} |
|
} |
|
|
|
ctx.putImageData(imageData, 0, 0); |
|
resolve(canvas.toDataURL('image/png')); |
|
}; |
|
|
|
img.onerror = () => { |
|
reject(new Error('Failed to load image')); |
|
}; |
|
|
|
img.src = imageUrl; |
|
}); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
export async function removeBackground(imageUrl: string): Promise<string> { |
|
try { |
|
|
|
return await removeBackgroundAI(imageUrl); |
|
} catch (aiError) { |
|
console.warn('AI background removal failed, falling back to simple method:', aiError); |
|
|
|
try { |
|
|
|
return await removeWhiteBackgroundSimple(imageUrl); |
|
} catch (fallbackError) { |
|
console.error('All background removal methods failed:', fallbackError); |
|
throw new Error('Background removal failed with all methods'); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
export async function isAIBackgroundRemovalAvailable(): Promise<boolean> { |
|
return true; |
|
} |
|
|
|
|
|
|
|
|
|
export async function removeBackgroundBatch( |
|
imageUrls: string[], |
|
onProgress?: (completed: number, total: number, currentImage: string) => void |
|
): Promise<{ url: string; result?: string; error?: string }[]> { |
|
const results: { url: string; result?: string; error?: string }[] = []; |
|
|
|
for (let i = 0; i < imageUrls.length; i++) { |
|
const imageUrl = imageUrls[i]; |
|
|
|
try { |
|
const result = await removeBackground(imageUrl); |
|
results.push({ url: imageUrl, result }); |
|
} catch (error) { |
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error'; |
|
results.push({ url: imageUrl, error: errorMessage }); |
|
} |
|
|
|
if (onProgress) { |
|
onProgress(i + 1, imageUrls.length, imageUrl); |
|
} |
|
} |
|
|
|
return results; |
|
} |