@pixerate/editor 0.207.0 → 0.209.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 (72) hide show
  1. package/dist/animation-editor/index.cjs +60 -59
  2. package/dist/animation-editor/index.js +6 -5
  3. package/dist/{brushstrokeRender-7LXCU7PD.js → brushstrokeRender-C3UU6GVC.js} +5 -4
  4. package/dist/{brushstrokeRender-VO4ZTWVA.cjs → brushstrokeRender-EAJNE6WP.cjs} +12 -11
  5. package/dist/canvas/index.cjs +8 -8
  6. package/dist/canvas/index.js +1 -1
  7. package/dist/{chunk-2N2QPO3H.js → chunk-2PBZBRP5.js} +9 -7
  8. package/dist/{chunk-7NW46N7I.cjs → chunk-3EHPLDFQ.cjs} +54 -52
  9. package/dist/{chunk-H367YTXI.js → chunk-42TWUPNJ.js} +13 -387
  10. package/dist/chunk-474IQG74.cjs +384 -0
  11. package/dist/{chunk-MLC7HUHO.js → chunk-BGOCAUXH.js} +1 -1
  12. package/dist/chunk-DWYQPL2A.js +2010 -0
  13. package/dist/{chunk-YXKLVD56.js → chunk-F7YA3MMC.js} +2 -2
  14. package/dist/{chunk-ZZGPYNS2.js → chunk-G4E6RUPC.js} +1 -1
  15. package/dist/chunk-HVVR5PZW.js +384 -0
  16. package/dist/{chunk-FR2Q2LVF.cjs → chunk-I7G3RSUJ.cjs} +35 -35
  17. package/dist/chunk-K6PXS6DO.cjs +102 -0
  18. package/dist/{chunk-ZIDUPSP4.js → chunk-KFIOEOCQ.js} +24 -761
  19. package/dist/{chunk-V7GWZIZK.cjs → chunk-KWNMBMKG.cjs} +23 -21
  20. package/dist/chunk-L3G23N5Y.js +763 -0
  21. package/dist/{chunk-GHCXLQ47.js → chunk-NDMXB4PR.js} +2 -2
  22. package/dist/{chunk-CWM3CUUX.cjs → chunk-OLNIPTB3.cjs} +39 -413
  23. package/dist/{chunk-EBDCRTZI.cjs → chunk-PQ3H2AAN.cjs} +92 -90
  24. package/dist/{chunk-BRKVNXDZ.cjs → chunk-QAUIZPYI.cjs} +7 -7
  25. package/dist/{chunk-UYXL6ZWQ.cjs → chunk-QE7D7TZR.cjs} +494 -1231
  26. package/dist/chunk-QYLWG22N.cjs +763 -0
  27. package/dist/{chunk-YQ5C5BVK.cjs → chunk-ROVK6AXX.cjs} +60 -60
  28. package/dist/{chunk-HGTDMKNE.cjs → chunk-UOGKSVRQ.cjs} +126 -221
  29. package/dist/{chunk-EL5PAHNP.js → chunk-USQCKRZG.js} +6 -4
  30. package/dist/{chunk-36OKQDCF.js → chunk-WJ2RBZMM.js} +5 -3
  31. package/dist/chunk-X4LUGTQX.cjs +2010 -0
  32. package/dist/{chunk-NQMP3CWF.js → chunk-YBJXCQTR.js} +15 -110
  33. package/dist/chunk-ZIF4UJJ6.js +102 -0
  34. package/dist/{chunk-WTW7QRTS.cjs → chunk-ZMHPQ6HP.cjs} +1 -1
  35. package/dist/image-editor/controller.d.cts +53 -5
  36. package/dist/image-editor/controller.d.ts +53 -5
  37. package/dist/image-editor/index.cjs +1806 -3356
  38. package/dist/image-editor/index.js +462 -2012
  39. package/dist/image-editor/selection/index.d.cts +1 -0
  40. package/dist/image-editor/selection/index.d.ts +1 -0
  41. package/dist/image-editor/selection/segment/focus.d.cts +2 -0
  42. package/dist/image-editor/selection/segment/focus.d.ts +2 -0
  43. package/dist/image-editor/selection/segment/grabcut.d.cts +4 -2
  44. package/dist/image-editor/selection/segment/grabcut.d.ts +4 -2
  45. package/dist/image-editor/selection/segment/sky.d.cts +2 -0
  46. package/dist/image-editor/selection/segment/sky.d.ts +2 -0
  47. package/dist/image-editor/selection/segment/subject.d.cts +2 -1
  48. package/dist/image-editor/selection/segment/subject.d.ts +2 -1
  49. package/dist/image-editor/selection/segment/work.d.cts +5 -0
  50. package/dist/image-editor/selection/segment/work.d.ts +5 -0
  51. package/dist/image-editor/selection/select-and-mask.d.cts +12 -2
  52. package/dist/image-editor/selection/select-and-mask.d.ts +12 -2
  53. package/dist/image-editor/selection/tool-options.d.cts +3 -1
  54. package/dist/image-editor/selection/tool-options.d.ts +3 -1
  55. package/dist/image-editor/selection/worker.d.cts +126 -0
  56. package/dist/image-editor/selection/worker.d.ts +126 -0
  57. package/dist/image-editor/selection-worker.cjs +14 -0
  58. package/dist/image-editor/selection-worker.d.cts +12 -0
  59. package/dist/image-editor/selection-worker.d.ts +12 -0
  60. package/dist/image-editor/selection-worker.js +14 -0
  61. package/dist/image-editor/types.d.cts +22 -0
  62. package/dist/image-editor/types.d.ts +22 -0
  63. package/dist/paint/index.cjs +6 -5
  64. package/dist/paint/index.js +5 -4
  65. package/dist/paint-editor/index.cjs +394 -390
  66. package/dist/paint-editor/index.js +18 -14
  67. package/dist/raster/index.cjs +22 -18
  68. package/dist/raster/index.js +29 -25
  69. package/dist/vector/index.cjs +986 -985
  70. package/dist/vector/index.js +6 -5
  71. package/package.json +11 -1
  72. package/skills/pixerate-image-editor/SKILL.md +1 -1
