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 +150 -339
- package/package.json +1 -1
- package/smart_downscaler.d.ts +5 -119
- package/smart_downscaler_bg.js +30 -106
- package/smart_downscaler_bg.wasm +0 -0
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.
|
|
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
|
-
|
|
8
|
+
## What's New in v0.3.5
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
### ⚡ Performance: Direct LUT Optimization
|
|
12
11
|
|
|
13
|
-
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
20
|
+
**Key Optimizations:**
|
|
25
21
|
|
|
26
|
-
1. **
|
|
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. **
|
|
24
|
+
2. **RGBA-Only Preprocessing**: Resolution capping and quantization now happen strictly in RGBA space before any expensive Oklab math.
|
|
29
25
|
|
|
30
|
-
3. **
|
|
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
|
-
|
|
28
|
+
<!---->
|
|
33
29
|
|
|
34
|
-
|
|
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
|
-
|
|
35
|
+
### 🎯 K-Centroid Tile Logic
|
|
39
36
|
|
|
40
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
|
60
|
-
|
|
|
61
|
-
| `
|
|
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
|
-
|
|
84
|
-
|
|
85
|
-
smart-downscaler = "0.3"
|
|
86
|
-
```
|
|
103
|
+
[dependencies]
|
|
104
|
+
smart-downscaler = "0.3.5"
|
|
87
105
|
|
|
88
|
-
### WebAssembly (npm)
|
|
89
106
|
|
|
90
|
-
|
|
91
|
-
npm install smart-downscaler
|
|
92
|
-
```
|
|
107
|
+
### WebAssembly (npm)
|
|
93
108
|
|
|
94
|
-
|
|
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
|
-
|
|
135
|
-
|
|
116
|
+
import init, { WasmDownscaleConfig, downscale_rgba } from 'smart-downscaler';
|
|
117
|
+
|
|
118
|
+
await init();
|
|
136
119
|
|
|
137
|
-
|
|
120
|
+
// Create config
|
|
121
|
+
const config = new WasmDownscaleConfig();
|
|
138
122
|
|
|
139
|
-
|
|
140
|
-
|
|
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
|
-
//
|
|
143
|
-
|
|
144
|
-
config.
|
|
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
|
-
//
|
|
147
|
-
config.
|
|
148
|
-
config.
|
|
131
|
+
// Standard settings
|
|
132
|
+
config.palette_size = 16;
|
|
133
|
+
config.palette_strategy = 'oklab';
|
|
149
134
|
|
|
150
|
-
//
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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
|
-
|
|
173
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
244
|
-
config.
|
|
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
|
-
//
|
|
247
|
-
config.
|
|
248
|
-
config.
|
|
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
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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
|
-
|
|
315
|
-
|
|
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
|
-
|
|
214
|
+
// Segmentation
|
|
215
|
+
config.segmentation_method = 'hierarchy_fast'; // 'none', 'slic', 'hierarchy', 'hierarchy_fast'
|
|
322
216
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
|
360
|
-
|
|
361
|
-
|
|
|
362
|
-
|
|
|
363
|
-
|
|
|
364
|
-
|
|
|
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
|
-
|
|
239
|
+
### WasmDownscaleResult
|
|
369
240
|
|
|
370
|
-
|
|
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
package/smart_downscaler.d.ts
CHANGED
|
@@ -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
|
-
*
|
|
56
|
+
* Iterations for tile centroid
|
|
84
57
|
*/
|
|
85
|
-
|
|
58
|
+
k_centroid_iterations: number;
|
|
86
59
|
/**
|
|
87
|
-
*
|
|
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
|
/**
|
package/smart_downscaler_bg.js
CHANGED
|
@@ -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
|
-
*
|
|
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
|
-
*
|
|
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
|
}
|
package/smart_downscaler_bg.wasm
CHANGED
|
Binary file
|