rn-remove-image-bg 0.0.20 → 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
@@ -325,18 +325,21 @@ try {
325
325
  > **First-time Use**: On Android, the ML Kit model downloads automatically on first use. The library waits for the download to complete (up to ~15 seconds with retries) before processing. Subsequent calls are instant.
326
326
 
327
327
  ### Web
328
- - **Technology**: [@imgly/background-removal](https://github.com/imgly/background-removal-js) running in a **Web Worker**.
329
- - **Performance**: Zero UI blocking. All processing happens in a background thread.
330
- - **Implementation**:
331
- - Uses an **Inline Worker** architecture.
332
- - Loads the library from CDN (`jsdelivr`) automatically on first use.
333
- - **No bundler configuration required**. Works with Metro, Webpack, Vite, etc. out of the box.
328
+
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.
335
+
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.
334
339
  - **Requirements**:
335
- - **Internet Connection**: Required for the first run to download the library and assets (~10MB) from CDN.
336
340
  - **CORS**: Images loaded from external URLs must be CORS-enabled (`Access-Control-Allow-Origin: *`).
337
- - **Output**: Data URL (`data:image/png;base64,...`) or WEBP Blob.
338
341
 
339
- > **Note on Local Development**: If you see CSP errors, ensure your development server allows loading scripts from `cdn.jsdelivr.net`.
342
+ > **Note**: The first call will download the WASM model files (~10MB) from the CDN. Ensure your CSP allows `cdn.jsdelivr.net`.
340
343
 
341
344
  ---
342
345
 
@@ -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.20",
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; }