pixel-data-js 0.11.1 → 0.13.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.
@@ -27,6 +27,7 @@ __export(src_exports, {
27
27
  FAST_BLEND_TO_INDEX: () => FAST_BLEND_TO_INDEX,
28
28
  INDEX_TO_FAST_BLEND: () => INDEX_TO_FAST_BLEND,
29
29
  INDEX_TO_PERFECT_BLEND: () => INDEX_TO_PERFECT_BLEND,
30
+ IndexedImage: () => IndexedImage,
30
31
  MaskType: () => MaskType,
31
32
  PERFECT_BLENDER_REGISTRY: () => PERFECT_BLENDER_REGISTRY,
32
33
  PERFECT_BLEND_MODES: () => PERFECT_BLEND_MODES,
@@ -81,6 +82,7 @@ __export(src_exports, {
81
82
  imageDataToImgBlob: () => imageDataToImgBlob,
82
83
  imgBlobToImageData: () => imgBlobToImageData,
83
84
  indexedImageToAverageColor: () => indexedImageToAverageColor,
85
+ indexedImageToImageData: () => indexedImageToImageData,
84
86
  invertAlphaMask: () => invertAlphaMask,
85
87
  invertBinaryMask: () => invertBinaryMask,
86
88
  invertImageData: () => invertImageData,
@@ -97,9 +99,9 @@ __export(src_exports, {
97
99
  linearDodgePerfect: () => linearDodgePerfect,
98
100
  linearLightFast: () => linearLightFast,
99
101
  linearLightPerfect: () => linearLightPerfect,
100
- makeIndexedImage: () => makeIndexedImage,
101
102
  makePixelCanvas: () => makePixelCanvas,
102
103
  makeReusableCanvas: () => makeReusableCanvas,
104
+ makeReusableImageData: () => makeReusableImageData,
103
105
  mergeMasks: () => mergeMasks,
104
106
  multiplyFast: () => multiplyFast,
105
107
  multiplyPerfect: () => multiplyPerfect,
@@ -138,6 +140,7 @@ __export(src_exports, {
138
140
  unpackRed: () => unpackRed,
139
141
  vividLightFast: () => vividLightFast,
140
142
  vividLightPerfect: () => vividLightPerfect,
143
+ writeImageData: () => writeImageData,
141
144
  writeImageDataPixels: () => writeImageDataPixels,
142
145
  writeImageDataToClipboard: () => writeImageDataToClipboard,
143
146
  writeImgBlobToClipboard: () => writeImgBlobToClipboard
@@ -171,9 +174,11 @@ var BlendMode = /* @__PURE__ */ ((BlendMode2) => {
171
174
  BlendMode2[BlendMode2["divide"] = 22] = "divide";
172
175
  return BlendMode2;
173
176
  })(BlendMode || {});
177
+ var overwriteBase = (src, _dst) => src;
178
+ overwriteBase.isOverwrite = true;
174
179
 
175
180
  // src/BlendModes/blend-modes-fast.ts
176
- var overwriteFast = (src, _dst) => src;
181
+ var overwriteFast = overwriteBase;
177
182
  var sourceOverFast = (src, dst) => {
178
183
  const sa = src >>> 24 & 255;
179
184
  if (sa === 255) return src;
@@ -988,7 +993,7 @@ function floodFillSelection(img, startX, startY, {
988
993
  }
989
994
 
990
995
  // src/BlendModes/blend-modes-perfect.ts
991
- var overwritePerfect = (src, _dst) => src;
996
+ var overwritePerfect = overwriteBase;
992
997
  var sourceOverPerfect = (src, dst) => {
993
998
  const sa = src >>> 24 & 255;
994
999
  if (sa === 255) return src;
@@ -1571,6 +1576,22 @@ async function writeImageDataToClipboard(imageData) {
1571
1576
  return writeImgBlobToClipboard(blob);
1572
1577
  }
1573
1578
 
1579
+ // src/ImageData/ReusableImageData.ts
1580
+ function makeReusableImageData() {
1581
+ let imageData = null;
1582
+ let buffer = null;
1583
+ return function getReusableImageData(width, height) {
1584
+ const hasInstance = !!imageData;
1585
+ const widthMatches = hasInstance && imageData.width === width;
1586
+ const heightMatches = hasInstance && imageData.height === height;
1587
+ if (!widthMatches || !heightMatches) {
1588
+ const buffer2 = new Uint8ClampedArray(width * height * 4);
1589
+ imageData = new ImageData(buffer2, width, height);
1590
+ }
1591
+ return imageData;
1592
+ };
1593
+ }
1594
+
1574
1595
  // src/ImageData/copyImageData.ts
1575
1596
  function copyImageData({ data, width, height }) {
1576
1597
  return new ImageData(data.slice(), width, height);
@@ -1750,6 +1771,60 @@ function deserializeNullableImageData(serialized) {
1750
1771
  return deserializeImageData(serialized);
1751
1772
  }
1752
1773
 
1774
+ // src/ImageData/writeImageData.ts
1775
+ function writeImageData(target, source, x, y, sx = 0, sy = 0, sw = source.width, sh = source.height, mask = null, maskType = 1 /* BINARY */) {
1776
+ const dstW = target.width;
1777
+ const dstH = target.height;
1778
+ const dstData = target.data;
1779
+ const srcW = source.width;
1780
+ const srcData = source.data;
1781
+ const x0 = Math.max(0, x);
1782
+ const y0 = Math.max(0, y);
1783
+ const x1 = Math.min(dstW, x + sw);
1784
+ const y1 = Math.min(dstH, y + sh);
1785
+ if (x1 <= x0 || y1 <= y0) {
1786
+ return;
1787
+ }
1788
+ const useMask = !!mask;
1789
+ const rowCount = y1 - y0;
1790
+ const rowLenPixels = x1 - x0;
1791
+ for (let row = 0; row < rowCount; row++) {
1792
+ const dstY = y0 + row;
1793
+ const srcY = sy + (dstY - y);
1794
+ const srcXBase = sx + (x0 - x);
1795
+ const dstStart = (dstY * dstW + x0) * 4;
1796
+ const srcStart = (srcY * srcW + srcXBase) * 4;
1797
+ if (useMask && mask) {
1798
+ for (let ix = 0; ix < rowLenPixels; ix++) {
1799
+ const mi = srcY * srcW + (srcXBase + ix);
1800
+ const alpha = mask[mi];
1801
+ if (alpha === 0) {
1802
+ continue;
1803
+ }
1804
+ const di = dstStart + ix * 4;
1805
+ const si = srcStart + ix * 4;
1806
+ if (maskType === 1 /* BINARY */ || alpha === 255) {
1807
+ dstData[di] = srcData[si];
1808
+ dstData[di + 1] = srcData[si + 1];
1809
+ dstData[di + 2] = srcData[si + 2];
1810
+ dstData[di + 3] = srcData[si + 3];
1811
+ } else {
1812
+ const a = alpha / 255;
1813
+ const invA = 1 - a;
1814
+ dstData[di] = srcData[si] * a + dstData[di] * invA;
1815
+ dstData[di + 1] = srcData[si + 1] * a + dstData[di + 1] * invA;
1816
+ dstData[di + 2] = srcData[si + 2] * a + dstData[di + 2] * invA;
1817
+ dstData[di + 3] = srcData[si + 3] * a + dstData[di + 3] * invA;
1818
+ }
1819
+ }
1820
+ } else {
1821
+ const byteLen = rowLenPixels * 4;
1822
+ const sub = srcData.subarray(srcStart, srcStart + byteLen);
1823
+ dstData.set(sub, dstStart);
1824
+ }
1825
+ }
1826
+ }
1827
+
1753
1828
  // src/ImageData/writeImageDataPixels.ts
1754
1829
  function writeImageDataPixels(imageData, data, _x, _y, _w, _h) {
1755
1830
  const { x, y, w, h } = typeof _x === "object" ? _x : { x: _x, y: _y, w: _w, h: _h };
@@ -1772,38 +1847,88 @@ function writeImageDataPixels(imageData, data, _x, _y, _w, _h) {
1772
1847
  }
1773
1848
 
1774
1849
  // src/IndexedImage/IndexedImage.ts
1775
- function makeIndexedImage(imageOrData, width, height) {
1776
- const isImageData = "width" in imageOrData;
1777
- const actualWidth = isImageData ? imageOrData.width : width;
1778
- const actualHeight = isImageData ? imageOrData.height : height;
1779
- const buffer = isImageData ? imageOrData.data.buffer : imageOrData.buffer;
1780
- const rawData = new Uint32Array(buffer);
1781
- const indexedData = new Int32Array(rawData.length);
1782
- const colorMap = /* @__PURE__ */ new Map();
1783
- const transparentColor = 0;
1784
- const transparentPalletIndex = 0;
1785
- colorMap.set(transparentColor, transparentPalletIndex);
1786
- for (let i = 0; i < rawData.length; i++) {
1787
- const pixel = rawData[i];
1788
- const alpha = pixel >>> 24 & 255;
1789
- const isTransparent = alpha === 0;
1790
- const colorKey = isTransparent ? transparentColor : pixel >>> 0;
1791
- let id = colorMap.get(colorKey);
1792
- if (id === void 0) {
1793
- id = colorMap.size;
1794
- colorMap.set(colorKey, id);
1850
+ var IndexedImage = class _IndexedImage {
1851
+ /** The width of the image in pixels. */
1852
+ width;
1853
+ /** The height of the image in pixels. */
1854
+ height;
1855
+ /** Flat array of palette indices. Index = x + (y * width). */
1856
+ data;
1857
+ /** The palette of unique 32-bit colors (ABGR/RGBA packed) found in the image. */
1858
+ palette;
1859
+ /** The specific index in the palette reserved for fully transparent pixels. */
1860
+ transparentPalletIndex;
1861
+ /**
1862
+ * @param width - Image width.
1863
+ * @param height - Image height.
1864
+ * @param data - The indexed pixel data.
1865
+ * @param palette - The array of packed colors.
1866
+ * @param transparentPalletIndex - The index representing alpha 0.
1867
+ */
1868
+ constructor(width, height, data, palette, transparentPalletIndex) {
1869
+ this.width = width;
1870
+ this.height = height;
1871
+ this.data = data;
1872
+ this.palette = palette;
1873
+ this.transparentPalletIndex = transparentPalletIndex;
1874
+ }
1875
+ /**
1876
+ * Creates an IndexedImage from standard browser ImageData.
1877
+ * @param imageData - The source ImageData to convert.
1878
+ * @returns A new IndexedImage instance.
1879
+ */
1880
+ static fromImageData(imageData) {
1881
+ return _IndexedImage.fromRaw(imageData.data, imageData.width, imageData.height);
1882
+ }
1883
+ /**
1884
+ * Creates an IndexedImage from a raw byte buffer and dimensions.
1885
+ * Any pixel with an alpha channel of 0 is normalized to the transparent palette index.
1886
+ * @param data - Raw RGBA byte data.
1887
+ * @param width - Image width.
1888
+ * @param height - Image height.
1889
+ * @returns A new IndexedImage instance.
1890
+ */
1891
+ static fromRaw(data, width, height) {
1892
+ const buffer = data.buffer;
1893
+ const rawData = new Uint32Array(buffer);
1894
+ const indexedData = new Int32Array(rawData.length);
1895
+ const colorMap = /* @__PURE__ */ new Map();
1896
+ const transparentColor = 0;
1897
+ const transparentPalletIndex = 0;
1898
+ colorMap.set(transparentColor, transparentPalletIndex);
1899
+ for (let i = 0; i < rawData.length; i++) {
1900
+ const pixel = rawData[i];
1901
+ const alpha = pixel >>> 24 & 255;
1902
+ const isTransparent = alpha === 0;
1903
+ const colorKey = isTransparent ? transparentColor : pixel >>> 0;
1904
+ let id = colorMap.get(colorKey);
1905
+ if (id === void 0) {
1906
+ id = colorMap.size;
1907
+ colorMap.set(colorKey, id);
1908
+ }
1909
+ indexedData[i] = id;
1795
1910
  }
1796
- indexedData[i] = id;
1911
+ const palette = Uint32Array.from(colorMap.keys());
1912
+ return new _IndexedImage(
1913
+ width,
1914
+ height,
1915
+ indexedData,
1916
+ palette,
1917
+ transparentPalletIndex
1918
+ );
1797
1919
  }
1798
- const palette = Uint32Array.from(colorMap.keys());
1799
- return {
1800
- width: actualWidth,
1801
- height: actualHeight,
1802
- data: indexedData,
1803
- transparentPalletIndex,
1804
- palette
1805
- };
1806
- }
1920
+ /**
1921
+ * Retrieves the 32-bit packed color value at the given coordinates.
1922
+ * @param x - X coordinate.
1923
+ * @param y - Y coordinate.
1924
+ * @returns The packed color from the palette.
1925
+ */
1926
+ getColorAt(x, y) {
1927
+ const index = x + y * this.width;
1928
+ const paletteIndex = this.data[index];
1929
+ return this.palette[paletteIndex];
1930
+ }
1931
+ };
1807
1932
 
1808
1933
  // src/IndexedImage/getIndexedImageColorCounts.ts
1809
1934
  function getIndexedImageColorCounts(indexedImage) {
@@ -1867,13 +1992,26 @@ function resampleIndexedImage(source, factor) {
1867
1992
  source.height,
1868
1993
  factor
1869
1994
  );
1870
- return {
1995
+ return new IndexedImage(
1871
1996
  width,
1872
1997
  height,
1873
1998
  data,
1874
- palette: source.palette,
1875
- transparentPalletIndex: source.transparentPalletIndex
1876
- };
1999
+ source.palette,
2000
+ source.transparentPalletIndex
2001
+ );
2002
+ }
2003
+
2004
+ // src/IndexedImage/indexedImageToImageData.ts
2005
+ function indexedImageToImageData(indexedImage) {
2006
+ const { width, height, data, palette } = indexedImage;
2007
+ const result = new ImageData(width, height);
2008
+ const data32 = new Uint32Array(result.data.buffer);
2009
+ for (let i = 0; i < data.length; i++) {
2010
+ const paletteIndex = data[i];
2011
+ const color = palette[paletteIndex];
2012
+ data32[i] = color;
2013
+ }
2014
+ return result;
1877
2015
  }
1878
2016
 
1879
2017
  // src/Input/fileInputChangeToImageData.ts
@@ -2160,14 +2298,14 @@ function applyMaskToPixelData(dst, mask, opts) {
2160
2298
  }
2161
2299
 
2162
2300
  // src/PixelData/blendColorPixelData.ts
2163
- function blendColorPixelData(dst, color, opts) {
2301
+ function blendColorPixelData(dst, color, opts = {}) {
2164
2302
  const {
2165
2303
  x: targetX = 0,
2166
2304
  y: targetY = 0,
2167
2305
  w: width = dst.width,
2168
2306
  h: height = dst.height,
2169
2307
  alpha: globalAlpha = 255,
2170
- blendFn = FAST_BLEND_MODES[1 /* sourceOver */],
2308
+ blendFn = sourceOverFast,
2171
2309
  mask,
2172
2310
  maskType = 0 /* ALPHA */,
2173
2311
  mw,
@@ -2176,6 +2314,9 @@ function blendColorPixelData(dst, color, opts) {
2176
2314
  invertMask = false
2177
2315
  } = opts;
2178
2316
  if (globalAlpha === 0) return;
2317
+ const baseSrcAlpha = color >>> 24;
2318
+ const isOverwrite = blendFn.isOverwrite;
2319
+ if (baseSrcAlpha === 0 && !isOverwrite) return;
2179
2320
  let x = targetX;
2180
2321
  let y = targetY;
2181
2322
  let w = width;
@@ -2201,15 +2342,8 @@ function blendColorPixelData(dst, color, opts) {
2201
2342
  let mIdx = (my + dy) * mPitch + (mx + dx);
2202
2343
  const dStride = dw - actualW;
2203
2344
  const mStride = mPitch - actualW;
2204
- const baseSrcColor = color;
2205
- const baseSrcAlpha = baseSrcColor >>> 24;
2206
2345
  for (let iy = 0; iy < actualH; iy++) {
2207
2346
  for (let ix = 0; ix < actualW; ix++) {
2208
- if (baseSrcAlpha === 0) {
2209
- dIdx++;
2210
- mIdx++;
2211
- continue;
2212
- }
2213
2347
  let weight = globalAlpha;
2214
2348
  if (mask) {
2215
2349
  const mVal = mask[mIdx];
@@ -2242,20 +2376,20 @@ function blendColorPixelData(dst, color, opts) {
2242
2376
  continue;
2243
2377
  }
2244
2378
  }
2245
- let currentSrcAlpha = baseSrcAlpha;
2246
- let currentSrcColor = baseSrcColor;
2379
+ let currentSrcColor = color;
2247
2380
  if (weight < 255) {
2381
+ let currentSrcAlpha = baseSrcAlpha;
2248
2382
  if (baseSrcAlpha === 255) {
2249
2383
  currentSrcAlpha = weight;
2250
2384
  } else {
2251
2385
  currentSrcAlpha = baseSrcAlpha * weight + 128 >> 8;
2252
2386
  }
2253
- if (currentSrcAlpha === 0) {
2387
+ if (!isOverwrite && currentSrcAlpha === 0) {
2254
2388
  dIdx++;
2255
2389
  mIdx++;
2256
2390
  continue;
2257
2391
  }
2258
- currentSrcColor = (baseSrcColor & 16777215 | currentSrcAlpha << 24) >>> 0;
2392
+ currentSrcColor = (color & 16777215 | currentSrcAlpha << 24) >>> 0;
2259
2393
  }
2260
2394
  dst32[dIdx] = blendFn(currentSrcColor, dst32[dIdx]);
2261
2395
  dIdx++;
@@ -2330,11 +2464,12 @@ function blendPixelData(dst, src, opts) {
2330
2464
  const dStride = dw - actualW;
2331
2465
  const sStride = sw - actualW;
2332
2466
  const mStride = mPitch - actualW;
2467
+ const isOverwrite = blendFn.isOverwrite;
2333
2468
  for (let iy = 0; iy < actualH; iy++) {
2334
2469
  for (let ix = 0; ix < actualW; ix++) {
2335
2470
  const baseSrcColor = src32[sIdx];
2336
2471
  const baseSrcAlpha = baseSrcColor >>> 24;
2337
- if (baseSrcAlpha === 0) {
2472
+ if (baseSrcAlpha === 0 && !isOverwrite) {
2338
2473
  dIdx++;
2339
2474
  sIdx++;
2340
2475
  mIdx++;
@@ -2375,15 +2510,15 @@ function blendPixelData(dst, src, opts) {
2375
2510
  continue;
2376
2511
  }
2377
2512
  }
2378
- let currentSrcAlpha = baseSrcAlpha;
2379
2513
  let currentSrcColor = baseSrcColor;
2380
2514
  if (weight < 255) {
2515
+ let currentSrcAlpha = baseSrcAlpha;
2381
2516
  if (baseSrcAlpha === 255) {
2382
2517
  currentSrcAlpha = weight;
2383
2518
  } else {
2384
2519
  currentSrcAlpha = baseSrcAlpha * weight + 128 >> 8;
2385
2520
  }
2386
- if (currentSrcAlpha === 0) {
2521
+ if (!isOverwrite && currentSrcAlpha === 0) {
2387
2522
  dIdx++;
2388
2523
  sIdx++;
2389
2524
  mIdx++;
@@ -2561,6 +2696,7 @@ function rotateSquareInPlace(pixelData) {
2561
2696
  FAST_BLEND_TO_INDEX,
2562
2697
  INDEX_TO_FAST_BLEND,
2563
2698
  INDEX_TO_PERFECT_BLEND,
2699
+ IndexedImage,
2564
2700
  MaskType,
2565
2701
  PERFECT_BLENDER_REGISTRY,
2566
2702
  PERFECT_BLEND_MODES,
@@ -2615,6 +2751,7 @@ function rotateSquareInPlace(pixelData) {
2615
2751
  imageDataToImgBlob,
2616
2752
  imgBlobToImageData,
2617
2753
  indexedImageToAverageColor,
2754
+ indexedImageToImageData,
2618
2755
  invertAlphaMask,
2619
2756
  invertBinaryMask,
2620
2757
  invertImageData,
@@ -2631,9 +2768,9 @@ function rotateSquareInPlace(pixelData) {
2631
2768
  linearDodgePerfect,
2632
2769
  linearLightFast,
2633
2770
  linearLightPerfect,
2634
- makeIndexedImage,
2635
2771
  makePixelCanvas,
2636
2772
  makeReusableCanvas,
2773
+ makeReusableImageData,
2637
2774
  mergeMasks,
2638
2775
  multiplyFast,
2639
2776
  multiplyPerfect,
@@ -2672,6 +2809,7 @@ function rotateSquareInPlace(pixelData) {
2672
2809
  unpackRed,
2673
2810
  vividLightFast,
2674
2811
  vividLightPerfect,
2812
+ writeImageData,
2675
2813
  writeImageDataPixels,
2676
2814
  writeImageDataToClipboard,
2677
2815
  writeImgBlobToClipboard