@@ -1,6 +1,13 @@
1
1
  import {
2
2
  parseCssColor
3
3
  } from "./chunk-3CI7FRMK.js";
4
+ import {
5
+ createSelectionMask,
6
+ decodeSelectionRle,
7
+ encodeSelectionRle,
8
+ hashMaskContent,
9
+ resizeSelection
10
+ } from "./chunk-L3G23N5Y.js";
4
11
  import {
5
12
  DEFAULT_GLOBAL_LIGHT,
6
13
  DeepCompositor,
@@ -21,7 +28,6 @@ import {
21
28
  effectsScale,
22
29
  findLayer,
23
30
  flattenLayers,
24
- gaussianBlur,
25
31
  insertLayer,
26
32
  isInterpolation,
27
33
  isLayerEffectKind,
@@ -37,7 +43,7 @@ import {
37
43
  validateEffectGradient,
38
44
  validateLayerEffects,
39
45
  warpSurface
40
- } from "./chunk-NQMP3CWF.js";
46
+ } from "./chunk-YBJXCQTR.js";
41
47
  import {
42
48
  affineFromHomography,
43
49
  applyHomography,
@@ -48,6 +54,9 @@ import {
48
54
  multiplyHomographies,
49
55
  rectToQuad
50
56
  } from "./chunk-OHKOFKBY.js";
57
+ import {
58
+ gaussianBlur
59
+ } from "./chunk-ZIF4UJJ6.js";
51
60
  import {
52
61
  Transform,
53
62
  builtinProfile,
@@ -90,7 +99,7 @@ import {
90
99
  transformTextRect,
91
100
  translateMatrix,
92
101
  warpPresetMesh
93
- } from "./chunk-GHCXLQ47.js";
102
+ } from "./chunk-NDMXB4PR.js";
94
103
  import {
95
104
  bezierPathBounds,
96
105
  outlineStroke,
@@ -99,36 +108,35 @@ import {
99
108
  transformBezierPath
100
109
  } from "./chunk-WEIK3UYB.js";
101
110
  import {
102
- TILE,
103
- TiledSurface,
104
111
  base64ToBytes,
105
112
  blendRgb,
106
113
  bytesToBase64,
107
- contentBounds,
108
114
  decodePng,
109
- emptySurface,
110
115
  encodePng,
111
- finishTile,
112
116
  isBlendMode,
113
117
  mixPigmentRgb,
114
118
  normalizeBlendMode,
115
119
  parseDataUrl,
116
120
  pngDataUrl,
117
121
  readDeepRegion,
118
- readPixel,
119
- readRegion,
120
122
  setLum,
121
123
  surfaceDepth,
122
124
  surfaceFromDeepPixels,
125
+ writeDeepRegion
126
+ } from "./chunk-42TWUPNJ.js";
127
+ import {
128
+ TILE,
129
+ TiledSurface,
130
+ contentBounds,
131
+ emptySurface,
132
+ finishTile,
133
+ readRegion,
123
134
  surfaceFromPixels,
124
- tileCoord,
125
135
  tileKey,
126
136
  tilesInRect,
127
137
  translateSurface,
128
- uniformTile,
129
- writeDeepRegion,
130
138
  writeRegion
131
- } from "./chunk-H367YTXI.js";
139
+ } from "./chunk-HVVR5PZW.js";
132
140
  import {
133
141
  ZlibError,
134
142
  deflate,
@@ -711,716 +719,6 @@ function hitTestAnnotation(imgPt, ann, padding = 10) {
711
719
  return imgPt.x >= b.x - padding && imgPt.x <= b.x + b.width + padding && imgPt.y >= b.y - padding && imgPt.y <= b.y + b.height + padding;
712
720
  }
713
721
 
714
- // src/image-editor/selection/mask.ts
715
- var SELECTION_MODES = ["replace", "add", "subtract", "intersect"];
716
- function isSelectionMode(value) {
717
- return typeof value === "string" && SELECTION_MODES.includes(value);
718
- }
719
- function parseSelectionMode(value) {
720
- return isSelectionMode(value) ? value : "replace";
721
- }
722
- var MAX_SIDE = 1 << 15;
723
- function checkSize(width, height) {
724
- if (!Number.isInteger(width) || !Number.isInteger(height) || width < 1 || height < 1 || width > MAX_SIDE || height > MAX_SIDE) {
725
- throw new Error(`Invalid selection size ${width}\xD7${height}`);
726
- }
727
- }
728
- function computeSelectionBounds(width, height, data) {
729
- let x0 = width;
730
- let x1 = -1;
731
- let y0 = -1;
732
- let y1 = -1;
733
- for (let y = 0; y < height; y++) {
734
- const row = y * width;
735
- let first = -1;
736
- for (let x = 0; x < width; x++) {
737
- if (data[row + x] !== 0) {
738
- first = x;
739
- break;
740
- }
741
- }
742
- if (first < 0) continue;
743
- let last = first;
744
- for (let x = width - 1; x > first; x--) {
745
- if (data[row + x] !== 0) {
746
- last = x;
747
- break;
748
- }
749
- }
750
- if (y0 < 0) y0 = y;
751
- y1 = y;
752
- if (first < x0) x0 = first;
753
- if (last > x1) x1 = last;
754
- }
755
- if (y0 < 0) return null;
756
- return { x: x0, y: y0, width: x1 - x0 + 1, height: y1 - y0 + 1 };
757
- }
758
- var TILE_PIXELS = TILE * TILE;
759
- var MATERIALIZED_LIMIT = 4;
760
- var materialized = /* @__PURE__ */ new Map();
761
- var lastRead = null;
762
- var lastData = null;
763
- var TiledSelectionMask = class {
764
- constructor(width, height, surface, bounds, data) {
765
- this.width = width;
766
- this.height = height;
767
- this.surface = surface;
768
- this.cachedBounds = bounds;
769
- if (data) this.remember(data);
770
- }
771
- width;
772
- height;
773
- surface;
774
- cachedBounds;
775
- weak = null;
776
- get bounds() {
777
- if (this.cachedBounds === void 0) this.cachedBounds = contentBounds(this.surface);
778
- return this.cachedBounds;
779
- }
780
- get data() {
781
- if (lastRead === this) return lastData;
782
- let d = materialized.get(this);
783
- if (d) {
784
- materialized.delete(this);
785
- materialized.set(this, d);
786
- lastRead = this;
787
- lastData = d;
788
- return d;
789
- }
790
- d = this.weak?.deref();
791
- if (!d) {
792
- const all = readRegion(this.surface, { x: 0, y: 0, width: this.width, height: this.height });
793
- d = new Uint8Array(all.buffer, all.byteOffset, all.length);
794
- }
795
- this.remember(d);
796
- return d;
797
- }
798
- remember(d) {
799
- lastRead = this;
800
- lastData = d;
801
- this.weak = typeof WeakRef === "function" ? new WeakRef(d) : null;
802
- materialized.set(this, d);
803
- while (materialized.size > MATERIALIZED_LIMIT) materialized.delete(materialized.keys().next().value);
804
- }
805
- };
806
- function tileGrid(width, height) {
807
- return { cols: Math.ceil(width / TILE), rows: Math.ceil(height / TILE) };
808
- }
809
- function insideTile(tx, ty, width, height) {
810
- return (tx + 1) * TILE <= width && (ty + 1) * TILE <= height;
811
- }
812
- function surfaceFromCoverage(width, height, data) {
813
- const tiles = /* @__PURE__ */ new Map();
814
- const { cols, rows } = tileGrid(width, height);
815
- for (let ty = 0; ty < rows; ty++) {
816
- for (let tx = 0; tx < cols; tx++) {
817
- const ox = tx * TILE;
818
- const oy = ty * TILE;
819
- const w = Math.min(TILE, width - ox);
820
- const h = Math.min(TILE, height - oy);
821
- let lo = 255;
822
- let hi = 0;
823
- for (let y = 0; y < h && !(hi > 0 && lo < hi); y++) {
824
- const row = (oy + y) * width + ox;
825
- for (let x = 0; x < w; x++) {
826
- const v = data[row + x];
827
- if (v < lo) lo = v;
828
- if (v > hi) hi = v;
829
- }
830
- }
831
- if (hi === 0) continue;
832
- if (lo === hi && w === TILE && h === TILE) {
833
- tiles.set(tileKey(tx, ty), uniformTile(1, hi));
834
- continue;
835
- }
836
- const t = new Uint8ClampedArray(TILE_PIXELS);
837
- for (let y = 0; y < h; y++) {
838
- const row = (oy + y) * width + ox;
839
- for (let x = 0; x < w; x++) t[y * TILE + x] = data[row + x];
840
- }
841
- tiles.set(tileKey(tx, ty), { data: t, uniform: null });
842
- }
843
- }
844
- return new TiledSurface(1, tiles, 0);
845
- }
846
- function clipTile(tile, w, h) {
847
- const d = tile.data;
848
- let outside = false;
849
- for (let y = 0; y < TILE && !outside; y++) {
850
- for (let x = y < h ? w : 0; x < TILE; x++) {
851
- if (d[y * TILE + x] !== 0) {
852
- outside = true;
853
- break;
854
- }
855
- }
856
- }
857
- if (!outside) return tile;
858
- const t = new Uint8ClampedArray(TILE_PIXELS);
859
- for (let y = 0; y < h; y++) t.set(d.subarray(y * TILE, y * TILE + w), y * TILE);
860
- return finishTile(t, 1, 0);
861
- }
862
- function selectionFromTiles(width, height, surface) {
863
- checkSize(width, height);
864
- if (surface.channels !== 1) throw new Error("A selection needs a 1-channel surface");
865
- if (surface.defaultValue !== 0) {
866
- const all = readRegion(surface, { x: 0, y: 0, width, height });
867
- return createSelectionMask(width, height, new Uint8Array(all.buffer, all.byteOffset, all.length));
868
- }
869
- const { cols, rows } = tileGrid(width, height);
870
- let tiles = null;
871
- for (const [key, tile] of surface.tiles) {
872
- const { tx, ty } = tileCoord(key);
873
- let next = tile;
874
- if (tx < 0 || ty < 0 || tx >= cols || ty >= rows) next = null;
875
- else if (!insideTile(tx, ty, width, height)) next = clipTile(tile, Math.min(TILE, width - tx * TILE), Math.min(TILE, height - ty * TILE));
876
- if (next === tile) continue;
877
- tiles ??= new Map(surface.tiles);
878
- if (next) tiles.set(key, next);
879
- else tiles.delete(key);
880
- }
881
- return new TiledSelectionMask(width, height, tiles ? new TiledSurface(1, tiles, 0) : surface);
882
- }
883
- function createSelectionMask(width, height, data) {
884
- checkSize(width, height);
885
- if (!data) return new TiledSelectionMask(width, height, new TiledSurface(1, /* @__PURE__ */ new Map(), 0), null);
886
- if (data.length !== width * height) throw new Error("Selection data does not match its size");
887
- return new TiledSelectionMask(width, height, surfaceFromCoverage(width, height, data), void 0, data);
888
- }
889
- function selectionFromRegion(width, height, rect, data) {
890
- checkSize(width, height);
891
- if (rect.x < 0 || rect.y < 0 || rect.x + rect.width > width || rect.y + rect.height > height) throw new Error("The region lies outside the selection");
892
- return new TiledSelectionMask(width, height, writeRegion(new TiledSurface(1, /* @__PURE__ */ new Map(), 0), rect, data));
893
- }
894
- function fullSelection(width, height) {
895
- checkSize(width, height);
896
- const tiles = /* @__PURE__ */ new Map();
897
- const { cols, rows } = tileGrid(width, height);
898
- for (let ty = 0; ty < rows; ty++) {
899
- for (let tx = 0; tx < cols; tx++) {
900
- if (insideTile(tx, ty, width, height)) {
901
- tiles.set(tileKey(tx, ty), uniformTile(1, 255));
902
- continue;
903
- }
904
- const t = new Uint8ClampedArray(TILE_PIXELS);
905
- const w = Math.min(TILE, width - tx * TILE);
906
- for (let y = 0; y < Math.min(TILE, height - ty * TILE); y++) t.fill(255, y * TILE, y * TILE + w);
907
- tiles.set(tileKey(tx, ty), { data: t, uniform: null });
908
- }
909
- }
910
- return new TiledSelectionMask(width, height, new TiledSurface(1, tiles, 0), { x: 0, y: 0, width, height });
911
- }
912
- function isSelectionEmpty(mask) {
913
- return !mask || mask.bounds === null;
914
- }
915
- function selectionValueAt(mask, x, y) {
916
- const xi = Math.floor(x);
917
- const yi = Math.floor(y);
918
- if (xi < 0 || yi < 0 || xi >= mask.width || yi >= mask.height) return 0;
919
- return readPixel(mask.surface, xi, yi)[0] / 255;
920
- }
921
- function coverageToByte(v) {
922
- if (!(v > 0)) return 0;
923
- if (v >= 1) return 255;
924
- return Math.floor(v * 255 + 0.5);
925
- }
926
- function selectionFromCoverage(width, height, coverage) {
927
- const n = width * height;
928
- const out = new Uint8Array(n);
929
- for (let i = 0; i < n; i++) out[i] = coverageToByte(coverage[i]);
930
- return createSelectionMask(width, height, out);
931
- }
932
- function selectionToCoverage(mask) {
933
- const out = new Float32Array(mask.data.length);
934
- for (let i = 0; i < out.length; i++) out[i] = mask.data[i] / 255;
935
- return out;
936
- }
937
- function selectionArea(mask) {
938
- if (!mask || !mask.bounds) return 0;
939
- let sum = 0;
940
- for (const tile of mask.surface.tiles.values()) {
941
- if (tile.uniform !== null) {
942
- sum += tile.uniform * TILE_PIXELS;
943
- continue;
944
- }
945
- const d = tile.data;
946
- for (let i = 0; i < d.length; i++) sum += d[i];
947
- }
948
- return sum / 255;
949
- }
950
- function combineSelections(prev, next, mode) {
951
- let result;
952
- if (mode === "replace" || !prev && mode === "add") {
953
- result = next;
954
- } else if (!prev) {
955
- return null;
956
- } else {
957
- if (prev.width !== next.width || prev.height !== next.height) throw new Error("Selections differ in size");
958
- result = new TiledSelectionMask(prev.width, prev.height, combineSurfaces(prev.surface, next.surface, mode));
959
- }
960
- return result.bounds ? result : null;
961
- }
962
- var FULL = 255;
963
- function combineTile(a, b, mode) {
964
- if (mode === "add") {
965
- if (!b || a?.uniform === FULL) return a;
966
- if (!a || b.uniform === FULL) return b;
967
- } else if (mode === "subtract") {
968
- if (!a || !b) return a;
969
- if (b.uniform === FULL) return void 0;
970
- } else {
971
- if (!a || !b) return void 0;
972
- if (a.uniform === FULL) return b;
973
- if (b.uniform === FULL) return a;
974
- }
975
- const x = a.data;
976
- const y = b.data;
977
- const out = new Uint8ClampedArray(TILE_PIXELS);
978
- if (mode === "add") for (let i = 0; i < out.length; i++) out[i] = x[i] > y[i] ? x[i] : y[i];
979
- else if (mode === "subtract") for (let i = 0; i < out.length; i++) out[i] = x[i] > y[i] ? x[i] - y[i] : 0;
980
- else for (let i = 0; i < out.length; i++) out[i] = x[i] < y[i] ? x[i] : y[i];
981
- return finishTile(out, 1, 0) ?? void 0;
982
- }
983
- function combineSurfaces(a, b, mode) {
984
- const tiles = /* @__PURE__ */ new Map();
985
- for (const key of /* @__PURE__ */ new Set([...a.tiles.keys(), ...b.tiles.keys()])) {
986
- const tile = combineTile(a.tiles.get(key), b.tiles.get(key), mode);
987
- if (tile) tiles.set(key, tile);
988
- }
989
- return new TiledSurface(1, tiles, 0);
990
- }
991
- function invertSelection(mask) {
992
- const { width, height } = mask;
993
- const tiles = /* @__PURE__ */ new Map();
994
- const { cols, rows } = tileGrid(width, height);
995
- for (let ty = 0; ty < rows; ty++) {
996
- for (let tx = 0; tx < cols; tx++) {
997
- const src = mask.surface.getTile(tx, ty);
998
- const key = tileKey(tx, ty);
999
- if (insideTile(tx, ty, width, height)) {
1000
- if (!src) tiles.set(key, uniformTile(1, FULL));
1001
- else if (src.uniform !== null) {
1002
- if (src.uniform !== FULL) tiles.set(key, uniformTile(1, FULL - src.uniform));
1003
- } else {
1004
- const out2 = new Uint8ClampedArray(TILE_PIXELS);
1005
- for (let i = 0; i < out2.length; i++) out2[i] = FULL - src.data[i];
1006
- const t2 = finishTile(out2, 1, 0);
1007
- if (t2) tiles.set(key, t2);
1008
- }
1009
- continue;
1010
- }
1011
- const w = Math.min(TILE, width - tx * TILE);
1012
- const h = Math.min(TILE, height - ty * TILE);
1013
- const out = new Uint8ClampedArray(TILE_PIXELS);
1014
- for (let y = 0; y < h; y++) for (let x = 0; x < w; x++) out[y * TILE + x] = FULL - (src ? src.data[y * TILE + x] : 0);
1015
- const t = finishTile(out, 1, 0);
1016
- if (t) tiles.set(key, t);
1017
- }
1018
- }
1019
- return new TiledSelectionMask(width, height, new TiledSurface(1, tiles, 0));
1020
- }
1021
- function resizeSelection(mask, width, height) {
1022
- if (mask.width === width && mask.height === height) return mask;
1023
- checkSize(width, height);
1024
- const out = new Uint8Array(width * height);
1025
- const sx = mask.width / width;
1026
- const sy = mask.height / height;
1027
- const src = mask.data;
1028
- const mw = mask.width;
1029
- for (let y = 0; y < height; y++) {
1030
- const fy = Math.min(mask.height - 1, Math.max(0, (y + 0.5) * sy - 0.5));
1031
- const y0 = Math.floor(fy);
1032
- const y1 = Math.min(mask.height - 1, y0 + 1);
1033
- const ty = fy - y0;
1034
- for (let x = 0; x < width; x++) {
1035
- const fx = Math.min(mw - 1, Math.max(0, (x + 0.5) * sx - 0.5));
1036
- const x0 = Math.floor(fx);
1037
- const x1 = Math.min(mw - 1, x0 + 1);
1038
- const tx = fx - x0;
1039
- const top = src[y0 * mw + x0] * (1 - tx) + src[y0 * mw + x1] * tx;
1040
- const bot = src[y1 * mw + x0] * (1 - tx) + src[y1 * mw + x1] * tx;
1041
- out[y * width + x] = Math.round(top * (1 - ty) + bot * ty);
1042
- }
1043
- }
1044
- return createSelectionMask(width, height, out);
1045
- }
1046
- function selectionFromPixels(pixels, options = {}) {
1047
- const { width, height, data } = pixels;
1048
- checkSize(width, height);
1049
- if (data.length < width * height * 4) throw new Error("Pixel data is shorter than width \xD7 height \xD7 4");
1050
- const channel = options.channel ?? "luminance";
1051
- const out = new Uint8Array(width * height);
1052
- const threshold = options.threshold;
1053
- for (let i = 0, p = 0; i < out.length; i++, p += 4) {
1054
- let v;
1055
- switch (channel) {
1056
- case "alpha":
1057
- v = data[p + 3];
1058
- break;
1059
- case "red":
1060
- v = data[p];
1061
- break;
1062
- case "green":
1063
- v = data[p + 1];
1064
- break;
1065
- case "blue":
1066
- v = data[p + 2];
1067
- break;
1068
- default:
1069
- v = Math.round((0.2126 * data[p] + 0.7152 * data[p + 1] + 0.0722 * data[p + 2]) * data[p + 3] / 255);
1070
- }
1071
- if (options.invert) v = 255 - v;
1072
- if (threshold !== void 0) v = v >= threshold ? 255 : 0;
1073
- out[i] = v;
1074
- }
1075
- return createSelectionMask(width, height, out);
1076
- }
1077
- function selectionToPixels(mask, as = "gray") {
1078
- const out = new Uint8ClampedArray(mask.data.length * 4);
1079
- for (let i = 0, p = 0; i < mask.data.length; i++, p += 4) {
1080
- const v = mask.data[i];
1081
- if (as === "gray") {
1082
- out[p] = out[p + 1] = out[p + 2] = v;
1083
- out[p + 3] = 255;
1084
- } else {
1085
- out[p] = out[p + 1] = out[p + 2] = 255;
1086
- out[p + 3] = v;
1087
- }
1088
- }
1089
- return { width: mask.width, height: mask.height, data: out };
1090
- }
1091
- var B64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1092
- var B64_INDEX = (() => {
1093
- const t = new Int16Array(128).fill(-1);
1094
- for (let i = 0; i < B64.length; i++) t[B64.charCodeAt(i)] = i;
1095
- return t;
1096
- })();
1097
- function toBase64(bytes, length) {
1098
- const parts = [];
1099
- let chunk = "";
1100
- for (let i = 0; i < length; i += 3) {
1101
- const a = bytes[i];
1102
- const b = i + 1 < length ? bytes[i + 1] : 0;
1103
- const c = i + 2 < length ? bytes[i + 2] : 0;
1104
- chunk += B64[a >> 2] + B64[(a & 3) << 4 | b >> 4];
1105
- chunk += i + 1 < length ? B64[(b & 15) << 2 | c >> 6] : "=";
1106
- chunk += i + 2 < length ? B64[c & 63] : "=";
1107
- if (chunk.length >= 8192) {
1108
- parts.push(chunk);
1109
- chunk = "";
1110
- }
1111
- }
1112
- parts.push(chunk);
1113
- return parts.join("");
1114
- }
1115
- function fromBase64(text3) {
1116
- if (text3.length % 4 !== 0) throw new Error("Invalid base64 length");
1117
- let pad = 0;
1118
- if (text3.endsWith("==")) pad = 2;
1119
- else if (text3.endsWith("=")) pad = 1;
1120
- const out = new Uint8Array(text3.length / 4 * 3 - pad);
1121
- let o = 0;
1122
- const digit = (i, k) => {
1123
- const ch = text3.charCodeAt(i + k);
1124
- if (ch === 61 && i + 4 === text3.length && k >= 4 - pad) return 0;
1125
- const idx = ch < 128 ? B64_INDEX[ch] : -1;
1126
- if (idx < 0) throw new Error("Invalid base64 character");
1127
- return idx;
1128
- };
1129
- for (let i = 0; i < text3.length; i += 4) {
1130
- const n = digit(i, 0) << 18 | digit(i, 1) << 12 | digit(i, 2) << 6 | digit(i, 3);
1131
- if (o < out.length) out[o++] = n >> 16 & 255;
1132
- if (o < out.length) out[o++] = n >> 8 & 255;
1133
- if (o < out.length) out[o++] = n & 255;
1134
- }
1135
- return out;
1136
- }
1137
- function encodeSelectionRle(data) {
1138
- let buf = new Uint8Array(64);
1139
- let len = 0;
1140
- const push = (b) => {
1141
- if (len === buf.length) {
1142
- const next = new Uint8Array(buf.length * 2);
1143
- next.set(buf);
1144
- buf = next;
1145
- }
1146
- buf[len++] = b;
1147
- };
1148
- let i = 0;
1149
- while (i < data.length) {
1150
- const v = data[i];
1151
- let j = i + 1;
1152
- while (j < data.length && data[j] === v) j++;
1153
- push(v);
1154
- let run = j - i;
1155
- while (run >= 128) {
1156
- push(run & 127 | 128);
1157
- run = Math.floor(run / 128);
1158
- }
1159
- push(run);
1160
- i = j;
1161
- }
1162
- return "r1:" + toBase64(buf, len);
1163
- }
1164
- function decodeSelectionRle(rle, length) {
1165
- if (typeof rle !== "string" || !rle.startsWith("r1:")) throw new Error("Unknown selection encoding");
1166
- const bytes = fromBase64(rle.slice(3));
1167
- const out = new Uint8Array(length);
1168
- let o = 0;
1169
- let i = 0;
1170
- while (i < bytes.length) {
1171
- const v = bytes[i++];
1172
- let run = 0;
1173
- let scale = 1;
1174
- for (; ; ) {
1175
- if (i >= bytes.length) throw new Error("Truncated selection run");
1176
- const b = bytes[i++];
1177
- run += (b & 127) * scale;
1178
- if (b < 128) break;
1179
- scale *= 128;
1180
- if (scale > 2 ** 35) throw new Error("Selection run too long");
1181
- }
1182
- if (run === 0 || o + run > length) throw new Error("Selection runs do not match its size");
1183
- if (v !== 0) out.fill(v, o, o + run);
1184
- o += run;
1185
- }
1186
- if (o !== length) throw new Error("Selection runs do not match its size");
1187
- return out;
1188
- }
1189
- function serializeSelection(mask) {
1190
- return { width: mask.width, height: mask.height, rle: encodeSelectionRle(mask.data) };
1191
- }
1192
- function deserializeSelection(value) {
1193
- if (!value || typeof value !== "object") throw new Error("selection must be an object");
1194
- const v = value;
1195
- const width = v.width;
1196
- const height = v.height;
1197
- checkSize(width, height);
1198
- return createSelectionMask(width, height, decodeSelectionRle(v.rle, width * height));
1199
- }
1200
- function hashMaskContent(content) {
1201
- let h = 2166136261;
1202
- if (typeof content === "string") {
1203
- for (let i = 0; i < content.length; i++) {
1204
- h ^= content.charCodeAt(i);
1205
- h = Math.imul(h, 16777619);
1206
- }
1207
- } else {
1208
- for (let i = 0; i < content.length; i++) {
1209
- h ^= content[i];
1210
- h = Math.imul(h, 16777619);
1211
- }
1212
- }
1213
- return `${(h >>> 0).toString(16)}:${content.length}`;
1214
- }
1215
-
1216
- // src/image-editor/selection/modify.ts
1217
- var EMPTY_DISTANCE = 1e10;
1218
- function distanceTransform(inside, width, height) {
1219
- const n = width * height;
1220
- const out = new Float32Array(n);
1221
- let any = false;
1222
- let all = true;
1223
- for (let i = 0; i < n; i++) {
1224
- if (inside[i]) any = true;
1225
- else all = false;
1226
- }
1227
- if (!any) return out.fill(EMPTY_DISTANCE);
1228
- if (all) return out;
1229
- const NONE = 4294967295;
1230
- const vertical = new Uint32Array(n).fill(NONE);
1231
- for (let x = 0; x < width; x++) {
1232
- let nearest = -1;
1233
- for (let y = 0; y < height; y++) {
1234
- const i = y * width + x;
1235
- if (inside[i]) nearest = y;
1236
- if (nearest >= 0) vertical[i] = y - nearest;
1237
- }
1238
- nearest = -1;
1239
- for (let y = height - 1; y >= 0; y--) {
1240
- const i = y * width + x;
1241
- if (vertical[i] === 0) nearest = y;
1242
- if (nearest >= 0) vertical[i] = Math.min(vertical[i], nearest - y);
1243
- }
1244
- }
1245
- const sites = new Int32Array(width);
1246
- const starts = new Float64Array(width);
1247
- for (let y = 0; y < height; y++) {
1248
- const row = y * width;
1249
- let count = 0;
1250
- for (let q2 = 0; q2 < width; q2++) {
1251
- const dq = vertical[row + q2];
1252
- if (dq === NONE) continue;
1253
- const fq = dq * dq;
1254
- let start = -Infinity;
1255
- while (count > 0) {
1256
- const p = sites[count - 1];
1257
- const dp = vertical[row + p];
1258
- start = (fq - dp * dp) / (2 * (q2 - p)) + (q2 + p) * 0.5;
1259
- if (start > starts[count - 1]) break;
1260
- count--;
1261
- }
1262
- if (count === 0) start = -Infinity;
1263
- sites[count] = q2;
1264
- starts[count] = start;
1265
- count++;
1266
- }
1267
- if (count === 0) {
1268
- out.fill(EMPTY_DISTANCE, row, row + width);
1269
- continue;
1270
- }
1271
- let k = 0;
1272
- for (let x = 0; x < width; x++) {
1273
- while (k + 1 < count && starts[k + 1] < x) k++;
1274
- const site = sites[k];
1275
- const dx = x - site;
1276
- const dv = vertical[row + site];
1277
- out[row + x] = Math.sqrt(dx * dx + dv * dv);
1278
- }
1279
- }
1280
- return out;
1281
- }
1282
- function thresholdInside(m, threshold = 0.5) {
1283
- const out = new Uint8Array(m.length);
1284
- for (let i = 0; i < m.length; i++) out[i] = m[i] >= threshold ? 1 : 0;
1285
- return out;
1286
- }
1287
- function expandCoverage(m, w, h, r) {
1288
- const d = distanceTransform(thresholdInside(m), w, h);
1289
- const out = new Float32Array(m.length);
1290
- for (let i = 0; i < out.length; i++) out[i] = Math.max(m[i], Math.min(1, Math.max(0, r + 1 - d[i])));
1291
- return out;
1292
- }
1293
- function contractCoverage(m, w, h, r) {
1294
- const inv = new Float32Array(m.length);
1295
- for (let i = 0; i < inv.length; i++) inv[i] = 1 - m[i];
1296
- const e = expandCoverage(inv, w, h, r);
1297
- for (let i = 0; i < e.length; i++) e[i] = 1 - e[i];
1298
- return e;
1299
- }
1300
- function borderCoverage(m, w, h, r) {
1301
- const inside = thresholdInside(m);
1302
- const outside = new Uint8Array(inside.length);
1303
- for (let i = 0; i < inside.length; i++) outside[i] = inside[i] ? 0 : 1;
1304
- const out = new Float32Array(m.length);
1305
- if (!(r > 0)) return out;
1306
- const toInside = distanceTransform(inside, w, h);
1307
- const toOutside = distanceTransform(outside, w, h);
1308
- for (let i = 0; i < out.length; i++) {
1309
- const d = inside[i] ? toOutside[i] : toInside[i];
1310
- out[i] = Math.min(1, Math.max(0, 1 - (d - 1) / r));
1311
- }
1312
- return out;
1313
- }
1314
- function boxLineReplicate(src, srcOff, stride, len, r, dst) {
1315
- const at = (i) => src[srcOff + Math.min(len - 1, Math.max(0, i)) * stride];
1316
- let sum = 0;
1317
- for (let i = -r; i <= r; i++) sum += at(i);
1318
- const k = 2 * r + 1;
1319
- for (let i = 0; i < len; i++) {
1320
- dst[i] = sum / k;
1321
- sum += at(i + r + 1) - at(i - r);
1322
- }
1323
- }
1324
- function smoothCoverage(m, w, h, r) {
1325
- const rr = Number.isFinite(r) ? Math.max(0, Math.round(r)) : 0;
1326
- const src = Float32Array.from(m);
1327
- const tmp = new Float32Array(src.length);
1328
- const line = new Float32Array(Math.max(w, h));
1329
- if (rr > 0) {
1330
- for (let y = 0; y < h; y++) {
1331
- boxLineReplicate(src, y * w, 1, w, rr, line);
1332
- tmp.set(line.subarray(0, w), y * w);
1333
- }
1334
- for (let x = 0; x < w; x++) {
1335
- boxLineReplicate(tmp, x, w, h, rr, line);
1336
- for (let y = 0; y < h; y++) src[y * w + x] = line[y];
1337
- }
1338
- }
1339
- for (let i = 0; i < src.length; i++) src[i] = src[i] >= 0.5 ? 1 : 0;
1340
- return src;
1341
- }
1342
- function featherCoverage(m, w, h, radius) {
1343
- const out = gaussianBlur(m, w, h, Number.isFinite(radius) ? Math.max(0, radius) : 0, "zero");
1344
- for (let i = 0; i < out.length; i++) if (Math.abs(out[i]) < 1e-7) out[i] = 0;
1345
- return out;
1346
- }
1347
- function runningExtreme(src, off, stride, len, r, max, g, hb, dst) {
1348
- const k = 2 * r + 1;
1349
- const pick = max ? (a, b) => a > b ? a : b : (a, b) => a < b ? a : b;
1350
- const fill = max ? -Infinity : Infinity;
1351
- const plen = len + 2 * r;
1352
- const at = (i) => i < r || i >= r + len ? fill : src[off + (i - r) * stride];
1353
- for (let start = 0; start < plen; start += k) {
1354
- const end = Math.min(plen, start + k);
1355
- g[start] = at(start);
1356
- for (let i = start + 1; i < end; i++) g[i] = pick(g[i - 1], at(i));
1357
- hb[end - 1] = at(end - 1);
1358
- for (let i = end - 2; i >= start; i--) hb[i] = pick(hb[i + 1], at(i));
1359
- }
1360
- for (let i = 0; i < len; i++) {
1361
- const a = hb[i];
1362
- const b = g[i + 2 * r];
1363
- dst[i] = pick(a, b);
1364
- }
1365
- }
1366
- function greyMorphology(src, w, h, r, grow) {
1367
- const out = Float32Array.from(src);
1368
- if (r <= 0) return out;
1369
- const n = Math.max(w, h);
1370
- const g = new Float32Array(n + 2 * r);
1371
- const hb = new Float32Array(n + 2 * r);
1372
- const line = new Float32Array(n);
1373
- for (let y = 0; y < h; y++) {
1374
- runningExtreme(out, y * w, 1, w, r, grow, g, hb, line);
1375
- out.set(line.subarray(0, w), y * w);
1376
- }
1377
- for (let x = 0; x < w; x++) {
1378
- runningExtreme(out, x, w, h, r, grow, g, hb, line);
1379
- for (let y = 0; y < h; y++) out[y * w + x] = line[y];
1380
- }
1381
- return out;
1382
- }
1383
- function shiftCoverage(src, w, h, amount) {
1384
- const mag = Math.abs(amount);
1385
- if (!Number.isFinite(mag) || mag < 1e-4) return Float32Array.from(src);
1386
- const grow = amount > 0;
1387
- const whole = Math.floor(mag);
1388
- const frac = mag - whole;
1389
- if (frac < 1e-4) return greyMorphology(src, w, h, whole, grow);
1390
- const lo = whole === 0 ? Float32Array.from(src) : greyMorphology(src, w, h, whole, grow);
1391
- const hi = greyMorphology(src, w, h, whole + 1, grow);
1392
- for (let i = 0; i < lo.length; i++) lo[i] += (hi[i] - lo[i]) * frac;
1393
- return lo;
1394
- }
1395
- var SELECTION_MODIFY_OPS = ["expand", "contract", "feather", "border", "smooth", "grow", "shrink"];
1396
- function wrap(mask, coverage) {
1397
- const out = new Uint8Array(coverage.length);
1398
- for (let i = 0; i < out.length; i++) out[i] = coverageToByte(coverage[i]);
1399
- return createSelectionMask(mask.width, mask.height, out);
1400
- }
1401
- function modifySelection(mask, op, radius) {
1402
- const r = Number.isFinite(radius) ? Math.max(0, radius) : 0;
1403
- if (r === 0 && op !== "border") return mask;
1404
- const m = selectionToCoverage(mask);
1405
- const { width: w, height: h } = mask;
1406
- switch (op) {
1407
- case "expand":
1408
- case "grow":
1409
- return wrap(mask, expandCoverage(m, w, h, r));
1410
- case "contract":
1411
- case "shrink":
1412
- return wrap(mask, contractCoverage(m, w, h, r));
1413
- case "feather":
1414
- return wrap(mask, featherCoverage(m, w, h, r));
1415
- case "border":
1416
- return wrap(mask, borderCoverage(m, w, h, r));
1417
- case "smooth":
1418
- return wrap(mask, smoothCoverage(m, w, h, r));
1419
- default:
1420
- throw new Error(`Unknown selection modification "${op}"`);
1421
- }
1422
- }
1423
-
1424
722
  // src/image-editor/selection/layer-mask.ts
1425
723
  function layerMaskSelection(layer, width, height) {
1426
724
  if (!layer.mask || layer.mask.source) return null;
@@ -1429,12 +727,12 @@ function layerMaskSelection(layer, width, height) {
1429
727
  const data = readRegion(layer.mask.surface, { x: -ox, y: -oy, width, height });
1430
728
  return createSelectionMask(width, height, new Uint8Array(data.buffer, data.byteOffset, data.length));
1431
729
  }
1432
- var MAX_SIDE2 = 1 << 15;
730
+ var MAX_SIDE = 1 << 15;
1433
731
  function normalizeLayerMask(raw) {
1434
732
  if (!raw || typeof raw !== "object") return null;
1435
733
  const r = raw;
1436
734
  const { width, height, rle } = r;
1437
- if (typeof width !== "number" || typeof height !== "number" || !Number.isInteger(width) || !Number.isInteger(height) || width < 1 || height < 1 || width > MAX_SIDE2 || height > MAX_SIDE2 || typeof rle !== "string" || !rle.startsWith("r1:")) {
735
+ if (typeof width !== "number" || typeof height !== "number" || !Number.isInteger(width) || !Number.isInteger(height) || width < 1 || height < 1 || width > MAX_SIDE || height > MAX_SIDE || typeof rle !== "string" || !rle.startsWith("r1:")) {
1438
736
  return null;
1439
737
  }
1440
738
  const out = { width, height, rle };
@@ -12062,41 +11360,6 @@ export {
12062
11360
  calculateCropDrag,
12063
11361
  getAnnotationBounds,
12064
11362
  hitTestAnnotation,
12065
- SELECTION_MODES,
12066
- isSelectionMode,
12067
- parseSelectionMode,
12068
- computeSelectionBounds,
12069
- selectionFromTiles,
12070
- createSelectionMask,
12071
- selectionFromRegion,
12072
- fullSelection,
12073
- isSelectionEmpty,
12074
- selectionValueAt,
12075
- coverageToByte,
12076
- selectionFromCoverage,
12077
- selectionToCoverage,
12078
- selectionArea,
12079
- combineSelections,
12080
- invertSelection,
12081
- resizeSelection,
12082
- selectionFromPixels,
12083
- selectionToPixels,
12084
- encodeSelectionRle,
12085
- decodeSelectionRle,
12086
- serializeSelection,
12087
- deserializeSelection,
12088
- hashMaskContent,
12089
- EMPTY_DISTANCE,
12090
- distanceTransform,
12091
- expandCoverage,
12092
- contractCoverage,
12093
- borderCoverage,
12094
- smoothCoverage,
12095
- featherCoverage,
12096
- greyMorphology,
12097
- shiftCoverage,
12098
- SELECTION_MODIFY_OPS,
12099
- modifySelection,
12100
11363
  layerMaskSelection,
12101
11364
  normalizeLayerMask,
12102
11365
  layerMaskFromSelection,