smart-downscaler 0.3.4 → 0.3.5

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
@@ -1,453 +1,264 @@
1
1
  # Smart Pixel Art Downscaler
2
2
 
3
- A sophisticated Rust library for intelligent image downscaling with focus on pixel art quality. Combines global palette extraction, region-aware segmentation, and iterative refinement for optimal results.
3
+ A sophisticated Rust library for intelligent image downscaling with focus on pixel art quality.
4
4
 
5
5
  **Available as both a native Rust library and a WebAssembly module for browser/Node.js usage.**
6
6
 
7
- ## What's New in v0.3
8
7
 
9
- ### Performance Optimizations
8
+ ## What's New in v0.3.5
10
9
 
11
- Version 0.3 introduces **preprocessing optimizations** for large images, providing 2-10x speedup while maintaining 80%+ visual quality:
10
+ ### Performance: Direct LUT Optimization
12
11
 
13
- | Feature | Default | Description |
14
- |---------|---------|-------------|
15
- | `max_resolution_mp` | 1.5 | Cap input at 1.5 megapixels (0 = disabled) |
16
- | `max_color_preprocess` | 16384 | Pre-quantize to 16K unique colors max (0 = disabled) |
12
+ The preprocessing pipeline has been completely rewritten for speed:
17
13
 
18
- ```javascript
19
- const config = new WasmDownscaleConfig();
20
- config.max_resolution_mp = 1.5; // Cap at 1.5 megapixels (0 = disabled)
21
- config.max_color_preprocess = 16384; // Pre-quantize to 16K colors (0 = disabled)
22
- ```
14
+ | Old Method (v0.3) | New Method (v0.3.5) | Improvement |
15
+ | ------------------------------ | --------------------- | --------------------- |
16
+ | HashMap Pre-quantization | **Direct LUT (64MB)** | O(1) Access |
17
+ | Oklab Conversion on All Pixels | **Cached Oklab** | \~100x Fewer Math Ops |
18
+ | Iterative Resolution Cap | **One-pass NN** | Instant Resizing |
23
19
 
24
- ### Optimization Strategies
20
+ **Key Optimizations:**
25
21
 
26
- 1. **Resolution Capping**: Images larger than `max_resolution_mp` are downscaled using fast nearest-neighbor interpolation before processing. Images are only downsized, never upscaled.
22
+ 1. **Direct Lookup Table**: Uses a 64MB flat array to map 24-bit RGB colors to unique indices instantly. No hashing overhead.
27
23
 
28
- 2. **Color Pre-Quantization**: Images with more than `max_color_preprocess` unique colors are pre-quantized using fast bit-truncation (RGB555/RGB444) with weighted averaging.
24
+ 2. **RGBA-Only Preprocessing**: Resolution capping and quantization now happen strictly in RGBA space before any expensive Oklab math.
29
25
 
30
- 3. **Integer Edge Detection**: Uses integer arithmetic for edge detection on preprocessed images for ~2x faster edge computation.
26
+ 3. **Oklab Caching**: If color reduction is enabled (default), Oklab conversion is only performed once per unique color, not per pixel.
31
27
 
32
- 4. **Optimized Tile Processing**: Reduced allocations and stack-allocated arrays for small palettes (≤64 colors).
28
+ <!---->
33
29
 
34
- ## What's New in v0.2
30
+ const config = new WasmDownscaleConfig();
31
+ config.max_resolution_mp = 1.5; // Fast nearest-neighbor cap
32
+ config.max_color_preprocess = 16384; // Direct LUT quantization
35
33
 
36
- ### 🎨 Oklab Color Space
37
34
 
38
- Version 0.2 introduces **Oklab color space** for all color operations, solving the common problem of desaturated, muddy colors:
35
+ ### 🎯 K-Centroid Tile Logic
39
36
 
40
- | Before (RGB Median Cut) | After (Oklab Median Cut) |
41
- |-------------------------|--------------------------|
42
- | Colors appear tanned/darkened | True color preservation |
43
- | Saturated colors become muddy | Vibrant colors maintained |
44
- | RGB averaging loses chroma | Perceptually uniform blending |
37
+ New `k_centroid` configuration allows finer control over how a source tile is reduced to a single representative color before matching:
45
38
 
46
- ### Palette Strategies
39
+ | Mode | Name | Description | Best For |
40
+ | ---- | ------------ | ----------------------------------------------- | --------------------------------------------- |
41
+ | `1` | **Average** | Simple average of all pixels (Default) | Smooth gradients, noise reduction |
42
+ | `2` | **Dominant** | Average of the largest color cluster ($k=2$) | Sharp edges, separating foreground/background |
43
+ | `3` | **Foremost** | Average of the "foremost" distinct part ($k=3$) | Complex textures, detailed sprites |
47
44
 
48
- Choose the best strategy for your use case:
45
+ // Example: Use dominant part for sharper edges
46
+ config.k_centroid = 2;
47
+ config.k_centroid_iterations = 2;
49
48
 
50
- ```javascript
51
- const config = new WasmDownscaleConfig();
52
- config.palette_strategy = 'saturation'; // For vibrant pixel art
53
- ```
54
49
 
55
- | Strategy | Best For | Description |
56
- |----------|----------|-------------|
57
- | `oklab` | General use | Default, best overall quality |
58
- | `saturation` | Vibrant art | Preserves highly saturated colors |
59
- | `medoid` | Exact colors | Only uses colors from source image |
60
- | `kmeans` | Small palettes | K-Means++ clustering |
61
- | `legacy` | Comparison | Original RGB (not recommended) |
50
+ ## Configuration Reference
51
+
52
+ ### DownscaleConfig
53
+
54
+ | Field | Type | Default | Description |
55
+ | ----------------------- | ------ | --------- | ----------------------------- |
56
+ | `k_centroid` | usize | 1 | 1=Avg, 2=Dominant, 3=Foremost |
57
+ | `k_centroid_iterations` | usize | 0 | Refinement for tile color |
58
+ | `max_resolution_mp` | f32 | 1.6 | Resolution cap (0=disabled) |
59
+ | `max_color_preprocess` | usize | 16384 | LUT Quantization limit |
60
+ | `segmentation` | Method | Hierarchy | Region detection method |
61
+
62
+
63
+ ## Command Line Interface
64
+
65
+ # Enable Dominant Color mode (sharper details)
66
+ smart-downscaler input.png output.png --k-centroid 2 --k-centroid-iterations 2
67
+
68
+ # Fast mode (reduce preprocessing limits)
69
+ smart-downscaler input.png output.png --segmentation none --no-refinement
70
+
62
71
 
63
72
  ## Features
64
73
 
65
74
  - **Oklab Color Space**: Modern perceptual color space with superior hue linearity
