k-centroid-scaler 1.1.0 → 1.2.1
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 +259 -73
- package/k_centroid_scaler.d.ts +103 -0
- package/k_centroid_scaler.js +188 -52
- package/k_centroid_scaler_bg.wasm +0 -0
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -1,22 +1,47 @@
|
|
|
1
|
-
# K-Centroid Image Scaler - WebAssembly Module
|
|
1
|
+
# K-Centroid Image Scaler & Color Quantizer - WebAssembly Module
|
|
2
2
|
|
|
3
|
-
A Rust/WebAssembly implementation of the K-Centroid image downscaling algorithm, converted from the original Lua/Aseprite script.
|
|
3
|
+
A Rust/WebAssembly implementation of the K-Centroid image downscaling algorithm and advanced color quantization tools, converted from the original Lua/Aseprite script.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
### 1. K-Centroid Image Scaling
|
|
8
|
+
Intelligent downscaling using K-means clustering on image tiles to preserve important colors.
|
|
9
|
+
|
|
10
|
+
### 2. Color Quantization
|
|
11
|
+
Two high-quality algorithms for reducing color palettes:
|
|
12
|
+
- **Median Cut**: Best quality, ideal for photographs and complex images
|
|
13
|
+
- **K-Means**: Faster processing, great for graphics and illustrations
|
|
6
14
|
|
|
7
|
-
|
|
15
|
+
### 3. Color Analysis with Spatial Sorting
|
|
16
|
+
Advanced color analysis with multiple sorting algorithms:
|
|
17
|
+
- **Z-Order (Morton)**: Groups similar colors using space-filling curves
|
|
18
|
+
- **Hilbert Curve**: Superior locality preservation for color relationships
|
|
19
|
+
- **Hue-based**: Sort by color wheel position
|
|
20
|
+
- **Luminance**: Sort by brightness
|
|
21
|
+
- **Frequency**: Sort by usage percentage
|
|
8
22
|
|
|
23
|
+
### 4. Dominant Color Extraction
|
|
24
|
+
Automatically identifies and quantizes dominant colors with configurable minimum coverage thresholds.
|
|
25
|
+
|
|
26
|
+
### 5. Palette Extraction
|
|
27
|
+
Extract dominant colors from any image for analysis or design purposes.
|
|
28
|
+
|
|
29
|
+
## Algorithm Overview
|
|
30
|
+
|
|
31
|
+
### K-Centroid Scaling
|
|
9
32
|
1. **Tile Division**: The image is divided into tiles based on the target dimensions
|
|
10
33
|
2. **K-Means Clustering**: Each tile undergoes K-means clustering to identify dominant colors
|
|
11
34
|
3. **Color Selection**: The most dominant color (centroid with most pixels) represents each tile
|
|
12
35
|
4. **Downscaling**: Each pixel in the output image uses the dominant color from its corresponding tile
|
|
13
36
|
|
|
14
|
-
|
|
37
|
+
### Color Quantization
|
|
38
|
+
- **Median Cut**: Recursively divides the color space to find optimal palette
|
|
39
|
+
- **K-Means**: Clusters similar colors together for palette reduction
|
|
40
|
+
- **Floyd-Steinberg Dithering**: Optional error diffusion for smoother gradients
|
|
15
41
|
|
|
16
42
|
## Module Interface
|
|
17
43
|
|
|
18
|
-
###
|
|
19
|
-
|
|
44
|
+
### K-Centroid Resize
|
|
20
45
|
```rust
|
|
21
46
|
k_centroid_resize(
|
|
22
47
|
image_data: &[u8], // RGBA image buffer
|
|
@@ -29,110 +54,271 @@ k_centroid_resize(
|
|
|
29
54
|
) -> ImageResult
|
|
30
55
|
```
|
|
31
56
|
|
|
32
|
-
###
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
57
|
+
### Color Quantization (Median Cut)
|
|
58
|
+
```rust
|
|
59
|
+
quantize_colors_median_cut(
|
|
60
|
+
image_data: &[u8], // RGBA image buffer
|
|
61
|
+
width: u32, // Image width
|
|
62
|
+
height: u32, // Image height
|
|
63
|
+
num_colors: u32, // Target color count (2-256)
|
|
64
|
+
dithering: bool, // Apply Floyd-Steinberg dithering
|
|
65
|
+
) -> ImageResult
|
|
40
66
|
```
|
|
41
67
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
68
|
+
### Color Quantization (K-Means)
|
|
69
|
+
```rust
|
|
70
|
+
quantize_colors_kmeans(
|
|
71
|
+
image_data: &[u8], // RGBA image buffer
|
|
72
|
+
width: u32, // Image width
|
|
73
|
+
height: u32, // Image height
|
|
74
|
+
num_colors: u32, // Target color count (2-256)
|
|
75
|
+
iterations: u32, // K-means iterations
|
|
76
|
+
dithering: bool, // Apply Floyd-Steinberg dithering
|
|
77
|
+
) -> ImageResult
|
|
78
|
+
```
|
|
45
79
|
|
|
46
|
-
|
|
47
|
-
|
|
80
|
+
### Palette Extraction
|
|
81
|
+
```rust
|
|
82
|
+
extract_palette(
|
|
83
|
+
image_data: &[u8], // RGBA image buffer
|
|
84
|
+
max_colors: u32, // Maximum colors to extract
|
|
85
|
+
) -> ColorPalette
|
|
86
|
+
```
|
|
48
87
|
|
|
49
|
-
###
|
|
88
|
+
### Color Analysis with Sorting
|
|
89
|
+
```rust
|
|
90
|
+
analyze_colors(
|
|
91
|
+
image_data: &[u8], // RGBA image buffer
|
|
92
|
+
max_colors: u32, // Maximum colors to return (capped at 256)
|
|
93
|
+
sort_method: &str, // Sorting algorithm
|
|
94
|
+
) -> ColorAnalysis
|
|
95
|
+
```
|
|
50
96
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
97
|
+
**Sort Methods:**
|
|
98
|
+
- `"z-order"` or `"morton"`: Space-filling curve for color grouping
|
|
99
|
+
- `"hilbert"`: Hilbert curve for better locality preservation
|
|
100
|
+
- `"hue"`: Sort by hue value (color wheel position)
|
|
101
|
+
- `"luminance"` or `"brightness"`: Sort by perceived brightness
|
|
102
|
+
- `"frequency"`: Sort by usage percentage (most to least common)
|
|
54
103
|
|
|
55
|
-
|
|
56
|
-
|
|
104
|
+
**Return Structure:**
|
|
105
|
+
```javascript
|
|
106
|
+
{
|
|
107
|
+
colors: [{
|
|
108
|
+
hex: string, // "#RRGGBB" format
|
|
109
|
+
percentage: number, // % of image (0-100)
|
|
110
|
+
count: number, // Pixel count
|
|
111
|
+
r: number, // Red (0-255)
|
|
112
|
+
g: number, // Green (0-255)
|
|
113
|
+
b: number // Blue (0-255)
|
|
114
|
+
}],
|
|
115
|
+
totalColors: number, // Unique colors found
|
|
116
|
+
totalPixels: number // Pixels analyzed
|
|
117
|
+
}
|
|
118
|
+
```
|
|
57
119
|
|
|
58
|
-
|
|
59
|
-
|
|
120
|
+
### Dominant Colors with Auto-Quantization
|
|
121
|
+
```rust
|
|
122
|
+
get_dominant_colors(
|
|
123
|
+
image_data: &[u8], // RGBA image buffer
|
|
124
|
+
num_colors: u32, // Target dominant colors
|
|
125
|
+
min_coverage: f32, // Minimum % coverage threshold
|
|
126
|
+
) -> ColorAnalysis
|
|
60
127
|
```
|
|
61
128
|
|
|
62
|
-
## Usage
|
|
129
|
+
## Usage Examples
|
|
63
130
|
|
|
131
|
+
### Basic Color Quantization
|
|
64
132
|
```javascript
|
|
65
|
-
import init, {
|
|
133
|
+
import init, { quantize_colors_median_cut } from './pkg/k_centroid_scaler.js';
|
|
66
134
|
|
|
67
|
-
async function
|
|
68
|
-
// Initialize the WASM module
|
|
135
|
+
async function reduceColors() {
|
|
69
136
|
await init();
|
|
70
137
|
|
|
71
|
-
// Get
|
|
72
|
-
const canvas = document.getElementById('
|
|
138
|
+
// Get image data
|
|
139
|
+
const canvas = document.getElementById('canvas');
|
|
73
140
|
const ctx = canvas.getContext('2d');
|
|
74
141
|
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
75
142
|
|
|
76
|
-
//
|
|
77
|
-
const result =
|
|
143
|
+
// Reduce to 16 colors with dithering
|
|
144
|
+
const result = quantize_colors_median_cut(
|
|
78
145
|
imageData.data,
|
|
79
146
|
canvas.width,
|
|
80
147
|
canvas.height,
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
4, // 4 centroids per tile
|
|
84
|
-
5 // 5 iterations
|
|
148
|
+
16, // 16 colors
|
|
149
|
+
true // Enable dithering
|
|
85
150
|
);
|
|
86
151
|
|
|
87
|
-
//
|
|
152
|
+
// Display result
|
|
88
153
|
const outputImageData = new ImageData(
|
|
89
154
|
new Uint8ClampedArray(result.data),
|
|
90
155
|
result.width,
|
|
91
156
|
result.height
|
|
92
157
|
);
|
|
158
|
+
ctx.putImageData(outputImageData, 0, 0);
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Complete Processing Pipeline
|
|
163
|
+
```javascript
|
|
164
|
+
async function processImage(imageData, width, height) {
|
|
165
|
+
// Step 1: Downscale
|
|
166
|
+
const scaled = await downscaleImage(
|
|
167
|
+
imageData, width, height,
|
|
168
|
+
width / 2, height / 2,
|
|
169
|
+
{ centroids: 4, iterations: 5 }
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
// Step 2: Quantize colors
|
|
173
|
+
const quantized = await quantizeColorsMedianCut(
|
|
174
|
+
scaled.data,
|
|
175
|
+
scaled.width,
|
|
176
|
+
scaled.height,
|
|
177
|
+
{ numColors: 8, dithering: true }
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
return quantized;
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Extract Color Palette
|
|
185
|
+
```javascript
|
|
186
|
+
async function getPalette(imageData) {
|
|
187
|
+
const palette = await extractColorPalette(imageData, 16);
|
|
188
|
+
console.log(`Found ${palette.count} colors:`, palette.colors);
|
|
189
|
+
// Returns array of {r, g, b} objects
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Analyze Colors with Z-Order Sorting
|
|
194
|
+
```javascript
|
|
195
|
+
async function analyzeColors(imageData) {
|
|
196
|
+
const { analyze_colors } = await init();
|
|
197
|
+
|
|
198
|
+
// Get up to 256 colors sorted by Z-order (groups similar colors)
|
|
199
|
+
const analysis = analyze_colors(imageData, 256, 'z-order');
|
|
200
|
+
|
|
201
|
+
// Access color information
|
|
202
|
+
analysis.colors.forEach(color => {
|
|
203
|
+
console.log(`${color.hex}: ${color.percentage.toFixed(2)}% (${color.count} pixels)`);
|
|
204
|
+
});
|
|
93
205
|
|
|
94
|
-
//
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
outputCtx.putImageData(outputImageData, 0, 0);
|
|
206
|
+
// Generate CSS variables
|
|
207
|
+
const cssVars = analysis.colors
|
|
208
|
+
.slice(0, 10) // Top 10 colors
|
|
209
|
+
.map((c, i) => `--color-${i+1}: ${c.hex};`)
|
|
210
|
+
.join('\n');
|
|
100
211
|
}
|
|
101
212
|
```
|
|
102
213
|
|
|
103
|
-
|
|
214
|
+
### Get Dominant Colors
|
|
215
|
+
```javascript
|
|
216
|
+
async function getDominantPalette(imageData) {
|
|
217
|
+
const { get_dominant_colors } = await init();
|
|
218
|
+
|
|
219
|
+
// Get 16 dominant colors, ignoring colors below 0.1% coverage
|
|
220
|
+
const dominant = get_dominant_colors(imageData, 16, 0.1);
|
|
221
|
+
|
|
222
|
+
// Create HTML palette display
|
|
223
|
+
const paletteHTML = dominant.colors
|
|
224
|
+
.map(c => `
|
|
225
|
+
<div style="display: inline-block;">
|
|
226
|
+
<div style="width: 50px; height: 50px; background: ${c.hex};"></div>
|
|
227
|
+
<small>${c.percentage.toFixed(1)}%</small>
|
|
228
|
+
</div>
|
|
229
|
+
`)
|
|
230
|
+
.join('');
|
|
231
|
+
}
|
|
232
|
+
```
|
|
104
233
|
|
|
105
|
-
###
|
|
106
|
-
|
|
107
|
-
|
|
234
|
+
### Export Color Analysis Results
|
|
235
|
+
```javascript
|
|
236
|
+
// Export as JSON
|
|
237
|
+
const colorData = {
|
|
238
|
+
palette: analysis.colors.map(c => ({
|
|
239
|
+
hex: c.hex,
|
|
240
|
+
rgb: [c.r, c.g, c.b],
|
|
241
|
+
usage: c.percentage
|
|
242
|
+
}))
|
|
243
|
+
};
|
|
108
244
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
245
|
+
// Export as CSS custom properties
|
|
246
|
+
const css = `:root {
|
|
247
|
+
${analysis.colors.slice(0, 20).map((c, i) =>
|
|
248
|
+
` --palette-${i}: ${c.hex}; /* ${c.percentage.toFixed(1)}% */`
|
|
249
|
+
).join('\n')}
|
|
250
|
+
}`;
|
|
112
251
|
|
|
113
|
-
|
|
252
|
+
// Export as SCSS/Sass variables
|
|
253
|
+
const scss = analysis.colors.slice(0, 20)
|
|
254
|
+
.map((c, i) => `$color-${i}: ${c.hex};`)
|
|
255
|
+
.join('\n');
|
|
256
|
+
```
|
|
114
257
|
|
|
115
|
-
|
|
116
|
-
2. **Dominant Color Selection**: Always selects the centroid with the most assigned pixels
|
|
117
|
-
3. **Tile Processing**: Each tile is processed independently, maintaining local color characteristics
|
|
118
|
-
4. **Edge Handling**: Properly handles edge tiles that may be smaller than the standard tile size
|
|
258
|
+
## Parameter Guidelines
|
|
119
259
|
|
|
120
|
-
|
|
260
|
+
### Quantization Method Selection
|
|
261
|
+
- **Median Cut**: Use for photographs, natural images, gradients
|
|
262
|
+
- **K-Means**: Use for graphics, logos, illustrations with flat colors
|
|
121
263
|
|
|
122
|
-
|
|
123
|
-
- **
|
|
124
|
-
- **
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
- Optional wasm-opt post-processing
|
|
264
|
+
### `num_colors` (2-256)
|
|
265
|
+
- **2-4**: Extreme stylization, poster effect
|
|
266
|
+
- **8-16**: Retro gaming aesthetic
|
|
267
|
+
- **32-64**: Good balance of quality and compression
|
|
268
|
+
- **128-256**: Near-original quality with reduced file size
|
|
128
269
|
|
|
129
|
-
|
|
270
|
+
### `dithering` (true/false)
|
|
271
|
+
- **Enable**: For smooth gradients and photographs
|
|
272
|
+
- **Disable**: For pixel art or when crisp edges are needed
|
|
130
273
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
274
|
+
### `iterations` (K-Means only, 1-50)
|
|
275
|
+
- **5-10**: Fast processing, good results
|
|
276
|
+
- **20-30**: Better color accuracy
|
|
277
|
+
- **40-50**: Maximum quality, slower processing
|
|
135
278
|
|
|
136
|
-
##
|
|
279
|
+
## Performance Optimizations
|
|
137
280
|
|
|
138
|
-
|
|
281
|
+
### Algorithm Complexity
|
|
282
|
+
- **Median Cut**: O(n log n) where n = unique colors
|
|
283
|
+
- **K-Means**: O(n × k × i) where n = pixels, k = colors, i = iterations
|
|
284
|
+
- **Dithering**: O(w × h) single pass through image
|
|
285
|
+
|
|
286
|
+
### WebAssembly Optimizations
|
|
287
|
+
- K-means++ initialization for better convergence
|
|
288
|
+
- Weighted color averaging based on pixel frequency
|
|
289
|
+
- Efficient color distance calculations
|
|
290
|
+
- Floyd-Steinberg dithering with minimal memory overhead
|
|
291
|
+
|
|
292
|
+
## Build Instructions
|
|
293
|
+
|
|
294
|
+
### Prerequisites
|
|
295
|
+
- Rust toolchain (`curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh`)
|
|
296
|
+
- wasm-pack (`curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh`)
|
|
297
|
+
|
|
298
|
+
### Building
|
|
299
|
+
```bash
|
|
300
|
+
chmod +x build.sh
|
|
301
|
+
./build.sh
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## Comparison: Quantization Methods
|
|
305
|
+
|
|
306
|
+
| Method | Best For | Speed | Quality | Dithering Support |
|
|
307
|
+
|--------|----------|-------|---------|-------------------|
|
|
308
|
+
| Median Cut | Photos, gradients | Medium | Excellent | Yes |
|
|
309
|
+
| K-Means | Graphics, logos | Fast | Very Good | Yes |
|
|
310
|
+
| K-Centroid Resize | Downscaling | Fast | Good | No |
|
|
311
|
+
|
|
312
|
+
## Advanced Features
|
|
313
|
+
|
|
314
|
+
### Custom Initialization
|
|
315
|
+
The K-means algorithm uses K-means++ initialization for optimal starting centroids, ensuring better convergence and more consistent results.
|
|
316
|
+
|
|
317
|
+
### Weighted Clustering
|
|
318
|
+
Colors are weighted by their frequency in the image, ensuring common colors are better represented in the final palette.
|
|
319
|
+
|
|
320
|
+
### Error Diffusion
|
|
321
|
+
Floyd-Steinberg dithering distributes quantization errors to neighboring pixels, creating smoother gradients with limited colors.
|
|
322
|
+
|
|
323
|
+
## License
|
|
324
|
+
Converted to Rust/WebAssembly for web usage. Original K-Centroid algorithm from Aseprite Lua script.
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
export function get_dominant_colors(image_data: Uint8Array, num_colors: number, min_coverage: number): ColorAnalysis;
|
|
4
|
+
export function k_centroid_resize(image_data: Uint8Array, original_width: number, original_height: number, target_width: number, target_height: number, centroids: number, iterations: number): ImageResult;
|
|
5
|
+
export function process_image(data: Uint8Array, width: number, height: number, target_width: number, target_height: number, centroids: number, iterations: number): any;
|
|
6
|
+
export class Centroid {
|
|
7
|
+
private constructor();
|
|
8
|
+
free(): void;
|
|
9
|
+
[Symbol.dispose](): void;
|
|
10
|
+
}
|
|
11
|
+
export class ColorAnalysis {
|
|
12
|
+
private constructor();
|
|
13
|
+
free(): void;
|
|
14
|
+
[Symbol.dispose](): void;
|
|
15
|
+
total_colors: number;
|
|
16
|
+
total_pixels: number;
|
|
17
|
+
readonly colors: any[];
|
|
18
|
+
}
|
|
19
|
+
export class ColorInfo {
|
|
20
|
+
private constructor();
|
|
21
|
+
free(): void;
|
|
22
|
+
[Symbol.dispose](): void;
|
|
23
|
+
readonly hex: string;
|
|
24
|
+
readonly percentage: number;
|
|
25
|
+
readonly count: number;
|
|
26
|
+
readonly r: number;
|
|
27
|
+
readonly g: number;
|
|
28
|
+
readonly b: number;
|
|
29
|
+
}
|
|
30
|
+
export class ColorPalette {
|
|
31
|
+
private constructor();
|
|
32
|
+
free(): void;
|
|
33
|
+
[Symbol.dispose](): void;
|
|
34
|
+
count: number;
|
|
35
|
+
readonly colors: Uint8Array;
|
|
36
|
+
}
|
|
37
|
+
export class ImageResult {
|
|
38
|
+
private constructor();
|
|
39
|
+
free(): void;
|
|
40
|
+
[Symbol.dispose](): void;
|
|
41
|
+
width: number;
|
|
42
|
+
height: number;
|
|
43
|
+
readonly data: Uint8Array;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
|
47
|
+
|
|
48
|
+
export interface InitOutput {
|
|
49
|
+
readonly memory: WebAssembly.Memory;
|
|
50
|
+
readonly __wbg_imageresult_free: (a: number, b: number) => void;
|
|
51
|
+
readonly imageresult_data: (a: number, b: number) => void;
|
|
52
|
+
readonly __wbg_colorpalette_free: (a: number, b: number) => void;
|
|
53
|
+
readonly __wbg_set_colorpalette_count: (a: number, b: number) => void;
|
|
54
|
+
readonly colorpalette_colors: (a: number, b: number) => void;
|
|
55
|
+
readonly __wbg_colorinfo_free: (a: number, b: number) => void;
|
|
56
|
+
readonly colorinfo_hex: (a: number, b: number) => void;
|
|
57
|
+
readonly colorinfo_percentage: (a: number) => number;
|
|
58
|
+
readonly colorinfo_count: (a: number) => number;
|
|
59
|
+
readonly colorinfo_r: (a: number) => number;
|
|
60
|
+
readonly colorinfo_g: (a: number) => number;
|
|
61
|
+
readonly colorinfo_b: (a: number) => number;
|
|
62
|
+
readonly __wbg_coloranalysis_free: (a: number, b: number) => void;
|
|
63
|
+
readonly __wbg_get_coloranalysis_total_colors: (a: number) => number;
|
|
64
|
+
readonly __wbg_set_coloranalysis_total_colors: (a: number, b: number) => void;
|
|
65
|
+
readonly __wbg_get_coloranalysis_total_pixels: (a: number) => number;
|
|
66
|
+
readonly __wbg_set_coloranalysis_total_pixels: (a: number, b: number) => void;
|
|
67
|
+
readonly coloranalysis_colors: (a: number, b: number) => void;
|
|
68
|
+
readonly get_dominant_colors: (a: number, b: number, c: number, d: number) => number;
|
|
69
|
+
readonly __wbg_centroid_free: (a: number, b: number) => void;
|
|
70
|
+
readonly k_centroid_resize: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => number;
|
|
71
|
+
readonly process_image: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => number;
|
|
72
|
+
readonly __wbg_set_imageresult_width: (a: number, b: number) => void;
|
|
73
|
+
readonly __wbg_set_imageresult_height: (a: number, b: number) => void;
|
|
74
|
+
readonly __wbg_get_colorpalette_count: (a: number) => number;
|
|
75
|
+
readonly __wbg_get_imageresult_height: (a: number) => number;
|
|
76
|
+
readonly __wbg_get_imageresult_width: (a: number) => number;
|
|
77
|
+
readonly __wbindgen_export_0: (a: number) => void;
|
|
78
|
+
readonly __wbindgen_export_1: (a: number, b: number) => number;
|
|
79
|
+
readonly __wbindgen_export_2: (a: number, b: number, c: number, d: number) => number;
|
|
80
|
+
readonly __wbindgen_add_to_stack_pointer: (a: number) => number;
|
|
81
|
+
readonly __wbindgen_export_3: (a: number, b: number, c: number) => void;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export type SyncInitInput = BufferSource | WebAssembly.Module;
|
|
85
|
+
/**
|
|
86
|
+
* Instantiates the given `module`, which can either be bytes or
|
|
87
|
+
* a precompiled `WebAssembly.Module`.
|
|
88
|
+
*
|
|
89
|
+
* @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
|
|
90
|
+
*
|
|
91
|
+
* @returns {InitOutput}
|
|
92
|
+
*/
|
|
93
|
+
export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* If `module_or_path` is {RequestInfo} or {URL}, makes a request and
|
|
97
|
+
* for everything else, calls `WebAssembly.instantiate` directly.
|
|
98
|
+
*
|
|
99
|
+
* @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
|
|
100
|
+
*
|
|
101
|
+
* @returns {Promise<InitOutput>}
|
|
102
|
+
*/
|
|
103
|
+
export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;
|
package/k_centroid_scaler.js
CHANGED
|
@@ -200,6 +200,16 @@ function takeObject(idx) {
|
|
|
200
200
|
return ret;
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
+
function getArrayJsValueFromWasm0(ptr, len) {
|
|
204
|
+
ptr = ptr >>> 0;
|
|
205
|
+
const mem = getDataViewMemory0();
|
|
206
|
+
const result = [];
|
|
207
|
+
for (let i = ptr; i < ptr + 4 * len; i += 4) {
|
|
208
|
+
result.push(takeObject(mem.getUint32(i, true)));
|
|
209
|
+
}
|
|
210
|
+
return result;
|
|
211
|
+
}
|
|
212
|
+
|
|
203
213
|
function passArray8ToWasm0(arg, malloc) {
|
|
204
214
|
const ptr = malloc(arg.length * 1, 1) >>> 0;
|
|
205
215
|
getUint8ArrayMemory0().set(arg, ptr / 1);
|
|
@@ -208,64 +218,34 @@ function passArray8ToWasm0(arg, malloc) {
|
|
|
208
218
|
}
|
|
209
219
|
/**
|
|
210
220
|
* @param {Uint8Array} image_data
|
|
211
|
-
* @param {number} original_width
|
|
212
|
-
* @param {number} original_height
|
|
213
|
-
* @param {number} target_width
|
|
214
|
-
* @param {number} target_height
|
|
215
|
-
* @param {number} centroids
|
|
216
|
-
* @param {number} iterations
|
|
217
|
-
* @returns {ImageResult}
|
|
218
|
-
*/
|
|
219
|
-
export function k_centroid_resize(image_data, original_width, original_height, target_width, target_height, centroids, iterations) {
|
|
220
|
-
const ptr0 = passArray8ToWasm0(image_data, wasm.__wbindgen_export_1);
|
|
221
|
-
const len0 = WASM_VECTOR_LEN;
|
|
222
|
-
const ret = wasm.k_centroid_resize(ptr0, len0, original_width, original_height, target_width, target_height, centroids, iterations);
|
|
223
|
-
return ImageResult.__wrap(ret);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* @param {Uint8Array} image_data
|
|
228
|
-
* @param {number} width
|
|
229
|
-
* @param {number} height
|
|
230
221
|
* @param {number} num_colors
|
|
231
|
-
* @param {
|
|
232
|
-
* @returns {
|
|
222
|
+
* @param {number} min_coverage
|
|
223
|
+
* @returns {ColorAnalysis}
|
|
233
224
|
*/
|
|
234
|
-
export function
|
|
225
|
+
export function get_dominant_colors(image_data, num_colors, min_coverage) {
|
|
235
226
|
const ptr0 = passArray8ToWasm0(image_data, wasm.__wbindgen_export_1);
|
|
236
227
|
const len0 = WASM_VECTOR_LEN;
|
|
237
|
-
const ret = wasm.
|
|
238
|
-
return
|
|
228
|
+
const ret = wasm.get_dominant_colors(ptr0, len0, num_colors, min_coverage);
|
|
229
|
+
return ColorAnalysis.__wrap(ret);
|
|
239
230
|
}
|
|
240
231
|
|
|
241
232
|
/**
|
|
242
233
|
* @param {Uint8Array} image_data
|
|
243
|
-
* @param {number}
|
|
244
|
-
* @param {number}
|
|
245
|
-
* @param {number}
|
|
234
|
+
* @param {number} original_width
|
|
235
|
+
* @param {number} original_height
|
|
236
|
+
* @param {number} target_width
|
|
237
|
+
* @param {number} target_height
|
|
238
|
+
* @param {number} centroids
|
|
246
239
|
* @param {number} iterations
|
|
247
|
-
* @param {boolean} dithering
|
|
248
240
|
* @returns {ImageResult}
|
|
249
241
|
*/
|
|
250
|
-
export function
|
|
242
|
+
export function k_centroid_resize(image_data, original_width, original_height, target_width, target_height, centroids, iterations) {
|
|
251
243
|
const ptr0 = passArray8ToWasm0(image_data, wasm.__wbindgen_export_1);
|
|
252
244
|
const len0 = WASM_VECTOR_LEN;
|
|
253
|
-
const ret = wasm.
|
|
245
|
+
const ret = wasm.k_centroid_resize(ptr0, len0, original_width, original_height, target_width, target_height, centroids, iterations);
|
|
254
246
|
return ImageResult.__wrap(ret);
|
|
255
247
|
}
|
|
256
248
|
|
|
257
|
-
/**
|
|
258
|
-
* @param {Uint8Array} image_data
|
|
259
|
-
* @param {number} max_colors
|
|
260
|
-
* @returns {ColorPalette}
|
|
261
|
-
*/
|
|
262
|
-
export function extract_palette(image_data, max_colors) {
|
|
263
|
-
const ptr0 = passArray8ToWasm0(image_data, wasm.__wbindgen_export_1);
|
|
264
|
-
const len0 = WASM_VECTOR_LEN;
|
|
265
|
-
const ret = wasm.extract_palette(ptr0, len0, max_colors);
|
|
266
|
-
return ColorPalette.__wrap(ret);
|
|
267
|
-
}
|
|
268
|
-
|
|
269
249
|
/**
|
|
270
250
|
* @param {Uint8Array} data
|
|
271
251
|
* @param {number} width
|
|
@@ -283,20 +263,176 @@ export function process_image(data, width, height, target_width, target_height,
|
|
|
283
263
|
return takeObject(ret);
|
|
284
264
|
}
|
|
285
265
|
|
|
286
|
-
const
|
|
266
|
+
const CentroidFinalization = (typeof FinalizationRegistry === 'undefined')
|
|
287
267
|
? { register: () => {}, unregister: () => {} }
|
|
288
|
-
: new FinalizationRegistry(ptr => wasm.
|
|
268
|
+
: new FinalizationRegistry(ptr => wasm.__wbg_centroid_free(ptr >>> 0, 1));
|
|
289
269
|
|
|
290
|
-
export class
|
|
270
|
+
export class Centroid {
|
|
271
|
+
|
|
272
|
+
__destroy_into_raw() {
|
|
273
|
+
const ptr = this.__wbg_ptr;
|
|
274
|
+
this.__wbg_ptr = 0;
|
|
275
|
+
CentroidFinalization.unregister(this);
|
|
276
|
+
return ptr;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
free() {
|
|
280
|
+
const ptr = this.__destroy_into_raw();
|
|
281
|
+
wasm.__wbg_centroid_free(ptr, 0);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
if (Symbol.dispose) Centroid.prototype[Symbol.dispose] = Centroid.prototype.free;
|
|
285
|
+
|
|
286
|
+
const ColorAnalysisFinalization = (typeof FinalizationRegistry === 'undefined')
|
|
287
|
+
? { register: () => {}, unregister: () => {} }
|
|
288
|
+
: new FinalizationRegistry(ptr => wasm.__wbg_coloranalysis_free(ptr >>> 0, 1));
|
|
289
|
+
|
|
290
|
+
export class ColorAnalysis {
|
|
291
291
|
|
|
292
292
|
static __wrap(ptr) {
|
|
293
293
|
ptr = ptr >>> 0;
|
|
294
|
-
const obj = Object.create(
|
|
294
|
+
const obj = Object.create(ColorAnalysis.prototype);
|
|
295
295
|
obj.__wbg_ptr = ptr;
|
|
296
|
-
|
|
296
|
+
ColorAnalysisFinalization.register(obj, obj.__wbg_ptr, obj);
|
|
297
297
|
return obj;
|
|
298
298
|
}
|
|
299
299
|
|
|
300
|
+
__destroy_into_raw() {
|
|
301
|
+
const ptr = this.__wbg_ptr;
|
|
302
|
+
this.__wbg_ptr = 0;
|
|
303
|
+
ColorAnalysisFinalization.unregister(this);
|
|
304
|
+
return ptr;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
free() {
|
|
308
|
+
const ptr = this.__destroy_into_raw();
|
|
309
|
+
wasm.__wbg_coloranalysis_free(ptr, 0);
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* @returns {number}
|
|
313
|
+
*/
|
|
314
|
+
get total_colors() {
|
|
315
|
+
const ret = wasm.__wbg_get_coloranalysis_total_colors(this.__wbg_ptr);
|
|
316
|
+
return ret >>> 0;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* @param {number} arg0
|
|
320
|
+
*/
|
|
321
|
+
set total_colors(arg0) {
|
|
322
|
+
wasm.__wbg_set_coloranalysis_total_colors(this.__wbg_ptr, arg0);
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* @returns {number}
|
|
326
|
+
*/
|
|
327
|
+
get total_pixels() {
|
|
328
|
+
const ret = wasm.__wbg_get_coloranalysis_total_pixels(this.__wbg_ptr);
|
|
329
|
+
return ret >>> 0;
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* @param {number} arg0
|
|
333
|
+
*/
|
|
334
|
+
set total_pixels(arg0) {
|
|
335
|
+
wasm.__wbg_set_coloranalysis_total_pixels(this.__wbg_ptr, arg0);
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* @returns {any[]}
|
|
339
|
+
*/
|
|
340
|
+
get colors() {
|
|
341
|
+
try {
|
|
342
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
343
|
+
wasm.coloranalysis_colors(retptr, this.__wbg_ptr);
|
|
344
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
345
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
346
|
+
var v1 = getArrayJsValueFromWasm0(r0, r1).slice();
|
|
347
|
+
wasm.__wbindgen_export_3(r0, r1 * 4, 4);
|
|
348
|
+
return v1;
|
|
349
|
+
} finally {
|
|
350
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
if (Symbol.dispose) ColorAnalysis.prototype[Symbol.dispose] = ColorAnalysis.prototype.free;
|
|
355
|
+
|
|
356
|
+
const ColorInfoFinalization = (typeof FinalizationRegistry === 'undefined')
|
|
357
|
+
? { register: () => {}, unregister: () => {} }
|
|
358
|
+
: new FinalizationRegistry(ptr => wasm.__wbg_colorinfo_free(ptr >>> 0, 1));
|
|
359
|
+
|
|
360
|
+
export class ColorInfo {
|
|
361
|
+
|
|
362
|
+
__destroy_into_raw() {
|
|
363
|
+
const ptr = this.__wbg_ptr;
|
|
364
|
+
this.__wbg_ptr = 0;
|
|
365
|
+
ColorInfoFinalization.unregister(this);
|
|
366
|
+
return ptr;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
free() {
|
|
370
|
+
const ptr = this.__destroy_into_raw();
|
|
371
|
+
wasm.__wbg_colorinfo_free(ptr, 0);
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* @returns {string}
|
|
375
|
+
*/
|
|
376
|
+
get hex() {
|
|
377
|
+
let deferred1_0;
|
|
378
|
+
let deferred1_1;
|
|
379
|
+
try {
|
|
380
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
381
|
+
wasm.colorinfo_hex(retptr, this.__wbg_ptr);
|
|
382
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
383
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
384
|
+
deferred1_0 = r0;
|
|
385
|
+
deferred1_1 = r1;
|
|
386
|
+
return getStringFromWasm0(r0, r1);
|
|
387
|
+
} finally {
|
|
388
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
389
|
+
wasm.__wbindgen_export_3(deferred1_0, deferred1_1, 1);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* @returns {number}
|
|
394
|
+
*/
|
|
395
|
+
get percentage() {
|
|
396
|
+
const ret = wasm.colorinfo_percentage(this.__wbg_ptr);
|
|
397
|
+
return ret;
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* @returns {number}
|
|
401
|
+
*/
|
|
402
|
+
get count() {
|
|
403
|
+
const ret = wasm.colorinfo_count(this.__wbg_ptr);
|
|
404
|
+
return ret >>> 0;
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* @returns {number}
|
|
408
|
+
*/
|
|
409
|
+
get r() {
|
|
410
|
+
const ret = wasm.colorinfo_r(this.__wbg_ptr);
|
|
411
|
+
return ret;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* @returns {number}
|
|
415
|
+
*/
|
|
416
|
+
get g() {
|
|
417
|
+
const ret = wasm.colorinfo_g(this.__wbg_ptr);
|
|
418
|
+
return ret;
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* @returns {number}
|
|
422
|
+
*/
|
|
423
|
+
get b() {
|
|
424
|
+
const ret = wasm.colorinfo_b(this.__wbg_ptr);
|
|
425
|
+
return ret;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
if (Symbol.dispose) ColorInfo.prototype[Symbol.dispose] = ColorInfo.prototype.free;
|
|
429
|
+
|
|
430
|
+
const ColorPaletteFinalization = (typeof FinalizationRegistry === 'undefined')
|
|
431
|
+
? { register: () => {}, unregister: () => {} }
|
|
432
|
+
: new FinalizationRegistry(ptr => wasm.__wbg_colorpalette_free(ptr >>> 0, 1));
|
|
433
|
+
|
|
434
|
+
export class ColorPalette {
|
|
435
|
+
|
|
300
436
|
__destroy_into_raw() {
|
|
301
437
|
const ptr = this.__wbg_ptr;
|
|
302
438
|
this.__wbg_ptr = 0;
|
|
@@ -312,7 +448,7 @@ export class ColorPalette {
|
|
|
312
448
|
* @returns {number}
|
|
313
449
|
*/
|
|
314
450
|
get count() {
|
|
315
|
-
const ret = wasm.
|
|
451
|
+
const ret = wasm.__wbg_get_coloranalysis_total_colors(this.__wbg_ptr);
|
|
316
452
|
return ret >>> 0;
|
|
317
453
|
}
|
|
318
454
|
/**
|
|
@@ -369,27 +505,27 @@ export class ImageResult {
|
|
|
369
505
|
* @returns {number}
|
|
370
506
|
*/
|
|
371
507
|
get width() {
|
|
372
|
-
const ret = wasm.
|
|
508
|
+
const ret = wasm.__wbg_get_coloranalysis_total_colors(this.__wbg_ptr);
|
|
373
509
|
return ret >>> 0;
|
|
374
510
|
}
|
|
375
511
|
/**
|
|
376
512
|
* @param {number} arg0
|
|
377
513
|
*/
|
|
378
514
|
set width(arg0) {
|
|
379
|
-
wasm.
|
|
515
|
+
wasm.__wbg_set_coloranalysis_total_colors(this.__wbg_ptr, arg0);
|
|
380
516
|
}
|
|
381
517
|
/**
|
|
382
518
|
* @returns {number}
|
|
383
519
|
*/
|
|
384
520
|
get height() {
|
|
385
|
-
const ret = wasm.
|
|
521
|
+
const ret = wasm.__wbg_get_coloranalysis_total_pixels(this.__wbg_ptr);
|
|
386
522
|
return ret >>> 0;
|
|
387
523
|
}
|
|
388
524
|
/**
|
|
389
525
|
* @param {number} arg0
|
|
390
526
|
*/
|
|
391
527
|
set height(arg0) {
|
|
392
|
-
wasm.
|
|
528
|
+
wasm.__wbg_set_coloranalysis_total_pixels(this.__wbg_ptr, arg0);
|
|
393
529
|
}
|
|
394
530
|
/**
|
|
395
531
|
* @returns {Uint8Array}
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "k-centroid-scaler",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.1
|
|
4
|
+
"version": "1.2.1",
|
|
5
5
|
"files": [
|
|
6
6
|
"k_centroid_scaler_bg.wasm",
|
|
7
|
-
"k_centroid_scaler.js"
|
|
7
|
+
"k_centroid_scaler.js",
|
|
8
|
+
"k_centroid_scaler.d.ts"
|
|
8
9
|
],
|
|
9
10
|
"main": "k_centroid_scaler.js",
|
|
11
|
+
"types": "k_centroid_scaler.d.ts",
|
|
10
12
|
"sideEffects": [
|
|
11
13
|
"./snippets/*"
|
|
12
14
|
]
|