Fraser commited on
Commit
f37f26b
·
1 Parent(s): 2a88efb

rm background

Browse files
src/lib/components/MonsterGenerator/MonsterGenerator.svelte CHANGED
@@ -329,7 +329,8 @@ Write your response within \`\`\`json\`\`\``;
329
  // Process the image to make white background transparent
330
  console.log('Processing image for transparency...');
331
  try {
332
- const transparentBase64 = await makeWhiteTransparent(url);
 
333
  state.monsterImage = {
334
  imageUrl: url,
335
  imageData: transparentBase64,
 
329
  // Process the image to make white background transparent
330
  console.log('Processing image for transparency...');
331
  try {
332
+ const largeWhiteSegmentThreshold = 0.1; // 10% of image area
333
+ const transparentBase64 = await makeWhiteTransparent(url, largeWhiteSegmentThreshold);
334
  state.monsterImage = {
335
  imageUrl: url,
336
  imageData: transparentBase64,
src/lib/utils/imageProcessing.ts CHANGED
@@ -1,8 +1,9 @@
1
  /**
2
  * Converts an image URL to a base64 data URL with white background made transparent
3
  * Uses flood-fill from edges to only remove background white, preserving internal white
 
4
  */
5
- export async function makeWhiteTransparent(imageUrl: string): Promise<string> {
6
  return new Promise((resolve, reject) => {
7
  const img = new Image();
8
  img.crossOrigin = 'anonymous';
@@ -114,13 +115,77 @@ export async function makeWhiteTransparent(imageUrl: string): Promise<string> {
114
  }
115
  }
116
 
117
- // Apply transparency based on mask
118
  for (let i = 0; i < mask.length; i++) {
119
  if (mask[i]) {
120
  data[i * 4 + 3] = 0; // Set alpha to 0
121
  }
122
  }
123
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  // Put the modified image data back
125
  ctx.putImageData(imageData, 0, 0);
126
 
 
1
  /**
2
  * Converts an image URL to a base64 data URL with white background made transparent
3
  * Uses flood-fill from edges to only remove background white, preserving internal white
4
+ * Also removes large white segments that exceed the threshold percentage
5
  */
6
+ export async function makeWhiteTransparent(imageUrl: string, largeSegmentThreshold: number = 0.1): Promise<string> {
7
  return new Promise((resolve, reject) => {
8
  const img = new Image();
9
  img.crossOrigin = 'anonymous';
 
115
  }
116
  }
117
 
118
+ // Apply transparency based on edge flood fill mask
119
  for (let i = 0; i < mask.length; i++) {
120
  if (mask[i]) {
121
  data[i * 4 + 3] = 0; // Set alpha to 0
122
  }
123
  }
124
 
125
+ // Now detect and remove large white segments
126
+ const totalPixels = width * height;
127
+ const segmentMask = new Uint8Array(width * height);
128
+ const visited = new Uint8Array(width * height);
129
+
130
+ // Find all white segments using flood fill
131
+ for (let y = 0; y < height; y++) {
132
+ for (let x = 0; x < width; x++) {
133
+ const idx = y * width + x;
134
+
135
+ // Skip if already transparent, visited, or not white
136
+ if (mask[idx] || visited[idx] || !isWhite(idx)) continue;
137
+
138
+ // Start flood fill for this white segment
139
+ const segmentPixels: number[] = [];
140
+ const segmentQueue: number[] = [idx];
141
+ visited[idx] = 1;
142
+
143
+ while (segmentQueue.length > 0) {
144
+ const currentIdx = segmentQueue.pop()!;
145
+ segmentPixels.push(currentIdx);
146
+
147
+ const cx = currentIdx % width;
148
+ const cy = Math.floor(currentIdx / width);
149
+
150
+ // Check 4 neighbors
151
+ const neighbors = [
152
+ { dx: -1, dy: 0 }, { dx: 1, dy: 0 },
153
+ { dx: 0, dy: -1 }, { dx: 0, dy: 1 }
154
+ ];
155
+
156
+ for (const { dx, dy } of neighbors) {
157
+ const nx = cx + dx;
158
+ const ny = cy + dy;
159
+
160
+ if (nx >= 0 && nx < width && ny >= 0 && ny < height) {
161
+ const nIdx = ny * width + nx;
162
+
163
+ if (!visited[nIdx] && !mask[nIdx] && isWhite(nIdx) && colorSimilar(currentIdx, nIdx)) {
164
+ visited[nIdx] = 1;
165
+ segmentQueue.push(nIdx);
166
+ }
167
+ }
168
+ }
169
+ }
170
+
171
+ // Check if this segment is larger than threshold
172
+ const segmentSize = segmentPixels.length / totalPixels;
173
+ if (segmentSize > largeSegmentThreshold) {
174
+ // Mark all pixels in this segment for removal
175
+ for (const pixelIdx of segmentPixels) {
176
+ segmentMask[pixelIdx] = 1;
177
+ }
178
+ }
179
+ }
180
+ }
181
+
182
+ // Apply transparency to large segments
183
+ for (let i = 0; i < segmentMask.length; i++) {
184
+ if (segmentMask[i]) {
185
+ data[i * 4 + 3] = 0; // Set alpha to 0
186
+ }
187
+ }
188
+
189
  // Put the modified image data back
190
  ctx.putImageData(imageData, 0, 0);
191