@xprite/pixelate 0.0.0-stage → 0.1.0

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.
Files changed (110) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +12 -0
  3. package/README.md +238 -2
  4. package/README.zh-CN.md +209 -0
  5. package/dist/analyze.d.ts +8 -0
  6. package/dist/analyze.js +217 -0
  7. package/dist/base.d.ts +18 -0
  8. package/dist/base.js +42 -0
  9. package/dist/cell-color-picker.d.ts +14 -0
  10. package/dist/cell-color-picker.js +278 -0
  11. package/dist/color-lab.d.ts +3 -0
  12. package/dist/color-lab.js +31 -0
  13. package/dist/color-step.d.ts +33 -0
  14. package/dist/color-step.js +62 -0
  15. package/dist/contours.d.ts +4 -0
  16. package/dist/contours.js +66 -0
  17. package/dist/denoise.d.ts +3 -0
  18. package/dist/denoise.js +37 -0
  19. package/dist/deskew.d.ts +24 -0
  20. package/dist/deskew.js +202 -0
  21. package/dist/grid-ac-rl-consensus.d.ts +127 -0
  22. package/dist/grid-ac-rl-consensus.js +497 -0
  23. package/dist/grid-arbitrate.d.ts +52 -0
  24. package/dist/grid-arbitrate.js +366 -0
  25. package/dist/grid-cut-snap.d.ts +15 -0
  26. package/dist/grid-cut-snap.js +77 -0
  27. package/dist/grid-description-length.d.ts +47 -0
  28. package/dist/grid-description-length.js +697 -0
  29. package/dist/grid-detect.d.ts +8 -0
  30. package/dist/grid-detect.js +665 -0
  31. package/dist/grid-edge-coherence.d.ts +4 -0
  32. package/dist/grid-edge-coherence.js +158 -0
  33. package/dist/grid-edge-path.d.ts +9 -0
  34. package/dist/grid-edge-path.js +201 -0
  35. package/dist/grid-frame-lattice.d.ts +25 -0
  36. package/dist/grid-frame-lattice.js +420 -0
  37. package/dist/grid-frequency-spectrum.d.ts +11 -0
  38. package/dist/grid-frequency-spectrum.js +89 -0
  39. package/dist/grid-period-boundary.d.ts +13 -0
  40. package/dist/grid-period-boundary.js +255 -0
  41. package/dist/grid-period-comb.d.ts +4 -0
  42. package/dist/grid-period-comb.js +230 -0
  43. package/dist/grid-period-distance.d.ts +7 -0
  44. package/dist/grid-period-distance.js +233 -0
  45. package/dist/grid-phase-field.d.ts +11 -0
  46. package/dist/grid-phase-field.js +446 -0
  47. package/dist/grid-pitch-lattice.d.ts +4 -0
  48. package/dist/grid-pitch-lattice.js +255 -0
  49. package/dist/grid-pitch-search.d.ts +11 -0
  50. package/dist/grid-pitch-search.js +233 -0
  51. package/dist/grid-sample.d.ts +4 -0
  52. package/dist/grid-sample.js +164 -0
  53. package/dist/grid-sampling.d.ts +13 -0
  54. package/dist/grid-sampling.js +132 -0
  55. package/dist/grid-strip-shift.d.ts +44 -0
  56. package/dist/grid-strip-shift.js +223 -0
  57. package/dist/grid-test-images.d.ts +69 -0
  58. package/dist/grid-test-images.js +547 -0
  59. package/dist/grid-warp.d.ts +38 -0
  60. package/dist/grid-warp.js +252 -0
  61. package/dist/grid.d.ts +8 -0
  62. package/dist/grid.js +43 -0
  63. package/dist/index.d.ts +16 -0
  64. package/dist/index.js +14 -0
  65. package/dist/line-guided/cv-lab.d.ts +4 -0
  66. package/dist/line-guided/cv-lab.js +134 -0
  67. package/dist/line-guided/cv-ops.d.ts +29 -0
  68. package/dist/line-guided/cv-ops.js +759 -0
  69. package/dist/line-guided/pixeloe-entry.d.ts +15 -0
  70. package/dist/line-guided/pixeloe-entry.js +122 -0
  71. package/dist/line-guided/pixeloe-legacy.d.ts +31 -0
  72. package/dist/line-guided/pixeloe-legacy.js +301 -0
  73. package/dist/line-guided/xdog.d.ts +7 -0
  74. package/dist/line-guided/xdog.js +84 -0
  75. package/dist/most-frequent.d.ts +3 -0
  76. package/dist/most-frequent.js +56 -0
  77. package/dist/outline-prepass.d.ts +37 -0
  78. package/dist/outline-prepass.js +56 -0
  79. package/dist/palette-snap.d.ts +4 -0
  80. package/dist/palette-snap.js +371 -0
  81. package/dist/palette.d.ts +21 -0
  82. package/dist/palette.js +280 -0
  83. package/dist/pixelate.d.ts +15 -0
  84. package/dist/pixelate.js +214 -0
  85. package/dist/pixelation-algorithm-registry.d.ts +34 -0
  86. package/dist/pixelation-algorithm-registry.js +716 -0
  87. package/dist/pixeloe-prepass.d.ts +12 -0
  88. package/dist/pixeloe-prepass.js +527 -0
  89. package/dist/quantization.d.ts +6 -0
  90. package/dist/quantization.js +145 -0
  91. package/dist/remove-background.d.ts +40 -0
  92. package/dist/remove-background.js +229 -0
  93. package/dist/resize.d.ts +3 -0
  94. package/dist/resize.js +86 -0
  95. package/dist/sampling.d.ts +7 -0
  96. package/dist/sampling.js +301 -0
  97. package/dist/settings.d.ts +36 -0
  98. package/dist/settings.js +181 -0
  99. package/dist/types.d.ts +255 -0
  100. package/dist/types.js +87 -0
  101. package/licenses/PixelOE-Apache-2.0.txt +201 -0
  102. package/licenses/pixel-art-fixer-MIT.txt +21 -0
  103. package/licenses/proper-pixel-art-MIT.txt +21 -0
  104. package/licenses/tensorhead-dithering-MIT.txt +21 -0
  105. package/package.json +62 -4
  106. package/wasm/ac-rl-detect-browser-worker.js +45 -0
  107. package/wasm/ac-rl-detect-worker.mjs +51 -0
  108. package/wasm/pixelfixer_detect.d.ts +65 -0
  109. package/wasm/pixelfixer_detect.js +334 -0
  110. package/wasm/pixelfixer_detect_bg.wasm +0 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 rhinoc
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/NOTICE.md ADDED
@@ -0,0 +1,12 @@
1
+ # Third-party notices
2
+
3
+ | Part | Source | License | Text |
4
+ | --- | --- | --- | --- |
5
+ | `wasm/` and `wasm-src/`: AC+RL grid-count consensus (`acf`, `autocorr`, `runlengths`, `gray`, `sigproc`), made sequential and compiled to WebAssembly | [Retro-Diffusion/pixel-art-fixer](https://github.com/Retro-Diffusion/pixel-art-fixer), Copyright (c) 2026 Astropulse, LLC | MIT | [licenses/pixel-art-fixer-MIT.txt](licenses/pixel-art-fixer-MIT.txt) |
6
+ | `src/line-guided/pixeloe-legacy.ts`, `cv-ops.ts`, `cv-lab.ts`: port of PixelOE's legacy `pixelize()` | [KohakuBlueleaf/PixelOE](https://github.com/KohakuBlueleaf/PixelOE) | Apache-2.0 | [licenses/PixelOE-Apache-2.0.txt](licenses/PixelOE-Apache-2.0.txt) |
7
+ | `src/pixeloe-prepass.ts`: port of PixelOE's outline expansion and colour match (`torch/outline.py`, `torch/color.py`); `src/cell-color-picker.ts`: its contrast-based downscale | [KohakuBlueleaf/PixelOE](https://github.com/KohakuBlueleaf/PixelOE) | Apache-2.0 | [licenses/PixelOE-Apache-2.0.txt](licenses/PixelOE-Apache-2.0.txt) |
8
+ | `src/grid-detect.ts`: the edge-mesh idea (anchor cuts on projected edges, fill gaps at an even pitch); `src/cell-color-picker.ts`: per-cell colour choice and output colour merging | [KennethJAllen/proper-pixel-art](https://github.com/KennethJAllen/proper-pixel-art), Copyright (c) 2024 Kenneth Allen | MIT | [licenses/proper-pixel-art-MIT.txt](licenses/proper-pixel-art-MIT.txt) |
9
+ | `src/palette-snap.ts`: Bayer 8x8 matrix and ordered dithering to a palette (`matrices.rs`, `ordered.rs`) | [tensorhead/dithering](https://github.com/tensorhead/dithering) | MIT | [licenses/tensorhead-dithering-MIT.txt](licenses/tensorhead-dithering-MIT.txt) |
10
+
11
+ The PixelOE ports are modified versions: they were rewritten from Python, OpenCV and NumPy into
12
+ TypeScript, and the legacy port's expansion weight can be replaced by a line guide.
package/README.md CHANGED
@@ -1,3 +1,239 @@
1
- # Temporary Holding Version
1
+ # @xprite/pixelate
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [![npm](https://img.shields.io/npm/v/@xprite/pixelate)](https://www.npmjs.com/package/@xprite/pixelate)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
5
+
6
+ English | [简体中文](https://github.com/rhinoc/xprite-pixelate/blob/main/README.zh-CN.md)
7
+
8
+ | AI-generated, 887×887 | Recovered grid | Real pixel art, 48×49 |
9
+ | :---: | :---: | :---: |
10
+ | ![Input](docs/images/griffith-input.png) | ![Grid](docs/images/griffith-mesh.png) | ![Result](docs/images/griffith-result.png) |
11
+
12
+ ## Summary
13
+
14
+ Image generators draw "pixel art" with soft edges, noise, half-transparent outlines and cells of
15
+ uneven width. This package finds the real pixel grid in such an image and gives back one clean
16
+ pixel per cell. It also turns ordinary images into pixel art.
17
+
18
+ It runs in browsers and Node and has no runtime dependencies. One WebAssembly module ships inside
19
+ the package. It is the importer of the [Xprite](https://xprite.cc) pixel editor.
20
+
21
+ ## Contents
22
+
23
+ - [Examples](#examples)
24
+ - [Compared with other tools](#compared-with-other-tools)
25
+ - [Install](#install)
26
+ - [Usage](#usage)
27
+ - [How it works](#how-it-works)
28
+ - [Benchmark](#benchmark)
29
+ - [License](#license)
30
+
31
+ ## Examples
32
+
33
+ These inputs come from the benchmark's AI suite: CC0 pixel art rendered the way generators fake
34
+ it. Each result has exactly the size of the original art.
35
+
36
+ ### Two sprites on one canvas
37
+
38
+ - Goblins by LuizMelo ([Monsters Creatures Fantasy](https://luizmelo.itch.io/monsters-creatures-fantasy), CC0)
39
+
40
+ | Input, 1800×845 | Recovered grid | Result, 103×49 |
41
+ | :---: | :---: | :---: |
42
+ | ![Input](docs/images/goblins-input.png) | ![Grid](docs/images/goblins-mesh.png) | ![Result](docs/images/goblins-result.png) |
43
+
44
+ ### Painterly shading inside cells
45
+
46
+ - Naga mage from [Dungeon Crawl Stone Soup tiles](https://github.com/crawl/tiles) (CC0)
47
+
48
+ | Input, 411×425 | Recovered grid | Result, 50×50 |
49
+ | :---: | :---: | :---: |
50
+ | ![Input](docs/images/naga-input.png) | ![Grid](docs/images/naga-mesh.png) | ![Result](docs/images/naga-result.png) |
51
+
52
+ ### Cells that drift and jitter
53
+
54
+ - Monster by Denzi ([Denzi's public domain art](https://opengameart.org/content/denzis-public-domain-art), CC0)
55
+
56
+ | Input, 606×924 | Recovered grid | Result, 45×67 |
57
+ | :---: | :---: | :---: |
58
+ | ![Input](docs/images/wobble-input.png) | ![Grid](docs/images/wobble-mesh.png) | ![Result](docs/images/wobble-result.png) |
59
+
60
+ ### Small cells and WebP damage
61
+
62
+ - Old man by ansimuz ([Gothicvania Town](https://opengameart.org/content/gothicvania-town), CC0)
63
+
64
+ | Input, 250×380 | Recovered grid | Result, 39×57 |
65
+ | :---: | :---: | :---: |
66
+ | ![Input](docs/images/oldman-input.png) | ![Grid](docs/images/oldman-mesh.png) | ![Result](docs/images/oldman-result.png) |
67
+
68
+ ## Compared with other tools
69
+
70
+ The image at the top, recovered by each tool with its default settings:
71
+
72
+ | Xprite Auto, 48×49 | [pixel-art-fixer](https://github.com/Retro-Diffusion/pixel-art-fixer), 47×48 | [perfectPixel](https://github.com/theamusing/perfectPixel), 50×50 | [proper-pixel-art](https://github.com/KennethJAllen/proper-pixel-art), 53×54 |
73
+ | :---: | :---: | :---: | :---: |
74
+ | ![Xprite](docs/images/griffith-result.png) | ![pixel-art-fixer](docs/images/griffith-fixer.png) | ![perfectPixel](docs/images/griffith-perfectpixel.png) | ![proper-pixel-art](docs/images/griffith-proper.png) |
75
+
76
+ The cells of this image are 15 to 21 px wide, so a grid of even cells cuts through drawn pixels
77
+ somewhere. Xprite puts each cut on a colour edge. The [Benchmark](#benchmark) section has scores
78
+ on 1746 cases.
79
+
80
+ ## Install
81
+
82
+ ```bash
83
+ npm install @xprite/pixelate
84
+ ```
85
+
86
+ ## Usage
87
+
88
+ An image is `{ width, height, data }`, where `data` holds RGBA bytes, row by row, with straight
89
+ alpha. `ImageData` from a canvas has this shape.
90
+
91
+ ### Recover a grid
92
+
93
+ ```ts
94
+ import {
95
+ CellColorPicker,
96
+ PixelationAlgorithm,
97
+ PixelationMode,
98
+ detectWithAlgorithm,
99
+ pixelateImage,
100
+ preloadWasm,
101
+ } from "@xprite/pixelate";
102
+
103
+ await preloadWasm(); // optional: loads the grid-count detector once, before the first image
104
+
105
+ const image = { width, height, data: new Uint8ClampedArray(rgba) };
106
+
107
+ const grid = detectWithAlgorithm(image, PixelationAlgorithm.Auto);
108
+ if (grid.reliable) {
109
+ const art = pixelateImage(image, {
110
+ mode: PixelationMode.RecoverGrid,
111
+ grid,
112
+ colorPicker: CellColorPicker.TwoStage,
113
+ paletteSnap: { adaptive: true }, // merge the near-shades a generator leaves behind
114
+ });
115
+ // art.width × art.height is the native size: one pixel per recovered cell.
116
+ }
117
+ ```
118
+
119
+ `grid.reliable` is false when the image has no consistent grid (a photo, a drawing, or real 1×
120
+ pixel art). `RecoverGrid` mode throws an error for such a grid. Use `Convert` mode for those
121
+ images.
122
+
123
+ ### Convert an image
124
+
125
+ ```ts
126
+ const art = pixelateImage(photo, {
127
+ mode: PixelationMode.Convert,
128
+ targetSize: { width: 64, height: 64 },
129
+ paletteSnap: { colors: 16 },
130
+ });
131
+ ```
132
+
133
+ ### Remove a flat background
134
+
135
+ ```ts
136
+ import { removeBackground } from "@xprite/pixelate";
137
+
138
+ const clear = removeBackground(image); // keys the most common border colour
139
+ ```
140
+
141
+ Call it before detection when a generator painted a white or checkerboard background.
142
+
143
+ ### Options
144
+
145
+ `pixelateImage(image, options)`:
146
+
147
+ | Option | Description |
148
+ | --- | --- |
149
+ | `mode` | `RecoverGrid` uses a detected grid. `Convert` makes pixel art at a size you give. |
150
+ | `grid` | A grid from `detectWithAlgorithm`. If you omit it, the grid is detected with `algorithm`. |
151
+ | `algorithm` | Grid detector. `Auto` runs all of them and picks one grid. |
152
+ | `colorPicker` | Colour rule per cell: `TwoStage`, `MostCommon` (default), `Median`, `Average`, `KMeans`, `Contrast` and others. |
153
+ | `targetSize`, `targetWidth`, `targetHeight`, `blockSize` | Output size in `Convert` mode. |
154
+ | `paletteSnap` | Limit colours: `{ adaptive: true }`, `{ colors: 16 }` or `{ palette: [...] }`, with optional `dither`. |
155
+ | `prepass` | Outline pre-pass from PixelOE (`Pixeloe`, `PixeloeLines`). |
156
+ | `removeNoise` | Light smoothing of similar neighbour colours. |
157
+ | `preserveDimensions` | Scale the result back up to the source size, nearest neighbour. |
158
+
159
+ [`src/types.ts`](src/types.ts) documents every option.
160
+
161
+ ### Workers
162
+
163
+ `detectWithAlgorithm` and `pixelateImage` are synchronous and can take a few seconds on large
164
+ images, so run them in a Web Worker. In a browser, Auto can also run its grid-count detector in a
165
+ nested worker, in parallel with the other detectors:
166
+
167
+ ```ts
168
+ import { setAcRlBrowserWorkerFactory, detectWithAlgorithmAsync } from "@xprite/pixelate";
169
+
170
+ setAcRlBrowserWorkerFactory(
171
+ () =>
172
+ new Worker(
173
+ new URL("@xprite/pixelate/wasm/ac-rl-detect-browser-worker.js", import.meta.url),
174
+ { type: "module" },
175
+ ),
176
+ );
177
+ const grid = await detectWithAlgorithmAsync(image);
178
+ ```
179
+
180
+ In Node, the detector starts a `worker_threads` worker from `wasm/ac-rl-detect-worker.mjs` by
181
+ itself. Set `XPRITE_AC_RL_WORKER=0` to keep it on the calling thread.
182
+
183
+ ## How it works
184
+
185
+ 1. **Straighten.** Auto estimates the tilt. When the tilt is clear, it detects on a straightened
186
+ copy.
187
+ 2. **Propose.** Seven detectors propose grids: uniform grid, edge grid, frame lattice, pitch
188
+ lattice, colour period, border runs and edge spacing. A WebAssembly port of pixel-art-fixer's
189
+ autocorrelation and run-length vote gives an independent cell count.
190
+ 3. **Follow the edges.** At each pitch the detectors keep, a dynamic program walks each axis and
191
+ puts every cut on a colour edge. Each cell stays within 0.75 to 1.25 of the pitch, and a change
192
+ of width costs extra. This step handles cells of uneven width.
193
+ 4. **Filter.** A candidate is dropped when its cuts miss the colour edges that a coarser grid
194
+ follows.
195
+ 5. **Choose.** The grid that describes the image in the fewest bits wins (minimum description
196
+ length). A grid that is not locked to the content's phase pays a penalty. Drift and sheared
197
+ rows are read as strip shifts or as a phase field.
198
+ 6. **Sample.** Each cell gets one colour (`TwoStage` packs the cell's colours in two steps).
199
+ Adaptive palette snapping then merges near-duplicate shades.
200
+ 7. **Settle alpha.** Cells that the art covers become fully opaque, and cells outside the art
201
+ become clear.
202
+
203
+ Each source file in [`src/`](src) describes its step.
204
+
205
+ ## Benchmark
206
+
207
+ [`bench/`](bench) compares this package with three other tools on CC0 native pixel art. The
208
+ benchmark damages the art in known ways and scores each result against the original. Every tool
209
+ runs with its default settings.
210
+
211
+ AI suite (1746 cases rendered the way generators fake pixel art):
212
+
213
+ | Method | Exact size | Within 1 cell | Pixel match | ΔE | Half-transparent fringe | Median time |
214
+ | --- | --- | --- | --- | --- | --- | --- |
215
+ | Xprite Auto | **83.6%** | **90.0%** | **99.8%** | 0.82 | 0.1% | 1.55 s |
216
+ | pixel-art-fixer | 49.7% | 80.9% | 98.3% | 1.74 | 0.0% | 0.18 s |
217
+ | perfectPixel | 53.3% | 68.0% | 96.7% | 2.42 | - | 0.03 s |
218
+ | proper-pixel-art | 72.2% | 80.4% | 99.7% | **0.64** | 0.0% | 0.49 s |
219
+
220
+ [pixel-bench](https://github.com/Retro-Diffusion/pixel-bench) suite v1 (7651 cases of upscales and
221
+ lossy pipelines):
222
+
223
+ | Method | Exact size | Within 1 cell | Pixel match | ΔE | Median time |
224
+ | --- | --- | --- | --- | --- | --- |
225
+ | Xprite Auto | **87.1%** | **90.1%** | 94.3% | **2.79** | 0.24 s |
226
+ | pixel-art-fixer | 77.8% | 83.5% | **94.4%** | 2.83 | 0.04 s |
227
+ | perfectPixel | 24.2% | 32.9% | 89.7% | 4.31 | 0.002 s |
228
+ | proper-pixel-art | 16.5% | 28.6% | 93.0% | 3.85 | 0.05 s |
229
+
230
+ Pixel match and ΔE are measured only on the cases with the exact size. Xprite is the slowest of
231
+ the four tools. The damage is synthetic, so the scores show how the tools rank on these features,
232
+ not how often they succeed on real images. [bench/README.md](bench/README.md) gives the method,
233
+ the categories and the steps to run it.
234
+
235
+ ## License
236
+
237
+ MIT. Parts are adapted from pixel-art-fixer, PixelOE, proper-pixel-art and tensorhead/dithering
238
+ (see [NOTICE.md](NOTICE.md)). The example art is CC0 (see
239
+ [bench/corpus/CREDITS.md](bench/corpus/CREDITS.md)).
@@ -0,0 +1,209 @@
1
+ # @xprite/pixelate
2
+
3
+ [![npm](https://img.shields.io/npm/v/@xprite/pixelate)](https://www.npmjs.com/package/@xprite/pixelate)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
5
+
6
+ [English](https://github.com/rhinoc/xprite-pixelate/blob/main/README.md) | 简体中文
7
+
8
+ | AI 生成,887×887 | 找到的网格 | 真正的像素画,48×49 |
9
+ | :---: | :---: | :---: |
10
+ | ![输入](docs/images/griffith-input.png) | ![网格](docs/images/griffith-mesh.png) | ![结果](docs/images/griffith-result.png) |
11
+
12
+ ## 简介
13
+
14
+ 图像生成模型画出的“像素画”边缘发虚,有噪点,轮廓半透明,每一格的宽度也不一样。这个包找出图里真正的像素网格,每一格还原成一个干净的像素。它也能把普通图片转成像素画。
15
+
16
+ 它可以在浏览器和 Node 中运行,没有运行时依赖,包内自带一个 WebAssembly 模块。它是像素编辑器 [Xprite](https://xprite.cc) 的导入器。
17
+
18
+ ## 目录
19
+
20
+ - [示例](#示例)
21
+ - [与其他工具对比](#与其他工具对比)
22
+ - [安装](#安装)
23
+ - [用法](#用法)
24
+ - [原理](#原理)
25
+ - [基准测试](#基准测试)
26
+ - [许可证](#许可证)
27
+
28
+ ## 示例
29
+
30
+ 下面的输入来自基准测试的 AI 套件:把 CC0 像素画按生成模型的方式渲染成假像素画。每个结果的尺寸都和原画完全一致。
31
+
32
+ ### 一张画布上的两个角色
33
+
34
+ - 哥布林,作者 LuizMelo([Monsters Creatures Fantasy](https://luizmelo.itch.io/monsters-creatures-fantasy),CC0)
35
+
36
+ | 输入,1800×845 | 找到的网格 | 结果,103×49 |
37
+ | :---: | :---: | :---: |
38
+ | ![输入](docs/images/goblins-input.png) | ![网格](docs/images/goblins-mesh.png) | ![结果](docs/images/goblins-result.png) |
39
+
40
+ ### 格内有绘画式明暗
41
+
42
+ - 娜迦法师,来自 [Dungeon Crawl Stone Soup tiles](https://github.com/crawl/tiles)(CC0)
43
+
44
+ | 输入,411×425 | 找到的网格 | 结果,50×50 |
45
+ | :---: | :---: | :---: |
46
+ | ![输入](docs/images/naga-input.png) | ![网格](docs/images/naga-mesh.png) | ![结果](docs/images/naga-result.png) |
47
+
48
+ ### 格子漂移和抖动
49
+
50
+ - 怪物,作者 Denzi([Denzi's public domain art](https://opengameart.org/content/denzis-public-domain-art),CC0)
51
+
52
+ | 输入,606×924 | 找到的网格 | 结果,45×67 |
53
+ | :---: | :---: | :---: |
54
+ | ![输入](docs/images/wobble-input.png) | ![网格](docs/images/wobble-mesh.png) | ![结果](docs/images/wobble-result.png) |
55
+
56
+ ### 小格子和 WebP 压缩损伤
57
+
58
+ - 老人,作者 ansimuz([Gothicvania Town](https://opengameart.org/content/gothicvania-town),CC0)
59
+
60
+ | 输入,250×380 | 找到的网格 | 结果,39×57 |
61
+ | :---: | :---: | :---: |
62
+ | ![输入](docs/images/oldman-input.png) | ![网格](docs/images/oldman-mesh.png) | ![结果](docs/images/oldman-result.png) |
63
+
64
+ ## 与其他工具对比
65
+
66
+ 顶部那张图,各工具用默认设置还原的结果:
67
+
68
+ | Xprite Auto,48×49 | [pixel-art-fixer](https://github.com/Retro-Diffusion/pixel-art-fixer),47×48 | [perfectPixel](https://github.com/theamusing/perfectPixel),50×50 | [proper-pixel-art](https://github.com/KennethJAllen/proper-pixel-art),53×54 |
69
+ | :---: | :---: | :---: | :---: |
70
+ | ![Xprite](docs/images/griffith-result.png) | ![pixel-art-fixer](docs/images/griffith-fixer.png) | ![perfectPixel](docs/images/griffith-perfectpixel.png) | ![proper-pixel-art](docs/images/griffith-proper.png) |
71
+
72
+ 这张图的格宽在 15 到 21 像素之间,所以等宽网格总会在某处切进画好的像素。Xprite 把每一刀都切在颜色边缘上。1746 个用例的得分见[基准测试](#基准测试)。
73
+
74
+ ## 安装
75
+
76
+ ```bash
77
+ npm install @xprite/pixelate
78
+ ```
79
+
80
+ ## 用法
81
+
82
+ 图像是 `{ width, height, data }`,`data` 是逐行排列的 RGBA 字节,alpha 未预乘。canvas 的 `ImageData` 就是这个结构。
83
+
84
+ ### 还原网格
85
+
86
+ ```ts
87
+ import {
88
+ CellColorPicker,
89
+ PixelationAlgorithm,
90
+ PixelationMode,
91
+ detectWithAlgorithm,
92
+ pixelateImage,
93
+ preloadWasm,
94
+ } from "@xprite/pixelate";
95
+
96
+ await preloadWasm(); // 可选:在处理第一张图之前加载格数检测器
97
+
98
+ const image = { width, height, data: new Uint8ClampedArray(rgba) };
99
+
100
+ const grid = detectWithAlgorithm(image, PixelationAlgorithm.Auto);
101
+ if (grid.reliable) {
102
+ const art = pixelateImage(image, {
103
+ mode: PixelationMode.RecoverGrid,
104
+ grid,
105
+ colorPicker: CellColorPicker.TwoStage,
106
+ paletteSnap: { adaptive: true }, // 合并生成模型留下的相近色
107
+ });
108
+ // art.width × art.height 是原生尺寸:每个格子一个像素。
109
+ }
110
+ ```
111
+
112
+ 图里没有一致的网格时(照片、手绘,或本来就是 1× 的像素画),`grid.reliable` 为 false,`RecoverGrid` 模式会对这种网格抛出错误。这类图片请用 `Convert` 模式。
113
+
114
+ ### 转换图片
115
+
116
+ ```ts
117
+ const art = pixelateImage(photo, {
118
+ mode: PixelationMode.Convert,
119
+ targetSize: { width: 64, height: 64 },
120
+ paletteSnap: { colors: 16 },
121
+ });
122
+ ```
123
+
124
+ ### 去除纯色背景
125
+
126
+ ```ts
127
+ import { removeBackground } from "@xprite/pixelate";
128
+
129
+ const clear = removeBackground(image); // 以边框上最常见的颜色为键
130
+ ```
131
+
132
+ 生成模型画了白色或棋盘格背景时,先调用它,再检测网格。
133
+
134
+ ### 选项
135
+
136
+ `pixelateImage(image, options)`:
137
+
138
+ | 选项 | 说明 |
139
+ | --- | --- |
140
+ | `mode` | `RecoverGrid` 使用检测到的网格;`Convert` 按给定尺寸生成像素画。 |
141
+ | `grid` | `detectWithAlgorithm` 返回的网格。省略时用 `algorithm` 检测。 |
142
+ | `algorithm` | 网格检测器。`Auto` 运行全部检测器并选出一个网格。 |
143
+ | `colorPicker` | 每格的取色规则:`TwoStage`、`MostCommon`(默认)、`Median`、`Average`、`KMeans`、`Contrast` 等。 |
144
+ | `targetSize`、`targetWidth`、`targetHeight`、`blockSize` | `Convert` 模式的输出尺寸。 |
145
+ | `paletteSnap` | 限制颜色:`{ adaptive: true }`、`{ colors: 16 }` 或 `{ palette: [...] }`,可选 `dither`。 |
146
+ | `prepass` | 来自 PixelOE 的轮廓预处理(`Pixeloe`、`PixeloeLines`)。 |
147
+ | `removeNoise` | 对相近的相邻颜色做轻度平滑。 |
148
+ | `preserveDimensions` | 用最近邻把结果放大回原图尺寸。 |
149
+
150
+ 所有选项见 [`src/types.ts`](src/types.ts)。
151
+
152
+ ### Worker
153
+
154
+ `detectWithAlgorithm` 和 `pixelateImage` 是同步函数,大图可能要几秒,请在 Web Worker 中运行。在浏览器中,Auto 还可以把格数检测器放进嵌套 Worker,和其他检测器并行:
155
+
156
+ ```ts
157
+ import { setAcRlBrowserWorkerFactory, detectWithAlgorithmAsync } from "@xprite/pixelate";
158
+
159
+ setAcRlBrowserWorkerFactory(
160
+ () =>
161
+ new Worker(
162
+ new URL("@xprite/pixelate/wasm/ac-rl-detect-browser-worker.js", import.meta.url),
163
+ { type: "module" },
164
+ ),
165
+ );
166
+ const grid = await detectWithAlgorithmAsync(image);
167
+ ```
168
+
169
+ 在 Node 中,检测器会自己从 `wasm/ac-rl-detect-worker.mjs` 启动一个 `worker_threads` Worker。设置 `XPRITE_AC_RL_WORKER=0` 可以让它留在调用线程。
170
+
171
+ ## 原理
172
+
173
+ 1. **扶正。** Auto 先估计倾斜角。倾斜明确时,在扶正后的副本上检测。
174
+ 2. **提议。** 七个检测器提议网格:均匀网格、边缘网格、边框晶格、格距晶格、颜色周期、边界游程和边缘间距。pixel-art-fixer 的自相关与游程投票移植成 WebAssembly,给出一个独立的格数。
175
+ 3. **沿边缘切。** 在检测器保留的每个格宽上,动态规划沿每条轴走一遍,把每一刀切在颜色边缘上。每格宽度保持在格宽的 0.75 到 1.25 倍之间,宽度变化另有代价。这一步处理宽度不均的格子。
176
+ 4. **过滤。** 候选网格的切线若没有落在更粗网格所跟随的颜色边缘上,就被剔除。
177
+ 5. **选择。** 描述图像所需比特数最少的网格胜出(最小描述长度)。没有锁定到内容相位的网格要付出额外代价。漂移和错位的行读作条带位移或相位场。
178
+ 6. **取色。** 每格取一个颜色(`TwoStage` 分两步归并格内颜色),自适应调色板再合并近似色。
179
+ 7. **整理透明度。** 被画覆盖的格子变为完全不透明,画外的格子变为透明。
180
+
181
+ `src/` 中每个源文件都说明了自己负责的步骤,见 [`src/`](src)。
182
+
183
+ ## 基准测试
184
+
185
+ [`bench/`](bench) 在 CC0 原生像素画上比较本包和另外三个工具。基准测试以已知方式损伤原画,再把每个结果和原画对比打分。每个工具都使用默认设置。
186
+
187
+ AI 套件(1746 个用例,按生成模型伪造像素画的方式渲染):
188
+
189
+ | 方法 | 尺寸完全正确 | 差 1 格以内 | 像素一致率 | ΔE | 半透明毛边 | 中位耗时 |
190
+ | --- | --- | --- | --- | --- | --- | --- |
191
+ | Xprite Auto | **83.6%** | **90.0%** | **99.8%** | 0.82 | 0.1% | 1.55 s |
192
+ | pixel-art-fixer | 49.7% | 80.9% | 98.3% | 1.74 | 0.0% | 0.18 s |
193
+ | perfectPixel | 53.3% | 68.0% | 96.7% | 2.42 | - | 0.03 s |
194
+ | proper-pixel-art | 72.2% | 80.4% | 99.7% | **0.64** | 0.0% | 0.49 s |
195
+
196
+ [pixel-bench](https://github.com/Retro-Diffusion/pixel-bench) v1 套件(7651 个放大和有损处理用例):
197
+
198
+ | 方法 | 尺寸完全正确 | 差 1 格以内 | 像素一致率 | ΔE | 中位耗时 |
199
+ | --- | --- | --- | --- | --- | --- |
200
+ | Xprite Auto | **87.1%** | **90.1%** | 94.3% | **2.79** | 0.24 s |
201
+ | pixel-art-fixer | 77.8% | 83.5% | **94.4%** | 2.83 | 0.04 s |
202
+ | perfectPixel | 24.2% | 32.9% | 89.7% | 4.31 | 0.002 s |
203
+ | proper-pixel-art | 16.5% | 28.6% | 93.0% | 3.85 | 0.05 s |
204
+
205
+ 像素一致率和 ΔE 只在尺寸完全正确的用例上统计。四个工具中 Xprite 最慢。损伤是合成的,所以得分反映各工具在这些特征上的排名,不代表在真实图片上的成功率。方法、类别和运行步骤见 [bench/README.md](bench/README.md)。
206
+
207
+ ## 许可证
208
+
209
+ MIT。部分代码改编自 pixel-art-fixer、PixelOE、proper-pixel-art 和 tensorhead/dithering(见 [NOTICE.md](NOTICE.md))。示例图均为 CC0(见 [bench/corpus/CREDITS.md](bench/corpus/CREDITS.md))。
@@ -0,0 +1,8 @@
1
+ import type { PixelBuffer } from "./base.ts";
2
+ import type { PixelArtAnalysis, PixelArtAnalysisOptions } from "./types.ts";
3
+ export declare function analyzePixelArt(image: PixelBuffer, options?: PixelArtAnalysisOptions): PixelArtAnalysis;
4
+ /**
5
+ * Async analyze for product import-worker. Same metrics/classification as analyzePixelArt;
6
+ * Auto grid uses detectWithAlgorithmAsync (WASM||proposers Promise overlap).
7
+ */
8
+ export declare function analyzePixelArtAsync(image: PixelBuffer, options?: PixelArtAnalysisOptions): Promise<PixelArtAnalysis>;