75
+
66
76
  - **Global Palette Extraction**: Median Cut + K-Means++ refinement
77
+
67
78
  - **Multiple Segmentation Methods**:
79
+
68
80
  - SLIC superpixels for fast, balanced regions
81
+
69
82
  - VTracer-style hierarchical clustering for content-aware boundaries
83
+
70
84
  - Union-find based fast hierarchical clustering
85
+
71
86
  - **Edge-Aware Processing**: Sobel/Scharr edge detection to preserve boundaries
87
+
72
88
  - **Neighbor-Coherent Assignment**: Spatial coherence through neighbor and region voting
89
+
73
90
  - **Two-Pass Refinement**: Iterative optimization for smooth results
91
+
74
92
  - **WebAssembly Support**: Run in browsers with full performance
93
+
75
94
  - **Performance Preprocessing**: Resolution capping and color pre-quantization
76
95
 
96
+
77
97
  ## Installation
78
98
 
79
99
  ### Native (Rust)
80
100
 
81
101
  Add to your `Cargo.toml`:
82
102
 
83
- ```toml
84
- [dependencies]
85
- smart-downscaler = "0.3"
86
- ```
103
+ [dependencies]
104
+ smart-downscaler = "0.3.5"
87
105
 
88
- ### WebAssembly (npm)
89
106
 
90
- ```bash
91
- npm install smart-downscaler
92
- ```
107
+ ### WebAssembly (npm)
93
108
 
94
- Or use directly in browser:
109
+ npm install smart-downscaler
95
110
 
96
- ```html
97
- <script type="module">
98
- import init, { downscale } from './pkg/web/smart_downscaler.js';
99
- await init();
100
- </script>
101
- ```
102
111
 
103
112
  ## Quick Start
104
113
 
105
- ### Native Rust
106
-
107
- ```rust
108
- use smart_downscaler::prelude::*;
109
- use smart_downscaler::palette::PaletteStrategy;
110
-
111
- fn main() {
112
- let img = image::open("input.png").unwrap().to_rgb8();
113
-
114
- // Simple usage
115
- let result = downscale(&img, 64, 64, 16);
116
- result.save("output.png").unwrap();
117
-
118
- // Advanced: preserve vibrant colors with preprocessing
119
- let config = DownscaleConfig {
120
- palette_size: 24,
121
- palette_strategy: PaletteStrategy::SaturationWeighted,
122
- max_resolution_mp: 1.5, // Performance: cap at 1.5MP
123
- max_color_preprocess: 16384, // Performance: pre-quantize colors
124
- ..Default::default()
125
- };
126
-
127
- let pixels: Vec<Rgb> = img.pixels().map(|&p| p.into()).collect();
128
- let result = smart_downscale(&pixels, img.width() as usize, img.height() as usize, 64, 64, &config);
129
- }
130
- ```
131
-
132
114
  ### WebAssembly (Browser)
133
115
 
134
- ```javascript
135
- import init, { WasmDownscaleConfig, downscale_rgba } from 'smart-downscaler';
116
+ import init, { WasmDownscaleConfig, downscale_rgba } from 'smart-downscaler';
117
+
118
+ await init();
136
119
 
137
- await init();
120
+ // Create config
121
+ const config = new WasmDownscaleConfig();
138
122
 
139
- const ctx = canvas.getContext('2d');
140
- const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
123
+ // PERFORMANCE: New Direct LUT settings
124
+ config.max_resolution_mp = 1.5; // Nearest-neighbor cap (0 = disabled)
125
+ config.max_color_preprocess = 16384; // Trigger LUT path if < 16k colors
141
126
 
142
- // Use vibrant preset for saturated colors
143
- const config = WasmDownscaleConfig.vibrant();
144
- config.palette_size = 16;
127
+ // QUALITY: New K-Centroid settings
128
+ config.k_centroid = 2; // 2 = Dominant Color Mode
129
+ config.k_centroid_iterations = 2; // Refine the dominant color
145
130
 
146
- // Performance settings (already set in presets)
147
- config.max_resolution_mp = 1.5;
148
- config.max_color_preprocess = 16384;
131
+ // Standard settings
132
+ config.palette_size = 16;
133
+ config.palette_strategy = 'oklab';
149
134
 
150
- // Or configure manually
151
- const config2 = new WasmDownscaleConfig();
152
- config2.palette_size = 16;
153
- config2.palette_strategy = 'saturation';
154
- config2.neighbor_weight = 0.3;
155
- config2.max_resolution_mp = 1.5;
156
- config2.max_color_preprocess = 16384;
135
+ // Run
136
+ const result = downscale_rgba(
137
+ imageData.data,
138
+ imageData.width, imageData.height,
139
+ 64, 64, // Target size
140
+ config
141
+ );
157
142
 
158
- const result = downscale_rgba(
159
- imageData.data,
160
- canvas.width,
161
- canvas.height,
162
- 64, 64,
163
- config
164
- );
143
+ // Draw result
144
+ const output = new ImageData(result.data, result.width, result.height);
145
+ ctx.putImageData(output, 0, 0);
165
146
 
166
- const outputData = new ImageData(result.data, result.width, result.height);
167
- outputCtx.putImageData(outputData, 0, 0);
168
- ```
169
147
 
170
148
  ### Configuration Presets
171
149
 
172
- ```javascript
173
- // Speed optimized (max_resolution_mp: 1.0, max_color_preprocess: 8192)
174
- const fast = WasmDownscaleConfig.fast();
150
+ // Speed optimized (max_resolution_mp: 1.0, max_color_preprocess: 8192)
151
+ const fast = WasmDownscaleConfig.fast();
175
152
 
176
- // Best quality (max_resolution_mp: 2.0, max_color_preprocess: 32768)
177
- const quality = WasmDownscaleConfig.quality();
153
+ // Best quality (max_resolution_mp: 2.0, max_color_preprocess: 32768)
154
+ const quality = WasmDownscaleConfig.quality();
178
155
 
179
- // Preserve vibrant colors (max_resolution_mp: 1.5, max_color_preprocess: 16384)
180
- const vibrant = WasmDownscaleConfig.vibrant();
156
+ // Preserve vibrant colors (max_resolution_mp: 1.5, max_color_preprocess: 16384)
157
+ const vibrant = WasmDownscaleConfig.vibrant();
158
+
159
+ // Use only exact source colors
160
+ const exact = WasmDownscaleConfig.exact_colors();
181
161
 
182
- // Use only exact source colors
183
- const exact = WasmDownscaleConfig.exact_colors();
184
- ```
185
162
 
186
163
  ## Why Oklab?
187
164
 
188
165
  Traditional RGB-based palette extraction has fundamental problems:
