diff --git a/plans/260417-1125-image-importer-enhancements/phase-06-skip-white.md b/plans/260417-1125-image-importer-enhancements/phase-06-skip-white.md
index 5ed2f12..f02bfd0 100644
--- a/plans/260417-1125-image-importer-enhancements/phase-06-skip-white.md
+++ b/plans/260417-1125-image-importer-enhancements/phase-06-skip-white.md
@@ -2,7 +2,7 @@
## Overview
- **Priority:** P3 (low, easy win)
-- **Status:** Todo
+- **Status:** Done
- Two cheap toggles: treat near-white pixels as transparent (useful for logos on white backgrounds), and optionally paint pixels with alpha < threshold as white instead of skipping.
## Requirements
@@ -40,10 +40,10 @@ Logic:
5. Tests: near-white pixel → -1 iff skipWhite on; low-alpha pixel → -1 iff paintTransparent off.
## Todo
-- [ ] Extend `rgbaToPalette` options
-- [ ] UI toggles + threshold
-- [ ] CLI flags
-- [ ] Tests
+- [x] Extend `rgbaToPalette` options (`skipWhite`, `whiteThreshold`, `paintTransparent`)
+- [x] UI toggles + threshold slider
+- [x] CLI `--skip-white`, `--white-threshold`, `--paint-transparent`
+- [x] Tests (4 new cases in image-to-palette.test.js)
## Success Criteria
- With defaults, output matches pre-change output.
diff --git a/plans/260417-1125-image-importer-enhancements/plan.md b/plans/260417-1125-image-importer-enhancements/plan.md
index a3fc357..655f9ab 100644
--- a/plans/260417-1125-image-importer-enhancements/plan.md
+++ b/plans/260417-1125-image-importer-enhancements/plan.md
@@ -20,7 +20,7 @@ Grow the in-app Image Import panel into a full pre-placement pipeline: resize, t
| 3 | [Transforms (flip / rotate)](phase-03-transforms.md) | Done | Medium — quick fixes without re-editing source |
| 4 | [More dithering algorithms](phase-04-dithering-algorithms.md) | Done | Medium — different looks per source |
| 5 | [Color correction sliders](phase-05-color-correction.md) | Done | Medium — photos benefit most |
-| 6 | [Skip-white + paint-transparent toggles](phase-06-skip-white.md) | Todo | Low — easy win, often useful for logos |
+| 6 | [Skip-white + paint-transparent toggles](phase-06-skip-white.md) | Done | Low — easy win, often useful for logos |
Later / parked: multi-algorithm color distance (Lab/Oklab), Kuwahara smoothing, template save/load, repair mode. Revisit after Phase 6.
diff --git a/scripts/image-to-colors.js b/scripts/image-to-colors.js
index 48bca1f..483c892 100644
--- a/scripts/image-to-colors.js
+++ b/scripts/image-to-colors.js
@@ -35,6 +35,9 @@ const { values, positionals } = parseArgs({
contrast: { type: 'string', default: '0' },
saturation: { type: 'string', default: '0' },
gamma: { type: 'string', default: '1' },
+ 'skip-white': { type: 'boolean', default: false },
+ 'white-threshold': { type: 'string', default: '230' },
+ 'paint-transparent': { type: 'boolean', default: false },
},
allowPositionals: true,
});
@@ -100,7 +103,13 @@ const working = hasCorrection
// sharp raw buffer has channels=4 after ensureAlpha; same layout as Canvas ImageData.
const ditherMethod = values['dither-method'] ?? (values.dither ? 'floyd' : 'none');
-const indices = rgbaToPalette(working, outW, outH, { alphaThreshold, method: ditherMethod });
+const indices = rgbaToPalette(working, outW, outH, {
+ alphaThreshold,
+ method: ditherMethod,
+ skipWhite: values['skip-white'],
+ whiteThreshold: parseInt(values['white-threshold'], 10),
+ paintTransparent: values['paint-transparent'],
+});
const pixels = Array.from(indices);
const opaque = pixels.reduce((n, p) => n + (p >= 0 ? 1 : 0), 0);
diff --git a/src/client/components/ImageImporter.svelte b/src/client/components/ImageImporter.svelte
index c96658c..dda5bcf 100644
--- a/src/client/components/ImageImporter.svelte
+++ b/src/client/components/ImageImporter.svelte
@@ -26,6 +26,9 @@
let originY = $state(0);
let skipMatching = $state(true);
let ditherMethod = $state('none'); // see DITHER_METHODS
+ let skipWhite = $state(false);
+ let whiteThreshold = $state(230);
+ let paintTransparent = $state(false);
// Resize controls — init to source dims on file load
let resizeW = $state(0);
@@ -108,7 +111,11 @@
const corrected = (brightness !== 0 || contrast !== 0 || saturation !== 0 || gamma !== 1)
? applyColorCorrection(resized, resizeW, resizeH, { brightness, contrast, saturation, gamma })
: resized;
- const idx = rgbaToPalette(corrected, resizeW, resizeH, { method: ditherMethod });
+ const idx = rgbaToPalette(corrected, resizeW, resizeH, {
+ method: ditherMethod,
+ skipWhite, whiteThreshold,
+ paintTransparent,
+ });
paletteIndices = idx;
let count = 0;
for (let i = 0; i < idx.length; i++) if (idx[i] >= 0) count++;
@@ -362,6 +369,25 @@
Skip pixels that already match
+
+
+
+ {#if skipWhite}
+
+ {/if}
+
+
+