@nice2dev/ui-graphics 1.3.15 → 1.3.16

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 (294) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/cjs/animation/AnimatedPerson.js +470 -143
  3. package/dist/cjs/animation/AnimationEditor.js +289 -101
  4. package/dist/cjs/animation/Audience.js +83 -61
  5. package/dist/cjs/animation/BodyRenderer.js +69 -28
  6. package/dist/cjs/animation/animationHelper.js +281 -288
  7. package/dist/cjs/animation/characterTypes.js +200 -203
  8. package/dist/cjs/animation/choreoDSL.js +205 -219
  9. package/dist/cjs/animation/choreography.js +4 -32
  10. package/dist/cjs/animation/karaokeIntegration.js +68 -77
  11. package/dist/cjs/animation/lottieExport.js +108 -114
  12. package/dist/cjs/animation/motionPath.js +225 -248
  13. package/dist/cjs/animation/physics.js +227 -254
  14. package/dist/cjs/animation/rig/RigPlayer.js +53 -56
  15. package/dist/cjs/animation/rig/RiggedBody.js +71 -26
  16. package/dist/cjs/animation/rig/choreoRigBridge.js +72 -77
  17. package/dist/cjs/animation/rig/ik.js +13 -18
  18. package/dist/cjs/animation/rig/poseOps.js +34 -41
  19. package/dist/cjs/animation/rig/presets.js +64 -72
  20. package/dist/cjs/animation/rig/rigMath.js +25 -32
  21. package/dist/cjs/animation/rig/rigTypes.js +59 -63
  22. package/dist/cjs/animation/shapes/arms.js +31 -13
  23. package/dist/cjs/animation/shapes/eyes.js +129 -47
  24. package/dist/cjs/animation/shapes/hair.js +72 -45
  25. package/dist/cjs/animation/shapes/heads.js +131 -57
  26. package/dist/cjs/animation/shapes/headwear.js +47 -38
  27. package/dist/cjs/animation/shapes/legs.js +31 -13
  28. package/dist/cjs/animation/shapes/mouths.js +120 -44
  29. package/dist/cjs/animation/shapes/noses.js +80 -25
  30. package/dist/cjs/animation/shapes/outfits.js +101 -39
  31. package/dist/cjs/animation/shapes/torsos.js +15 -11
  32. package/dist/cjs/animation/spineExport.js +103 -121
  33. package/dist/cjs/core/LocalUI.js +108 -43
  34. package/dist/cjs/core/NiceBrushEngine.js +758 -552
  35. package/dist/cjs/core/collaboration.js +249 -251
  36. package/dist/cjs/core/colorBlindness.js +100 -115
  37. package/dist/cjs/core/dragDrop.js +155 -158
  38. package/dist/cjs/core/editorAsk.js +51 -41
  39. package/dist/cjs/core/fixes.js +140 -171
  40. package/dist/cjs/core/gridGuides.js +166 -201
  41. package/dist/cjs/core/historyVisual.js +156 -135
  42. package/dist/cjs/core/i18n.js +13 -14
  43. package/dist/cjs/core/integrations.js +238 -249
  44. package/dist/cjs/core/minimap.js +149 -151
  45. package/dist/cjs/core/plugins.js +98 -113
  46. package/dist/cjs/core/rtl.js +71 -83
  47. package/dist/cjs/core/shortcuts.js +196 -225
  48. package/dist/cjs/core/theme.js +142 -149
  49. package/dist/cjs/core/yjsCollaboration.js +232 -293
  50. package/dist/cjs/design/design-tools.js +12 -22
  51. package/dist/cjs/font/NiceFontEditor.js +877 -316
  52. package/dist/cjs/font/fontFormatUtils.js +388 -448
  53. package/dist/cjs/game/GameAsset2dEditor.js +1201 -392
  54. package/dist/cjs/game/GameAsset2dEditor.module.css.js +146 -5
  55. package/dist/cjs/game/gameAssetTypes.js +7 -16
  56. package/dist/cjs/game/gameAssetUtils.js +390 -413
  57. package/dist/cjs/game/useGameAssetEditor.js +820 -763
  58. package/dist/cjs/index.js +81 -84
  59. package/dist/cjs/nice2dev-ui-graphics.css +1 -1
  60. package/dist/cjs/node_modules/lib0/array.js +8 -70
  61. package/dist/cjs/node_modules/lib0/binary.js +3 -20
  62. package/dist/cjs/node_modules/lib0/broadcastchannel.js +24 -86
  63. package/dist/cjs/node_modules/lib0/buffer.js +15 -82
  64. package/dist/cjs/node_modules/lib0/conditions.js +3 -16
  65. package/dist/cjs/node_modules/lib0/decoding.js +108 -287
  66. package/dist/cjs/node_modules/lib0/dom.js +14 -44
  67. package/dist/cjs/node_modules/lib0/encoding.js +68 -418
  68. package/dist/cjs/node_modules/lib0/environment.js +26 -92
  69. package/dist/cjs/node_modules/lib0/error.js +5 -29
  70. package/dist/cjs/node_modules/lib0/function.js +27 -66
  71. package/dist/cjs/node_modules/lib0/iterator.js +8 -33
  72. package/dist/cjs/node_modules/lib0/logging.common.js +12 -22
  73. package/dist/cjs/node_modules/lib0/logging.js +32 -71
  74. package/dist/cjs/node_modules/lib0/map.js +16 -86
  75. package/dist/cjs/node_modules/lib0/math.js +3 -32
  76. package/dist/cjs/node_modules/lib0/number.js +4 -15
  77. package/dist/cjs/node_modules/lib0/object.js +14 -88
  78. package/dist/cjs/node_modules/lib0/observable.js +38 -78
  79. package/dist/cjs/node_modules/lib0/pair.js +3 -20
  80. package/dist/cjs/node_modules/lib0/prng.js +8 -77
  81. package/dist/cjs/node_modules/lib0/promise.js +6 -30
  82. package/dist/cjs/node_modules/lib0/random.js +8 -23
  83. package/dist/cjs/node_modules/lib0/schema.js +313 -687
  84. package/dist/cjs/node_modules/lib0/set.js +3 -10
  85. package/dist/cjs/node_modules/lib0/storage.js +20 -55
  86. package/dist/cjs/node_modules/lib0/string.js +17 -72
  87. package/dist/cjs/node_modules/lib0/symbol.js +2 -12
  88. package/dist/cjs/node_modules/lib0/time.js +2 -15
  89. package/dist/cjs/node_modules/lib0/trait/equality.js +3 -28
  90. package/dist/cjs/node_modules/lib0/url.js +4 -18
  91. package/dist/cjs/node_modules/lib0/webcrypto.js +2 -5
  92. package/dist/cjs/node_modules/y-protocols/auth.js +5 -19
  93. package/dist/cjs/node_modules/y-protocols/awareness.js +53 -116
  94. package/dist/cjs/node_modules/y-protocols/sync.js +16 -103
  95. package/dist/cjs/node_modules/y-websocket/src/y-websocket.js +77 -219
  96. package/dist/cjs/node_modules/yjs/dist/yjs.js +2128 -4868
  97. package/dist/cjs/photo/FilterThumb.js +37 -25
  98. package/dist/cjs/photo/NiceAITools.js +679 -467
  99. package/dist/cjs/photo/PhotoEditor.js +34 -20
  100. package/dist/cjs/photo/PhotoEditor.module.css.js +296 -5
  101. package/dist/cjs/photo/PhotoEditorCanvas.js +250 -91
  102. package/dist/cjs/photo/PhotoEditorLeftPanel.js +1086 -224
  103. package/dist/cjs/photo/PhotoEditorToolbar.js +135 -19
  104. package/dist/cjs/photo/photoEditorActions.js +89 -72
  105. package/dist/cjs/photo/photoEditorTypes.js +29 -32
  106. package/dist/cjs/photo/photoFilters.js +959 -985
  107. package/dist/cjs/photo/photoOverlays.js +899 -945
  108. package/dist/cjs/photo/photoSelection.js +427 -499
  109. package/dist/cjs/photo/usePhotoEditor.js +739 -741
  110. package/dist/cjs/pixel/HSVPicker.js +191 -175
  111. package/dist/cjs/pixel/PixelEditor.js +159 -48
  112. package/dist/cjs/pixel/PixelEditor.module.css.js +209 -5
  113. package/dist/cjs/pixel/PixelEditorCanvas.js +29 -16
  114. package/dist/cjs/pixel/PixelEditorMenuBar.js +160 -162
  115. package/dist/cjs/pixel/PixelEditorRightPanel.js +377 -45
  116. package/dist/cjs/pixel/PixelEditorStatusBar.js +47 -20
  117. package/dist/cjs/pixel/PixelEditorTimeline.js +106 -23
  118. package/dist/cjs/pixel/PixelEditorToolbar.js +99 -21
  119. package/dist/cjs/pixel/SpriteGeneratorPanel.js +483 -303
  120. package/dist/cjs/pixel/animalGeneratorPresets.js +776 -601
  121. package/dist/cjs/pixel/asepriteFormat.js +511 -560
  122. package/dist/cjs/pixel/buildingGeneratorPresets.js +693 -520
  123. package/dist/cjs/pixel/characterGeneratorPresets.js +644 -544
  124. package/dist/cjs/pixel/pixel-pro.js +52 -63
  125. package/dist/cjs/pixel/pixelEditorExports.js +388 -428
  126. package/dist/cjs/pixel/pixelEditorTypes.js +91 -108
  127. package/dist/cjs/pixel/pixelEditorUtils.js +519 -561
  128. package/dist/cjs/pixel/spriteGeneratorCore.js +206 -257
  129. package/dist/cjs/pixel/usePixelEditor.js +1321 -1343
  130. package/dist/cjs/texture/Nice3DTexturePainter.js +707 -440
  131. package/dist/cjs/ui/NiceUIDesigner.js +954 -527
  132. package/dist/cjs/vector/NiceSvgToCode.js +586 -446
  133. package/dist/cjs/vector/VectorEditor.js +290 -117
  134. package/dist/cjs/vector/VectorEditor.module.css.js +86 -5
  135. package/dist/cjs/vector/VectorEditorMenuBar.js +333 -275
  136. package/dist/cjs/vector/VectorEditorRightPanel.js +1094 -371
  137. package/dist/cjs/vector/VectorEditorShapeRenderer.js +198 -60
  138. package/dist/cjs/vector/VectorEditorStatusBar.js +39 -13
  139. package/dist/cjs/vector/useVectorEditor.js +848 -889
  140. package/dist/cjs/vector/vectorAnimation.js +110 -137
  141. package/dist/cjs/vector/vectorBooleanOps.js +398 -485
  142. package/dist/cjs/vector/vectorEditorExport.js +201 -203
  143. package/dist/cjs/vector/vectorEditorImport.js +173 -189
  144. package/dist/cjs/vector/vectorEditorTypes.js +42 -49
  145. package/dist/cjs/vector/vectorGradients.js +151 -174
  146. package/dist/cjs/vector/vectorIconExport.js +52 -59
  147. package/dist/cjs/vector/vectorIconImport.js +169 -219
  148. package/dist/esm/animation/AnimatedPerson.js +470 -141
  149. package/dist/esm/animation/AnimationEditor.js +290 -100
  150. package/dist/esm/animation/Audience.js +83 -59
  151. package/dist/esm/animation/BodyRenderer.js +71 -25
  152. package/dist/esm/animation/animationHelper.js +284 -287
  153. package/dist/esm/animation/characterTypes.js +204 -202
  154. package/dist/esm/animation/choreoDSL.js +212 -218
  155. package/dist/esm/animation/choreography.js +8 -31
  156. package/dist/esm/animation/karaokeIntegration.js +74 -76
  157. package/dist/esm/animation/lottieExport.js +112 -113
  158. package/dist/esm/animation/motionPath.js +235 -247
  159. package/dist/esm/animation/physics.js +235 -253
  160. package/dist/esm/animation/rig/RigPlayer.js +53 -54
  161. package/dist/esm/animation/rig/RiggedBody.js +71 -24
  162. package/dist/esm/animation/rig/choreoRigBridge.js +74 -76
  163. package/dist/esm/animation/rig/ik.js +14 -17
  164. package/dist/esm/animation/rig/poseOps.js +37 -40
  165. package/dist/esm/animation/rig/presets.js +70 -71
  166. package/dist/esm/animation/rig/rigMath.js +28 -31
  167. package/dist/esm/animation/rig/rigTypes.js +62 -62
  168. package/dist/esm/animation/shapes/arms.js +32 -12
  169. package/dist/esm/animation/shapes/eyes.js +135 -46
  170. package/dist/esm/animation/shapes/hair.js +80 -44
  171. package/dist/esm/animation/shapes/heads.js +140 -56
  172. package/dist/esm/animation/shapes/headwear.js +54 -37
  173. package/dist/esm/animation/shapes/legs.js +32 -12
  174. package/dist/esm/animation/shapes/mouths.js +127 -43
  175. package/dist/esm/animation/shapes/noses.js +87 -24
  176. package/dist/esm/animation/shapes/outfits.js +106 -38
  177. package/dist/esm/animation/shapes/torsos.js +16 -10
  178. package/dist/esm/animation/spineExport.js +106 -120
  179. package/dist/esm/core/LocalUI.js +111 -42
  180. package/dist/esm/core/NiceBrushEngine.js +761 -551
  181. package/dist/esm/core/collaboration.js +255 -250
  182. package/dist/esm/core/colorBlindness.js +106 -114
  183. package/dist/esm/core/dragDrop.js +157 -157
  184. package/dist/esm/core/editorAsk.js +53 -40
  185. package/dist/esm/core/fixes.js +145 -170
  186. package/dist/esm/core/gridGuides.js +178 -200
  187. package/dist/esm/core/historyVisual.js +158 -134
  188. package/dist/esm/core/i18n.js +15 -13
  189. package/dist/esm/core/integrations.js +244 -248
  190. package/dist/esm/core/minimap.js +151 -150
  191. package/dist/esm/core/plugins.js +102 -112
  192. package/dist/esm/core/rtl.js +77 -82
  193. package/dist/esm/core/shortcuts.js +200 -224
  194. package/dist/esm/core/theme.js +150 -148
  195. package/dist/esm/core/yjsCollaboration.js +240 -292
  196. package/dist/esm/design/design-tools.js +13 -21
  197. package/dist/esm/font/NiceFontEditor.js +880 -315
  198. package/dist/esm/font/fontFormatUtils.js +394 -447
  199. package/dist/esm/game/GameAsset2dEditor.js +1202 -391
  200. package/dist/esm/game/GameAsset2dEditor.module.css.js +146 -3
  201. package/dist/esm/game/gameAssetTypes.js +8 -15
  202. package/dist/esm/game/gameAssetUtils.js +408 -412
  203. package/dist/esm/game/useGameAssetEditor.js +821 -762
  204. package/dist/esm/index.js +332 -69
  205. package/dist/esm/nice2dev-ui-graphics.css +1 -1
  206. package/dist/esm/node_modules/lib0/array.js +15 -69
  207. package/dist/esm/node_modules/lib0/binary.js +14 -19
  208. package/dist/esm/node_modules/lib0/broadcastchannel.js +27 -85
  209. package/dist/esm/node_modules/lib0/buffer.js +20 -80
  210. package/dist/esm/node_modules/lib0/conditions.js +4 -15
  211. package/dist/esm/node_modules/lib0/decoding.js +128 -286
  212. package/dist/esm/node_modules/lib0/dom.js +20 -43
  213. package/dist/esm/node_modules/lib0/encoding.js +90 -415
  214. package/dist/esm/node_modules/lib0/environment.js +33 -91
  215. package/dist/esm/node_modules/lib0/error.js +8 -28
  216. package/dist/esm/node_modules/lib0/function.js +31 -65
  217. package/dist/esm/node_modules/lib0/iterator.js +11 -32
  218. package/dist/esm/node_modules/lib0/logging.common.js +22 -21
  219. package/dist/esm/node_modules/lib0/logging.js +44 -70
  220. package/dist/esm/node_modules/lib0/map.js +21 -85
  221. package/dist/esm/node_modules/lib0/math.js +9 -31
  222. package/dist/esm/node_modules/lib0/number.js +7 -14
  223. package/dist/esm/node_modules/lib0/object.js +26 -87
  224. package/dist/esm/node_modules/lib0/observable.js +40 -77
  225. package/dist/esm/node_modules/lib0/pair.js +5 -19
  226. package/dist/esm/node_modules/lib0/prng.js +15 -76
  227. package/dist/esm/node_modules/lib0/promise.js +7 -29
  228. package/dist/esm/node_modules/lib0/random.js +10 -22
  229. package/dist/esm/node_modules/lib0/schema.js +367 -686
  230. package/dist/esm/node_modules/lib0/set.js +4 -9
  231. package/dist/esm/node_modules/lib0/storage.js +23 -54
  232. package/dist/esm/node_modules/lib0/string.js +26 -71
  233. package/dist/esm/node_modules/lib0/symbol.js +3 -11
  234. package/dist/esm/node_modules/lib0/time.js +3 -14
  235. package/dist/esm/node_modules/lib0/trait/equality.js +5 -27
  236. package/dist/esm/node_modules/lib0/url.js +5 -17
  237. package/dist/esm/node_modules/lib0/webcrypto.js +3 -4
  238. package/dist/esm/node_modules/y-protocols/auth.js +7 -18
  239. package/dist/esm/node_modules/y-protocols/awareness.js +58 -115
  240. package/dist/esm/node_modules/y-protocols/sync.js +26 -102
  241. package/dist/esm/node_modules/y-websocket/src/y-websocket.js +82 -218
  242. package/dist/esm/node_modules/yjs/dist/yjs.js +2263 -4899
  243. package/dist/esm/photo/FilterThumb.js +37 -23
  244. package/dist/esm/photo/NiceAITools.js +685 -466
  245. package/dist/esm/photo/PhotoEditor.js +34 -18
  246. package/dist/esm/photo/PhotoEditor.module.css.js +296 -3
  247. package/dist/esm/photo/PhotoEditorCanvas.js +250 -89
  248. package/dist/esm/photo/PhotoEditorLeftPanel.js +1086 -222
  249. package/dist/esm/photo/PhotoEditorToolbar.js +135 -17
  250. package/dist/esm/photo/photoEditorActions.js +93 -71
  251. package/dist/esm/photo/photoEditorTypes.js +32 -31
  252. package/dist/esm/photo/photoFilters.js +967 -984
  253. package/dist/esm/photo/photoOverlays.js +913 -944
  254. package/dist/esm/photo/photoSelection.js +438 -498
  255. package/dist/esm/photo/usePhotoEditor.js +740 -740
  256. package/dist/esm/pixel/HSVPicker.js +192 -174
  257. package/dist/esm/pixel/PixelEditor.js +160 -47
  258. package/dist/esm/pixel/PixelEditor.module.css.js +209 -3
  259. package/dist/esm/pixel/PixelEditorCanvas.js +29 -14
  260. package/dist/esm/pixel/PixelEditorMenuBar.js +160 -160
  261. package/dist/esm/pixel/PixelEditorRightPanel.js +377 -43
  262. package/dist/esm/pixel/PixelEditorStatusBar.js +47 -18
  263. package/dist/esm/pixel/PixelEditorTimeline.js +106 -21
  264. package/dist/esm/pixel/PixelEditorToolbar.js +99 -19
  265. package/dist/esm/pixel/SpriteGeneratorPanel.js +483 -301
  266. package/dist/esm/pixel/animalGeneratorPresets.js +782 -600
  267. package/dist/esm/pixel/asepriteFormat.js +517 -559
  268. package/dist/esm/pixel/buildingGeneratorPresets.js +699 -519
  269. package/dist/esm/pixel/characterGeneratorPresets.js +650 -543
  270. package/dist/esm/pixel/pixel-pro.js +53 -62
  271. package/dist/esm/pixel/pixelEditorExports.js +397 -427
  272. package/dist/esm/pixel/pixelEditorTypes.js +103 -107
  273. package/dist/esm/pixel/pixelEditorUtils.js +551 -560
  274. package/dist/esm/pixel/spriteGeneratorCore.js +223 -256
  275. package/dist/esm/pixel/usePixelEditor.js +1322 -1342
  276. package/dist/esm/texture/Nice3DTexturePainter.js +709 -439
  277. package/dist/esm/ui/NiceUIDesigner.js +957 -526
  278. package/dist/esm/vector/NiceSvgToCode.js +589 -445
  279. package/dist/esm/vector/VectorEditor.js +291 -116
  280. package/dist/esm/vector/VectorEditor.module.css.js +86 -3
  281. package/dist/esm/vector/VectorEditorMenuBar.js +333 -273
  282. package/dist/esm/vector/VectorEditorRightPanel.js +1094 -369
  283. package/dist/esm/vector/VectorEditorShapeRenderer.js +199 -59
  284. package/dist/esm/vector/VectorEditorStatusBar.js +39 -11
  285. package/dist/esm/vector/useVectorEditor.js +849 -888
  286. package/dist/esm/vector/vectorAnimation.js +115 -136
  287. package/dist/esm/vector/vectorBooleanOps.js +401 -484
  288. package/dist/esm/vector/vectorEditorExport.js +207 -202
  289. package/dist/esm/vector/vectorEditorImport.js +174 -188
  290. package/dist/esm/vector/vectorEditorTypes.js +50 -48
  291. package/dist/esm/vector/vectorGradients.js +158 -173
  292. package/dist/esm/vector/vectorIconExport.js +53 -58
  293. package/dist/esm/vector/vectorIconImport.js +171 -218
  294. package/package.json +9 -15