189
166
 
167
+
190
168
  ### The Problem: RGB Averaging Desaturates Colors
191
169
 
192
- ```
193
- Red [255, 0, 0] + Cyan [0, 255, 255]
194
- RGB Average → Gray [127, 127, 127] ❌
195
- ```
170
+ Red [255, 0, 0] + Cyan [0, 255, 255]
171
+ RGB Average Gray [127, 127, 127]
196
172
 
197
173
  When you average colors in RGB space, saturated colors get pulled toward gray. This is why downscaled images often look "washed out" or "tanned."
198
174
 
175
+
199
176
  ### The Solution: Oklab Color Space
200
177
 
201
178
  Oklab is a **perceptually uniform** color space where:
179
+
202
180
  - Euclidean distance = perceived color difference
181
+
203
182
  - Averaging preserves hue and saturation
183
+
204
184
  - Interpolations look natural
205
185
 
206
- ```
207
- Red (Oklab) + Cyan (Oklab)
208
- Oklab Average → Preserves colorfulness ✔
209
- ```
186
+ <!---->
210
187
 
211
- ### Visual Comparison
188
+ Red (Oklab) + Cyan (Oklab)
189
+ Oklab Average → Preserves colorfulness ✔
212
190
 
213
- | Issue | RGB Median Cut | Oklab Median Cut |
214
- |-------|----------------|------------------|
215
- | Saturated colors | Become muddy | Stay vibrant |
216
- | Gradients | Shift in hue | Stay consistent |
217
- | Dark colors | Get darker | Accurate lightness |
218
- | Overall look | Desaturated | True to source |
219
191
 
220
192
  ## API Reference
221
193
 
222
194
  ### WasmDownscaleConfig
223
195
 
224
- ```javascript
225
- const config = new WasmDownscaleConfig();
226
-
227
- // Palette settings
228
- config.palette_size = 16; // Number of output colors
229
- config.palette_strategy = 'oklab'; // 'oklab', 'saturation', 'medoid', 'kmeans', 'legacy'
230
- config.kmeans_iterations = 5; // Refinement iterations
231
-
232
- // Spatial coherence
233
- config.neighbor_weight = 0.3; // [0-1] Prefer neighbor colors
234
- config.region_weight = 0.2; // [0-1] Prefer region colors
235
-
236
- // Refinement
237
- config.two_pass_refinement = true;
238
- config.refinement_iterations = 3;
239
-
240
- // Edge detection
241
- config.edge_weight = 0.5;
196
+ const config = new WasmDownscaleConfig();
242
197
 
243
- // Segmentation
244
- config.segmentation_method = 'hierarchy_fast'; // 'none', 'slic', 'hierarchy', 'hierarchy_fast'
198
+ // Palette settings
199
+ config.palette_size = 16; // Number of output colors
200
+ config.palette_strategy = 'oklab'; // 'oklab', 'saturation', 'medoid', 'kmeans', 'legacy'
201
+ config.kmeans_iterations = 5; // Refinement iterations
245
202
 
246
- // Performance preprocessing
247
- config.max_resolution_mp = 1.5; // Cap resolution at 1.5 megapixels (0 = disabled)
248
- config.max_color_preprocess = 16384; // Pre-quantize to 16K colors max (0 = disabled)
249
- ```
203
+ // Spatial coherence
204
+ config.neighbor_weight = 0.3; // [0-1] Prefer neighbor colors
205
+ config.region_weight = 0.2; // [0-1] Prefer region colors
250
206
 
251
- ### Available Functions
252
-
253
- | Function | Description |
254
- |----------|-------------|
255
- | `downscale(data, w, h, tw, th, config?)` | Main downscale function |
256
- | `downscale_rgba(data, w, h, tw, th, config?)` | For Uint8ClampedArray input |
257
- | `downscale_simple(data, w, h, tw, th, colors)` | Simple API |
258
- | `downscale_with_palette(...)` | Use custom palette |
259
- | `extract_palette_from_image(data, w, h, colors, iters, strategy?)` | Extract palette only |
260
- | `quantize_to_palette(data, w, h, palette)` | Quantize without resizing |
261
- | `get_palette_strategies()` | List available strategies |
262
-
263
- ### WasmDownscaleResult
264
-
265
- ```javascript
266
- result.width // Output width
267
- result.height // Output height
268
- result.data // Uint8ClampedArray (RGBA)
269
- result.rgb_data() // Uint8Array (RGB only)
270
- result.palette // Uint8Array (RGB, 3 bytes per color)
271
- result.indices // Uint8Array (palette index per pixel)
272
- result.palette_size // Number of colors
273
- ```
274
-
275
- ## Command Line Interface
276
-
277
- ```bash
278
- # Basic usage
279
- smart-downscaler input.png output.png -w 64 -h 64
280
-
281
- # With saturation preservation
282
- smart-downscaler input.png output.png -w 64 -h 64 --palette-strategy saturation
283
-
284
- # Using exact source colors only
285
- smart-downscaler input.png output.png -w 64 -h 64 --palette-strategy medoid -p 24
286
-
287
- # Full options
288
- smart-downscaler input.png output.png \
289
- -w 128 -h 128 \
290
- -p 32 \
291
- --palette-strategy saturation \
292
- --segmentation hierarchy-fast \
293
- --neighbor-weight 0.4
294
- ```
295
-
296
- ## Algorithm Details
297
-
298
- ### 0. Preprocessing (v0.3)
299
-
300
- Before main processing, large images are optimized:
301
-
302
- 1. **Resolution Capping**: If pixels > `max_resolution_mp × 1,000,000`:
303
- - Scale factor = sqrt(max_resolution_mp / current_mp)
304
- - Downscale using nearest-neighbor interpolation
305
- - Only downsizes (never upscales)
306
-
307
- 2. **Color Pre-Quantization**: If unique colors > `max_color_preprocess`:
308
- - Build hash-based color histogram
309
- - Apply bit truncation (RGB555 or RGB444)
310
- - Map colors to weighted bucket averages
311
-
312
- ### 1. Palette Extraction (Oklab Median Cut)
207
+ // Refinement
208
+ config.two_pass_refinement = true;
209
+ config.refinement_iterations = 3;
313
210
 
314
- 1. Convert all pixels to Oklab color space
315
- 2. Build weighted color histogram
316
- 3. Apply Median Cut to partition Oklab space
317
- 4. For each bucket, compute centroid in Oklab
318
- 5. Convert centroids back to RGB
319
- 6. Refine with K-Means++ in Oklab space
211
+ // Edge detection
212
+ config.edge_weight = 0.5;
320
213
 
