rn-remove-image-bg 0.0.20 → 0.0.23

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,25 @@ 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` setup to your web `index.html`.
330
+ Since the library is distributed as an ES Module, you need to import it and assign it to the window object:
331
+ ```html
332
+ <script type="module">
333
+ import { removeBackground } from "https://cdn.jsdelivr.net/npm/@imgly/background-removal@1.7.0/+esm";
334
+ window.imglyRemoveBackground = removeBackground;
335
+ </script>
336
+ ```
337
+
338
+ 2. **Usage**: The library will automatically detect the global `imglyRemoveBackground` function.
339
+
340
+ - **Technology**: [@imgly/background-removal](https://github.com/imgly/background-removal-js) running in a Web Worker (managed by the library).
341
+ - **Performance**: Zero UI blocking.
342
+ - **Output**: Data URL (`data:image/png;base64,...`) or WEBP Blob.
334
343
  - **Requirements**:
335
- - **Internet Connection**: Required for the first run to download the library and assets (~10MB) from CDN.
336
344
  - **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
345
 
339
- > **Note on Local Development**: If you see CSP errors, ensure your development server allows loading scripts from `cdn.jsdelivr.net`.
346
+ > **Note**: The first call will download the WASM model files (~10MB) from the CDN. Ensure your CSP allows `cdn.jsdelivr.net`.
340
347
 
341
348
  ---
342
349
 
@@ -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,51 @@
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;
5
+ export async function removeBgImage(uri, options = {}) {
6
+ const { onProgress, debug = false } = options;
7
+ // Safety check
8
+ // @ts-ignore
9
+ if (typeof window !== 'undefined' && !window.imglyRemoveBackground) {
10
+ // Also check if user defined it as imglyRemoveBackground globally
11
+ // @ts-ignore
12
+ if (typeof imglyRemoveBackground !== 'undefined') {
13
+ // @ts-ignore
14
+ window.imglyRemoveBackground = imglyRemoveBackground;
37
15
  }
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
16
  }
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
- };
17
+ // @ts-ignore
18
+ if (typeof window.imglyRemoveBackground === 'undefined') {
19
+ throw new Error('[rn-remove-image-bg] Library not found. Please add the following script to your web index.html:\n' +
20
+ '<script type="module">\n' +
21
+ ' import { removeBackground } from "https://cdn.jsdelivr.net/npm/@imgly/background-removal@1.7.0/+esm";\n' +
22
+ ' window.imglyRemoveBackground = removeBackground;\n' +
23
+ '</script>');
92
24
  }
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
- export async function removeBgImage(uri, options = {}) {
111
- const { onProgress, debug = false } = options;
112
25
  if (debug)
113
26
  console.log('[rmbg] Starting...');
114
27
  onProgress?.(1);
115
- // Ensure worker is ready
116
- await ensureInit();
117
28
  // Config for imgly
118
29
  const config = {
119
30
  debug: debug,
120
- // We can pass other options supported by imgly if needed
121
- // device: 'gpu' is auto-detected usually
31
+ // Point publicPath to CDN for assets (wasm/models)
32
+ publicPath: 'https://cdn.jsdelivr.net/npm/@imgly/background-removal@1.7.0/dist/',
33
+ progress: (_key, current, total) => {
34
+ if (onProgress && total > 0) {
35
+ onProgress((current / total) * 100);
36
+ }
37
+ }
122
38
  };
123
- const result = await sendToWorker('removeBg', { uri, config }, onProgress);
39
+ // @ts-ignore
40
+ const blob = await window.imglyRemoveBackground(uri, config);
124
41
  onProgress?.(100);
125
- return result;
42
+ // Convert blob to DataURL
43
+ return new Promise((resolve, reject) => {
44
+ const reader = new FileReader();
45
+ reader.onloadend = () => resolve(reader.result);
46
+ reader.onerror = reject;
47
+ reader.readAsDataURL(blob);
48
+ });
126
49
  }
127
50
  export const removeBackground = removeBgImage;
128
51
  // ==========================================
@@ -192,11 +115,7 @@ export async function generateThumbhash(imageUri, options = {}) {
192
115
  }
193
116
  }
194
117
  export async function clearCache() {
195
- if (worker) {
196
- worker.terminate();
197
- worker = null;
198
- }
199
- initPromise = null;
118
+ // Caching is handled internally by the library
200
119
  }
201
120
  export function getCacheSize() { return 0; }
202
121
  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.23",
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 imglyRemoveBackground: any;
125
18
 
126
19
  export async function removeBgImage(
127
20
  uri: string,
@@ -129,23 +22,54 @@ export async function removeBgImage(
129
22
  ): Promise<string> {
130
23
  const { onProgress, debug = false } = options;
131
24
 
25
+ // Safety check
26
+ // @ts-ignore
27
+ if (typeof window !== 'undefined' && !window.imglyRemoveBackground) {
28
+ // Also check if user defined it as imglyRemoveBackground globally
29
+ // @ts-ignore
30
+ if (typeof imglyRemoveBackground !== 'undefined') {
31
+ // @ts-ignore
32
+ window.imglyRemoveBackground = imglyRemoveBackground;
33
+ }
34
+ }
35
+
36
+ // @ts-ignore
37
+ if (typeof window.imglyRemoveBackground === 'undefined') {
38
+ throw new Error(
39
+ '[rn-remove-image-bg] Library not found. Please add the following script to your web index.html:\n' +
40
+ '<script type="module">\n' +
41
+ ' import { removeBackground } from "https://cdn.jsdelivr.net/npm/@imgly/background-removal@1.7.0/+esm";\n' +
42
+ ' window.imglyRemoveBackground = removeBackground;\n' +
43
+ '</script>'
44
+ );
45
+ }
46
+
132
47
  if (debug) console.log('[rmbg] Starting...');
133
48
  onProgress?.(1);
134
49
 
135
- // Ensure worker is ready
136
- await ensureInit();
137
-
138
50
  // Config for imgly
139
51
  const config = {
140
52
  debug: debug,
141
- // We can pass other options supported by imgly if needed
142
- // device: 'gpu' is auto-detected usually
53
+ // Point publicPath to CDN for assets (wasm/models)
54
+ publicPath: 'https://cdn.jsdelivr.net/npm/@imgly/background-removal@1.7.0/dist/',
55
+ progress: (_key: string, current: number, total: number) => {
56
+ if (onProgress && total > 0) {
57
+ onProgress((current / total) * 100);
58
+ }
59
+ }
143
60
  };
144
61
 
145
- const result = await sendToWorker('removeBg', { uri, config }, onProgress);
146
-
62
+ // @ts-ignore
63
+ const blob = await window.imglyRemoveBackground(uri, config);
147
64
  onProgress?.(100);
148
- return result as string;
65
+
66
+ // Convert blob to DataURL
67
+ return new Promise((resolve, reject) => {
68
+ const reader = new FileReader();
69
+ reader.onloadend = () => resolve(reader.result as string);
70
+ reader.onerror = reject;
71
+ reader.readAsDataURL(blob);
72
+ });
149
73
  }
150
74
 
151
75
  export const removeBackground = removeBgImage;
@@ -250,11 +174,7 @@ export async function generateThumbhash(
250
174
  }
251
175
 
252
176
  export async function clearCache(): Promise<void> {
253
- if (worker) {
254
- worker.terminate();
255
- worker = null;
256
- }
257
- initPromise = null;
177
+ // Caching is handled internally by the library
258
178
  }
259
179
 
260
180
  export function getCacheSize(): number { return 0; }