@@ -1,472 +1,432 @@
1
- 'use strict';
2
-
3
- var uiCore = require('@nice2dev/ui-core');
4
- var asepriteFormat = require('./asepriteFormat.js');
5
- var pixelEditorTypes = require('./pixelEditorTypes.js');
6
-
7
- /**
8
- * pixelEditorExports — pixel editor file export utilities as pure functions.
9
- */
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const uiCore = require("@nice2dev/ui-core");
4
+ const asepriteFormat = require("./asepriteFormat.js");
5
+ const pixelEditorTypes = require("./pixelEditorTypes.js");
10
6
  const log = { error: console.error, warn: console.warn };
11
7
  async function exportAse(ctx) {
12
- const { dw, dh, layers, fc, fDur, pal, cels } = ctx;
13
- const doc = asepriteFormat.createEmptyAseDocument(dw, dh);
14
- doc.layers = layers.map((l) => ({
15
- name: l.name,
16
- visible: l.visible,
17
- opacity: l.opacity,
18
- blendMode: 0,
19
- childLevel: 0,
20
- layerType: 0,
21
- }));
22
- doc.palette = pal.map(asepriteFormat.hexToAseColor);
23
- doc.frames = [];
24
- for (let fi = 0; fi < fc; fi++) {
25
- const frameCels = [];
26
- for (let li = 0; li < layers.length; li++) {
27
- const cel = cels.get(pixelEditorTypes.celKey(fi, li));
28
- if (!cel) {
29
- continue;
30
- }
31
- // tight bounding box
32
- let x1 = dw, y1 = dh, x2 = -1, y2 = -1;
33
- for (let y = 0; y < dh; y++) {
34
- for (let x = 0; x < dw; x++) {
35
- if (cel.data[(y * dw + x) * 4 + 3] > 0) {
36
- x1 = Math.min(x1, x);
37
- y1 = Math.min(y1, y);
38
- x2 = Math.max(x2, x);
39
- y2 = Math.max(y2, y);
40
- }
41
- }
42
- }
43
- if (x2 < 0) {
44
- continue;
45
- }
46
- const cw2 = x2 - x1 + 1, ch2 = y2 - y1 + 1;
47
- const px2 = new Uint8Array(cw2 * ch2 * 4);
48
- for (let y = 0; y < ch2; y++) {
49
- for (let x = 0; x < cw2; x++) {
50
- const si = ((y1 + y) * dw + (x1 + x)) * 4;
51
- const di = (y * cw2 + x) * 4;
52
- px2[di] = cel.data[si];
53
- px2[di + 1] = cel.data[si + 1];
54
- px2[di + 2] = cel.data[si + 2];
55
- px2[di + 3] = cel.data[si + 3];
56
- }
57
- }
58
- frameCels.push({
59
- layerIndex: li,
60
- x: x1,
61
- y: y1,
62
- opacity: 255,
63
- width: cw2,
64
- height: ch2,
65
- pixels: px2,
66
- });
8
+ const { dw, dh, layers, fc, fDur, pal, cels } = ctx;
9
+ const doc = asepriteFormat.createEmptyAseDocument(dw, dh);
10
+ doc.layers = layers.map((l) => ({
11
+ name: l.name,
12
+ visible: l.visible,
13
+ opacity: l.opacity,
14
+ blendMode: 0,
15
+ childLevel: 0,
16
+ layerType: 0
17
+ }));
18
+ doc.palette = pal.map(asepriteFormat.hexToAseColor);
19
+ doc.frames = [];
20
+ for (let fi = 0; fi < fc; fi++) {
21
+ const frameCels = [];
22
+ for (let li = 0; li < layers.length; li++) {
23
+ const cel = cels.get(pixelEditorTypes.celKey(fi, li));
24
+ if (!cel) {
25
+ continue;
26
+ }
27
+ let x1 = dw, y1 = dh, x2 = -1, y2 = -1;
28
+ for (let y = 0; y < dh; y++) {
29
+ for (let x = 0; x < dw; x++) {
30
+ if (cel.data[(y * dw + x) * 4 + 3] > 0) {
31
+ x1 = Math.min(x1, x);
32
+ y1 = Math.min(y1, y);
33
+ x2 = Math.max(x2, x);
34
+ y2 = Math.max(y2, y);
35
+ }
67
36
  }
68
- doc.frames.push({ duration: fDur[fi] || 100, cels: frameCels });
69
- }
70
- try {
71
- const buf = await asepriteFormat.writeAseFile(doc);
72
- pixelEditorTypes.downloadBlob(new Blob([buf]), 'sprite.ase');
73
- }
74
- catch (err) {
75
- log.error('Export ASE failed', err);
76
- console.warn('[PixelEditor] Export failed.');
37
+ }
38
+ if (x2 < 0) {
39
+ continue;
40
+ }
41
+ const cw2 = x2 - x1 + 1, ch2 = y2 - y1 + 1;
42
+ const px2 = new Uint8Array(cw2 * ch2 * 4);
43
+ for (let y = 0; y < ch2; y++) {
44
+ for (let x = 0; x < cw2; x++) {
45
+ const si = ((y1 + y) * dw + (x1 + x)) * 4;
46
+ const di = (y * cw2 + x) * 4;
47
+ px2[di] = cel.data[si];
48
+ px2[di + 1] = cel.data[si + 1];
49
+ px2[di + 2] = cel.data[si + 2];
50
+ px2[di + 3] = cel.data[si + 3];
51
+ }
52
+ }
53
+ frameCels.push({
54
+ layerIndex: li,
55
+ x: x1,
56
+ y: y1,
57
+ opacity: 255,
58
+ width: cw2,
59
+ height: ch2,
60
+ pixels: px2
61
+ });
77
62
  }
63
+ doc.frames.push({ duration: fDur[fi] || 100, cels: frameCels });
64
+ }
65
+ try {
66
+ const buf = await asepriteFormat.writeAseFile(doc);
67
+ pixelEditorTypes.downloadBlob(new Blob([buf]), "sprite.ase");
68
+ } catch (err) {
69
+ log.error("Export ASE failed", err);
70
+ console.warn("[PixelEditor] Export failed.");
71
+ }
78
72
  }
79
73
  function exportPNG(afi, dw, dh, compFrame) {
80
- const data = compFrame(afi);
81
- const cv = document.createElement('canvas');
82
- cv.width = dw;
83
- cv.height = dh;
84
- cv.getContext('2d').putImageData(data, 0, 0);
85
- cv.toBlob((b) => b && pixelEditorTypes.downloadBlob(b, 'sprite.png'));
74
+ const data = compFrame(afi);
75
+ const cv = document.createElement("canvas");
76
+ cv.width = dw;
77
+ cv.height = dh;
78
+ cv.getContext("2d").putImageData(data, 0, 0);
79
+ cv.toBlob((b) => b && pixelEditorTypes.downloadBlob(b, "sprite.png"));
86
80
  }
87
81
  function exportJPG(afi, dw, dh, compFrame) {
88
- const data = compFrame(afi);
89
- const cv = document.createElement('canvas');
90
- cv.width = dw;
91
- cv.height = dh;
92
- const ctx = cv.getContext('2d');
93
- // JPG doesn't support transparency — fill white background first
94
- ctx.fillStyle = uiCore.resolveCssColor('var(--nice-bg, #fff)', ctx.canvas);
95
- ctx.fillRect(0, 0, dw, dh);
96
- // Use drawImage instead of putImageData to properly composite over white
97
- const tmp = document.createElement('canvas');
98
- tmp.width = dw;
99
- tmp.height = dh;
100
- tmp.getContext('2d').putImageData(data, 0, 0);
101
- ctx.drawImage(tmp, 0, 0);
102
- cv.toBlob((b) => b && pixelEditorTypes.downloadBlob(b, 'sprite.jpg'), 'image/jpeg', 0.92);
82
+ const data = compFrame(afi);
83
+ const cv = document.createElement("canvas");
84
+ cv.width = dw;
85
+ cv.height = dh;
86
+ const ctx = cv.getContext("2d");
87
+ ctx.fillStyle = uiCore.resolveCssColor("var(--nice-bg, #fff)", ctx.canvas);
88
+ ctx.fillRect(0, 0, dw, dh);
89
+ const tmp = document.createElement("canvas");
90
+ tmp.width = dw;
91
+ tmp.height = dh;
92
+ tmp.getContext("2d").putImageData(data, 0, 0);
93
+ ctx.drawImage(tmp, 0, 0);
94
+ cv.toBlob((b) => b && pixelEditorTypes.downloadBlob(b, "sprite.jpg"), "image/jpeg", 0.92);
103
95
  }
104
96
  function exportWebP(afi, dw, dh, compFrame) {
105
- const data = compFrame(afi);
106
- const cv = document.createElement('canvas');
107
- cv.width = dw;
108
- cv.height = dh;
109
- cv.getContext('2d').putImageData(data, 0, 0);
110
- cv.toBlob((b) => b && pixelEditorTypes.downloadBlob(b, 'sprite.webp'), 'image/webp', 0.92);
97
+ const data = compFrame(afi);
98
+ const cv = document.createElement("canvas");
99
+ cv.width = dw;
100
+ cv.height = dh;
101
+ cv.getContext("2d").putImageData(data, 0, 0);
102
+ cv.toBlob((b) => b && pixelEditorTypes.downloadBlob(b, "sprite.webp"), "image/webp", 0.92);
111
103
  }
112
104
  function exportBMP(afi, dw, dh, compFrame) {
113
- const data = compFrame(afi);
114
- // Build BMP file manually (24-bit uncompressed)
115
- const w = dw, h = dh;
116
- const rowSize = Math.ceil((w * 3) / 4) * 4;
117
- const pixelDataSize = rowSize * h;
118
- const fileSize = 54 + pixelDataSize;
119
- const buf = new ArrayBuffer(fileSize);
120
- const view = new DataView(buf);
121
- // BMP Header
122
- view.setUint8(0, 0x42);
123
- view.setUint8(1, 0x4d); // 'BM'
124
- view.setUint32(2, fileSize, true);
125
- view.setUint32(10, 54, true); // pixel data offset
126
- // DIB Header (BITMAPINFOHEADER)
127
- view.setUint32(14, 40, true); // header size
128
- view.setInt32(18, w, true);
129
- view.setInt32(22, h, true);
130
- view.setUint16(26, 1, true); // planes
131
- view.setUint16(28, 24, true); // bpp
132
- view.setUint32(34, pixelDataSize, true);
133
- // Pixel data (bottom-up, BGR)
134
- const d = data.data;
135
- for (let y = 0; y < h; y++) {
136
- const srcRow = (h - 1 - y) * w * 4;
137
- const dstRow = 54 + y * rowSize;
138
- for (let x = 0; x < w; x++) {
139
- const si = srcRow + x * 4;
140
- const di = dstRow + x * 3;
141
- view.setUint8(di, d[si + 2]); // B
142
- view.setUint8(di + 1, d[si + 1]); // G
143
- view.setUint8(di + 2, d[si]); // R
144
- }
105
+ const data = compFrame(afi);
106
+ const w = dw, h = dh;
107
+ const rowSize = Math.ceil(w * 3 / 4) * 4;
108
+ const pixelDataSize = rowSize * h;
109
+ const fileSize = 54 + pixelDataSize;
110
+ const buf = new ArrayBuffer(fileSize);
111
+ const view = new DataView(buf);
112
+ view.setUint8(0, 66);
113
+ view.setUint8(1, 77);
114
+ view.setUint32(2, fileSize, true);
115
+ view.setUint32(10, 54, true);
116
+ view.setUint32(14, 40, true);
117
+ view.setInt32(18, w, true);
118
+ view.setInt32(22, h, true);
119
+ view.setUint16(26, 1, true);
120
+ view.setUint16(28, 24, true);
121
+ view.setUint32(34, pixelDataSize, true);
122
+ const d = data.data;
123
+ for (let y = 0; y < h; y++) {
124
+ const srcRow = (h - 1 - y) * w * 4;
125
+ const dstRow = 54 + y * rowSize;
126
+ for (let x = 0; x < w; x++) {
127
+ const si = srcRow + x * 4;
128
+ const di = dstRow + x * 3;
129
+ view.setUint8(di, d[si + 2]);
130
+ view.setUint8(di + 1, d[si + 1]);
131
+ view.setUint8(di + 2, d[si]);
145
132
  }
146
- pixelEditorTypes.downloadBlob(new Blob([buf], { type: 'image/bmp' }), 'sprite.bmp');
133
+ }
134
+ pixelEditorTypes.downloadBlob(new Blob([buf], { type: "image/bmp" }), "sprite.bmp");
147
135
  }
148
136
  function exportSVG(afi, dw, dh, compFrame) {
149
- // Trace pixel art to SVG by emitting 1 rect per non-transparent pixel
150
- const data = compFrame(afi);
151
- const d = data.data;
152
- const rects = [];
153
- for (let y = 0; y < dh; y++) {
154
- for (let x = 0; x < dw; x++) {
155
- const i = (y * dw + x) * 4;
156
- const a = d[i + 3];
157
- if (a === 0) {
158
- continue;
159
- }
160
- const r = d[i], g = d[i + 1], b = d[i + 2];
161
- const hex = `#${((1 << 24) | (r << 16) | (g << 8) | b).toString(16).slice(1)}`;
162
- if (a < 255) {
163
- rects.push(`<rect x="${x}" y="${y}" width="1" height="1" fill="${hex}" opacity="${(a / 255).toFixed(2)}"/>`);
164
- }
165
- else {
166
- rects.push(`<rect x="${x}" y="${y}" width="1" height="1" fill="${hex}"/>`);
167
- }
168
- }
137
+ const data = compFrame(afi);
138
+ const d = data.data;
139
+ const rects = [];
140
+ for (let y = 0; y < dh; y++) {
141
+ for (let x = 0; x < dw; x++) {
142
+ const i = (y * dw + x) * 4;
143
+ const a = d[i + 3];
144
+ if (a === 0) {
145
+ continue;
146
+ }
147
+ const r = d[i], g = d[i + 1], b = d[i + 2];
148
+ const hex = `#${(1 << 24 | r << 16 | g << 8 | b).toString(16).slice(1)}`;
149
+ if (a < 255) {
150
+ rects.push(
151
+ `<rect x="${x}" y="${y}" width="1" height="1" fill="${hex}" opacity="${(a / 255).toFixed(2)}"/>`
152
+ );
153
+ } else {
154
+ rects.push(`<rect x="${x}" y="${y}" width="1" height="1" fill="${hex}"/>`);
155
+ }
169
156
  }
170
- const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${dw}" height="${dh}" viewBox="0 0 ${dw} ${dh}" shape-rendering="crispEdges">\n${rects.join('\n')}\n</svg>`;
171
- pixelEditorTypes.downloadBlob(new Blob([svg], { type: 'image/svg+xml' }), 'sprite.svg');
157
+ }
158
+ const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${dw}" height="${dh}" viewBox="0 0 ${dw} ${dh}" shape-rendering="crispEdges">
159
+ ${rects.join("\n")}
160
+ </svg>`;
161
+ pixelEditorTypes.downloadBlob(new Blob([svg], { type: "image/svg+xml" }), "sprite.svg");
172
162
  }
173
163
  function exportSheet(dw, dh, fc, compFrame) {
174
- const cv = document.createElement('canvas');
175
- cv.width = dw * fc;
176
- cv.height = dh;
177
- const ctx = cv.getContext('2d');
178
- for (let fi = 0; fi < fc; fi++) {
179
- const fd = compFrame(fi);
180
- const tmp = new OffscreenCanvas(dw, dh);
181
- tmp.getContext('2d').putImageData(fd, 0, 0);
182
- ctx.drawImage(tmp, fi * dw, 0);
183
- }
184
- cv.toBlob((b) => b && pixelEditorTypes.downloadBlob(b, 'spritesheet.png'));
164
+ const cv = document.createElement("canvas");
165
+ cv.width = dw * fc;
166
+ cv.height = dh;
167
+ const ctx = cv.getContext("2d");
168
+ for (let fi = 0; fi < fc; fi++) {
169
+ const fd = compFrame(fi);
170
+ const tmp = new OffscreenCanvas(dw, dh);
171
+ tmp.getContext("2d").putImageData(fd, 0, 0);
172
+ ctx.drawImage(tmp, fi * dw, 0);
173
+ }
174
+ cv.toBlob((b) => b && pixelEditorTypes.downloadBlob(b, "spritesheet.png"));
185
175
  }
186
176
  function exportSpriteSheetAdvanced(dw, dh, fc, compFrame, fDur, options = {}) {
187
- const { columns = Math.ceil(Math.sqrt(fc)), padding = 0, includeMeta = false, fileName = 'spritesheet', } = options;
188
- const rows = Math.ceil(fc / columns);
189
- const frameW = dw + padding * 2;
190
- const frameH = dh + padding * 2;
191
- const cv = document.createElement('canvas');
192
- cv.width = columns * frameW;
193
- cv.height = rows * frameH;
194
- const ctx = cv.getContext('2d');
195
- // Transparent background
196
- ctx.clearRect(0, 0, cv.width, cv.height);
197
- const frames = [];
198
- for (let fi = 0; fi < fc; fi++) {
199
- const col = fi % columns;
200
- const row = Math.floor(fi / columns);
201
- const x = col * frameW + padding;
202
- const y = row * frameH + padding;
203
- const fd = compFrame(fi);
204
- const tmp = new OffscreenCanvas(dw, dh);
205
- tmp.getContext('2d').putImageData(fd, 0, 0);
206
- ctx.drawImage(tmp, x, y);
207
- frames.push({
208
- filename: `frame_${fi.toString().padStart(3, '0')}`,
209
- frame: { x, y, w: dw, h: dh },
210
- duration: fDur[fi] || 100,
211
- });
212
- }
213
- cv.toBlob((b) => b && pixelEditorTypes.downloadBlob(b, `${fileName}.png`));
214
- if (includeMeta) {
215
- const meta = {
216
- frames,
217
- meta: {
218
- app: 'NiceToDev PixelEditor',
219
- version: '1.0',
220
- image: `${fileName}.png`,
221
- format: 'RGBA8888',
222
- size: { w: cv.width, h: cv.height },
223
- frameTags: [],
224
- },
225
- };
226
- pixelEditorTypes.downloadBlob(new Blob([JSON.stringify(meta, null, 2)], { type: 'application/json' }), `${fileName}.json`);
227
- }
177
+ const {
178
+ columns = Math.ceil(Math.sqrt(fc)),
179
+ padding = 0,
180
+ includeMeta = false,
181
+ fileName = "spritesheet"
182
+ } = options;
183
+ const rows = Math.ceil(fc / columns);
184
+ const frameW = dw + padding * 2;
185
+ const frameH = dh + padding * 2;
186
+ const cv = document.createElement("canvas");
187
+ cv.width = columns * frameW;
188
+ cv.height = rows * frameH;
189
+ const ctx = cv.getContext("2d");
190
+ ctx.clearRect(0, 0, cv.width, cv.height);
191
+ const frames = [];
192
+ for (let fi = 0; fi < fc; fi++) {
193
+ const col = fi % columns;
194
+ const row = Math.floor(fi / columns);
195
+ const x = col * frameW + padding;
196
+ const y = row * frameH + padding;
197
+ const fd = compFrame(fi);
198
+ const tmp = new OffscreenCanvas(dw, dh);
199
+ tmp.getContext("2d").putImageData(fd, 0, 0);
200
+ ctx.drawImage(tmp, x, y);
201
+ frames.push({
202
+ filename: `frame_${fi.toString().padStart(3, "0")}`,
203
+ frame: { x, y, w: dw, h: dh },
204
+ duration: fDur[fi] || 100
205
+ });
206
+ }
207
+ cv.toBlob((b) => b && pixelEditorTypes.downloadBlob(b, `${fileName}.png`));
208
+ if (includeMeta) {
209
+ const meta = {
210
+ frames,
211
+ meta: {
212
+ app: "NiceToDev PixelEditor",
213
+ version: "1.0",
214
+ image: `${fileName}.png`,
215
+ format: "RGBA8888",
216
+ size: { w: cv.width, h: cv.height },
217
+ frameTags: []
218
+ }
219
+ };
220
+ pixelEditorTypes.downloadBlob(
221
+ new Blob([JSON.stringify(meta, null, 2)], { type: "application/json" }),
222
+ `${fileName}.json`
223
+ );
224
+ }
228
225
  }
229
- /* ────────────────────────────────────────────────────────────────
230
- GIF EXPORT
231
- ──────────────────────────────────────────────────────────────── */
232
- // Simple GIF encoder (LZW-based)
233
226
  async function exportGIF(dw, dh, fc, compFrame, fDur, options = {}) {
234
- const { loop = true, quality = 10 } = options;
235
- // Build GIF using simple encoding
236
- const frames = [];
237
- for (let fi = 0; fi < fc; fi++) {
238
- frames.push({
239
- data: compFrame(fi),
240
- delay: Math.round((fDur[fi] || 100) / 10), // GIF uses centiseconds
241
- });
242
- }
243
- try {
244
- const gifData = encodeGIF(frames, dw, dh, loop, quality);
245
- pixelEditorTypes.downloadBlob(new Blob([gifData.buffer], { type: 'image/gif' }), 'animation.gif');
246
- }
247
- catch (err) {
248
- log.error('GIF export failed', err);
249
- console.warn('[PixelEditor] GIF export failed. Try reducing colors or frame count.');
250
- }
227
+ const { loop = true, quality = 10 } = options;
228
+ const frames = [];
229
+ for (let fi = 0; fi < fc; fi++) {
230
+ frames.push({
231
+ data: compFrame(fi),
232
+ delay: Math.round((fDur[fi] || 100) / 10)
233
+ // GIF uses centiseconds
234
+ });
235
+ }
236
+ try {
237
+ const gifData = encodeGIF(frames, dw, dh, loop, quality);
238
+ pixelEditorTypes.downloadBlob(new Blob([gifData.buffer], { type: "image/gif" }), "animation.gif");
239
+ } catch (err) {
240
+ log.error("GIF export failed", err);
241
+ console.warn("[PixelEditor] GIF export failed. Try reducing colors or frame count.");
242
+ }
251
243
  }
252
- // Simple GIF encoder implementation
253
244
  function encodeGIF(frames, width, height, loop, _quality) {
254
- const buffer = [];
255
- // Helper to write bytes
256
- const writeByte = (b) => buffer.push(b & 0xff);
257
- const writeShort = (s) => {
258
- writeByte(s);
259
- writeByte(s >> 8);
260
- };
261
- const writeString = (str) => {
262
- for (let i = 0; i < str.length; i++) {
263
- writeByte(str.charCodeAt(i));
264
- }
265
- };
266
- // Build global color table from first frame
267
- const firstFrame = frames[0].data;
268
- const colors = extractColors(firstFrame, 256);
269
- const colorTableBits = 8;
270
- // Header
271
- writeString('GIF89a');
272
- // Logical Screen Descriptor
273
- writeShort(width);
274
- writeShort(height);
275
- writeByte(0xf0 | (colorTableBits - 1)); // Global color table flag + color resolution
276
- writeByte(0); // Background color index
277
- writeByte(0); // Pixel aspect ratio
278
- // Global Color Table
279
- for (let i = 0; i < 256; i++) {
280
- if (i < colors.length) {
281
- writeByte(colors[i][0]); // R
282
- writeByte(colors[i][1]); // G
283
- writeByte(colors[i][2]); // B
284
- }
285
- else {
286
- writeByte(0);
287
- writeByte(0);
288
- writeByte(0);
289
- }
245
+ const buffer = [];
246
+ const writeByte = (b) => buffer.push(b & 255);
247
+ const writeShort = (s) => {
248
+ writeByte(s);
249
+ writeByte(s >> 8);
250
+ };
251
+ const writeString = (str) => {
252
+ for (let i = 0; i < str.length; i++) {
253
+ writeByte(str.charCodeAt(i));
290
254
  }
291
- // NETSCAPE extension for looping
292
- if (loop) {
293
- writeByte(0x21); // Extension introducer
294
- writeByte(0xff); // Application extension
295
- writeByte(11); // Block size
296
- writeString('NETSCAPE2.0');
297
- writeByte(3); // Sub-block size
298
- writeByte(1); // Loop sub-block ID
299
- writeShort(0); // Loop count (0 = infinite)
300
- writeByte(0); // Block terminator
255
+ };
256
+ const firstFrame = frames[0].data;
257
+ const colors = extractColors(firstFrame, 256);
258
+ const colorTableBits = 8;
259
+ writeString("GIF89a");
260
+ writeShort(width);
261
+ writeShort(height);
262
+ writeByte(240 | colorTableBits - 1);
263
+ writeByte(0);
264
+ writeByte(0);
265
+ for (let i = 0; i < 256; i++) {
266
+ if (i < colors.length) {
267
+ writeByte(colors[i][0]);
268
+ writeByte(colors[i][1]);
269
+ writeByte(colors[i][2]);
270
+ } else {
271
+ writeByte(0);
272
+ writeByte(0);
273
+ writeByte(0);
301
274
  }
302
- // Write each frame
303
- for (const frame of frames) {
304
- // Graphic Control Extension
305
- writeByte(0x21); // Extension
306
- writeByte(0xf9); // Graphic Control
307
- writeByte(4); // Block size
308
- writeByte(0x04); // Dispose: do not dispose, no transparency
309
- writeShort(frame.delay); // Delay
310
- writeByte(0); // Transparent color index
311
- writeByte(0); // Block terminator
312
- // Image Descriptor
313
- writeByte(0x2c); // Image separator
314
- writeShort(0); // Left
315
- writeShort(0); // Top
316
- writeShort(width);
317
- writeShort(height);
318
- writeByte(0); // No local color table
319
- // Image Data
320
- const indexedPixels = quantizeFrame(frame.data, colors);
321
- const lzwMinCodeSize = colorTableBits;
322
- writeByte(lzwMinCodeSize);
323
- // LZW encode
324
- const lzwData = lzwEncode(indexedPixels, lzwMinCodeSize);
325
- // Write in sub-blocks
326
- let offset = 0;
327
- while (offset < lzwData.length) {
328
- const chunkSize = Math.min(255, lzwData.length - offset);
329
- writeByte(chunkSize);
330
- for (let i = 0; i < chunkSize; i++) {
331
- writeByte(lzwData[offset + i]);
332
- }
333
- offset += chunkSize;
334
- }
335
- writeByte(0); // Block terminator
275
+ }
276
+ if (loop) {
277
+ writeByte(33);
278
+ writeByte(255);
279
+ writeByte(11);
280
+ writeString("NETSCAPE2.0");
281
+ writeByte(3);
282
+ writeByte(1);
283
+ writeShort(0);
284
+ writeByte(0);
285
+ }
286
+ for (const frame of frames) {
287
+ writeByte(33);
288
+ writeByte(249);
289
+ writeByte(4);
290
+ writeByte(4);
291
+ writeShort(frame.delay);
292
+ writeByte(0);
293
+ writeByte(0);
294
+ writeByte(44);
295
+ writeShort(0);
296
+ writeShort(0);
297
+ writeShort(width);
298
+ writeShort(height);
299
+ writeByte(0);
300
+ const indexedPixels = quantizeFrame(frame.data, colors);
301
+ const lzwMinCodeSize = colorTableBits;
302
+ writeByte(lzwMinCodeSize);
303
+ const lzwData = lzwEncode(indexedPixels, lzwMinCodeSize);
304
+ let offset = 0;
305
+ while (offset < lzwData.length) {
306
+ const chunkSize = Math.min(255, lzwData.length - offset);
307
+ writeByte(chunkSize);
308
+ for (let i = 0; i < chunkSize; i++) {
309
+ writeByte(lzwData[offset + i]);
310
+ }
311
+ offset += chunkSize;
336
312
  }
337
- // Trailer
338
- writeByte(0x3b);
339
- return new Uint8Array(buffer);
313
+ writeByte(0);
314
+ }
315
+ writeByte(59);
316
+ return new Uint8Array(buffer);
340
317
  }
341
- // Extract most common colors from image
342
318
  function extractColors(img, maxColors) {
343
- const colorCounts = new Map();
344
- const data = img.data;
345
- for (let i = 0; i < data.length; i += 4) {
346
- if (data[i + 3] < 128) {
347
- continue;
348
- } // Skip transparent
349
- // Quantize colors to reduce variations
350
- const r = data[i] & 0xf8;
351
- const g = data[i + 1] & 0xf8;
352
- const b = data[i + 2] & 0xf8;
353
- const key = `${r},${g},${b}`;
354
- const existing = colorCounts.get(key);
355
- if (existing) {
356
- existing.count++;
357
- }
358
- else {
359
- colorCounts.set(key, { count: 1, r, g, b });
360
- }
319
+ const colorCounts = /* @__PURE__ */ new Map();
320
+ const data = img.data;
321
+ for (let i = 0; i < data.length; i += 4) {
322
+ if (data[i + 3] < 128) {
323
+ continue;
324
+ }
325
+ const r = data[i] & 248;
326
+ const g = data[i + 1] & 248;
327
+ const b = data[i + 2] & 248;
328
+ const key = `${r},${g},${b}`;
329
+ const existing = colorCounts.get(key);
330
+ if (existing) {
331
+ existing.count++;
332
+ } else {
333
+ colorCounts.set(key, { count: 1, r, g, b });
361
334
  }
362
- // Sort by frequency and take top colors
363
- const sorted = Array.from(colorCounts.values())
364
- .sort((a, b) => b.count - a.count)
365
- .slice(0, maxColors);
366
- return sorted.map((c) => [c.r, c.g, c.b]);
335
+ }
336
+ const sorted = Array.from(colorCounts.values()).sort((a, b) => b.count - a.count).slice(0, maxColors);
337
+ return sorted.map((c) => [c.r, c.g, c.b]);
367
338
  }
368
- // Map pixels to palette indices
369
339
  function quantizeFrame(img, palette) {
370
- const result = new Uint8Array(img.width * img.height);
371
- const data = img.data;
372
- for (let i = 0, pi = 0; i < data.length; i += 4, pi++) {
373
- if (data[i + 3] < 128) {
374
- result[pi] = 0; // Map transparent to index 0
375
- continue;
376
- }
377
- const r = data[i];
378
- const g = data[i + 1];
379
- const b = data[i + 2];
380
- // Find closest color in palette
381
- let minDist = Infinity;
382
- let minIdx = 0;
383
- for (let j = 0; j < palette.length; j++) {
384
- const pr = palette[j][0];
385
- const pg = palette[j][1];
386
- const pb = palette[j][2];
387
- const dist = (r - pr) ** 2 + (g - pg) ** 2 + (b - pb) ** 2;
388
- if (dist < minDist) {
389
- minDist = dist;
390
- minIdx = j;
391
- }
392
- }
393
- result[pi] = minIdx;
340
+ const result = new Uint8Array(img.width * img.height);
341
+ const data = img.data;
342
+ for (let i = 0, pi = 0; i < data.length; i += 4, pi++) {
343
+ if (data[i + 3] < 128) {
344
+ result[pi] = 0;
345
+ continue;
346
+ }
347
+ const r = data[i];
348
+ const g = data[i + 1];
349
+ const b = data[i + 2];
350
+ let minDist = Infinity;
351
+ let minIdx = 0;
352
+ for (let j = 0; j < palette.length; j++) {
353
+ const pr = palette[j][0];
354
+ const pg = palette[j][1];
355
+ const pb = palette[j][2];
356
+ const dist = (r - pr) ** 2 + (g - pg) ** 2 + (b - pb) ** 2;
357
+ if (dist < minDist) {
358
+ minDist = dist;
359
+ minIdx = j;
360
+ }
394
361
  }
395
- return result;
362
+ result[pi] = minIdx;
363
+ }
364
+ return result;
396
365
  }
397
- // LZW compression for GIF
398
366
  function lzwEncode(data, minCodeSize) {
399
- const clearCode = 1 << minCodeSize;
400
- const eoiCode = clearCode + 1;
401
- let codeSize = minCodeSize + 1;
402
- let nextCode = eoiCode + 1;
403
- let maxCode = 1 << codeSize;
404
- const dictionary = new Map();
405
- // Initialize dictionary with single-character codes
406
- for (let i = 0; i < clearCode; i++) {
407
- dictionary.set(String.fromCharCode(i), i);
367
+ const clearCode = 1 << minCodeSize;
368
+ const eoiCode = clearCode + 1;
369
+ let codeSize = minCodeSize + 1;
370
+ let nextCode = eoiCode + 1;
371
+ let maxCode = 1 << codeSize;
372
+ const dictionary = /* @__PURE__ */ new Map();
373
+ for (let i = 0; i < clearCode; i++) {
374
+ dictionary.set(String.fromCharCode(i), i);
375
+ }
376
+ const output = [];
377
+ let bits = 0;
378
+ let bitCount = 0;
379
+ const writeBits = (code, size) => {
380
+ bits |= code << bitCount;
381
+ bitCount += size;
382
+ while (bitCount >= 8) {
383
+ output.push(bits & 255);
384
+ bits >>= 8;
385
+ bitCount -= 8;
408
386
  }
409
- const output = [];
410
- let bits = 0;
411
- let bitCount = 0;
412
- const writeBits = (code, size) => {
413
- bits |= code << bitCount;
414
- bitCount += size;
415
- while (bitCount >= 8) {
416
- output.push(bits & 0xff);
417
- bits >>= 8;
418
- bitCount -= 8;
419
- }
420
- };
421
- // Write clear code
422
- writeBits(clearCode, codeSize);
423
- if (data.length === 0) {
424
- writeBits(eoiCode, codeSize);
425
- if (bitCount > 0) {
426
- output.push(bits);
427
- }
428
- return new Uint8Array(output);
429
- }
430
- let prefix = String.fromCharCode(data[0]);
431
- for (let i = 1; i < data.length; i++) {
432
- const k = String.fromCharCode(data[i]);
433
- const wk = prefix + k;
434
- if (dictionary.has(wk)) {
435
- prefix = wk;
436
- }
437
- else {
438
- writeBits(dictionary.get(prefix), codeSize);
439
- if (nextCode < 4096) {
440
- dictionary.set(wk, nextCode++);
441
- if (nextCode > maxCode && codeSize < 12) {
442
- codeSize++;
443
- maxCode = 1 << codeSize;
444
- }
445
- }
446
- else {
447
- // Reset dictionary
448
- writeBits(clearCode, codeSize);
449
- dictionary.clear();
450
- for (let j = 0; j < clearCode; j++) {
451
- dictionary.set(String.fromCharCode(j), j);
452
- }
453
- codeSize = minCodeSize + 1;
454
- nextCode = eoiCode + 1;
455
- maxCode = 1 << codeSize;
456
- }
457
- prefix = k;
458
- }
459
- }
460
- // Write final code
461
- writeBits(dictionary.get(prefix), codeSize);
387
+ };
388
+ writeBits(clearCode, codeSize);
389
+ if (data.length === 0) {
462
390
  writeBits(eoiCode, codeSize);
463
- // Flush remaining bits
464
391
  if (bitCount > 0) {
465
- output.push(bits);
392
+ output.push(bits);
466
393
  }
467
394
  return new Uint8Array(output);
395
+ }
396
+ let prefix = String.fromCharCode(data[0]);
397
+ for (let i = 1; i < data.length; i++) {
398
+ const k = String.fromCharCode(data[i]);
399
+ const wk = prefix + k;
400
+ if (dictionary.has(wk)) {
401
+ prefix = wk;
402
+ } else {
403
+ writeBits(dictionary.get(prefix), codeSize);
404
+ if (nextCode < 4096) {
405
+ dictionary.set(wk, nextCode++);
406
+ if (nextCode > maxCode && codeSize < 12) {
407
+ codeSize++;
408
+ maxCode = 1 << codeSize;
409
+ }
410
+ } else {
411
+ writeBits(clearCode, codeSize);
412
+ dictionary.clear();
413
+ for (let j = 0; j < clearCode; j++) {
414
+ dictionary.set(String.fromCharCode(j), j);
415
+ }
416
+ codeSize = minCodeSize + 1;
417
+ nextCode = eoiCode + 1;
418
+ maxCode = 1 << codeSize;
419
+ }
420
+ prefix = k;
421
+ }
422
+ }
423
+ writeBits(dictionary.get(prefix), codeSize);
424
+ writeBits(eoiCode, codeSize);
425
+ if (bitCount > 0) {
426
+ output.push(bits);
427
+ }
428
+ return new Uint8Array(output);
468
429
  }
469
-
470
430
  exports.exportAse = exportAse;
471
431
  exports.exportBMP = exportBMP;
472
432
  exports.exportGIF = exportGIF;