rn-remove-image-bg 0.0.14 → 0.0.15

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.
@@ -60,22 +60,89 @@ export async function removeBgImage(uri, options = {}) {
60
60
  const result = Array.isArray(results) ? results[0] : results;
61
61
  if (!result?.mask)
62
62
  throw new Error('No mask returned');
63
- // Convert to data URL
64
- const dataUrl = typeof result.mask === 'string'
65
- ? result.mask
66
- : toDataUrl(result.mask, format, quality);
63
+ // Apply mask to original image
64
+ const original = await loadImage(uri);
65
+ const dataUrl = await applyMask(original, result.mask, format, quality);
67
66
  if (debug)
68
67
  console.log('[rmbg] Done');
69
68
  onProgress?.(100);
70
69
  return dataUrl;
71
70
  }
72
- function toDataUrl(mask, format, quality) {
71
+ async function applyMask(image, mask, format, quality) {
73
72
  const canvas = document.createElement('canvas');
74
- canvas.width = mask.width;
75
- canvas.height = mask.height;
73
+ // Use original image dimensions
74
+ canvas.width = image.width;
75
+ canvas.height = image.height;
76
76
  const ctx = canvas.getContext('2d');
77
- const imageData = ctx.createImageData(mask.width, mask.height);
78
- imageData.data.set(mask.data);
77
+ if (!ctx)
78
+ throw new Error('Could not get canvas context');
79
+ // Draw original image
80
+ ctx.drawImage(image, 0, 0);
81
+ // Get image data to manipulate pixels
82
+ const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
83
+ const pixelData = imageData.data;
84
+ // Process mask
85
+ let maskData;
86
+ let maskWidth;
87
+ let maskHeight;
88
+ if (typeof mask === 'string') {
89
+ // If mask is a URL, load it
90
+ const maskImg = await loadImage(mask);
91
+ const maskCanvas = document.createElement('canvas');
92
+ maskCanvas.width = canvas.width;
93
+ maskCanvas.height = canvas.height;
94
+ const maskCtx = maskCanvas.getContext('2d');
95
+ if (!maskCtx)
96
+ throw new Error('Could not get mask context');
97
+ // Draw and resize mask to match image
98
+ maskCtx.drawImage(maskImg, 0, 0, canvas.width, canvas.height);
99
+ const maskImageData = maskCtx.getImageData(0, 0, canvas.width, canvas.height);
100
+ maskData = maskImageData.data;
101
+ maskWidth = canvas.width;
102
+ maskHeight = canvas.height;
103
+ }
104
+ else {
105
+ // @ts-ignore - Transformers.js types are loose
106
+ maskData = mask.data;
107
+ maskWidth = mask.width;
108
+ maskHeight = mask.height;
109
+ }
110
+ // Helper to get alpha value from mask data
111
+ const getAlpha = (index, data, width, height, targetWidth, targetHeight) => {
112
+ // If dimensions match
113
+ if (width === targetWidth && height === targetHeight) {
114
+ // Check if mask is single channel (grayscale) or RGBA
115
+ if (data.length === width * height) {
116
+ return data[index / 4];
117
+ }
118
+ else if (data.length === width * height * 3) {
119
+ return data[Math.floor(index / 4) * 3];
120
+ }
121
+ else {
122
+ return data[index]; // Assume RGBA red channel or alpha channel usage
123
+ }
124
+ }
125
+ // Nearest neighbor resizing
126
+ const x = (index / 4) % targetWidth;
127
+ const y = Math.floor((index / 4) / targetWidth);
128
+ const maskX = Math.floor(x * (width / targetWidth));
129
+ const maskY = Math.floor(y * (height / targetHeight));
130
+ const maskIndex = (maskY * width + maskX);
131
+ if (data.length === width * height) {
132
+ return data[maskIndex];
133
+ }
134
+ else if (data.length === width * height * 3) {
135
+ return data[maskIndex * 3];
136
+ }
137
+ else {
138
+ return data[maskIndex * 4];
139
+ }
140
+ };
141
+ // Apply alpha
142
+ for (let i = 0; i < pixelData.length; i += 4) {
143
+ const alpha = getAlpha(i, maskData, maskWidth, maskHeight, canvas.width, canvas.height) ?? 255;
144
+ pixelData[i + 3] = alpha;
145
+ }
79
146
  ctx.putImageData(imageData, 0, 0);
80
147
  return canvas.toDataURL(format === 'WEBP' ? 'image/webp' : 'image/png', quality / 100);
81
148
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rn-remove-image-bg",
3
- "version": "0.0.14",
3
+ "version": "0.0.15",
4
4
  "description": "rn-remove-image-bg",
5
5
  "homepage": "https://github.com/a-eid/rn-remove-image-bg",
6
6
  "main": "lib/index",
@@ -84,10 +84,9 @@ export async function removeBgImage(
84
84
  const result = Array.isArray(results) ? results[0] : results;
85
85
  if (!result?.mask) throw new Error('No mask returned');
86
86
 
87
- // Convert to data URL
88
- const dataUrl = typeof result.mask === 'string'
89
- ? result.mask
90
- : toDataUrl(result.mask, format, quality);
87
+ // Apply mask to original image
88
+ const original = await loadImage(uri);
89
+ const dataUrl = await applyMask(original, result.mask, format, quality);
91
90
 
92
91
  if (debug) console.log('[rmbg] Done');
93
92
  onProgress?.(100);
@@ -95,17 +94,90 @@ export async function removeBgImage(
95
94
  return dataUrl;
96
95
  }
97
96
 
98
- function toDataUrl(
99
- mask: { width: number; height: number; data: Uint8Array | Uint8ClampedArray },
97
+ async function applyMask(
98
+ image: HTMLImageElement,
99
+ mask: { width: number; height: number; data: Uint8Array | Uint8ClampedArray } | string,
100
100
  format: OutputFormat,
101
101
  quality: number
102
- ): string {
102
+ ): Promise<string> {
103
103
  const canvas = document.createElement('canvas');
104
- canvas.width = mask.width;
105
- canvas.height = mask.height;
106
- const ctx = canvas.getContext('2d')!;
107
- const imageData = ctx.createImageData(mask.width, mask.height);
108
- imageData.data.set(mask.data);
104
+ // Use original image dimensions
105
+ canvas.width = image.width;
106
+ canvas.height = image.height;
107
+ const ctx = canvas.getContext('2d');
108
+ if (!ctx) throw new Error('Could not get canvas context');
109
+
110
+ // Draw original image
111
+ ctx.drawImage(image, 0, 0);
112
+
113
+ // Get image data to manipulate pixels
114
+ const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
115
+ const pixelData = imageData.data;
116
+
117
+ // Process mask
118
+ let maskData: Uint8ClampedArray | Uint8Array;
119
+ let maskWidth: number;
120
+ let maskHeight: number;
121
+
122
+ if (typeof mask === 'string') {
123
+ // If mask is a URL, load it
124
+ const maskImg = await loadImage(mask);
125
+ const maskCanvas = document.createElement('canvas');
126
+ maskCanvas.width = canvas.width;
127
+ maskCanvas.height = canvas.height;
128
+ const maskCtx = maskCanvas.getContext('2d');
129
+ if (!maskCtx) throw new Error('Could not get mask context');
130
+
131
+ // Draw and resize mask to match image
132
+ maskCtx.drawImage(maskImg, 0, 0, canvas.width, canvas.height);
133
+ const maskImageData = maskCtx.getImageData(0, 0, canvas.width, canvas.height);
134
+ maskData = maskImageData.data;
135
+ maskWidth = canvas.width;
136
+ maskHeight = canvas.height;
137
+ } else {
138
+ // @ts-ignore - Transformers.js types are loose
139
+ maskData = mask.data;
140
+ maskWidth = mask.width;
141
+ maskHeight = mask.height;
142
+ }
143
+
144
+ // Helper to get alpha value from mask data
145
+ const getAlpha = (index: number, data: Uint8ClampedArray | Uint8Array, width: number, height: number, targetWidth: number, targetHeight: number) => {
146
+ // If dimensions match
147
+ if (width === targetWidth && height === targetHeight) {
148
+ // Check if mask is single channel (grayscale) or RGBA
149
+ if (data.length === width * height) {
150
+ return data[index / 4];
151
+ } else if (data.length === width * height * 3) {
152
+ return data[Math.floor(index / 4) * 3];
153
+ } else {
154
+ return data[index]; // Assume RGBA red channel or alpha channel usage
155
+ }
156
+ }
157
+
158
+ // Nearest neighbor resizing
159
+ const x = (index / 4) % targetWidth;
160
+ const y = Math.floor((index / 4) / targetWidth);
161
+
162
+ const maskX = Math.floor(x * (width / targetWidth));
163
+ const maskY = Math.floor(y * (height / targetHeight));
164
+ const maskIndex = (maskY * width + maskX);
165
+
166
+ if (data.length === width * height) {
167
+ return data[maskIndex];
168
+ } else if (data.length === width * height * 3) {
169
+ return data[maskIndex * 3];
170
+ } else {
171
+ return data[maskIndex * 4];
172
+ }
173
+ };
174
+
175
+ // Apply alpha
176
+ for (let i = 0; i < pixelData.length; i += 4) {
177
+ const alpha = getAlpha(i, maskData, maskWidth, maskHeight, canvas.width, canvas.height) ?? 255;
178
+ pixelData[i + 3] = alpha;
179
+ }
180
+
109
181
  ctx.putImageData(imageData, 0, 0);
110
182
  return canvas.toDataURL(format === 'WEBP' ? 'image/webp' : 'image/png', quality / 100);
111
183
  }