rn-remove-image-bg 0.0.31 → 0.0.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/cache.js ADDED
@@ -0,0 +1,228 @@
1
+ import * as FileSystem from 'expo-file-system/legacy';
2
+ const MANIFEST_FILENAME = 'cache-manifest.json';
3
+ const CACHE_VERSION = 1;
4
+ /**
5
+ * LRU cache for background removal results with optional disk persistence
6
+ */
7
+ class BackgroundRemovalCache {
8
+ cache = new Map();
9
+ _maxEntries;
10
+ _maxAgeMs;
11
+ persistToDisk;
12
+ cacheDirectory;
13
+ initialized = false;
14
+ constructor(config = {}) {
15
+ this._maxEntries = config.maxEntries ?? 50;
16
+ this._maxAgeMs = (config.maxAgeMinutes ?? 30) * 60 * 1000;
17
+ this.persistToDisk = config.persistToDisk ?? false;
18
+ this.cacheDirectory =
19
+ config.cacheDirectory ?? `${FileSystem.cacheDirectory}bg-removal/`;
20
+ }
21
+ /**
22
+ * Configure cache settings
23
+ */
24
+ configure(config) {
25
+ if (config.maxEntries !== undefined) {
26
+ this._maxEntries = config.maxEntries;
27
+ }
28
+ if (config.maxAgeMinutes !== undefined) {
29
+ this._maxAgeMs = config.maxAgeMinutes * 60 * 1000;
30
+ }
31
+ if (config.persistToDisk !== undefined) {
32
+ this.persistToDisk = config.persistToDisk;
33
+ }
34
+ if (config.cacheDirectory !== undefined) {
35
+ this.cacheDirectory = config.cacheDirectory;
36
+ }
37
+ }
38
+ /**
39
+ * Initialize disk cache (load manifest if exists)
40
+ */
41
+ async initialize() {
42
+ if (this.initialized || !this.persistToDisk)
43
+ return;
44
+ try {
45
+ // Ensure cache directory exists
46
+ const dirInfo = await FileSystem.getInfoAsync(this.cacheDirectory);
47
+ if (!dirInfo.exists) {
48
+ await FileSystem.makeDirectoryAsync(this.cacheDirectory, {
49
+ intermediates: true,
50
+ });
51
+ }
52
+ // Load manifest if exists
53
+ const manifestPath = `${this.cacheDirectory}${MANIFEST_FILENAME}`;
54
+ const manifestInfo = await FileSystem.getInfoAsync(manifestPath);
55
+ if (manifestInfo.exists) {
56
+ const manifestJson = await FileSystem.readAsStringAsync(manifestPath);
57
+ const manifest = JSON.parse(manifestJson);
58
+ if (manifest.version === CACHE_VERSION) {
59
+ // Validate and load entries
60
+ for (const [key, entry] of Object.entries(manifest.entries)) {
61
+ const fileInfo = await FileSystem.getInfoAsync(entry.resultPath);
62
+ if (fileInfo.exists) {
63
+ this.cache.set(key, entry);
64
+ }
65
+ }
66
+ }
67
+ }
68
+ }
69
+ catch (error) {
70
+ console.warn('[rn-remove-image-bg] Failed to load cache manifest:', error);
71
+ }
72
+ this.initialized = true;
73
+ }
74
+ /**
75
+ * Save cache manifest to disk
76
+ */
77
+ async saveManifest() {
78
+ if (!this.persistToDisk)
79
+ return;
80
+ try {
81
+ const manifest = {
82
+ version: CACHE_VERSION,
83
+ entries: Object.fromEntries(this.cache.entries()),
84
+ };
85
+ const manifestPath = `${this.cacheDirectory}${MANIFEST_FILENAME}`;
86
+ await FileSystem.writeAsStringAsync(manifestPath, JSON.stringify(manifest, null, 2));
87
+ }
88
+ catch (error) {
89
+ console.warn('[rn-remove-image-bg] Failed to save cache manifest:', error);
90
+ }
91
+ }
92
+ /**
93
+ * Generate a cache key from path and options
94
+ */
95
+ generateKey(path, optionsHash) {
96
+ return `${path}::${optionsHash}`;
97
+ }
98
+ /**
99
+ * Hash options object to string for cache key
100
+ */
101
+ hashOptions(options) {
102
+ const sorted = Object.keys(options)
103
+ .sort()
104
+ .reduce((acc, key) => {
105
+ const value = options[key];
106
+ // Exclude functions from hash
107
+ if (typeof value !== 'function') {
108
+ acc[key] = value;
109
+ }
110
+ return acc;
111
+ }, {});
112
+ return JSON.stringify(sorted);
113
+ }
114
+ /**
115
+ * Get cached result if valid
116
+ */
117
+ async get(path, optionsHash) {
118
+ await this.initialize();
119
+ const key = this.generateKey(path, optionsHash);
120
+ const entry = this.cache.get(key);
121
+ if (!entry) {
122
+ return null;
123
+ }
124
+ // Check if expired
125
+ if (Date.now() - entry.timestamp > this._maxAgeMs) {
126
+ this.cache.delete(key);
127
+ this.saveManifest();
128
+ return null;
129
+ }
130
+ // Verify result file still exists
131
+ try {
132
+ const info = await FileSystem.getInfoAsync(entry.resultPath);
133
+ if (!info.exists) {
134
+ this.cache.delete(key);
135
+ this.saveManifest();
136
+ return null;
137
+ }
138
+ }
139
+ catch {
140
+ this.cache.delete(key);
141
+ this.saveManifest();
142
+ return null;
143
+ }
144
+ // Move to end (most recently used)
145
+ this.cache.delete(key);
146
+ this.cache.set(key, entry);
147
+ return entry.resultPath;
148
+ }
149
+ /**
150
+ * Store result in cache
151
+ */
152
+ set(path, optionsHash, resultPath) {
153
+ const key = this.generateKey(path, optionsHash);
154
+ // Evict oldest entries if at capacity
155
+ while (this.cache.size >= this._maxEntries) {
156
+ const oldestKey = this.cache.keys().next().value;
157
+ if (oldestKey) {
158
+ this.cache.delete(oldestKey);
159
+ }
160
+ }
161
+ this.cache.set(key, {
162
+ originalPath: path,
163
+ resultPath,
164
+ timestamp: Date.now(),
165
+ optionsHash,
166
+ });
167
+ this.saveManifest();
168
+ }
169
+ /**
170
+ * Clear all cached entries
171
+ * @param deleteFiles - Also delete cached files from disk (default: false)
172
+ */
173
+ async clear(deleteFiles = false) {
174
+ if (deleteFiles && this.persistToDisk) {
175
+ try {
176
+ // Delete all cached result files
177
+ for (const entry of this.cache.values()) {
178
+ try {
179
+ await FileSystem.deleteAsync(entry.resultPath, {
180
+ idempotent: true,
181
+ });
182
+ }
183
+ catch {
184
+ // Ignore individual file deletion errors
185
+ }
186
+ }
187
+ // Delete manifest
188
+ const manifestPath = `${this.cacheDirectory}${MANIFEST_FILENAME}`;
189
+ await FileSystem.deleteAsync(manifestPath, { idempotent: true });
190
+ }
191
+ catch (error) {
192
+ console.warn('[rn-remove-image-bg] Error clearing cache files:', error);
193
+ }
194
+ }
195
+ this.cache.clear();
196
+ }
197
+ /**
198
+ * Get current cache size
199
+ */
200
+ get size() {
201
+ return this.cache.size;
202
+ }
203
+ /**
204
+ * Remove expired entries
205
+ */
206
+ prune() {
207
+ const now = Date.now();
208
+ let removed = 0;
209
+ for (const [key, entry] of this.cache.entries()) {
210
+ if (now - entry.timestamp > this._maxAgeMs) {
211
+ this.cache.delete(key);
212
+ removed++;
213
+ }
214
+ }
215
+ if (removed > 0) {
216
+ this.saveManifest();
217
+ }
218
+ return removed;
219
+ }
220
+ /**
221
+ * Get cache directory path
222
+ */
223
+ getCacheDirectory() {
224
+ return this.cacheDirectory;
225
+ }
226
+ }
227
+ // Export singleton instance
228
+ export const bgRemovalCache = new BackgroundRemovalCache();
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Error codes for background removal operations
3
+ */
4
+ export type BackgroundRemovalErrorCode = 'INVALID_PATH' | 'FILE_NOT_FOUND' | 'DECODE_FAILED' | 'ML_PROCESSING_FAILED' | 'SAVE_FAILED' | 'INVALID_OPTIONS' | 'UNKNOWN';
5
+ /**
6
+ * Custom error class for background removal operations
7
+ */
8
+ export declare class BackgroundRemovalError extends Error {
9
+ readonly code: BackgroundRemovalErrorCode;
10
+ readonly originalError?: Error;
11
+ constructor(message: string, code: BackgroundRemovalErrorCode, originalError?: Error);
12
+ /**
13
+ * Create a user-friendly error message
14
+ */
15
+ toUserMessage(): string;
16
+ }
17
+ /**
18
+ * Helper to wrap native errors with proper typing
19
+ */
20
+ export declare function wrapNativeError(error: unknown): BackgroundRemovalError;
package/lib/errors.js ADDED
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Custom error class for background removal operations
3
+ */
4
+ export class BackgroundRemovalError extends Error {
5
+ code;
6
+ originalError;
7
+ constructor(message, code, originalError) {
8
+ super(message);
9
+ this.name = 'BackgroundRemovalError';
10
+ this.code = code;
11
+ this.originalError = originalError;
12
+ // Maintain proper stack trace in V8 environments
13
+ if ('captureStackTrace' in Error) {
14
+ Error.captureStackTrace(this, BackgroundRemovalError);
15
+ }
16
+ }
17
+ /**
18
+ * Create a user-friendly error message
19
+ */
20
+ toUserMessage() {
21
+ switch (this.code) {
22
+ case 'INVALID_PATH':
23
+ return 'The image path provided is invalid.';
24
+ case 'FILE_NOT_FOUND':
25
+ return 'The image file could not be found.';
26
+ case 'DECODE_FAILED':
27
+ return 'The image could not be read. Please ensure it is a valid image file.';
28
+ case 'ML_PROCESSING_FAILED':
29
+ return 'Background removal failed. Please try with a different image.';
30
+ case 'SAVE_FAILED':
31
+ return 'Could not save the processed image.';
32
+ case 'INVALID_OPTIONS':
33
+ return 'Invalid options provided for background removal.';
34
+ default:
35
+ return 'An unexpected error occurred during background removal.';
36
+ }
37
+ }
38
+ }
39
+ /**
40
+ * Helper to wrap native errors with proper typing
41
+ */
42
+ export function wrapNativeError(error) {
43
+ if (error instanceof BackgroundRemovalError) {
44
+ return error;
45
+ }
46
+ const message = error instanceof Error ? error.message : String(error);
47
+ const originalError = error instanceof Error ? error : undefined;
48
+ // Try to determine error code from message
49
+ if (message.includes('does not exist') || message.includes('not found')) {
50
+ return new BackgroundRemovalError(message, 'FILE_NOT_FOUND', originalError);
51
+ }
52
+ if (message.includes('decode') || message.includes('load image')) {
53
+ return new BackgroundRemovalError(message, 'DECODE_FAILED', originalError);
54
+ }
55
+ if (message.includes('mask') ||
56
+ message.includes('segment') ||
57
+ message.includes('ML')) {
58
+ return new BackgroundRemovalError(message, 'ML_PROCESSING_FAILED', originalError);
59
+ }
60
+ if (message.includes('save') || message.includes('write')) {
61
+ return new BackgroundRemovalError(message, 'SAVE_FAILED', originalError);
62
+ }
63
+ return new BackgroundRemovalError(message, 'UNKNOWN', originalError);
64
+ }
package/lib/index.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ import { compressImage, generateThumbhash, removeBgImage, removeBackground, clearCache, getCacheSize, onLowMemory, configureCache, getCacheDirectory } from './ImageProcessing';
2
+ import type { CompressImageOptions, GenerateThumbhashOptions, RemoveBgImageOptions, OutputFormat } from './ImageProcessing';
3
+ import { BackgroundRemovalError, type BackgroundRemovalErrorCode } from './errors';
4
+ import type { CacheConfig } from './cache';
5
+ export { compressImage, generateThumbhash, removeBgImage, removeBackground, clearCache, getCacheSize, onLowMemory, configureCache, getCacheDirectory, BackgroundRemovalError, };
6
+ export type { CompressImageOptions, GenerateThumbhashOptions, RemoveBgImageOptions, OutputFormat, BackgroundRemovalErrorCode, CacheConfig, };
package/lib/index.js ADDED
@@ -0,0 +1,9 @@
1
+ import { compressImage, generateThumbhash, removeBgImage, removeBackground, clearCache, getCacheSize, onLowMemory, configureCache, getCacheDirectory, } from './ImageProcessing';
2
+ import { BackgroundRemovalError, } from './errors';
3
+ export {
4
+ // Functions
5
+ compressImage, generateThumbhash, removeBgImage, removeBackground, clearCache, getCacheSize,
6
+ // Memory management
7
+ onLowMemory, configureCache, getCacheDirectory,
8
+ // Errors
9
+ BackgroundRemovalError, };
File without changes
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ // TODO: Export specs that extend HybridObject<...> here
@@ -0,0 +1,41 @@
1
+ import type { HybridObject } from 'react-native-nitro-modules';
2
+ /**
3
+ * Output format for processed images
4
+ */
5
+ export type OutputFormat = 'PNG' | 'WEBP';
6
+ /**
7
+ * Native options for background removal
8
+ */
9
+ export interface NativeRemoveBackgroundOptions {
10
+ /**
11
+ * Maximum dimension (width or height) for processing
12
+ * Larger images will be downsampled for better performance
13
+ * Default: 2048
14
+ */
15
+ maxDimension: number;
16
+ /**
17
+ * Output image format
18
+ * PNG: Lossless, larger file size
19
+ * WEBP: Smaller file size, good quality
20
+ * Default: PNG
21
+ */
22
+ format: OutputFormat;
23
+ /**
24
+ * Quality for WEBP format (0-100)
25
+ * Ignored for PNG format
26
+ * Default: 100
27
+ */
28
+ quality: number;
29
+ }
30
+ export interface ImageBackgroundRemover extends HybridObject<{
31
+ ios: 'swift';
32
+ android: 'kotlin';
33
+ }> {
34
+ /**
35
+ * Remove background from an image
36
+ * @param imagePath - File path or file:// URI to the source image
37
+ * @param options - Processing options
38
+ * @returns Promise resolving to the output file path
39
+ */
40
+ removeBackground(imagePath: string, options: NativeRemoveBackgroundOptions): Promise<string>;
41
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,31 @@
1
+ import type { RemoveBgImageOptions } from './types';
2
+ type ImglyConfig = {
3
+ publicPath?: string;
4
+ progress?: (key: string, current: number, total: number) => void;
5
+ debug?: boolean;
6
+ output?: {
7
+ format?: 'image/png' | 'image/jpeg' | 'image/webp';
8
+ quality?: number;
9
+ type?: 'foreground' | 'background' | 'mask';
10
+ };
11
+ };
12
+ type ImglyRemoveBackground = (image: string | Blob | ArrayBuffer, config?: ImglyConfig) => Promise<Blob>;
13
+ declare global {
14
+ interface Window {
15
+ imglyRemoveBackground?: ImglyRemoveBackground;
16
+ }
17
+ }
18
+ export declare const BackgroundRemover: {
19
+ /**
20
+ * Checks if the background removal library is loaded.
21
+ */
22
+ isAvailable(): boolean;
23
+ /**
24
+ * Removes background from an image.
25
+ * Returns a Blob of the processed image (PNG with transparency).
26
+ *
27
+ * Requires @imgly/background-removal to be loaded via CDN script tag.
28
+ */
29
+ remove(uri: string, options: RemoveBgImageOptions): Promise<Blob>;
30
+ };
31
+ export {};
@@ -0,0 +1,64 @@
1
+ import { mapErrorToBackgroundRemovalError, BackgroundRemovalError } from '../errors/WebErrorAdapter';
2
+ import { normalizeUri } from '../utils/uriHelper';
3
+ /**
4
+ * Gets the @imgly removeBackground function from window.
5
+ * This must be loaded via CDN script tag before use.
6
+ */
7
+ function getImglyRemoveBackground() {
8
+ if (typeof window === 'undefined') {
9
+ throw new BackgroundRemovalError('Background removal is only available in browser environment.', 'ENVIRONMENT_ERROR');
10
+ }
11
+ if (!window.imglyRemoveBackground) {
12
+ throw new BackgroundRemovalError('Background removal library not loaded. Please add the following script to your HTML:\n' +
13
+ '<script type="module">\n' +
14
+ ' import { removeBackground } from "https://cdn.jsdelivr.net/npm/@imgly/background-removal@1.7.0/+esm";\n' +
15
+ ' window.imglyRemoveBackground = removeBackground;\n' +
16
+ '</script>', 'LIBRARY_NOT_LOADED');
17
+ }
18
+ return window.imglyRemoveBackground;
19
+ }
20
+ export const BackgroundRemover = {
21
+ /**
22
+ * Checks if the background removal library is loaded.
23
+ */
24
+ isAvailable() {
25
+ return typeof window !== 'undefined' && typeof window.imglyRemoveBackground === 'function';
26
+ },
27
+ /**
28
+ * Removes background from an image.
29
+ * Returns a Blob of the processed image (PNG with transparency).
30
+ *
31
+ * Requires @imgly/background-removal to be loaded via CDN script tag.
32
+ */
33
+ async remove(uri, options) {
34
+ try {
35
+ const imglyRemove = getImglyRemoveBackground();
36
+ const normalizedUri = await normalizeUri(uri);
37
+ const config = {
38
+ // Pass publicPath if provided (for self-hosted assets)
39
+ publicPath: options.publicPath,
40
+ // Map progress callback
41
+ progress: (_key, current, total) => {
42
+ if (options.onProgress && total > 0) {
43
+ const p = Math.min(100, Math.round((current / total) * 100));
44
+ options.onProgress(p);
45
+ }
46
+ },
47
+ // Enable debug logging if requested
48
+ debug: options.debug ?? false,
49
+ // Explicit output configuration for transparent PNG
50
+ output: {
51
+ format: 'image/png',
52
+ quality: 1.0,
53
+ type: 'foreground', // Extract foreground with transparency
54
+ },
55
+ };
56
+ // Execute removal
57
+ const blob = await imglyRemove(normalizedUri, config);
58
+ return blob;
59
+ }
60
+ catch (error) {
61
+ throw mapErrorToBackgroundRemovalError(error);
62
+ }
63
+ }
64
+ };
@@ -0,0 +1,16 @@
1
+ import type { RemoveBgImageOptions } from './types';
2
+ export declare class CacheManager {
3
+ private cache;
4
+ private readonly MAX_SIZE;
5
+ constructor();
6
+ /**
7
+ * Generates a unique cache key based on input URI and processing options
8
+ */
9
+ private generateKey;
10
+ get(uri: string, options: RemoveBgImageOptions): string | null;
11
+ set(uri: string, options: RemoveBgImageOptions, dataUrl: string): void;
12
+ clear(): void;
13
+ size(): number;
14
+ private evictOldest;
15
+ }
16
+ export declare const cacheManager: CacheManager;
@@ -0,0 +1,57 @@
1
+ export class CacheManager {
2
+ cache;
3
+ MAX_SIZE = 50; // Limit to 50 items to avoid memory leaks
4
+ constructor() {
5
+ this.cache = new Map();
6
+ }
7
+ /**
8
+ * Generates a unique cache key based on input URI and processing options
9
+ */
10
+ generateKey(uri, options) {
11
+ // We include relevant options that affect output
12
+ const { format = 'PNG', quality = 100, maxDimension = 0 } = options;
13
+ return `${uri}|${format}|${quality}|${maxDimension}`;
14
+ }
15
+ get(uri, options) {
16
+ const key = this.generateKey(uri, options);
17
+ const entry = this.cache.get(key);
18
+ if (entry) {
19
+ entry.timestamp = Date.now(); // Update usage timestamp (simple LRU)
20
+ return entry.dataUrl;
21
+ }
22
+ return null;
23
+ }
24
+ set(uri, options, dataUrl) {
25
+ const key = this.generateKey(uri, options);
26
+ // Evict if full
27
+ if (this.cache.size >= this.MAX_SIZE) {
28
+ this.evictOldest();
29
+ }
30
+ this.cache.set(key, {
31
+ dataUrl,
32
+ timestamp: Date.now()
33
+ });
34
+ }
35
+ clear() {
36
+ this.cache.clear();
37
+ }
38
+ size() {
39
+ return this.cache.size;
40
+ }
41
+ evictOldest() {
42
+ // Find oldest entry
43
+ let oldestKey = null;
44
+ let oldestTime = Infinity;
45
+ for (const [key, entry] of this.cache.entries()) {
46
+ if (entry.timestamp < oldestTime) {
47
+ oldestTime = entry.timestamp;
48
+ oldestKey = key;
49
+ }
50
+ }
51
+ if (oldestKey) {
52
+ this.cache.delete(oldestKey);
53
+ }
54
+ }
55
+ }
56
+ // Singleton instance
57
+ export const cacheManager = new CacheManager();
@@ -0,0 +1,47 @@
1
+ export type OutputFormat = 'PNG' | 'WEBP';
2
+ export interface RemoveBgImageOptions {
3
+ /**
4
+ * Output format of the processed image.
5
+ * Default: 'PNG'
6
+ */
7
+ format?: OutputFormat;
8
+ /**
9
+ * Quality of the output image (0-100). Only applies to WEBP/JPEG.
10
+ * Default: 100
11
+ */
12
+ quality?: number;
13
+ /**
14
+ * Callback to track download and processing progress (0-100).
15
+ */
16
+ onProgress?: (progress: number) => void;
17
+ /**
18
+ * Enable debug logging.
19
+ * Default: false
20
+ */
21
+ debug?: boolean;
22
+ /**
23
+ * Maximum dimension for the output image. Use this to resize large images before processing.
24
+ */
25
+ maxDimension?: number;
26
+ /**
27
+ * Public path to serve the model assets from.
28
+ * If not provided, it will attempt to fetch from @imgly CDN.
29
+ * Important for Metro bundler compatibility if not using CDN.
30
+ */
31
+ publicPath?: string;
32
+ /**
33
+ * Whether to use the cache for this request.
34
+ * Default: true
35
+ */
36
+ useCache?: boolean;
37
+ }
38
+ export interface CompressImageOptions {
39
+ maxSizeKB?: number;
40
+ width?: number;
41
+ height?: number;
42
+ quality?: number;
43
+ format?: 'webp' | 'png' | 'jpeg';
44
+ }
45
+ export interface GenerateThumbhashOptions {
46
+ size?: number;
47
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ export declare class BackgroundRemovalError extends Error {
2
+ code: string;
3
+ constructor(message: string, code?: string);
4
+ }
5
+ /**
6
+ * Maps library errors to standardized BackgroundRemovalError
7
+ */
8
+ export declare function mapErrorToBackgroundRemovalError(error: unknown): BackgroundRemovalError;
@@ -0,0 +1,29 @@
1
+ export class BackgroundRemovalError extends Error {
2
+ code;
3
+ constructor(message, code = 'UNKNOWN_ERROR') {
4
+ super(message);
5
+ this.name = 'BackgroundRemovalError';
6
+ this.code = code;
7
+ }
8
+ }
9
+ /**
10
+ * Maps library errors to standardized BackgroundRemovalError
11
+ */
12
+ export function mapErrorToBackgroundRemovalError(error) {
13
+ if (error instanceof BackgroundRemovalError)
14
+ return error;
15
+ const message = error instanceof Error ? error.message : String(error);
16
+ // Model loading errors
17
+ if (message.includes('fetch') || message.includes('network') || message.includes('Failed to load resource')) {
18
+ return new BackgroundRemovalError(`Failed to download AI model. Please check your internet connection. (Details: ${message})`, 'MODEL_DOWNLOAD_ERROR');
19
+ }
20
+ // WASM errors
21
+ if (message.includes('wasm') || message.includes('WebAssembly')) {
22
+ return new BackgroundRemovalError(`WebAssembly failed to initialize. Your browser might not support it. (Details: ${message})`, 'WASM_INIT_ERROR');
23
+ }
24
+ // Processing errors
25
+ if (message.includes('memory') || message.includes('allocation')) {
26
+ return new BackgroundRemovalError('Out of memory. Try using a smaller maxDimension or closing other tabs.', 'MEMORY_ERROR');
27
+ }
28
+ return new BackgroundRemovalError(message);
29
+ }
@@ -0,0 +1,2 @@
1
+ import type { CompressImageOptions } from '../core/types';
2
+ export declare function compressImage(uri: string, options: CompressImageOptions): Promise<string>;