depixel 1.0.2 → 1.0.3
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 +2 -1
- package/lib.js +26 -25
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,9 +7,10 @@ Based on the following paper:
|
|
|
7
7
|
And the [source code](https://github.com/falichs/Depixelizing-Pixel-Art-on-GPUs) included with this paper:
|
|
8
8
|
* [Depixelizing Pixel Art on GPUs](https://www.cg.tuwien.ac.at/research/publications/2014/KREUZER-2014-DPA/) by Felix Kreuzer
|
|
9
9
|
|
|
10
|
-
Improvements upon original
|
|
10
|
+
Improvements upon original GPU version:
|
|
11
11
|
* Add a threshold parameter to adjust how close two colors need to be to be consider similar
|
|
12
12
|
* Better handle alpha channels (treat as dissimilar from non-transparent pixels)
|
|
13
|
+
* Fix stretching/scaling due to texel misalignment
|
|
13
14
|
|
|
14
15
|
Notes
|
|
15
16
|
* Original GPU code is MIT licensed, the same license may apply here, all original code in this project is additionally released under the MIT License
|
package/lib.js
CHANGED
|
@@ -80,6 +80,16 @@ function fetchPixelRGBA(src, x, y) {
|
|
|
80
80
|
return [d[idx] / 255, d[idx + 1] / 255, d[idx + 2] / 255, d[idx + 3] / 255];
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
function fetchPixelRGBA8(src, x, y) {
|
|
84
|
+
const w = src.width;
|
|
85
|
+
const h = src.height;
|
|
86
|
+
const cx = clampInt(x, 0, w - 1);
|
|
87
|
+
const cy = clampInt(y, 0, h - 1);
|
|
88
|
+
const idx = pixelIndex(cx, cy, w);
|
|
89
|
+
const d = src.data;
|
|
90
|
+
return [d[idx], d[idx + 1], d[idx + 2], d[idx + 3]];
|
|
91
|
+
}
|
|
92
|
+
|
|
83
93
|
function isSimilar(a, b, threshold) {
|
|
84
94
|
const yA = 0.299 * a[0] + 0.587 * a[1] + 0.114 * a[2];
|
|
85
95
|
const uA = 0.493 * (a[2] - yA);
|
|
@@ -1428,8 +1438,8 @@ function gaussRasterize(src, sim, cell, positions, outW, outH) {
|
|
|
1428
1438
|
for (let ox = 0; ox < outW; ox++) {
|
|
1429
1439
|
let influencingPixels = [true, true, true, true];
|
|
1430
1440
|
const cellSpaceCoords = [
|
|
1431
|
-
(w
|
|
1432
|
-
(h
|
|
1441
|
+
(w * (ox + 0.5) / outW) - 0.5 + 0.00001,
|
|
1442
|
+
(h * (oy + 0.5) / outH) - 0.5 + 0.00001,
|
|
1433
1443
|
];
|
|
1434
1444
|
const fragmentBaseKnotIndex = (2 * Math.floor(cellSpaceCoords[0]) + Math.floor(cellSpaceCoords[1]) * 2 * (w - 1)) | 0;
|
|
1435
1445
|
const node0flags = cell.flags[fragmentBaseKnotIndex] | 0;
|
|
@@ -1768,10 +1778,13 @@ function gaussRasterize(src, sim, cell, positions, outW, outH) {
|
|
|
1768
1778
|
|
|
1769
1779
|
const outIdx = (oy * outW + ox) * 4;
|
|
1770
1780
|
if (weightSum === 0) {
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
out[outIdx
|
|
1781
|
+
const nx = Math.round(cellSpaceCoords[0]);
|
|
1782
|
+
const ny = Math.round(cellSpaceCoords[1]);
|
|
1783
|
+
const col = fetchPixelRGBA8(src, nx, ny);
|
|
1784
|
+
out[outIdx] = col[0];
|
|
1785
|
+
out[outIdx + 1] = col[1];
|
|
1786
|
+
out[outIdx + 2] = col[2];
|
|
1787
|
+
out[outIdx + 3] = col[3];
|
|
1775
1788
|
} else {
|
|
1776
1789
|
out[outIdx] = clampInt(Math.round((colorSum[0] / weightSum) * 255), 0, 255);
|
|
1777
1790
|
out[outIdx + 1] = clampInt(Math.round((colorSum[1] / weightSum) * 255), 0, 255);
|
|
@@ -1820,30 +1833,18 @@ function scaleImage(src, opts) {
|
|
|
1820
1833
|
|
|
1821
1834
|
const borderPx = Math.max(0, Math.round(opts.borderPx || 0));
|
|
1822
1835
|
if (borderPx > 0) {
|
|
1823
|
-
const doInvisBorder = Math.min(
|
|
1824
|
-
src.data[3],
|
|
1825
|
-
src.data[(inW - 1) * 4 + 3],
|
|
1826
|
-
src.data[(inH - 1) * inW * 4 + 3],
|
|
1827
|
-
src.data[((inH - 1) * inW + (inW - 1)) * 4 + 3],
|
|
1828
|
-
) < 255;
|
|
1829
1836
|
const padW = inW + 2 * borderPx;
|
|
1830
1837
|
const padH = inH + 2 * borderPx;
|
|
1831
1838
|
const padData = new Uint8Array(padW * padH * 4);
|
|
1832
|
-
//
|
|
1839
|
+
// copy src into center, expand into borders
|
|
1833
1840
|
for (let y = 0; y < padH; y++) {
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
padData[idx] = doInvisBorder ? 0 : 255;
|
|
1837
|
-
padData[idx + 1] = 0;
|
|
1838
|
-
padData[idx + 2] = doInvisBorder ? 0 : 255;
|
|
1839
|
-
padData[idx + 3] = doInvisBorder ? 0 : 255;
|
|
1840
|
-
}
|
|
1841
|
-
}
|
|
1842
|
-
// copy src into center
|
|
1843
|
-
for (let y = 0; y < inH; y++) {
|
|
1844
|
-
const srcRow = y * inW * 4;
|
|
1845
|
-
const dstRow = (y + borderPx) * padW * 4 + borderPx * 4;
|
|
1841
|
+
const srcRow = Math.min(inH - 1, Math.max(0, y - borderPx)) * inW * 4;
|
|
1842
|
+
const dstRow = y * padW * 4 + borderPx * 4;
|
|
1846
1843
|
padData.set(src.data.subarray(srcRow, srcRow + inW * 4), dstRow);
|
|
1844
|
+
for (let ii = 0; ii < borderPx * 4; ++ii) {
|
|
1845
|
+
padData[dstRow - borderPx * 4 + ii] = src.data[srcRow + ii % 4];
|
|
1846
|
+
padData[dstRow + inW * 4 + ii] = src.data[srcRow + ii % 4];
|
|
1847
|
+
}
|
|
1847
1848
|
}
|
|
1848
1849
|
const scale = outH / inH;
|
|
1849
1850
|
const outHpad = Math.max(1, Math.round(padH * scale));
|