rn-remove-image-bg 0.0.19 → 0.0.22

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/README.md CHANGED
@@ -326,14 +326,20 @@ try {
326
326
 
327
327
  ### Web
328
328
 
329
- - **Technology**: @imgly/background-removal (WebAssembly + ONNX)
330
- - **Model**: Downloads ~35MB on first use
331
- - **Output**: Data URL (`data:image/png;base64,...`) or WEBP
332
- - **Note**: Works in modern browsers with WebAssembly support
329
+ 1. **Add the Script**: You must add the `@imgly/background-removal` script to your web `index.html`:
330
+ ```html
331
+ <script src="https://cdn.jsdelivr.net/npm/@imgly/background-removal@1.7.0/dist/imgly-background-removal.min.js"></script>
332
+ ```
333
+
334
+ 2. **Usage**: The library will automatically detect the global `imglyBackgroundRemoval` object.
333
335
 
334
- > **Return Value Difference**: Web returns data URLs instead of file paths. Both work with `<Image>` components.
336
+ - **Technology**: [@imgly/background-removal](https://github.com/imgly/background-removal-js) running in a Web Worker (managed by the library).
337
+ - **Performance**: Zero UI blocking.
338
+ - **Output**: Data URL (`data:image/png;base64,...`) or WEBP Blob.
339
+ - **Requirements**:
340
+ - **CORS**: Images loaded from external URLs must be CORS-enabled (`Access-Control-Allow-Origin: *`).
335
341
 
336
- If you don't need web support, you can tree-shake the `@imgly/background-removal` dependency.
342
+ > **Note**: The first call will download the WASM model files (~10MB) from the CDN. Ensure your CSP allows `cdn.jsdelivr.net`.
337
343
 
338
344
  ---
339
345
 
@@ -416,10 +422,9 @@ If you don't need web support, you can tree-shake the `@imgly/background-removal
416
422
 
417
423
  ### Web Not Working?
418
424
 
419
- 1. Check browser console for errors
420
- 2. Ensure your bundler supports WebAssembly
421
- 3. The first call downloads a ~35MB WASM model
422
- 4. CORS may block model download - check network tab
425
+ 1. **CSP Errors**: If you see "Content Security Policy" errors, ensure your app allows loading scripts/workers from `https://cdn.jsdelivr.net` and `blob:` URLs.
426
+ 2. **CORS Errors**: If loading an image from a URL, the server *must* return `Access-Control-Allow-Origin: *`. If not, download the image to a Blob first or use a proxy.
427
+ 3. **Data URL**: Remember that the web result is a `data:` URL. You can use it directly in `<Image source={{ uri: result }} />`.
423
428
 
424
429
  ### Native Module Not Found?
425
430
 
@@ -1,7 +1,6 @@
1
1
  /**
2
- * Web implementation using @imgly/background-removal via Inline Web Worker.
3
- * Moves all heavy processing to a background thread to prevent UI freezing.
4
- * Loads library from CDN to bypass Metro bundler issues.
2
+ * Web implementation using @imgly/background-removal via Script Tag.
3
+ * Requires the script to be added manually to index.html.
5
4
  */
6
5
  export type OutputFormat = 'PNG' | 'WEBP';
7
6
  export interface RemoveBgImageOptions {
@@ -1,128 +1,38 @@
1
1
  /**
2
- * Web implementation using @imgly/background-removal via Inline Web Worker.
3
- * Moves all heavy processing to a background thread to prevent UI freezing.
4
- * Loads library from CDN to bypass Metro bundler issues.
2
+ * Web implementation using @imgly/background-removal via Script Tag.
3
+ * Requires the script to be added manually to index.html.
5
4
  */
6
- // ==========================================
7
- // INLINE WORKER CODE (Run in background)
8
- // ==========================================
9
- const WORKER_CODE = `
10
- let removeBackground = null;
11
-
12
- self.onmessage = async (e) => {
13
- const { id, type, payload } = e.data;
14
-
15
- try {
16
- if (type === 'init') {
17
- if (typeof self.imglyBackgroundRemoval === 'undefined' || !removeBackground) {
18
- // Use importScripts (Classic Worker) - most robust for Blob URLs
19
- importScripts('https://cdn.jsdelivr.net/npm/@imgly/background-removal@1.7.0/dist/imgly-background-removal.min.js');
20
-
21
- if (!self.imglyBackgroundRemoval) {
22
- throw new Error('imglyBackgroundRemoval not loaded via importScripts');
23
- }
24
-
25
- removeBackground = self.imglyBackgroundRemoval.removeBackground;
26
- }
27
- self.postMessage({ id, type: 'success', payload: true });
28
- return;
29
- }
30
-
31
- if (type === 'removeBg') {
32
- const { uri, config } = payload;
33
-
34
- if (!removeBackground) {
35
- importScripts('https://cdn.jsdelivr.net/npm/@imgly/background-removal@1.7.0/dist/imgly-background-removal.min.js');
36
- removeBackground = self.imglyBackgroundRemoval.removeBackground;
37
- }
38
-
39
- // Run Inference
40
- // CRITICAL: Must point publicPath to CDN so it finds WASM/Models
41
- // otherwise it tries to load from blob: URL
42
- const blob = await removeBackground(uri, {
43
- publicPath: 'https://cdn.jsdelivr.net/npm/@imgly/background-removal@1.7.0/dist/',
44
- progress: (key, current, total) => {
45
- const p = current / total;
46
- self.postMessage({ id, type: 'progress', payload: { progress: p } });
47
- },
48
- ...config
49
- });
50
-
51
- // Convert blob to DataURL for return
52
- const reader = new FileReader();
53
- reader.onloadend = () => {
54
- self.postMessage({ id, type: 'success', payload: reader.result });
55
- };
56
- reader.readAsDataURL(blob);
57
- }
58
- } catch (err) {
59
- self.postMessage({ id, type: 'error', payload: err.message || JSON.stringify(err) });
60
- }
61
- };
62
- `;
63
- // ==========================================
64
- // MAIN THREAD BRIDGE
65
- // ==========================================
66
- let worker = null;
67
- const pendingMessages = new Map();
68
- function getWorker() {
69
- if (!worker) {
70
- const blob = new Blob([WORKER_CODE], { type: 'application/javascript' });
71
- const url = URL.createObjectURL(blob);
72
- worker = new Worker(url);
73
- worker.onmessage = (e) => {
74
- const { id, type, payload } = e.data;
75
- const deferred = pendingMessages.get(id);
76
- if (!deferred)
77
- return;
78
- if (type === 'progress') {
79
- if (deferred.onProgress && payload.progress) {
80
- deferred.onProgress(payload.progress * 100);
81
- }
82
- }
83
- else if (type === 'success') {
84
- deferred.resolve(payload);
85
- pendingMessages.delete(id);
86
- }
87
- else if (type === 'error') {
88
- deferred.reject(new Error(payload));
89
- pendingMessages.delete(id);
90
- }
91
- };
92
- }
93
- return worker;
94
- }
95
- function sendToWorker(type, payload, onProgress) {
96
- return new Promise((resolve, reject) => {
97
- const id = Math.random().toString(36).substring(7);
98
- pendingMessages.set(id, { resolve, reject, onProgress });
99
- getWorker().postMessage({ id, type, payload });
100
- });
101
- }
102
- // Initialize
103
- let initPromise = null;
104
- async function ensureInit() {
105
- if (!initPromise) {
106
- initPromise = sendToWorker('init', {});
107
- }
108
- return initPromise;
109
- }
110
5
  export async function removeBgImage(uri, options = {}) {
111
6
  const { onProgress, debug = false } = options;
7
+ // Safety check
8
+ if (typeof imglyBackgroundRemoval === 'undefined') {
9
+ throw new Error('[rn-remove-image-bg] Library not found. Please add the following script to your web index.html:\n' +
10
+ '<script src="https://cdn.jsdelivr.net/npm/@imgly/background-removal@1.7.0/dist/imgly-background-removal.min.js"></script>');
11
+ }
112
12
  if (debug)
113
13
  console.log('[rmbg] Starting...');
114
14
  onProgress?.(1);
115
- // Ensure worker is ready
116
- await ensureInit();
117
15
  // Config for imgly
118
16
  const config = {
119
17
  debug: debug,
120
- // We can pass other options supported by imgly if needed
121
- // device: 'gpu' is auto-detected usually
18
+ // Point publicPath to CDN for assets (wasm/models)
19
+ // This is crucial for UMD build to find its dependencies on the CDN
20
+ publicPath: 'https://cdn.jsdelivr.net/npm/@imgly/background-removal@1.7.0/dist/',
21
+ progress: (_key, current, total) => {
22
+ if (onProgress && total > 0) {
23
+ onProgress((current / total) * 100);
24
+ }
25
+ }
122
26
  };
123
- const result = await sendToWorker('removeBg', { uri, config }, onProgress);
27
+ const blob = await imglyBackgroundRemoval.removeBackground(uri, config);
124
28
  onProgress?.(100);
125
- return result;
29
+ // Convert blob to DataURL
30
+ return new Promise((resolve, reject) => {
31
+ const reader = new FileReader();
32
+ reader.onloadend = () => resolve(reader.result);
33
+ reader.onerror = reject;
34
+ reader.readAsDataURL(blob);
35
+ });
126
36
  }
127
37
  export const removeBackground = removeBgImage;
128
38
  // ==========================================
@@ -192,11 +102,10 @@ export async function generateThumbhash(imageUri, options = {}) {
192
102
  }
193
103
  }
194
104
  export async function clearCache() {
195
- if (worker) {
196
- worker.terminate();
197
- worker = null;
105
+ // @ts-ignore
106
+ if (typeof imglyBackgroundRemoval !== 'undefined' && imglyBackgroundRemoval.preload) {
107
+ // no explicit clear cache in uMD version usually
198
108
  }
199
- initPromise = null;
200
109
  }
201
110
  export function getCacheSize() { return 0; }
202
111
  export async function onLowMemory() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rn-remove-image-bg",
3
- "version": "0.0.19",
3
+ "version": "0.0.22",
4
4
  "description": "rn-remove-image-bg",
5
5
  "homepage": "https://github.com/a-eid/rn-remove-image-bg",
6
6
  "main": "lib/index",
@@ -1,7 +1,6 @@
1
1
  /**
2
- * Web implementation using @imgly/background-removal via Inline Web Worker.
3
- * Moves all heavy processing to a background thread to prevent UI freezing.
4
- * Loads library from CDN to bypass Metro bundler issues.
2
+ * Web implementation using @imgly/background-removal via Script Tag.
3
+ * Requires the script to be added manually to index.html.
5
4
  */
6
5
 
7
6
  export type OutputFormat = 'PNG' | 'WEBP';
@@ -13,115 +12,9 @@ export interface RemoveBgImageOptions {
13
12
  debug?: boolean;
14
13
  }
15
14
 
16
- // ==========================================
17
- // INLINE WORKER CODE (Run in background)
18
- // ==========================================
19
- const WORKER_CODE = `
20
- let removeBackground = null;
21
-
22
- self.onmessage = async (e) => {
23
- const { id, type, payload } = e.data;
24
-
25
- try {
26
- if (type === 'init') {
27
- if (typeof self.imglyBackgroundRemoval === 'undefined' || !removeBackground) {
28
- // Use importScripts (Classic Worker) - most robust for Blob URLs
29
- importScripts('https://cdn.jsdelivr.net/npm/@imgly/background-removal@1.7.0/dist/imgly-background-removal.min.js');
30
-
31
- if (!self.imglyBackgroundRemoval) {
32
- throw new Error('imglyBackgroundRemoval not loaded via importScripts');
33
- }
34
-
35
- removeBackground = self.imglyBackgroundRemoval.removeBackground;
36
- }
37
- self.postMessage({ id, type: 'success', payload: true });
38
- return;
39
- }
40
-
41
- if (type === 'removeBg') {
42
- const { uri, config } = payload;
43
-
44
- if (!removeBackground) {
45
- importScripts('https://cdn.jsdelivr.net/npm/@imgly/background-removal@1.7.0/dist/imgly-background-removal.min.js');
46
- removeBackground = self.imglyBackgroundRemoval.removeBackground;
47
- }
48
-
49
- // Run Inference
50
- // CRITICAL: Must point publicPath to CDN so it finds WASM/Models
51
- // otherwise it tries to load from blob: URL
52
- const blob = await removeBackground(uri, {
53
- publicPath: 'https://cdn.jsdelivr.net/npm/@imgly/background-removal@1.7.0/dist/',
54
- progress: (key, current, total) => {
55
- const p = current / total;
56
- self.postMessage({ id, type: 'progress', payload: { progress: p } });
57
- },
58
- ...config
59
- });
60
-
61
- // Convert blob to DataURL for return
62
- const reader = new FileReader();
63
- reader.onloadend = () => {
64
- self.postMessage({ id, type: 'success', payload: reader.result });
65
- };
66
- reader.readAsDataURL(blob);
67
- }
68
- } catch (err) {
69
- self.postMessage({ id, type: 'error', payload: err.message || JSON.stringify(err) });
70
- }
71
- };
72
- `;
73
-
74
- // ==========================================
75
- // MAIN THREAD BRIDGE
76
- // ==========================================
77
-
78
- let worker: Worker | null = null;
79
- const pendingMessages = new Map<string, { resolve: (v: any) => void; reject: (e: any) => void; onProgress?: (p: number) => void }>();
80
-
81
- function getWorker() {
82
- if (!worker) {
83
- const blob = new Blob([WORKER_CODE], { type: 'application/javascript' });
84
- const url = URL.createObjectURL(blob);
85
- worker = new Worker(url);
86
-
87
- worker.onmessage = (e) => {
88
- const { id, type, payload } = e.data;
89
- const deferred = pendingMessages.get(id);
90
-
91
- if (!deferred) return;
92
-
93
- if (type === 'progress') {
94
- if (deferred.onProgress && payload.progress) {
95
- deferred.onProgress(payload.progress * 100);
96
- }
97
- } else if (type === 'success') {
98
- deferred.resolve(payload);
99
- pendingMessages.delete(id);
100
- } else if (type === 'error') {
101
- deferred.reject(new Error(payload));
102
- pendingMessages.delete(id);
103
- }
104
- };
105
- }
106
- return worker;
107
- }
108
-
109
- function sendToWorker(type: string, payload: any, onProgress?: (p: number) => void): Promise<any> {
110
- return new Promise((resolve, reject) => {
111
- const id = Math.random().toString(36).substring(7);
112
- pendingMessages.set(id, { resolve, reject, onProgress });
113
- getWorker().postMessage({ id, type, payload });
114
- });
115
- }
116
-
117
- // Initialize
118
- let initPromise: Promise<void> | null = null;
119
- async function ensureInit() {
120
- if (!initPromise) {
121
- initPromise = sendToWorker('init', {});
122
- }
123
- return initPromise;
124
- }
15
+ // Check for global variable
16
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
+ declare const imglyBackgroundRemoval: any;
125
18
 
126
19
  export async function removeBgImage(
127
20
  uri: string,
@@ -129,23 +22,40 @@ export async function removeBgImage(
129
22
  ): Promise<string> {
130
23
  const { onProgress, debug = false } = options;
131
24
 
25
+ // Safety check
26
+ if (typeof imglyBackgroundRemoval === 'undefined') {
27
+ throw new Error(
28
+ '[rn-remove-image-bg] Library not found. Please add the following script to your web index.html:\n' +
29
+ '<script src="https://cdn.jsdelivr.net/npm/@imgly/background-removal@1.7.0/dist/imgly-background-removal.min.js"></script>'
30
+ );
31
+ }
32
+
132
33
  if (debug) console.log('[rmbg] Starting...');
133
34
  onProgress?.(1);
134
35
 
135
- // Ensure worker is ready
136
- await ensureInit();
137
-
138
36
  // Config for imgly
139
37
  const config = {
140
38
  debug: debug,
141
- // We can pass other options supported by imgly if needed
142
- // device: 'gpu' is auto-detected usually
39
+ // Point publicPath to CDN for assets (wasm/models)
40
+ // This is crucial for UMD build to find its dependencies on the CDN
41
+ publicPath: 'https://cdn.jsdelivr.net/npm/@imgly/background-removal@1.7.0/dist/',
42
+ progress: (_key: string, current: number, total: number) => {
43
+ if (onProgress && total > 0) {
44
+ onProgress((current / total) * 100);
45
+ }
46
+ }
143
47
  };
144
48
 
145
- const result = await sendToWorker('removeBg', { uri, config }, onProgress);
146
-
49
+ const blob = await imglyBackgroundRemoval.removeBackground(uri, config);
147
50
  onProgress?.(100);
148
- return result as string;
51
+
52
+ // Convert blob to DataURL
53
+ return new Promise((resolve, reject) => {
54
+ const reader = new FileReader();
55
+ reader.onloadend = () => resolve(reader.result as string);
56
+ reader.onerror = reject;
57
+ reader.readAsDataURL(blob);
58
+ });
149
59
  }
150
60
 
151
61
  export const removeBackground = removeBgImage;
@@ -250,11 +160,10 @@ export async function generateThumbhash(
250
160
  }
251
161
 
252
162
  export async function clearCache(): Promise<void> {
253
- if (worker) {
254
- worker.terminate();
255
- worker = null;
163
+ // @ts-ignore
164
+ if (typeof imglyBackgroundRemoval !== 'undefined' && imglyBackgroundRemoval.preload) {
165
+ // no explicit clear cache in uMD version usually
256
166
  }
257
- initPromise = null;
258
167
  }
259
168
 
260
169
  export function getCacheSize(): number { return 0; }