rn-remove-image-bg 0.0.31 → 0.0.32

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.
@@ -0,0 +1,167 @@
1
+ import * as ImageManipulator from 'expo-image-manipulator';
2
+ import type { OutputFormat, NativeRemoveBackgroundOptions } from './specs/ImageBackgroundRemover.nitro';
3
+ export type { OutputFormat, NativeRemoveBackgroundOptions };
4
+ export interface CompressImageOptions {
5
+ /**
6
+ * Maximum file size in KB (default: 250)
7
+ */
8
+ maxSizeKB?: number;
9
+ /**
10
+ * Initial image width (default: 1024)
11
+ */
12
+ width?: number;
13
+ /**
14
+ * Initial image height (default: 1024)
15
+ */
16
+ height?: number;
17
+ /**
18
+ * Initial compression quality (0-1, default: 0.85)
19
+ */
20
+ quality?: number;
21
+ /**
22
+ * Image format (default: WEBP)
23
+ */
24
+ format?: ImageManipulator.SaveFormat;
25
+ }
26
+ export interface GenerateThumbhashOptions {
27
+ /**
28
+ * Thumbhash size (default: 32)
29
+ */
30
+ size?: number;
31
+ }
32
+ /**
33
+ * Options for background removal
34
+ */
35
+ export interface RemoveBgImageOptions {
36
+ /**
37
+ * Maximum dimension (width or height) for processing
38
+ * Larger images will be downsampled for better performance
39
+ * @default 2048
40
+ */
41
+ maxDimension?: number;
42
+ /**
43
+ * Output image format
44
+ * - PNG: Lossless, larger file size, best for transparency
45
+ * - WEBP: Smaller file size, good quality
46
+ * @default 'PNG'
47
+ */
48
+ format?: OutputFormat;
49
+ /**
50
+ * Quality for WEBP format (0-100)
51
+ * Ignored when format is PNG
52
+ * @default 100
53
+ */
54
+ quality?: number;
55
+ /**
56
+ * Progress callback (0-100)
57
+ * Note: Progress is approximate and may not be linear
58
+ */
59
+ onProgress?: (progress: number) => void;
60
+ /**
61
+ * Use cached result if available
62
+ * @default true
63
+ */
64
+ useCache?: boolean;
65
+ /**
66
+ * Enable debug logging
67
+ * @default false
68
+ */
69
+ debug?: boolean;
70
+ }
71
+ /**
72
+ * Compress image to WebP format with configurable options
73
+ */
74
+ export declare function compressImage(uri: string, options?: CompressImageOptions): Promise<string>;
75
+ /**
76
+ * Generate thumbhash from image URI (Native/Mobile)
77
+ */
78
+ export declare function generateThumbhash(imageUri: string, options?: GenerateThumbhashOptions): Promise<string>;
79
+ /**
80
+ * Remove background from image using native ML models
81
+ *
82
+ * @param uri - File path or file:// URI to the source image
83
+ * @param options - Processing options
84
+ * @returns Promise resolving to a URI suitable for use with `<Image>` component.
85
+ * - **iOS/Android**: File path (`file:///path/to/cache/bg_removed_xxx.png`)
86
+ * - **Web**: Data URL (`data:image/png;base64,...`)
87
+ *
88
+ * @throws {BackgroundRemovalError} When image cannot be processed
89
+ *
90
+ * @example
91
+ * ```typescript
92
+ * const result = await removeBgImage('file:///path/to/photo.jpg')
93
+ * // Use directly in Image component
94
+ * <Image source={{ uri: result }} />
95
+ * ```
96
+ *
97
+ * @example
98
+ * ```typescript
99
+ * // With options
100
+ * const result = await removeBgImage('file:///path/to/photo.jpg', {
101
+ * maxDimension: 1024,
102
+ * format: 'WEBP',
103
+ * quality: 90,
104
+ * onProgress: (p) => console.log(`Progress: ${p}%`)
105
+ * })
106
+ * ```
107
+ */
108
+ export declare function removeBgImage(uri: string, options?: RemoveBgImageOptions): Promise<string>;
109
+ /**
110
+ * Backward compatibility alias for removeBgImage
111
+ * @deprecated Use removeBgImage instead
112
+ */
113
+ export declare const removeBackground: typeof removeBgImage;
114
+ /**
115
+ * Clear the background removal cache
116
+ * @param deleteFiles - Also delete cached files from disk (default: false)
117
+ */
118
+ export declare function clearCache(deleteFiles?: boolean): Promise<void>;
119
+ /**
120
+ * Get the current cache size
121
+ */
122
+ export declare function getCacheSize(): number;
123
+ /**
124
+ * Handle low memory conditions by clearing the cache
125
+ * Call this when your app receives memory warnings
126
+ *
127
+ * @param deleteFiles - Also delete cached files from disk (default: true)
128
+ * @returns Number of entries that were cleared
129
+ *
130
+ * @example
131
+ * ```typescript
132
+ * import { AppState } from 'react-native'
133
+ * import { onLowMemory } from 'rn-remove-image-bg'
134
+ *
135
+ * // In your app initialization
136
+ * AppState.addEventListener('memoryWarning', () => {
137
+ * onLowMemory()
138
+ * })
139
+ * ```
140
+ */
141
+ export declare function onLowMemory(deleteFiles?: boolean): Promise<number>;
142
+ /**
143
+ * Configure the background removal cache
144
+ * Call this early in your app lifecycle to customize cache behavior
145
+ *
146
+ * @example
147
+ * ```typescript
148
+ * import { configureCache } from 'rn-remove-image-bg'
149
+ *
150
+ * configureCache({
151
+ * maxEntries: 100,
152
+ * maxAgeMinutes: 60,
153
+ * persistToDisk: true
154
+ * })
155
+ * ```
156
+ */
157
+ export declare function configureCache(config: {
158
+ maxEntries?: number;
159
+ maxAgeMinutes?: number;
160
+ persistToDisk?: boolean;
161
+ cacheDirectory?: string;
162
+ }): void;
163
+ /**
164
+ * Get the cache directory path
165
+ * Useful for debugging or manual cache management
166
+ */
167
+ export declare function getCacheDirectory(): string;
@@ -0,0 +1,323 @@
1
+ import { Image } from 'react-native';
2
+ import * as ImageManipulator from 'expo-image-manipulator';
3
+ import * as FileSystem from 'expo-file-system/legacy';
4
+ import { Buffer } from 'buffer';
5
+ import { rgbaToThumbHash } from 'thumbhash';
6
+ import { NitroModules } from 'react-native-nitro-modules';
7
+ import { BackgroundRemovalError, wrapNativeError } from './errors';
8
+ import { bgRemovalCache } from './cache';
9
+ let nativeRemover;
10
+ function getNativeRemover() {
11
+ if (!nativeRemover) {
12
+ nativeRemover = NitroModules.createHybridObject('ImageBackgroundRemover');
13
+ }
14
+ return nativeRemover;
15
+ }
16
+ /**
17
+ * Validate image path format
18
+ */
19
+ function validateImagePath(uri) {
20
+ if (!uri || uri.trim().length === 0) {
21
+ throw new BackgroundRemovalError('Image path cannot be empty', 'INVALID_PATH');
22
+ }
23
+ // Must be a file path or file:// URI
24
+ const isValidPath = uri.startsWith('file://') ||
25
+ uri.startsWith('/') ||
26
+ uri.match(/^[a-zA-Z]:\\/);
27
+ if (!isValidPath) {
28
+ throw new BackgroundRemovalError(`Invalid file path format: ${uri}. Expected file:// URI or absolute path.`, 'INVALID_PATH');
29
+ }
30
+ }
31
+ /**
32
+ * Validate options
33
+ */
34
+ function validateOptions(options) {
35
+ if (options.maxDimension !== undefined) {
36
+ if (options.maxDimension < 100 || options.maxDimension > 8192) {
37
+ throw new BackgroundRemovalError('maxDimension must be between 100 and 8192', 'INVALID_OPTIONS');
38
+ }
39
+ }
40
+ if (options.quality !== undefined) {
41
+ if (options.quality < 0 || options.quality > 100) {
42
+ throw new BackgroundRemovalError('quality must be between 0 and 100', 'INVALID_OPTIONS');
43
+ }
44
+ }
45
+ if (options.format !== undefined &&
46
+ !['PNG', 'WEBP'].includes(options.format)) {
47
+ throw new BackgroundRemovalError('format must be either "PNG" or "WEBP"', 'INVALID_OPTIONS');
48
+ }
49
+ }
50
+ /** Default options for background removal */
51
+ const DEFAULT_OPTIONS = {
52
+ maxDimension: 2048,
53
+ format: 'PNG',
54
+ quality: 100,
55
+ useCache: true,
56
+ debug: false,
57
+ };
58
+ /**
59
+ * Compress image to WebP format with configurable options
60
+ */
61
+ export async function compressImage(uri, options = {}) {
62
+ const { maxSizeKB = 250, width = 1024, height = 1024, quality = 0.85, format = ImageManipulator.SaveFormat.WEBP, } = options;
63
+ const startTime = Date.now();
64
+ const maxSize = maxSizeKB * 1024;
65
+ // Get original file size and dimensions
66
+ const originalInfo = await FileSystem.getInfoAsync(uri);
67
+ const originalSize = 'size' in originalInfo ? originalInfo.size : 0;
68
+ const { width: originalWidth, height: originalHeight } = await new Promise((resolve, reject) => {
69
+ Image.getSize(uri, (w, h) => resolve({ width: w, height: h }), reject);
70
+ });
71
+ // Calculate target dimensions maintaining aspect ratio
72
+ // We want the image to fit WITHIN the bounding box defined by width x height
73
+ const scale = Math.min(width / originalWidth, height / originalHeight);
74
+ // If image is smaller than target box, we can keep original size (scale = 1) if we don't want to upscale.
75
+ // Generally "compress" implies making smaller or equal.
76
+ // If the image is larger, scale < 1. If smaller, scale >= 1.
77
+ // Let's cap scale at 1 to prevent upscaling unless explicitly desired (usually not for compression).
78
+ const finalScale = Math.min(scale, 1);
79
+ const resizeWidth = Math.round(originalWidth * finalScale);
80
+ const resizeHeight = Math.round(originalHeight * finalScale);
81
+ // Start with calculated dimensions and quality
82
+ let result = await ImageManipulator.manipulateAsync(uri, [{ resize: { width: resizeWidth, height: resizeHeight } }], {
83
+ compress: quality,
84
+ format,
85
+ });
86
+ let fileInfo = await FileSystem.getInfoAsync(result.uri);
87
+ // If still too large, reduce quality
88
+ if ('size' in fileInfo && fileInfo.size > maxSize) {
89
+ let currentQuality = quality * 0.9;
90
+ while (currentQuality > 0.5 &&
91
+ 'size' in fileInfo &&
92
+ fileInfo.size > maxSize) {
93
+ result = await ImageManipulator.manipulateAsync(uri, [{ resize: { width: resizeWidth, height: resizeHeight } }], {
94
+ compress: currentQuality,
95
+ format,
96
+ });
97
+ fileInfo = await FileSystem.getInfoAsync(result.uri);
98
+ if ('size' in fileInfo && fileInfo.size <= maxSize)
99
+ break;
100
+ currentQuality -= 0.05;
101
+ }
102
+ // If still too large, reduce dimensions
103
+ if ('size' in fileInfo && fileInfo.size > maxSize) {
104
+ const smallerWidth = Math.floor(resizeWidth * 0.75);
105
+ const smallerHeight = Math.floor(resizeHeight * 0.75);
106
+ result = await ImageManipulator.manipulateAsync(uri, [{ resize: { width: smallerWidth, height: smallerHeight } }], {
107
+ compress: 0.75,
108
+ format,
109
+ });
110
+ fileInfo = await FileSystem.getInfoAsync(result.uri);
111
+ // Final quality reduction if needed
112
+ if ('size' in fileInfo && fileInfo.size > maxSize) {
113
+ let finalQuality = 0.7;
114
+ while (finalQuality > 0.5 &&
115
+ 'size' in fileInfo &&
116
+ fileInfo.size > maxSize) {
117
+ result = await ImageManipulator.manipulateAsync(uri, [{ resize: { width: smallerWidth, height: smallerHeight } }], {
118
+ compress: finalQuality,
119
+ format,
120
+ });
121
+ fileInfo = await FileSystem.getInfoAsync(result.uri);
122
+ if ('size' in fileInfo && fileInfo.size <= maxSize)
123
+ break;
124
+ finalQuality -= 0.05;
125
+ }
126
+ }
127
+ }
128
+ }
129
+ const finalSize = 'size' in fileInfo ? fileInfo.size : 0;
130
+ const duration = Date.now() - startTime;
131
+ console.log(`[Native] Image Compression:`, {
132
+ originalSize: `${(originalSize / 1024).toFixed(2)} KB`,
133
+ compressedSize: `${(finalSize / 1024).toFixed(2)} KB`,
134
+ reduction: `${(((originalSize - finalSize) / originalSize) * 100).toFixed(1)}%`,
135
+ duration: `${duration}ms`,
136
+ dimensions: `${resizeWidth}x${resizeHeight}`,
137
+ });
138
+ return result.uri;
139
+ }
140
+ /**
141
+ * Generate thumbhash from image URI (Native/Mobile)
142
+ */
143
+ export async function generateThumbhash(imageUri, options = {}) {
144
+ const { size = 32 } = options;
145
+ // 1. Create tiny PNG
146
+ const tiny = await ImageManipulator.manipulateAsync(imageUri, [{ resize: { width: size, height: size } }], { format: ImageManipulator.SaveFormat.PNG });
147
+ // 2. Read as base64
148
+ const base64 = await FileSystem.readAsStringAsync(tiny.uri, {
149
+ encoding: 'base64',
150
+ });
151
+ // 3. Decode PNG and generate thumbhash
152
+ const UPNG = require('upng-js');
153
+ const buffer = Buffer.from(base64, 'base64');
154
+ const img = UPNG.decode(buffer);
155
+ const rgba = UPNG.toRGBA8(img)[0];
156
+ const hash = rgbaToThumbHash(size, size, new Uint8Array(rgba));
157
+ // 4. Convert to base64
158
+ return Buffer.from(hash).toString('base64');
159
+ }
160
+ /**
161
+ * Remove background from image using native ML models
162
+ *
163
+ * @param uri - File path or file:// URI to the source image
164
+ * @param options - Processing options
165
+ * @returns Promise resolving to a URI suitable for use with `<Image>` component.
166
+ * - **iOS/Android**: File path (`file:///path/to/cache/bg_removed_xxx.png`)
167
+ * - **Web**: Data URL (`data:image/png;base64,...`)
168
+ *
169
+ * @throws {BackgroundRemovalError} When image cannot be processed
170
+ *
171
+ * @example
172
+ * ```typescript
173
+ * const result = await removeBgImage('file:///path/to/photo.jpg')
174
+ * // Use directly in Image component
175
+ * <Image source={{ uri: result }} />
176
+ * ```
177
+ *
178
+ * @example
179
+ * ```typescript
180
+ * // With options
181
+ * const result = await removeBgImage('file:///path/to/photo.jpg', {
182
+ * maxDimension: 1024,
183
+ * format: 'WEBP',
184
+ * quality: 90,
185
+ * onProgress: (p) => console.log(`Progress: ${p}%`)
186
+ * })
187
+ * ```
188
+ */
189
+ export async function removeBgImage(uri, options = {}) {
190
+ const startTime = Date.now();
191
+ const opts = { ...DEFAULT_OPTIONS, ...options };
192
+ const { onProgress, debug } = opts;
193
+ // Validate inputs
194
+ validateImagePath(uri);
195
+ validateOptions(options);
196
+ if (debug) {
197
+ console.log('[rn-remove-image-bg] Starting background removal:', uri);
198
+ console.log('[rn-remove-image-bg] Options:', opts);
199
+ }
200
+ // Report initial progress
201
+ onProgress?.(5);
202
+ // Check cache if enabled
203
+ if (opts.useCache) {
204
+ const optionsHash = bgRemovalCache.hashOptions({
205
+ maxDimension: opts.maxDimension,
206
+ format: opts.format,
207
+ quality: opts.quality,
208
+ });
209
+ const cached = await bgRemovalCache.get(uri, optionsHash);
210
+ if (cached) {
211
+ if (debug) {
212
+ console.log('[rn-remove-image-bg] Cache hit:', cached);
213
+ }
214
+ onProgress?.(100);
215
+ return cached.startsWith('file://') ? cached : `file://${cached}`;
216
+ }
217
+ }
218
+ onProgress?.(10);
219
+ try {
220
+ // Prepare native options
221
+ const nativeOptions = {
222
+ maxDimension: opts.maxDimension,
223
+ format: opts.format,
224
+ quality: opts.quality,
225
+ };
226
+ onProgress?.(20);
227
+ // Call native implementation
228
+ const result = await getNativeRemover().removeBackground(uri, nativeOptions);
229
+ onProgress?.(90);
230
+ // Normalize result path
231
+ const resultPath = result.startsWith('file://')
232
+ ? result
233
+ : `file://${result}`;
234
+ // Cache the result
235
+ if (opts.useCache) {
236
+ const optionsHash = bgRemovalCache.hashOptions({
237
+ maxDimension: opts.maxDimension,
238
+ format: opts.format,
239
+ quality: opts.quality,
240
+ });
241
+ bgRemovalCache.set(uri, optionsHash, resultPath);
242
+ }
243
+ if (debug) {
244
+ console.log('[rn-remove-image-bg] Completed in', Date.now() - startTime, 'ms');
245
+ console.log('[rn-remove-image-bg] Result:', resultPath);
246
+ }
247
+ onProgress?.(100);
248
+ return resultPath;
249
+ }
250
+ catch (error) {
251
+ if (debug) {
252
+ console.error('[rn-remove-image-bg] Failed:', error);
253
+ }
254
+ throw wrapNativeError(error);
255
+ }
256
+ }
257
+ /**
258
+ * Backward compatibility alias for removeBgImage
259
+ * @deprecated Use removeBgImage instead
260
+ */
261
+ export const removeBackground = removeBgImage;
262
+ /**
263
+ * Clear the background removal cache
264
+ * @param deleteFiles - Also delete cached files from disk (default: false)
265
+ */
266
+ export async function clearCache(deleteFiles = false) {
267
+ await bgRemovalCache.clear(deleteFiles);
268
+ }
269
+ /**
270
+ * Get the current cache size
271
+ */
272
+ export function getCacheSize() {
273
+ return bgRemovalCache.size;
274
+ }
275
+ /**
276
+ * Handle low memory conditions by clearing the cache
277
+ * Call this when your app receives memory warnings
278
+ *
279
+ * @param deleteFiles - Also delete cached files from disk (default: true)
280
+ * @returns Number of entries that were cleared
281
+ *
282
+ * @example
283
+ * ```typescript
284
+ * import { AppState } from 'react-native'
285
+ * import { onLowMemory } from 'rn-remove-image-bg'
286
+ *
287
+ * // In your app initialization
288
+ * AppState.addEventListener('memoryWarning', () => {
289
+ * onLowMemory()
290
+ * })
291
+ * ```
292
+ */
293
+ export async function onLowMemory(deleteFiles = true) {
294
+ const size = bgRemovalCache.size;
295
+ await bgRemovalCache.clear(deleteFiles);
296
+ console.log(`[rn-remove-image-bg] Cleared ${size} cache entries due to memory pressure`);
297
+ return size;
298
+ }
299
+ /**
300
+ * Configure the background removal cache
301
+ * Call this early in your app lifecycle to customize cache behavior
302
+ *
303
+ * @example
304
+ * ```typescript
305
+ * import { configureCache } from 'rn-remove-image-bg'
306
+ *
307
+ * configureCache({
308
+ * maxEntries: 100,
309
+ * maxAgeMinutes: 60,
310
+ * persistToDisk: true
311
+ * })
312
+ * ```
313
+ */
314
+ export function configureCache(config) {
315
+ bgRemovalCache.configure(config);
316
+ }
317
+ /**
318
+ * Get the cache directory path
319
+ * Useful for debugging or manual cache management
320
+ */
321
+ export function getCacheDirectory() {
322
+ return bgRemovalCache.getCacheDirectory();
323
+ }
@@ -0,0 +1,25 @@
1
+ import type { RemoveBgImageOptions, CompressImageOptions, GenerateThumbhashOptions, OutputFormat } from './web/core/types';
2
+ export type { RemoveBgImageOptions, CompressImageOptions, GenerateThumbhashOptions, OutputFormat };
3
+ export type NativeRemoveBackgroundOptions = RemoveBgImageOptions;
4
+ /**
5
+ * Remove background from image (Web Implementation)
6
+ */
7
+ export declare function removeBgImage(uri: string, options?: RemoveBgImageOptions): Promise<string>;
8
+ /**
9
+ * Backward compatibility alias
10
+ * @deprecated Use removeBgImage
11
+ */
12
+ export declare const removeBackground: typeof removeBgImage;
13
+ /**
14
+ * Compress image (Web Implementation)
15
+ */
16
+ export declare function compressImage(uri: string, options?: CompressImageOptions): Promise<string>;
17
+ /**
18
+ * Generate thumbhash (Web Implementation)
19
+ */
20
+ export declare function generateThumbhash(uri: string, _options?: GenerateThumbhashOptions): Promise<string>;
21
+ export declare function clearCache(_deleteFiles?: boolean): Promise<void>;
22
+ export declare function getCacheSize(): number;
23
+ export declare function onLowMemory(_deleteFiles?: boolean): Promise<number>;
24
+ export declare function configureCache(_config: Record<string, unknown>): void;
25
+ export declare function getCacheDirectory(): string;
@@ -0,0 +1,89 @@
1
+ import { BackgroundRemover } from './web/core/BackgroundRemover';
2
+ import { cacheManager } from './web/core/CacheManager';
3
+ import { compressImage as compressImageWeb } from './web/utils/CompressImage';
4
+ import { generateThumbhash as generateThumbhashWeb } from './web/utils/ThumbhashGenerator';
5
+ import { blobToDataUrl } from './web/utils/formatConverter';
6
+ /**
7
+ * Remove background from image (Web Implementation)
8
+ */
9
+ export async function removeBgImage(uri, options = {}) {
10
+ const { onProgress, useCache = true, debug = false } = options;
11
+ if (debug)
12
+ console.log('[Web] removeBgImage called with:', uri, options);
13
+ // 1. Check Cache
14
+ if (useCache) {
15
+ const cached = cacheManager.get(uri, options);
16
+ if (cached) {
17
+ if (debug)
18
+ console.log('[Web] Cache hit');
19
+ onProgress?.(100);
20
+ return cached;
21
+ }
22
+ }
23
+ // 2. Process
24
+ onProgress?.(10); // Start
25
+ const blob = await BackgroundRemover.remove(uri, {
26
+ ...options,
27
+ onProgress: (p) => {
28
+ // Map progress to 10-90 range to leave room for start/end
29
+ const mapped = 10 + Math.round((p * 0.8));
30
+ onProgress?.(mapped);
31
+ }
32
+ });
33
+ if (debug) {
34
+ console.log('[Web] Blob received:', {
35
+ type: blob.type,
36
+ size: blob.size,
37
+ });
38
+ }
39
+ // 3. Convert to Data URL
40
+ const dataUrl = await blobToDataUrl(blob);
41
+ if (debug) {
42
+ console.log('[Web] DataURL prefix:', dataUrl.substring(0, 50));
43
+ }
44
+ onProgress?.(100);
45
+ // 4. Cache Result
46
+ if (useCache) {
47
+ cacheManager.set(uri, options, dataUrl);
48
+ }
49
+ return dataUrl;
50
+ }
51
+ /**
52
+ * Backward compatibility alias
53
+ * @deprecated Use removeBgImage
54
+ */
55
+ export const removeBackground = removeBgImage;
56
+ /**
57
+ * Compress image (Web Implementation)
58
+ */
59
+ export async function compressImage(uri, options = {}) {
60
+ return compressImageWeb(uri, options);
61
+ }
62
+ /**
63
+ * Generate thumbhash (Web Implementation)
64
+ */
65
+ export async function generateThumbhash(uri, _options = {}) {
66
+ // Web implementation currently doesn't use options (size hardcoded or auto-scaled)
67
+ return generateThumbhashWeb(uri);
68
+ }
69
+ // Cache Management APIs
70
+ export async function clearCache(_deleteFiles = false) {
71
+ cacheManager.clear();
72
+ console.log('[Web] Cache cleared');
73
+ }
74
+ export function getCacheSize() {
75
+ return cacheManager.size();
76
+ }
77
+ export async function onLowMemory(_deleteFiles = true) {
78
+ const size = cacheManager.size();
79
+ cacheManager.clear();
80
+ console.log(`[Web] Cleared ${size} items due to low memory`);
81
+ return size;
82
+ }
83
+ export function configureCache(_config) {
84
+ // Web cache is simple in-memory LRU, config not fully supported yet but stubbed
85
+ console.log('[Web] Cache configuration updated (no-op on web)');
86
+ }
87
+ export function getCacheDirectory() {
88
+ return ''; // No file system on web
89
+ }
package/lib/cache.d.ts ADDED
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Configuration for the background removal cache
3
+ */
4
+ export interface CacheConfig {
5
+ /** Maximum number of entries in memory (default: 50) */
6
+ maxEntries?: number;
7
+ /** Maximum age of cache entries in minutes (default: 30) */
8
+ maxAgeMinutes?: number;
9
+ /** Enable disk persistence (default: false) */
10
+ persistToDisk?: boolean;
11
+ /** Custom cache directory (default: FileSystem.cacheDirectory + 'bg-removal/') */
12
+ cacheDirectory?: string;
13
+ }
14
+ /**
15
+ * LRU cache for background removal results with optional disk persistence
16
+ */
17
+ declare class BackgroundRemovalCache {
18
+ private cache;
19
+ private _maxEntries;
20
+ private _maxAgeMs;
21
+ private persistToDisk;
22
+ private cacheDirectory;
23
+ private initialized;
24
+ constructor(config?: CacheConfig);
25
+ /**
26
+ * Configure cache settings
27
+ */
28
+ configure(config: CacheConfig): void;
29
+ /**
30
+ * Initialize disk cache (load manifest if exists)
31
+ */
32
+ initialize(): Promise<void>;
33
+ /**
34
+ * Save cache manifest to disk
35
+ */
36
+ private saveManifest;
37
+ /**
38
+ * Generate a cache key from path and options
39
+ */
40
+ private generateKey;
41
+ /**
42
+ * Hash options object to string for cache key
43
+ */
44
+ hashOptions(options: Record<string, unknown>): string;
45
+ /**
46
+ * Get cached result if valid
47
+ */
48
+ get(path: string, optionsHash: string): Promise<string | null>;
49
+ /**
50
+ * Store result in cache
51
+ */
52
+ set(path: string, optionsHash: string, resultPath: string): void;
53
+ /**
54
+ * Clear all cached entries
55
+ * @param deleteFiles - Also delete cached files from disk (default: false)
56
+ */
57
+ clear(deleteFiles?: boolean): Promise<void>;
58
+ /**
59
+ * Get current cache size
60
+ */
61
+ get size(): number;
62
+ /**
63
+ * Remove expired entries
64
+ */
65
+ prune(): number;
66
+ /**
67
+ * Get cache directory path
68
+ */
69
+ getCacheDirectory(): string;
70
+ }
71
+ export declare const bgRemovalCache: BackgroundRemovalCache;
72
+ export {};