321
- ### 2. Saturation-Weighted Strategy
214
+ // Segmentation
215
+ config.segmentation_method = 'hierarchy_fast'; // 'none', 'slic', 'hierarchy', 'hierarchy_fast'
322
216
 
323
- When using `saturation` strategy:
324
- ```
325
- effective_weight = pixel_count × (1 + chroma × 2)
326
- ```
217
+ // Performance preprocessing
218
+ config.max_resolution_mp = 1.5; // Cap resolution at 1.5 megapixels (0 = disabled)
219
+ config.max_color_preprocess = 16384; // Pre-quantize to 16K colors max (0 = disabled)
327
220
 
328
- This boosts the influence of highly saturated colors during Median Cut partitioning.
221
+ // Tile Logic
222
+ config.k_centroid = 1; // 1=Avg, 2=Dom, 3=Foremost
223
+ config.k_centroid_iterations = 0; // Refine the dominant color
329
224
 
330
- ### 3. Medoid Strategy
331
225
 
332
- Instead of computing centroids (averages), selects the actual image color closest to the centroid. Guarantees output palette contains only exact source colors.
333
-
334
- ### 4. Region Pre-Segmentation
335
-
336
- Before downscaling, identifies coherent regions:
337
- - **SLIC**: Fast, regular superpixels
338
- - **Hierarchy**: Content-aware boundaries
339
- - **Hierarchy Fast**: O(α(n)) union-find
340
-
341
- ### 5. Edge-Aware Tile Computation
342
-
343
- ```
344
- weight(pixel) = 1 / (1 + edge_strength × edge_weight)
345
- ```
346
-
347
- Reduces influence of transitional edge pixels.
348
-
349
- ### 6. Neighbor-Coherent Assignment
350
-
351
- ```
352
- score(color) = oklab_distance(color, tile_avg) × (1 - neighbor_bias - region_bias)
353
- ```
354
-
355
- ## Performance
356
-
357
- Typical performance (single-threaded, with preprocessing enabled):
226
+ ### Available Functions
358
227
 
359
- | Image Size | Target Size | Palette | Time (v0.3) | Time (v0.2) |
360
- |------------|-------------|---------|-------------|-------------|
361
- | 256×256 | 32×32 | 16 | ~40ms | ~50ms |
362
- | 512×512 | 64×64 | 32 | ~150ms | ~200ms |
363
- | 1024×1024 | 128×128 | 32 | ~400ms | ~800ms |
364
- | 2048×2048 | 256×256 | 32 | ~600ms | ~3200ms |
228
+ | Function | Description |
229
+ | ------------------------------------------------------------------ | --------------------------- |
230
+ | `downscale(data, w, h, tw, th, config?)` | Main downscale function |
231
+ | `downscale_rgba(data, w, h, tw, th, config?)` | For Uint8ClampedArray input |
232
+ | `downscale_simple(data, w, h, tw, th, colors)` | Simple API |
233
+ | `downscale_with_palette(...)` | Use custom palette |
234
+ | `extract_palette_from_image(data, w, h, colors, iters, strategy?)` | Extract palette only |
235
+ | `quantize_to_palette(data, w, h, palette)` | Quantize without resizing |
236
+ | `get_palette_strategies()` | List available strategies |
365
237
 
366
- **Note**: Performance improvements are most significant for large images (>1MP) due to resolution capping.
367
238
 
368
- Enable `parallel` feature for multi-threaded processing.
239
+ ### WasmDownscaleResult
369
240
 
370
- ## Configuration Reference
241
+ result.width // Output width
242
+ result.height // Output height
243
+ result.data // Uint8ClampedArray (RGBA)
244
+ result.rgb_data() // Uint8Array (RGB only)
245
+ result.palette // Uint8Array (RGB, 3 bytes per color)
246
+ result.indices // Uint8Array (palette index per pixel)
247
+ result.palette_size // Number of colors
371
248
 
372
- ### DownscaleConfig (Rust)
373
-
374
- | Field | Type | Default | Description |
375
- |-------|------|---------|-------------|
376
- | `palette_size` | usize | 16 | Output colors |
377
- | `palette_strategy` | PaletteStrategy | OklabMedianCut | Extraction method |
378
- | `kmeans_iterations` | usize | 5 | Refinement iterations |
379
- | `neighbor_weight` | f32 | 0.3 | Neighbor coherence |
380
- | `region_weight` | f32 | 0.2 | Region coherence |
381
- | `two_pass_refinement` | bool | true | Enable refinement |
382
- | `refinement_iterations` | usize | 3 | Max iterations |
383
- | `segmentation` | SegmentationMethod | Hierarchy | Pre-segmentation |
384
- | `edge_weight` | f32 | 0.5 | Edge influence |
385
- | `max_resolution_mp` | f32 | 1.5 | Max megapixels before downscale (0 = disabled) |
386
- | `max_color_preprocess` | usize | 16384 | Max unique colors before quantize (0 = disabled) |
387
-
388
- ### PaletteStrategy
389
-
390
- | Value | Description |
391
- |-------|-------------|
392
- | `OklabMedianCut` | Default, best general quality |
393
- | `SaturationWeighted` | Preserves vibrant colors |
394
- | `Medoid` | Exact source colors only |
395
- | `KMeansPlusPlus` | K-Means++ clustering |
396
- | `LegacyRgb` | Original RGB (not recommended) |
397
-
398
- ## Troubleshooting
399
-
400
- ### Colors still look desaturated
401
-
402
- Try increasing palette size or using `saturation` strategy:
403
- ```javascript
404
- config.palette_size = 24; // Up from 16
405
- config.palette_strategy = 'saturation';
406
- ```
407
-
408
- ### Want exact source colors
409
-
410
- Use medoid strategy with no K-Means refinement:
411
- ```javascript
412
- config.palette_strategy = 'medoid';
413
- config.kmeans_iterations = 0;
414
- ```
415
-
416
- ### Output looks noisy
417
-
418
- Increase neighbor weight for smoother results:
419
- ```javascript
420
- config.neighbor_weight = 0.5; // Up from 0.3
421
- config.two_pass_refinement = true;
422
- ```
423
-
424
- ### Processing too slow for large images
425
-
426
- Reduce preprocessing limits:
427
- ```javascript
428
- config.max_resolution_mp = 1.0; // Aggressive cap
429
- config.max_color_preprocess = 8192; // Fewer colors
430
- // Or use the 'fast' preset
431
- const config = WasmDownscaleConfig.fast();
432
- ```
433
-
434
- ### Want maximum quality (ignore performance)
435
-
436
- Disable preprocessing by setting limits to 0:
437
- ```javascript
438
- config.max_resolution_mp = 0; // Disable resolution capping
439
- config.max_color_preprocess = 0; // Disable color pre-quantization
440
- // Or use the 'quality' preset which has higher limits
441
- const config = WasmDownscaleConfig.quality();
442
- ```
443
249
 
444
250
  ## License
445
251
 
446
252
  MIT
447
253
 
254
+
448
255
  ## Credits
449
256
 
450
257
  - Oklab color space by Björn Ottosson
258
+
451
259
  - SLIC superpixel algorithm
260
+
452
261
  - K-Means++ initialization
262
+
453
263
  - VTracer hierarchical clustering approach
264
+
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "Pixagram"
6
6
  ],
7
7
  "description": "Intelligent pixel art downscaler with region-aware color quantization",
8
- "version": "0.3.4",
8
+ "version": "0.3.5",
9
9
  "license": "MIT",
10
10
  "repository": {
11
11
  "type": "git",
@@ -41,140 +41,49 @@ export class ColorEntry {
41
41
  readonly r: number;
42
42
  }
43
43
 
44
- /**
45
- * Configuration options for the downscaler (JavaScript-compatible)
46
- */
47
44
  export class WasmDownscaleConfig {
48
45
  free(): void;
49
46
  [Symbol.dispose](): void;
50
- /**
51
- * Create configuration that uses only exact image colors (medoid)
52
- */
53
47
  static exact_colors(): WasmDownscaleConfig;
54
- /**
55
- * Create configuration optimized for speed
56
- */
57
48
  static fast(): WasmDownscaleConfig;
58
- /**
59
- * Create a new configuration with default values
60
- */
61
49
  constructor();
62
- /**
63
- * Create configuration optimized for quality
64
- */
65
50
  static quality(): WasmDownscaleConfig;
66
- /**
67
- * Create configuration optimized for vibrant colors
68
- */
69
51
  static vibrant(): WasmDownscaleConfig;
70
- /**
71
- * Edge weight in tile color computation (default: 0.5)
72
- */
73
52
  edge_weight: number;
74
- /**
75
- * For hierarchy: minimum region size (default: 4)
76
- */
77
53
  hierarchy_min_size: number;
78
- /**
79
- * For hierarchy: merge threshold (default: 15.0)
80
- */
81
54
  hierarchy_threshold: number;
82
55
  /**
83
- * K-Means iterations for palette refinement (default: 5)
56
+ * Iterations for tile centroid
84
57
  */
85
- kmeans_iterations: number;
58
+ k_centroid_iterations: number;
86
59
  /**
87
- * Maximum unique colors for preprocessing (default: 16384, 0 = disabled)
60
+ * K-Means centroid mode (1=Avg, 2=Dom, 3=Foremost)
88
61
  */
62
+ k_centroid: number;
63
+ kmeans_iterations: number;
89
64
  max_color_preprocess: number;
90
- /**
91
- * Maximum resolution in megapixels for preprocessing (default: 1.5, 0 = disabled)
92
- */
93
65
  max_resolution_mp: number;
94
- /**
95
- * Weight for neighbor color coherence [0.0, 1.0] (default: 0.3)
96
- */
97
66
  neighbor_weight: number;
98
- /**
99
- * Number of colors in the output palette (default: 16)
100
- */
101
67
  palette_size: number;
102
- /**
103
- * Maximum refinement iterations (default: 3)
104
- */
105
68
  refinement_iterations: number;
106
- /**
107
- * Weight for region membership coherence [0.0, 1.0] (default: 0.2)
108
- */
109
69
  region_weight: number;
110
- /**
111
- * For SLIC: compactness factor (default: 10.0)
112
- */
113
70
  slic_compactness: number;
114
- /**
115
- * For SLIC: approximate number of superpixels (default: 100)
116
- */
117
71
  slic_superpixels: number;
118
- /**
119
- * Number of K-Means clusters for local tile refinement (0 or 1 = disabled, average only)
120
- */
121
- tile_kmeans_clusters: number;
122
- /**
123
- * Number of K-Means iterations for local tile refinement
124
- */
125
- tile_kmeans_iterations: number;
126
- /**
127
- * Enable two-pass refinement (default: true)
128
- */
129
72
  two_pass_refinement: boolean;
130
- /**
131
- * Get the palette extraction strategy
132
- */
133
73
  palette_strategy: string;
134
- /**
135
- * Get the segmentation method
136
- */
137
74
  segmentation_method: string;
138
75
  }
139
76
 
140
- /**
141
- * Result of downscaling operation
142
- */
143
77
  export class WasmDownscaleResult {
144
78
  private constructor();
145
79
  free(): void;
146
80
  [Symbol.dispose](): void;
147
- /**
148
- * Get palette color at index as [r, g, b]
149
- */
150
- get_palette_color(index: number): Uint8Array;
151
- /**
152
- * Get RGB pixel data as Uint8Array (without alpha)
153
- */
154
81
  rgb_data(): Uint8Array;
155
- /**
156
- * Get RGBA pixel data as Uint8ClampedArray (for ImageData)
157
- */
158
82
  readonly data: Uint8ClampedArray;
159
- /**
160
- * Get output height
161
- */
162
83
  readonly height: number;
163
- /**
164
- * Get palette indices for each pixel
165
- */
166
84
  readonly indices: Uint8Array;
167
- /**
168
- * Get palette as Uint8Array (RGB, 3 bytes per color)
169
- */
170
85
  readonly palette: Uint8Array;
171
- /**
172
- * Get number of colors in palette
173
- */
174
86
  readonly palette_size: number;
175
- /**
176
- * Get output width
177
- */
178
87
  readonly width: number;
179
88
  }
180
89
 
@@ -197,25 +106,8 @@ export function analyze_colors(image_data: Uint8Array, max_colors: number, sort_
197
106
  */
198
107
  export function color_distance(r1: number, g1: number, b1: number, r2: number, g2: number, b2: number): number;
199
108
 
200
- /**
201
- * Main downscaling function for WebAssembly
202
- *
203
- * # Arguments
204
- * * `image_data` - RGBA pixel data as Uint8Array or Uint8ClampedArray
205
- * * `width` - Source image width
206
- * * `height` - Source image height
207
- * * `target_width` - Output image width
208
- * * `target_height` - Output image height
209
- * * `config` - Optional configuration (uses defaults if not provided)
210
- *
211
- * # Returns
212
- * WasmDownscaleResult containing the downscaled image data
213
- */
214
109
  export function downscale(image_data: Uint8Array, width: number, height: number, target_width: number, target_height: number, config?: WasmDownscaleConfig | null): WasmDownscaleResult;
215
110
 
216
- /**
217
- * Downscale with RGBA input directly from ImageData
218
- */
219
111
  export function downscale_rgba(image_data: Uint8ClampedArray, width: number, height: number, target_width: number, target_height: number, config?: WasmDownscaleConfig | null): WasmDownscaleResult;
220
112
 
221
113
  /**
@@ -223,9 +115,6 @@ export function downscale_rgba(image_data: Uint8ClampedArray, width: number, hei
223
115
  */
224
116
  export function downscale_simple(image_data: Uint8Array, width: number, height: number, target_width: number, target_height: number, num_colors: number): WasmDownscaleResult;
225
117
 
226
- /**
227
- * Downscale with a pre-defined palette
228
- */
229
118
  export function downscale_with_palette(image_data: Uint8Array, width: number, height: number, target_width: number, target_height: number, palette_data: Uint8Array, config?: WasmDownscaleConfig | null): WasmDownscaleResult;
230
119
 
231
120
  /**
@@ -248,9 +137,6 @@ export function get_lightness(r: number, g: number, b: number): number;
248
137
  */
249
138
  export function get_palette_strategies(): Array<any>;
250
139
 
251
- /**
252
- * Initialize panic hook for better error messages in browser console
253
- */
254
140
  export function init(): void;
255
141
 
256
142
  /**
@@ -146,9 +146,6 @@ export class ColorEntry {
146
146
  }
147
147
  if (Symbol.dispose) ColorEntry.prototype[Symbol.dispose] = ColorEntry.prototype.free;
148
148
 
149
- /**
150
- * Configuration options for the downscaler (JavaScript-compatible)
151
- */
152
149
  export class WasmDownscaleConfig {
153
150
  static __wrap(ptr) {
154
151
  ptr = ptr >>> 0;
@@ -168,7 +165,6 @@ export class WasmDownscaleConfig {
168
165
  wasm.__wbg_wasmdownscaleconfig_free(ptr, 0);
169
166
  }
170
167
  /**
171
- * Edge weight in tile color computation (default: 0.5)
172
168
  * @returns {number}
173
169
  */
174
170
  get edge_weight() {
@@ -176,7 +172,6 @@ export class WasmDownscaleConfig {
176
172
  return ret;
177
173
  }
178
174
  /**
179
- * For hierarchy: minimum region size (default: 4)
180
175
  * @returns {number}
181
176
  */
182
177
  get hierarchy_min_size() {
@@ -184,7 +179,6 @@ export class WasmDownscaleConfig {
184
179
  return ret >>> 0;
185
180
  }
186
181
  /**
187
- * For hierarchy: merge threshold (default: 15.0)
188
182
  * @returns {number}
189
183
  */
190
184
  get hierarchy_threshold() {
@@ -192,7 +186,22 @@ export class WasmDownscaleConfig {
192
186
  return ret;
193
187
  }
194
188
  /**
195
- * K-Means iterations for palette refinement (default: 5)
189
+ * Iterations for tile centroid
190
+ * @returns {number}
191
+ */
192
+ get k_centroid_iterations() {
193
+ const ret = wasm.__wbg_get_wasmdownscaleconfig_k_centroid_iterations(this.__wbg_ptr);
194
+ return ret >>> 0;
195
+ }
196
+ /**
197
+ * K-Means centroid mode (1=Avg, 2=Dom, 3=Foremost)
198
+ * @returns {number}
199
+ */
200
+ get k_centroid() {
201
+ const ret = wasm.__wbg_get_wasmdownscaleconfig_k_centroid(this.__wbg_ptr);
202
+ return ret >>> 0;
203
+ }
204
+ /**
196
205
  * @returns {number}
197
206
  */
198
207
  get kmeans_iterations() {
@@ -200,7 +209,6 @@ export class WasmDownscaleConfig {
200
209
  return ret >>> 0;
201
210
  }
202
211
  /**
203
- * Maximum unique colors for preprocessing (default: 16384, 0 = disabled)
204
212
  * @returns {number}
205
213
  */
206
214
  get max_color_preprocess() {
@@ -208,7 +216,6 @@ export class WasmDownscaleConfig {
208
216
  return ret >>> 0;
209
217
  }
210
218
  /**
211
- * Maximum resolution in megapixels for preprocessing (default: 1.5, 0 = disabled)
212
219
  * @returns {number}
213
220
  */
214
221
  get max_resolution_mp() {
@@ -216,7 +223,6 @@ export class WasmDownscaleConfig {
216
223
  return ret;
217
224
  }
218
225
  /**
219
- * Weight for neighbor color coherence [0.0, 1.0] (default: 0.3)
220
226
  * @returns {number}
221
227
  */
222
228
  get neighbor_weight() {
@@ -224,7 +230,6 @@ export class WasmDownscaleConfig {
224
230
  return ret;
225
231
  }
226
232
  /**
227
- * Number of colors in the output palette (default: 16)
228
233
  * @returns {number}
229
234
  */
230
235
  get palette_size() {
@@ -232,7 +237,6 @@ export class WasmDownscaleConfig {
232
237
  return ret >>> 0;
233
238
  }
234
239
  /**
235
- * Maximum refinement iterations (default: 3)
236
240
  * @returns {number}
237
241
  */
238
242
  get refinement_iterations() {
@@ -240,7 +244,6 @@ export class WasmDownscaleConfig {
240
244
  return ret >>> 0;
241
245
  }
242
246
  /**
243
- * Weight for region membership coherence [0.0, 1.0] (default: 0.2)
244
247
  * @returns {number}
245
248
  */
246
249
  get region_weight() {
@@ -248,7 +251,6 @@ export class WasmDownscaleConfig {
248
251
  return ret;
249
252
  }
250
253
  /**
251
- * For SLIC: compactness factor (default: 10.0)
252
254
  * @returns {number}
253
255
  */
254
256
  get slic_compactness() {
@@ -256,7 +258,6 @@ export class WasmDownscaleConfig {
256
258
  return ret;
257
259
  }
258
260
  /**
259
- * For SLIC: approximate number of superpixels (default: 100)
260
261
  * @returns {number}
261
262
  */
262
263
  get slic_superpixels() {
@@ -264,23 +265,6 @@ export class WasmDownscaleConfig {
264
265
  return ret >>> 0;
265
266
  }
266
267
  /**
267
- * Number of K-Means clusters for local tile refinement (0 or 1 = disabled, average only)
268
- * @returns {number}
269
- */
270
- get tile_kmeans_clusters() {
271
- const ret = wasm.__wbg_get_wasmdownscaleconfig_tile_kmeans_clusters(this.__wbg_ptr);
272
- return ret >>> 0;
273
- }
274
- /**
275
- * Number of K-Means iterations for local tile refinement
276
- * @returns {number}
277
- */
278
- get tile_kmeans_iterations() {
279
- const ret = wasm.__wbg_get_wasmdownscaleconfig_tile_kmeans_iterations(this.__wbg_ptr);
280
- return ret >>> 0;
281
- }
282
- /**
283
- * Enable two-pass refinement (default: true)
284
268
  * @returns {boolean}
285
269
  */
286
270
  get two_pass_refinement() {
@@ -288,112 +272,98 @@ export class WasmDownscaleConfig {
288
272
  return ret !== 0;
289
273
  }
290
274
  /**
291
- * Edge weight in tile color computation (default: 0.5)
292
275
  * @param {number} arg0
293
276
  */
294
277
  set edge_weight(arg0) {
295
278
  wasm.__wbg_set_wasmdownscaleconfig_edge_weight(this.__wbg_ptr, arg0);
296
279
  }
297
280
  /**
298
- * For hierarchy: minimum region size (default: 4)
299
281
  * @param {number} arg0
300
282
  */
301
283
  set hierarchy_min_size(arg0) {
302
284
  wasm.__wbg_set_wasmdownscaleconfig_hierarchy_min_size(this.__wbg_ptr, arg0);
303
285
  }
304
286
  /**
305
- * For hierarchy: merge threshold (default: 15.0)
306
287
  * @param {number} arg0
307
288
  */
308
289
  set hierarchy_threshold(arg0) {
309
290
  wasm.__wbg_set_wasmdownscaleconfig_hierarchy_threshold(this.__wbg_ptr, arg0);
310
291
  }
311
292
  /**
312
- * K-Means iterations for palette refinement (default: 5)
293
+ * Iterations for tile centroid
294
+ * @param {number} arg0
295
+ */
296
+ set k_centroid_iterations(arg0) {
297
+ wasm.__wbg_set_wasmdownscaleconfig_k_centroid_iterations(this.__wbg_ptr, arg0);
298
+ }
299
+ /**
300
+ * K-Means centroid mode (1=Avg, 2=Dom, 3=Foremost)
301
+ * @param {number} arg0
302
+ */
303
+ set k_centroid(arg0) {
304
+ wasm.__wbg_set_wasmdownscaleconfig_k_centroid(this.__wbg_ptr, arg0);
305
+ }
306
+ /**
313
307
  * @param {number} arg0
314
308
  */
315
309
  set kmeans_iterations(arg0) {
316
310
  wasm.__wbg_set_wasmdownscaleconfig_kmeans_iterations(this.__wbg_ptr, arg0);
317
311
  }
318
312
  /**
319
- * Maximum unique colors for preprocessing (default: 16384, 0 = disabled)
320
313
  * @param {number} arg0
321
314
  */
322
315
  set max_color_preprocess(arg0) {
323
316
  wasm.__wbg_set_wasmdownscaleconfig_max_color_preprocess(this.__wbg_ptr, arg0);
324
317
  }
325
318
  /**
326
- * Maximum resolution in megapixels for preprocessing (default: 1.5, 0 = disabled)
327
319
  * @param {number} arg0
328
320
  */
329
321
  set max_resolution_mp(arg0) {
330
322
  wasm.__wbg_set_wasmdownscaleconfig_max_resolution_mp(this.__wbg_ptr, arg0);
331
323
  }
332
324
  /**
333
- * Weight for neighbor color coherence [0.0, 1.0] (default: 0.3)
334
325
  * @param {number} arg0
335
326
  */
336
327
  set neighbor_weight(arg0) {
337
328
  wasm.__wbg_set_wasmdownscaleconfig_neighbor_weight(this.__wbg_ptr, arg0);
338
329
  }
339
330
  /**
340
- * Number of colors in the output palette (default: 16)
341
331
  * @param {number} arg0
342
332
  */
343
333
  set palette_size(arg0) {
344
334
  wasm.__wbg_set_wasmdownscaleconfig_palette_size(this.__wbg_ptr, arg0);
345
335
  }
346
336
  /**
347
- * Maximum refinement iterations (default: 3)
348
337
  * @param {number} arg0
349
338
  */
350
339
  set refinement_iterations(arg0) {
351
340
  wasm.__wbg_set_wasmdownscaleconfig_refinement_iterations(this.__wbg_ptr, arg0);
352
341
  }
353
342
  /**
354
- * Weight for region membership coherence [0.0, 1.0] (default: 0.2)
355
343
  * @param {number} arg0
356
344
  */
357
345
  set region_weight(arg0) {
358
346
  wasm.__wbg_set_wasmdownscaleconfig_region_weight(this.__wbg_ptr, arg0);
359
347
  }
360
348
  /**
361
- * For SLIC: compactness factor (default: 10.0)
362
349
  * @param {number} arg0
363
350
  */
364
351
  set slic_compactness(arg0) {
365
352
  wasm.__wbg_set_wasmdownscaleconfig_slic_compactness(this.__wbg_ptr, arg0);
366
353
  }
367
354
  /**
368
- * For SLIC: approximate number of superpixels (default: 100)
369
355
  * @param {number} arg0
370
356
  */
371
357
  set slic_superpixels(arg0) {
372
358
  wasm.__wbg_set_wasmdownscaleconfig_slic_superpixels(this.__wbg_ptr, arg0);
373
359
  }
374
360
  /**
375
- * Number of K-Means clusters for local tile refinement (0 or 1 = disabled, average only)
376
- * @param {number} arg0
377
- */
378
- set tile_kmeans_clusters(arg0) {
379
- wasm.__wbg_set_wasmdownscaleconfig_tile_kmeans_clusters(this.__wbg_ptr, arg0);
380
- }
381
- /**
382
- * Number of K-Means iterations for local tile refinement
383
- * @param {number} arg0
384
- */
385
- set tile_kmeans_iterations(arg0) {
386
- wasm.__wbg_set_wasmdownscaleconfig_tile_kmeans_iterations(this.__wbg_ptr, arg0);
387
- }
388
- /**
389
- * Enable two-pass refinement (default: true)
390
361
  * @param {boolean} arg0
391
362
  */
392
363
  set two_pass_refinement(arg0) {
393
364
  wasm.__wbg_set_wasmdownscaleconfig_two_pass_refinement(this.__wbg_ptr, arg0);
394
365
  }
395
366
  /**
396
- * Create configuration that uses only exact image colors (medoid)
397
367
  * @returns {WasmDownscaleConfig}
398
368
  */
399
369
  static exact_colors() {
@@ -401,16 +371,12 @@ export class WasmDownscaleConfig {
401
371
  return WasmDownscaleConfig.__wrap(ret);
402
372
  }
403
373
  /**
404
- * Create configuration optimized for speed
405
374
  * @returns {WasmDownscaleConfig}
406
375
  */
407
376
  static fast() {
408
377
  const ret = wasm.wasmdownscaleconfig_fast();
409
378
  return WasmDownscaleConfig.__wrap(ret);
410
379
  }
411
- /**
412
- * Create a new configuration with default values
413
- */
414
380
  constructor() {
415
381
  const ret = wasm.wasmdownscaleconfig_new();
416
382
  this.__wbg_ptr = ret >>> 0;
@@ -418,7 +384,6 @@ export class WasmDownscaleConfig {
418
384
  return this;
419
385
  }
420
386
  /**
421
- * Get the palette extraction strategy
422
387
  * @returns {string}
423
388
  */
424
389
  get palette_strategy() {
@@ -434,7 +399,6 @@ export class WasmDownscaleConfig {
434
399
  }
435
400
  }
436
401
  /**
437
- * Create configuration optimized for quality
438
402
  * @returns {WasmDownscaleConfig}
439
403
  */
440
404
  static quality() {
@@ -442,7 +406,6 @@ export class WasmDownscaleConfig {
442
406
  return WasmDownscaleConfig.__wrap(ret);
443
407
  }
444
408
  /**
445
- * Get the segmentation method
446
409
  * @returns {string}
447
410
  */
448
411
  get segmentation_method() {
@@ -458,7 +421,6 @@ export class WasmDownscaleConfig {
458
421
  }
459
422
  }
460
423
  /**
461
- * Set the palette extraction strategy
462
424
  * @param {string} strategy
463
425
  */
464
426
  set palette_strategy(strategy) {
@@ -467,7 +429,6 @@ export class WasmDownscaleConfig {
467
429
  wasm.wasmdownscaleconfig_set_palette_strategy(this.__wbg_ptr, ptr0, len0);
468
430
  }
469
431
  /**
470
- * Set the segmentation method
471
432
  * @param {string} method
472
433
  */
473
434
  set segmentation_method(method) {
@@ -476,7 +437,6 @@ export class WasmDownscaleConfig {
476
437
  wasm.wasmdownscaleconfig_set_segmentation_method(this.__wbg_ptr, ptr0, len0);
477
438
  }
478
439
  /**
479
- * Create configuration optimized for vibrant colors
480
440
  * @returns {WasmDownscaleConfig}
481
441
  */
482
442
  static vibrant() {
@@ -486,9 +446,6 @@ export class WasmDownscaleConfig {
486
446
  }
487
447
  if (Symbol.dispose) WasmDownscaleConfig.prototype[Symbol.dispose] = WasmDownscaleConfig.prototype.free;
488
448
 
489
- /**
490
- * Result of downscaling operation
491
- */
492
449
  export class WasmDownscaleResult {
493
450
  static __wrap(ptr) {
494
451
  ptr = ptr >>> 0;
@@ -508,7 +465,6 @@ export class WasmDownscaleResult {
508
465
  wasm.__wbg_wasmdownscaleresult_free(ptr, 0);
509
466
  }
510
467
  /**
511
- * Get RGBA pixel data as Uint8ClampedArray (for ImageData)
512
468
  * @returns {Uint8ClampedArray}
513
469
  */
514
470
  get data() {
@@ -516,16 +472,6 @@ export class WasmDownscaleResult {
516
472
  return ret;
517
473
  }
518
474
  /**
519
- * Get palette color at index as [r, g, b]
520
- * @param {number} index
521
- * @returns {Uint8Array}
522
- */
523
- get_palette_color(index) {
524
- const ret = wasm.wasmdownscaleresult_get_palette_color(this.__wbg_ptr, index);
525
- return ret;
526
- }
527
- /**
528
- * Get output height
529
475
  * @returns {number}
530
476
  */
531
477
  get height() {
@@ -533,7 +479,6 @@ export class WasmDownscaleResult {
533
479
  return ret >>> 0;
534
480
  }
535
481
  /**
536
- * Get palette indices for each pixel
537
482
  * @returns {Uint8Array}
538
483
  */
539
484
  get indices() {
@@ -541,7 +486,6 @@ export class WasmDownscaleResult {
541
486
  return ret;
542
487
  }
543
488
  /**
544
- * Get palette as Uint8Array (RGB, 3 bytes per color)
545
489
  * @returns {Uint8Array}
546
490
  */
547
491
  get palette() {
@@ -549,7 +493,6 @@ export class WasmDownscaleResult {
549
493
  return ret;
550
494
  }
551
495
  /**
552
- * Get number of colors in palette
553
496
  * @returns {number}
554
497
  */
555
498
  get palette_size() {
@@ -557,7 +500,6 @@ export class WasmDownscaleResult {
557
500
  return ret >>> 0;
558
501
  }
559
502
  /**
560
- * Get RGB pixel data as Uint8Array (without alpha)
561
503
  * @returns {Uint8Array}
562
504
  */
563
505
  rgb_data() {
@@ -565,7 +507,6 @@ export class WasmDownscaleResult {
565
507
  return ret;
566
508
  }
567
509
  /**
568
- * Get output width
569
510
  * @returns {number}
570
511
  */
571
512
  get width() {
@@ -617,18 +558,6 @@ export function color_distance(r1, g1, b1, r2, g2, b2) {
617
558
  }
618
559
 
619
560
  /**
620
- * Main downscaling function for WebAssembly
621
- *
622
- * # Arguments
623
- * * `image_data` - RGBA pixel data as Uint8Array or Uint8ClampedArray
624
- * * `width` - Source image width
625
- * * `height` - Source image height
626
- * * `target_width` - Output image width
627
- * * `target_height` - Output image height
628
- * * `config` - Optional configuration (uses defaults if not provided)
629
- *
630
- * # Returns
631
- * WasmDownscaleResult containing the downscaled image data
632
561
  * @param {Uint8Array} image_data
633
562
  * @param {number} width
634
563
  * @param {number} height
@@ -651,7 +580,6 @@ export function downscale(image_data, width, height, target_width, target_height
651
580
  }
652
581
 
653
582
  /**
654
- * Downscale with RGBA input directly from ImageData
655
583
  * @param {Uint8ClampedArray} image_data
656
584
  * @param {number} width
657
585
  * @param {number} height
@@ -692,7 +620,6 @@ export function downscale_simple(image_data, width, height, target_width, target
692
620
  }
693
621
 
694
622
  /**
695
- * Downscale with a pre-defined palette
696
623
  * @param {Uint8Array} image_data
697
624
  * @param {number} width
698
625
  * @param {number} height
@@ -768,9 +695,6 @@ export function get_palette_strategies() {
768
695
  return ret;
769
696
  }
770
697
 
771
- /**
772
- * Initialize panic hook for better error messages in browser console
773
- */
774
698
  export function init() {
775
699
  wasm.init();
776
700
  }
Binary file