ag-psd 30.1.1 → 31.0.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 (285) hide show
  1. package/.v8-cache/v24.13.1-x64-cf738c9d/017325ac +0 -0
  2. package/.v8-cache/v24.13.1-x64-cf738c9d/01e5e61b +0 -0
  3. package/.v8-cache/v24.13.1-x64-cf738c9d/043c7b90 +0 -0
  4. package/.v8-cache/v24.13.1-x64-cf738c9d/05135617 +0 -0
  5. package/.v8-cache/v24.13.1-x64-cf738c9d/059f8558 +0 -0
  6. package/.v8-cache/v24.13.1-x64-cf738c9d/06423db9 +0 -0
  7. package/.v8-cache/v24.13.1-x64-cf738c9d/06e765df +0 -0
  8. package/.v8-cache/v24.13.1-x64-cf738c9d/0706ecb8 +0 -0
  9. package/.v8-cache/v24.13.1-x64-cf738c9d/0930679d +0 -0
  10. package/.v8-cache/v24.13.1-x64-cf738c9d/09519a62 +0 -0
  11. package/.v8-cache/v24.13.1-x64-cf738c9d/0a6607b0 +0 -0
  12. package/.v8-cache/v24.13.1-x64-cf738c9d/0ad8fa6e +0 -0
  13. package/.v8-cache/v24.13.1-x64-cf738c9d/0d390e10 +0 -0
  14. package/.v8-cache/v24.13.1-x64-cf738c9d/0db754a7 +0 -0
  15. package/.v8-cache/v24.13.1-x64-cf738c9d/0dfa7b16 +0 -0
  16. package/.v8-cache/v24.13.1-x64-cf738c9d/0e9e09db +0 -0
  17. package/.v8-cache/v24.13.1-x64-cf738c9d/1130885f +0 -0
  18. package/.v8-cache/v24.13.1-x64-cf738c9d/1222cb8c +0 -0
  19. package/.v8-cache/v24.13.1-x64-cf738c9d/15e2c039 +0 -0
  20. package/.v8-cache/v24.13.1-x64-cf738c9d/15f0e479 +0 -0
  21. package/.v8-cache/v24.13.1-x64-cf738c9d/1a2d469d +0 -0
  22. package/.v8-cache/v24.13.1-x64-cf738c9d/1b300c82 +0 -0
  23. package/.v8-cache/v24.13.1-x64-cf738c9d/1bc3d370 +0 -0
  24. package/.v8-cache/v24.13.1-x64-cf738c9d/1e44e5af +0 -0
  25. package/.v8-cache/v24.13.1-x64-cf738c9d/1efa10a1 +0 -0
  26. package/.v8-cache/v24.13.1-x64-cf738c9d/1f6c8743 +0 -0
  27. package/.v8-cache/v24.13.1-x64-cf738c9d/20477c23 +0 -0
  28. package/.v8-cache/v24.13.1-x64-cf738c9d/20b27e40 +0 -0
  29. package/.v8-cache/v24.13.1-x64-cf738c9d/20dfa422 +0 -0
  30. package/.v8-cache/v24.13.1-x64-cf738c9d/257c62ba +0 -0
  31. package/.v8-cache/v24.13.1-x64-cf738c9d/25d60154 +0 -0
  32. package/.v8-cache/v24.13.1-x64-cf738c9d/26f822f3 +0 -0
  33. package/.v8-cache/v24.13.1-x64-cf738c9d/2a19133e +0 -0
  34. package/.v8-cache/v24.13.1-x64-cf738c9d/2a1e2a8d +0 -0
  35. package/.v8-cache/v24.13.1-x64-cf738c9d/2b02fded +0 -0
  36. package/.v8-cache/v24.13.1-x64-cf738c9d/2b069ee0 +0 -0
  37. package/.v8-cache/v24.13.1-x64-cf738c9d/2c76dc0d +0 -0
  38. package/.v8-cache/v24.13.1-x64-cf738c9d/2de09439 +0 -0
  39. package/.v8-cache/v24.13.1-x64-cf738c9d/2deb286a +0 -0
  40. package/.v8-cache/v24.13.1-x64-cf738c9d/2e44f5f0 +0 -0
  41. package/.v8-cache/v24.13.1-x64-cf738c9d/2fb229a9 +0 -0
  42. package/.v8-cache/v24.13.1-x64-cf738c9d/3144b401 +0 -0
  43. package/.v8-cache/v24.13.1-x64-cf738c9d/32018e44 +0 -0
  44. package/.v8-cache/v24.13.1-x64-cf738c9d/341402c3 +0 -0
  45. package/.v8-cache/v24.13.1-x64-cf738c9d/34e0fa2e +0 -0
  46. package/.v8-cache/v24.13.1-x64-cf738c9d/37481985 +0 -0
  47. package/.v8-cache/v24.13.1-x64-cf738c9d/3bbf643e +0 -0
  48. package/.v8-cache/v24.13.1-x64-cf738c9d/3ceff89e +0 -0
  49. package/.v8-cache/v24.13.1-x64-cf738c9d/404f5cdc +0 -0
  50. package/.v8-cache/v24.13.1-x64-cf738c9d/4087aa2b +0 -0
  51. package/.v8-cache/v24.13.1-x64-cf738c9d/4376c1f9 +0 -0
  52. package/.v8-cache/v24.13.1-x64-cf738c9d/44903df4 +0 -0
  53. package/.v8-cache/v24.13.1-x64-cf738c9d/44d58dc8 +0 -0
  54. package/.v8-cache/v24.13.1-x64-cf738c9d/4511bacf +0 -0
  55. package/.v8-cache/v24.13.1-x64-cf738c9d/47da0ce8 +0 -0
  56. package/.v8-cache/v24.13.1-x64-cf738c9d/48cd54a9 +0 -0
  57. package/.v8-cache/v24.13.1-x64-cf738c9d/49d22b79 +0 -0
  58. package/.v8-cache/v24.13.1-x64-cf738c9d/4d938476 +0 -0
  59. package/.v8-cache/v24.13.1-x64-cf738c9d/4ec6d390 +0 -0
  60. package/.v8-cache/v24.13.1-x64-cf738c9d/4f5702bd +0 -0
  61. package/.v8-cache/v24.13.1-x64-cf738c9d/514cc428 +0 -0
  62. package/.v8-cache/v24.13.1-x64-cf738c9d/557d3b42 +0 -0
  63. package/.v8-cache/v24.13.1-x64-cf738c9d/56abbff7 +0 -0
  64. package/.v8-cache/v24.13.1-x64-cf738c9d/57b540ee +0 -0
  65. package/.v8-cache/v24.13.1-x64-cf738c9d/57d3380b +0 -0
  66. package/.v8-cache/v24.13.1-x64-cf738c9d/5e20c081 +0 -0
  67. package/.v8-cache/v24.13.1-x64-cf738c9d/6024ce3f +0 -0
  68. package/.v8-cache/v24.13.1-x64-cf738c9d/61735b23 +0 -0
  69. package/.v8-cache/v24.13.1-x64-cf738c9d/63dbdb75 +0 -0
  70. package/.v8-cache/v24.13.1-x64-cf738c9d/651c4ada +0 -0
  71. package/.v8-cache/v24.13.1-x64-cf738c9d/652a0d59 +0 -0
  72. package/.v8-cache/v24.13.1-x64-cf738c9d/6a0e89ee +0 -0
  73. package/.v8-cache/v24.13.1-x64-cf738c9d/6af33b91 +0 -0
  74. package/.v8-cache/v24.13.1-x64-cf738c9d/6c2562d2 +0 -0
  75. package/.v8-cache/v24.13.1-x64-cf738c9d/6cbfc0ec +0 -0
  76. package/.v8-cache/v24.13.1-x64-cf738c9d/6dae0cfa +0 -0
  77. package/.v8-cache/v24.13.1-x64-cf738c9d/6e2529ce +0 -0
  78. package/.v8-cache/v24.13.1-x64-cf738c9d/6f08372c +0 -0
  79. package/.v8-cache/v24.13.1-x64-cf738c9d/7100ee08 +0 -0
  80. package/.v8-cache/v24.13.1-x64-cf738c9d/71df9cb3 +0 -0
  81. package/.v8-cache/v24.13.1-x64-cf738c9d/72e1d543 +0 -0
  82. package/.v8-cache/v24.13.1-x64-cf738c9d/75519c80 +0 -0
  83. package/.v8-cache/v24.13.1-x64-cf738c9d/75e41e43 +0 -0
  84. package/.v8-cache/v24.13.1-x64-cf738c9d/79bf115c +0 -0
  85. package/.v8-cache/v24.13.1-x64-cf738c9d/7a39347c +0 -0
  86. package/.v8-cache/v24.13.1-x64-cf738c9d/7b83e3d3 +0 -0
  87. package/.v8-cache/v24.13.1-x64-cf738c9d/7cd71bc5 +0 -0
  88. package/.v8-cache/v24.13.1-x64-cf738c9d/7da78512 +0 -0
  89. package/.v8-cache/v24.13.1-x64-cf738c9d/7ea06cea +0 -0
  90. package/.v8-cache/v24.13.1-x64-cf738c9d/82c3b573 +0 -0
  91. package/.v8-cache/v24.13.1-x64-cf738c9d/84c186e4 +0 -0
  92. package/.v8-cache/v24.13.1-x64-cf738c9d/8568576b +0 -0
  93. package/.v8-cache/v24.13.1-x64-cf738c9d/8607bd36 +0 -0
  94. package/.v8-cache/v24.13.1-x64-cf738c9d/87372817 +0 -0
  95. package/.v8-cache/v24.13.1-x64-cf738c9d/87cf2209 +0 -0
  96. package/.v8-cache/v24.13.1-x64-cf738c9d/882aaa05 +0 -0
  97. package/.v8-cache/v24.13.1-x64-cf738c9d/8a4d3de8 +0 -0
  98. package/.v8-cache/v24.13.1-x64-cf738c9d/8e223473 +0 -0
  99. package/.v8-cache/v24.13.1-x64-cf738c9d/92b7aefd +0 -0
  100. package/.v8-cache/v24.13.1-x64-cf738c9d/932f0770 +0 -0
  101. package/.v8-cache/v24.13.1-x64-cf738c9d/937c03a1 +0 -0
  102. package/.v8-cache/v24.13.1-x64-cf738c9d/991e4758 +0 -0
  103. package/.v8-cache/v24.13.1-x64-cf738c9d/9af658fb +0 -0
  104. package/.v8-cache/v24.13.1-x64-cf738c9d/9ed80ba5 +0 -0
  105. package/.v8-cache/v24.13.1-x64-cf738c9d/9f0dc993 +0 -0
  106. package/.v8-cache/v24.13.1-x64-cf738c9d/a19c0c4f +0 -0
  107. package/.v8-cache/v24.13.1-x64-cf738c9d/a6409d95 +0 -0
  108. package/.v8-cache/v24.13.1-x64-cf738c9d/a79a40bb +0 -0
  109. package/.v8-cache/v24.13.1-x64-cf738c9d/a7e80865 +0 -0
  110. package/.v8-cache/v24.13.1-x64-cf738c9d/ac9802c6 +0 -0
  111. package/.v8-cache/v24.13.1-x64-cf738c9d/acc36e66 +0 -0
  112. package/.v8-cache/v24.13.1-x64-cf738c9d/ad11e2dc +0 -0
  113. package/.v8-cache/v24.13.1-x64-cf738c9d/b0c8fcd8 +0 -0
  114. package/.v8-cache/v24.13.1-x64-cf738c9d/b1762958 +0 -0
  115. package/.v8-cache/v24.13.1-x64-cf738c9d/b3c2fab7 +0 -0
  116. package/.v8-cache/v24.13.1-x64-cf738c9d/b5b3329b +0 -0
  117. package/.v8-cache/v24.13.1-x64-cf738c9d/b69ed3a3 +0 -0
  118. package/.v8-cache/v24.13.1-x64-cf738c9d/b806679e +0 -0
  119. package/.v8-cache/v24.13.1-x64-cf738c9d/bc1cdd48 +0 -0
  120. package/.v8-cache/v24.13.1-x64-cf738c9d/bc7ebd1d +0 -0
  121. package/.v8-cache/v24.13.1-x64-cf738c9d/bdff1628 +0 -0
  122. package/.v8-cache/v24.13.1-x64-cf738c9d/c0b789d2 +0 -0
  123. package/.v8-cache/v24.13.1-x64-cf738c9d/c314aece +0 -0
  124. package/.v8-cache/v24.13.1-x64-cf738c9d/c399a5dc +0 -0
  125. package/.v8-cache/v24.13.1-x64-cf738c9d/c681cbc8 +0 -0
  126. package/.v8-cache/v24.13.1-x64-cf738c9d/c6834ffc +0 -0
  127. package/.v8-cache/v24.13.1-x64-cf738c9d/c6f12ed5 +0 -0
  128. package/.v8-cache/v24.13.1-x64-cf738c9d/cb0f0a3d +0 -0
  129. package/.v8-cache/v24.13.1-x64-cf738c9d/cbcb7c95 +0 -0
  130. package/.v8-cache/v24.13.1-x64-cf738c9d/cdd9107c +0 -0
  131. package/.v8-cache/v24.13.1-x64-cf738c9d/cdf2c4a3 +0 -0
  132. package/.v8-cache/v24.13.1-x64-cf738c9d/cfc49f4f +0 -0
  133. package/.v8-cache/v24.13.1-x64-cf738c9d/cff9434a +0 -0
  134. package/.v8-cache/v24.13.1-x64-cf738c9d/d02dd6f7 +0 -0
  135. package/.v8-cache/v24.13.1-x64-cf738c9d/d0507bf3 +0 -0
  136. package/.v8-cache/v24.13.1-x64-cf738c9d/d60fce19 +0 -0
  137. package/.v8-cache/v24.13.1-x64-cf738c9d/d733d619 +0 -0
  138. package/.v8-cache/v24.13.1-x64-cf738c9d/d75b7803 +0 -0
  139. package/.v8-cache/v24.13.1-x64-cf738c9d/dc86f000 +0 -0
  140. package/.v8-cache/v24.13.1-x64-cf738c9d/de74e659 +0 -0
  141. package/.v8-cache/v24.13.1-x64-cf738c9d/defa4f7f +0 -0
  142. package/.v8-cache/v24.13.1-x64-cf738c9d/e03e2acd +0 -0
  143. package/.v8-cache/v24.13.1-x64-cf738c9d/e0e3f52c +0 -0
  144. package/.v8-cache/v24.13.1-x64-cf738c9d/e158d332 +0 -0
  145. package/.v8-cache/v24.13.1-x64-cf738c9d/e6735171 +0 -0
  146. package/.v8-cache/v24.13.1-x64-cf738c9d/e6745c2b +0 -0
  147. package/.v8-cache/v24.13.1-x64-cf738c9d/e6b99945 +0 -0
  148. package/.v8-cache/v24.13.1-x64-cf738c9d/e6d8ceb8 +0 -0
  149. package/.v8-cache/v24.13.1-x64-cf738c9d/e7ffec37 +0 -0
  150. package/.v8-cache/v24.13.1-x64-cf738c9d/ea33b6de +0 -0
  151. package/.v8-cache/v24.13.1-x64-cf738c9d/eaafa3c4 +0 -0
  152. package/.v8-cache/v24.13.1-x64-cf738c9d/ebb50fca +0 -0
  153. package/.v8-cache/v24.13.1-x64-cf738c9d/ec805f2e +0 -0
  154. package/.v8-cache/v24.13.1-x64-cf738c9d/edaef8f1 +0 -0
  155. package/.v8-cache/v24.13.1-x64-cf738c9d/ee4401c8 +0 -0
  156. package/.v8-cache/v24.13.1-x64-cf738c9d/eeeebdfe +0 -0
  157. package/.v8-cache/v24.13.1-x64-cf738c9d/f3d51676 +0 -0
  158. package/.v8-cache/v24.13.1-x64-cf738c9d/f7b50a75 +0 -0
  159. package/.v8-cache/v24.13.1-x64-cf738c9d/fa58ca72 +0 -0
  160. package/.v8-cache/v24.13.1-x64-cf738c9d/fbca6276 +0 -0
  161. package/.v8-cache/v24.13.1-x64-cf738c9d/fc97d72d +0 -0
  162. package/.v8-cache/v24.13.1-x64-cf738c9d/fd0a2987 +0 -0
  163. package/CHANGELOG.md +9 -0
  164. package/README.md +65 -1
  165. package/README_PSD.md +1 -1
  166. package/TODO.md +2 -0
  167. package/dist/abr.d.ts +196 -196
  168. package/dist/abr.js +364 -378
  169. package/dist/abr.js.map +1 -1
  170. package/dist/additionalInfo.d.ts +26 -26
  171. package/dist/additionalInfo.js +3478 -3516
  172. package/dist/additionalInfo.js.map +1 -1
  173. package/dist/ase.d.ts +32 -32
  174. package/dist/ase.js +81 -82
  175. package/dist/ase.js.map +1 -1
  176. package/dist/bundle.js +12380 -12445
  177. package/dist/csh.d.ts +10 -10
  178. package/dist/csh.js +35 -47
  179. package/dist/csh.js.map +1 -1
  180. package/dist/descriptor.d.ts +601 -601
  181. package/dist/descriptor.js +2003 -2038
  182. package/dist/descriptor.js.map +1 -1
  183. package/dist/effectsHelpers.d.ts +5 -5
  184. package/dist/effectsHelpers.js +286 -308
  185. package/dist/effectsHelpers.js.map +1 -1
  186. package/dist/engineData.d.ts +2 -2
  187. package/dist/engineData.js +334 -341
  188. package/dist/engineData.js.map +1 -1
  189. package/dist/engineData2.d.ts +2 -2
  190. package/dist/engineData2.js +409 -411
  191. package/dist/engineData2.js.map +1 -1
  192. package/dist/helpers.d.ts +74 -74
  193. package/dist/helpers.js +353 -348
  194. package/dist/helpers.js.map +1 -1
  195. package/dist/imageResources.d.ts +17 -17
  196. package/dist/imageResources.js +1040 -1079
  197. package/dist/imageResources.js.map +1 -1
  198. package/dist/index.d.ts +20 -22
  199. package/dist/index.js +61 -56
  200. package/dist/index.js.map +1 -1
  201. package/dist/initializeCanvas.d.ts +1 -1
  202. package/dist/initializeCanvas.js +9 -10
  203. package/dist/initializeCanvas.js.map +1 -1
  204. package/dist/jpeg.d.ts +1 -1
  205. package/dist/jpeg.js +1020 -1021
  206. package/dist/jpeg.js.map +1 -1
  207. package/dist/psd.d.ts +1877 -1873
  208. package/dist/psd.js +45 -45
  209. package/dist/psd.js.map +1 -1
  210. package/dist/psdReader.d.ts +52 -45
  211. package/dist/psdReader.js +1385 -1293
  212. package/dist/psdReader.js.map +1 -1
  213. package/dist/psdWriter.d.ts +34 -33
  214. package/dist/psdWriter.js +834 -805
  215. package/dist/psdWriter.js.map +1 -1
  216. package/dist/text.d.ts +179 -179
  217. package/dist/text.js +552 -577
  218. package/dist/text.js.map +1 -1
  219. package/dist/utf8.d.ts +4 -6
  220. package/dist/utf8.js +156 -157
  221. package/dist/utf8.js.map +1 -1
  222. package/dist-es/abr.d.ts +196 -196
  223. package/dist-es/abr.js +364 -374
  224. package/dist-es/abr.js.map +1 -1
  225. package/dist-es/additionalInfo.d.ts +26 -26
  226. package/dist-es/additionalInfo.js +3478 -3510
  227. package/dist-es/additionalInfo.js.map +1 -1
  228. package/dist-es/ase.d.ts +32 -32
  229. package/dist-es/ase.js +81 -78
  230. package/dist-es/ase.js.map +1 -1
  231. package/dist-es/csh.d.ts +10 -10
  232. package/dist-es/csh.js +35 -43
  233. package/dist-es/csh.js.map +1 -1
  234. package/dist-es/descriptor.d.ts +601 -601
  235. package/dist-es/descriptor.js +2003 -2005
  236. package/dist-es/descriptor.js.map +1 -1
  237. package/dist-es/effectsHelpers.d.ts +5 -5
  238. package/dist-es/effectsHelpers.js +286 -303
  239. package/dist-es/effectsHelpers.js.map +1 -1
  240. package/dist-es/engineData.d.ts +2 -2
  241. package/dist-es/engineData.js +334 -336
  242. package/dist-es/engineData.js.map +1 -1
  243. package/dist-es/engineData2.d.ts +2 -2
  244. package/dist-es/engineData2.js +409 -407
  245. package/dist-es/engineData2.js.map +1 -1
  246. package/dist-es/helpers.d.ts +74 -74
  247. package/dist-es/helpers.js +353 -330
  248. package/dist-es/helpers.js.map +1 -1
  249. package/dist-es/imageResources.d.ts +17 -17
  250. package/dist-es/imageResources.js +1040 -1076
  251. package/dist-es/imageResources.js.map +1 -1
  252. package/dist-es/index.d.ts +20 -22
  253. package/dist-es/index.js +61 -33
  254. package/dist-es/index.js.map +1 -1
  255. package/dist-es/initializeCanvas.d.ts +1 -1
  256. package/dist-es/initializeCanvas.js +9 -6
  257. package/dist-es/initializeCanvas.js.map +1 -1
  258. package/dist-es/jpeg.d.ts +1 -1
  259. package/dist-es/jpeg.js +1020 -1017
  260. package/dist-es/jpeg.js.map +1 -1
  261. package/dist-es/psd.d.ts +1877 -1873
  262. package/dist-es/psd.js +45 -42
  263. package/dist-es/psd.js.map +1 -1
  264. package/dist-es/psdReader.d.ts +52 -45
  265. package/dist-es/psdReader.js +1385 -1255
  266. package/dist-es/psdReader.js.map +1 -1
  267. package/dist-es/psdWriter.d.ts +34 -33
  268. package/dist-es/psdWriter.js +834 -776
  269. package/dist-es/psdWriter.js.map +1 -1
  270. package/dist-es/text.d.ts +179 -179
  271. package/dist-es/text.js +552 -572
  272. package/dist-es/text.js.map +1 -1
  273. package/dist-es/utf8.d.ts +4 -6
  274. package/dist-es/utf8.js +156 -150
  275. package/dist-es/utf8.js.map +1 -1
  276. package/package.json +4 -3
  277. package/publish.js +24 -0
  278. package/src/additionalInfo.ts +15 -11
  279. package/src/helpers.ts +13 -3
  280. package/src/index.ts +4 -6
  281. package/src/psd.ts +4 -0
  282. package/src/psdReader.ts +136 -43
  283. package/src/psdWriter.ts +118 -24
  284. package/tsconfig-es6.json +2 -1
  285. package/tsconfig.json +5 -3
package/src/psd.ts CHANGED
@@ -1788,6 +1788,7 @@ export interface Psd extends LayerAdditionalInfo {
1788
1788
  children?: Layer[];
1789
1789
  canvas?: HTMLCanvasElement;
1790
1790
  imageData?: PixelData;
1791
+ rawCompositeData?: Uint8Array;
1791
1792
  imageResources?: ImageResources;
1792
1793
  linkedFiles?: LinkedFile[]; // used in smart objects
1793
1794
  artboards?: {
@@ -1814,6 +1815,8 @@ export interface ReadOptions {
1814
1815
  skipThumbnail?: boolean;
1815
1816
  /** Does not load linked files (used in smart-objects). */
1816
1817
  skipLinkedFilesData?: boolean;
1818
+ /** Total memory limit to use when decoding bitmaps (default: 2GB). */
1819
+ totalMemoryLimit?: number;
1817
1820
  /** Throws exception if features are missing. */
1818
1821
  throwForMissingFeatures?: boolean;
1819
1822
  /** Logs if features are missing. */
@@ -1822,6 +1825,7 @@ export interface ReadOptions {
1822
1825
  * (image data will appear in `imageData` fields instead of `canvas` fields)
1823
1826
  * This avoids issues with canvas premultiplied alpha corrupting image data. */
1824
1827
  useImageData?: boolean;
1828
+ /** Skips decoding layer and composite bitmaps, they can be later decoded using helper functions */
1825
1829
  useRawData?: boolean;
1826
1830
  /** Loads thumbnail raw data instead of decoding it's content into canvas.
1827
1831
  * `thumnailRaw` field is used instead. */
package/src/psdReader.ts CHANGED
@@ -234,6 +234,7 @@ export function readPsd(reader: PsdReader, readOptions: ReadOptions = {}) {
234
234
  Object.assign(reader, readOptions);
235
235
  reader.large = version === 2;
236
236
  reader.globalAlpha = false;
237
+ if (!reader.totalMemoryLimit) reader.totalMemoryLimit = 2 * 1024 * 1024 * 1024; // default 2GB memory limit
237
238
 
238
239
  // color mode data
239
240
  readSection(reader, 1, left => {
@@ -327,7 +328,16 @@ export function readPsd(reader: PsdReader, readOptions: ReadOptions = {}) {
327
328
  const skipComposite = reader.skipCompositeImageData && (reader.skipLayerImageData || hasChildren);
328
329
 
329
330
  if (!skipComposite) {
330
- readImageData(reader, psd);
331
+ if (reader.useRawData) {
332
+ psd.rawCompositeData = new Uint8Array(reader.view.buffer, reader.view.byteOffset + reader.offset);
333
+ } else {
334
+ const imageData = readImageData(reader, psd);
335
+ if (reader.useImageData) {
336
+ psd.imageData = imageData;
337
+ } else {
338
+ psd.canvas = imageDataToCanvas(imageData);
339
+ }
340
+ }
331
341
  }
332
342
 
333
343
  // TODO: show converted color mode instead of original PSD file color mode
@@ -556,7 +566,7 @@ function readLayerChannelImageData(reader: PsdReader, psd: Psd, layer: Layer, ch
556
566
  }
557
567
 
558
568
  if (!reader.useRawData) {
559
- decodeLayerImageData(layer, !!reader.useImageData, !!reader.throwForMissingFeatures);
569
+ decodeLayerImageData(layer, reader);
560
570
  }
561
571
  }
562
572
 
@@ -571,8 +581,91 @@ function resetAlpha({ data }: PixelData, cmyk: boolean) {
571
581
  }
572
582
  }
573
583
 
574
- export function decodeLayerImageData(layer: Layer, useImageData?: boolean, throwForMissingFeatures?: boolean) {
575
- if (!layer.rawData) return;
584
+ export function getCompositeImageData(psd: Psd) {
585
+ const data = psd.rawCompositeData;
586
+ if (!data) return undefined;
587
+
588
+ const reader = createReader(data.buffer, data.byteOffset, data.byteLength);
589
+ const imageData = readImageData(reader, psd);
590
+ return imageData;
591
+ }
592
+
593
+ export function getCompositeCanvas(psd: Psd) {
594
+ return imageDataToCanvasSafe(getCompositeImageData(psd));
595
+ }
596
+
597
+ export function getLayerImageData(layer: Layer) {
598
+ return getDataFromLayer(layer, LayerDataType.Layer, false, undefined);
599
+ }
600
+
601
+ export function getLayerMaskImageData(layer: Layer) {
602
+ return getDataFromLayer(layer, LayerDataType.Mask, false, undefined);
603
+ }
604
+
605
+ export function getLayerRealMaskImageData(layer: Layer) {
606
+ return getDataFromLayer(layer, LayerDataType.RealMask, false, undefined);
607
+ }
608
+
609
+ export function getLayerCanvas(layer: Layer) {
610
+ return imageDataToCanvasSafe(getLayerImageData(layer));
611
+ }
612
+
613
+ export function getLayerMaskCanvas(layer: Layer) {
614
+ return imageDataToCanvasSafe(getLayerMaskImageData(layer));
615
+ }
616
+
617
+ export function getLayerRealMaskCanvas(layer: Layer) {
618
+ return imageDataToCanvasSafe(getLayerRealMaskImageData(layer));
619
+ }
620
+
621
+ function imageDataToCanvasSafe(imageData: PixelData | undefined) {
622
+ return imageData && imageDataToCanvas(imageData);
623
+ }
624
+
625
+ function setImageDataOrCanvas(obj: Layer | LayerMaskData, imageData: PixelData | undefined, useImageData: boolean | undefined) {
626
+ if (!imageData) return;
627
+
628
+ if (useImageData) {
629
+ obj.imageData = imageData;
630
+ } else {
631
+ obj.canvas = imageDataToCanvas(imageData);
632
+ }
633
+ }
634
+
635
+ export function decodeLayerPixels(layer: Layer, useImageData?: boolean) {
636
+ decodeLayerImageData(layer, { useImageData });
637
+ }
638
+
639
+ function decodeLayerImageData(layer: Layer, options: { useImageData?: boolean, throwForMissingFeatures?: boolean, memoryLimit?: number }) {
640
+ let { throwForMissingFeatures, useImageData } = options;
641
+
642
+ const imageData = getDataFromLayer(layer, LayerDataType.Layer, throwForMissingFeatures, options.memoryLimit);
643
+ setImageDataOrCanvas(layer, imageData, useImageData);
644
+ if (options.memoryLimit !== undefined) options.memoryLimit -= imageData?.data.byteLength ?? 0;
645
+
646
+ if (layer.mask) {
647
+ const maskData = getDataFromLayer(layer, LayerDataType.Mask, throwForMissingFeatures, options.memoryLimit);
648
+ setImageDataOrCanvas(layer.mask, maskData, useImageData);
649
+ if (options.memoryLimit !== undefined) options.memoryLimit -= maskData?.data.byteLength ?? 0;
650
+ }
651
+
652
+ if (layer.realMask) {
653
+ const maskData = getDataFromLayer(layer, LayerDataType.RealMask, throwForMissingFeatures, options.memoryLimit);
654
+ setImageDataOrCanvas(layer.realMask, maskData, useImageData);
655
+ if (options.memoryLimit !== undefined) options.memoryLimit -= maskData?.data.byteLength ?? 0;
656
+ }
657
+
658
+ delete layer.rawData;
659
+ }
660
+
661
+ enum LayerDataType {
662
+ Layer,
663
+ Mask,
664
+ RealMask,
665
+ }
666
+
667
+ function getDataFromLayer(layer: Layer, read: LayerDataType, throwForMissingFeatures?: boolean, memoryLimit?: number) {
668
+ if (!layer.rawData) return undefined;
576
669
 
577
670
  const { colorMode, bitsPerChannel, channels, large } = layer.rawData;
578
671
  const layerWidth = (layer.right || 0) - (layer.left || 0);
@@ -580,14 +673,15 @@ export function decodeLayerImageData(layer: Layer, useImageData?: boolean, throw
580
673
  const cmyk = colorMode === ColorMode.CMYK;
581
674
 
582
675
  let imageData: PixelData | undefined;
676
+ let maskData: PixelData | undefined;
583
677
  let initializedAlpha = false;
584
678
 
585
- if (layerWidth && layerHeight) {
679
+ if (layerWidth && layerHeight && read === LayerDataType.Layer) {
586
680
  if (cmyk) {
587
681
  if (bitsPerChannel !== 8) throw new Error('bitsPerChannel Not supproted');
588
682
  imageData = { width: layerWidth, height: layerHeight, data: new Uint8ClampedArray(layerWidth * layerHeight * 5) } as any as ImageData;
589
683
  } else {
590
- imageData = createImageDataBitDepth(layerWidth, layerHeight, bitsPerChannel);
684
+ imageData = createImageDataBitDepth(layerWidth, layerHeight, bitsPerChannel, 4, memoryLimit);
591
685
  }
592
686
  }
593
687
 
@@ -602,6 +696,9 @@ export function decodeLayerImageData(layer: Layer, useImageData?: boolean, throw
602
696
  const dataReader = createReader(data.buffer, data.byteOffset, data.byteLength);
603
697
 
604
698
  if (id === ChannelID.UserMask || id === ChannelID.RealUserMask) {
699
+ if (id === ChannelID.UserMask && read !== LayerDataType.Mask) continue;
700
+ if (id === ChannelID.RealUserMask && read !== LayerDataType.RealMask) continue;
701
+
605
702
  const mask = id === ChannelID.UserMask ? layer.mask : layer.realMask;
606
703
  if (!mask) throw new Error(`Missing layer ${id === ChannelID.UserMask ? 'mask' : 'real mask'} data`);
607
704
 
@@ -610,10 +707,8 @@ export function decodeLayerImageData(layer: Layer, useImageData?: boolean, throw
610
707
  if (maskWidth < 0 || maskHeight < 0 || maskWidth > 30000 || maskHeight > 30000) throw new Error('Invalid mask size');
611
708
 
612
709
  if (maskWidth && maskHeight) {
613
- const maskData = createImageDataBitDepth(maskWidth, maskHeight, bitsPerChannel);
614
-
710
+ maskData = createImageDataBitDepth(maskWidth, maskHeight, bitsPerChannel, 4, memoryLimit);
615
711
  readData(dataReader, data.byteLength, maskData, compression, maskWidth, maskHeight, bitsPerChannel, 0, large, 4);
616
-
617
712
  if (RAW_IMAGE_DATA) { // TODO: use layer.rawData instead
618
713
  if (id === ChannelID.UserMask) {
619
714
  (layer as any).maskDataRawCompression = compression;
@@ -623,17 +718,12 @@ export function decodeLayerImageData(layer: Layer, useImageData?: boolean, throw
623
718
  (layer as any).realMaskDataRaw = data;
624
719
  }
625
720
  }
626
-
627
721
  setupGrayscale(maskData);
628
722
  resetAlpha(maskData, false);
629
-
630
- if (useImageData) {
631
- mask.imageData = maskData;
632
- } else {
633
- mask.canvas = imageDataToCanvas(maskData);
634
- }
635
723
  }
636
724
  } else {
725
+ if (read !== LayerDataType.Layer) continue;
726
+
637
727
  const offset = offsetForChannel(id, cmyk);
638
728
  let targetData = imageData;
639
729
 
@@ -670,15 +760,9 @@ export function decodeLayerImageData(layer: Layer, useImageData?: boolean, throw
670
760
  imageData = createImageData(cmykData.width, cmykData.height);
671
761
  cmykToRgb(cmykData, imageData, false);
672
762
  }
673
-
674
- if (useImageData) {
675
- layer.imageData = imageData;
676
- } else {
677
- layer.canvas = imageDataToCanvas(imageData);
678
- }
679
763
  }
680
764
 
681
- delete layer.rawData;
765
+ return read === LayerDataType.Layer ? imageData : maskData;
682
766
  }
683
767
 
684
768
  function readData(reader: PsdReader, length: number, pixels: PixelData | undefined, compression: Compression, width: number, height: number, bitDepth: number, offset: number, large: boolean, step: number) {
@@ -774,7 +858,10 @@ export function readAdditionalLayerInfo(reader: PsdReader, target: LayerAddition
774
858
  }, false, u64);
775
859
  }
776
860
 
777
- export function createImageDataBitDepth(width: number, height: number, bitDepth: number, channels = 4): PixelData {
861
+ function createImageDataBitDepth(width: number, height: number, bitDepth: number, channels: number, memoryLimit: number | undefined): PixelData {
862
+ const sizeInBytes = width * height * channels * Math.max(1, bitDepth / 8);
863
+ if (memoryLimit !== undefined && sizeInBytes > memoryLimit) throw new Error('Exceeded memory limit');
864
+
778
865
  if (bitDepth === 1 || bitDepth === 8) {
779
866
  if (channels === 4) {
780
867
  return createImageData(width, height);
@@ -800,7 +887,8 @@ function readImageData(reader: PsdReader, psd: Psd) {
800
887
  if (compression !== Compression.RawData && compression !== Compression.RleCompressed)
801
888
  throw new Error(`Compression type not supported: ${compression}`);
802
889
 
803
- const imageData = createImageDataBitDepth(psd.width, psd.height, bitsPerChannel);
890
+ const imageData = createImageDataBitDepth(psd.width, psd.height, bitsPerChannel, 4, reader.totalMemoryLimit);
891
+ if (reader.totalMemoryLimit !== undefined) reader.totalMemoryLimit -= imageData.data.byteLength;
804
892
  resetImageData(imageData);
805
893
 
806
894
  switch (psd.colorMode) {
@@ -815,7 +903,7 @@ function readImageData(reader: PsdReader, psd: Psd) {
815
903
  bytes = new Uint8Array(psd.width * psd.height);
816
904
  readDataRLE(reader, { data: bytes, width: psd.width, height: psd.height }, psd.width, psd.height, 8, 1, [0], reader.large);
817
905
  } else {
818
- throw new Error(`Bitmap compression not supported: ${compression}`);
906
+ throw new Error(`Compression not supported: ${compression}`);
819
907
  }
820
908
 
821
909
  decodeBitmap(bytes, imageData.data, psd.width, psd.height);
@@ -843,6 +931,8 @@ function readImageData(reader: PsdReader, psd: Psd) {
843
931
  const start = reader.offset;
844
932
  readDataRLE(reader, imageData, psd.width, psd.height, bitsPerChannel, 4, channels, reader.large);
845
933
  if (RAW_IMAGE_DATA) (psd as any).imageDataRaw = new Uint8Array(reader.view.buffer, reader.view.byteOffset + start, reader.offset - start);
934
+ } else {
935
+ throw new Error(`Compression not supported: ${compression}`);
846
936
  }
847
937
 
848
938
  if (psd.colorMode === ColorMode.Grayscale) {
@@ -856,7 +946,7 @@ function readImageData(reader: PsdReader, psd: Psd) {
856
946
  if (!psd.palette) throw new Error('Missing color palette');
857
947
 
858
948
  if (compression === Compression.RawData) {
859
- throw new Error(`Not implemented`);
949
+ throw new Error(`Compression not supported: ${compression}`);
860
950
  } else if (compression === Compression.RleCompressed) {
861
951
  const indexedImageData: PixelData = {
862
952
  width: imageData.width,
@@ -866,7 +956,7 @@ function readImageData(reader: PsdReader, psd: Psd) {
866
956
  readDataRLE(reader, indexedImageData, psd.width, psd.height, bitsPerChannel, 1, [0], reader.large);
867
957
  indexedToRgb(indexedImageData, imageData, psd.palette);
868
958
  } else {
869
- throw new Error(`Not implemented`);
959
+ throw new Error(`Compression not supported: ${compression}`);
870
960
  }
871
961
 
872
962
  break;
@@ -879,7 +969,7 @@ function readImageData(reader: PsdReader, psd: Psd) {
879
969
  if (reader.globalAlpha) channels.push(4);
880
970
 
881
971
  if (compression === Compression.RawData) {
882
- throw new Error(`Not implemented`);
972
+ throw new Error(`Compression not supported: ${compression}`);
883
973
  // TODO: ...
884
974
  // for (let i = 0; i < channels.length; i++) {
885
975
  // readDataRaw(reader, imageData, channels[i], psd.width, psd.height);
@@ -897,7 +987,7 @@ function readImageData(reader: PsdReader, psd: Psd) {
897
987
 
898
988
  if (RAW_IMAGE_DATA) (psd as any).imageDataRaw = new Uint8Array(reader.view.buffer, reader.view.byteOffset + start, reader.offset - start);
899
989
  } else {
900
- throw new Error(`Not implemented`);
990
+ throw new Error(`Compression not supported: ${compression}`);
901
991
  }
902
992
 
903
993
  break;
@@ -923,11 +1013,7 @@ function readImageData(reader: PsdReader, psd: Psd) {
923
1013
  }
924
1014
  }
925
1015
 
926
- if (reader.useImageData) {
927
- psd.imageData = imageData;
928
- } else {
929
- psd.canvas = imageDataToCanvas(imageData);
930
- }
1016
+ return imageData;
931
1017
  }
932
1018
 
933
1019
  function cmykToRgb(cmyk: PixelData, rgb: PixelData, reverseAlpha: boolean) {
@@ -1310,9 +1396,7 @@ export function readPattern(reader: PsdReader): PatternInfo {
1310
1396
  data[dst + ch] = cdata[src];
1311
1397
  }
1312
1398
  }
1313
- }
1314
-
1315
- if (colorMode === ColorMode.Grayscale && ch < 1) {
1399
+ } else if (colorMode === ColorMode.Grayscale && ch < 1) {
1316
1400
  for (let y = 0; y < h; y++) {
1317
1401
  for (let x = 0; x < w; x++) {
1318
1402
  const src = x + y * w;
@@ -1323,11 +1407,20 @@ export function readPattern(reader: PsdReader): PatternInfo {
1323
1407
  data[dst + 2] = value;
1324
1408
  }
1325
1409
  }
1326
- }
1327
-
1328
- if (colorMode === ColorMode.Indexed) {
1329
- // TODO:
1330
- throw new Error('Indexed pattern color mode not implemented');
1410
+ } else if (colorMode === ColorMode.Indexed) {
1411
+ for (let y = 0; y < h; y++) {
1412
+ for (let x = 0; x < w; x++) {
1413
+ const src = x + y * w;
1414
+ const dst = (ox + x + (y + oy) * width) * 4;
1415
+ const index = cdata[src];
1416
+ const color = palette[index];
1417
+ data[dst + 0] = color.r;
1418
+ data[dst + 1] = color.g;
1419
+ data[dst + 2] = color.b;
1420
+ }
1421
+ }
1422
+ } else {
1423
+ if (reader.throwForMissingFeatures) throw new Error('Invalid color pattern');
1331
1424
  }
1332
1425
  } else if (compressionMode === 1) {
1333
1426
  const pixelData: PixelData = { data, width, height };
package/src/psdWriter.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Psd, Layer, LayerAdditionalInfo, ColorMode, SectionDividerType, WriteOptions, Color, GlobalLayerMaskInfo, PixelData, LayerMaskData, Compression, ChannelID } from './psd';
1
+ import { Psd, Layer, LayerAdditionalInfo, ColorMode, SectionDividerType, WriteOptions, Color, GlobalLayerMaskInfo, PixelData, LayerMaskData, Compression, ChannelID, PatternInfo } from './psd';
2
2
  import { hasAlpha, createCanvas, writeDataRLE, LayerChannelData, ChannelData, offsetForChannel, createImageData, fromBlendMode, clamp, LayerMaskFlags, MaskParams, ColorSpace, Bounds, largeAdditionalInfoKeys, RAW_IMAGE_DATA, writeDataZipWithoutPrediction, imageDataToCanvas } from './helpers';
3
3
  import { ExtendedWriteOptions, infoHandlers } from './additionalInfo';
4
4
  import { InternalImageResources, resourceHandlers } from './imageResources';
@@ -348,7 +348,7 @@ function writeLayerInfo(writer: PsdWriter, layers: Layer[], psd: Psd, globalAlph
348
348
  writeUint16(writer, channels.length);
349
349
 
350
350
  for (const c of channels) {
351
- writeInt16(writer, c.channelId);
351
+ writeInt16(writer, c.id);
352
352
  if (options.psb) writeUint32(writer, 0);
353
353
  writeUint32(writer, c.length);
354
354
  }
@@ -381,8 +381,8 @@ function writeLayerInfo(writer: PsdWriter, layers: Layer[], psd: Psd, globalAlph
381
381
  for (const channel of layerData.channels) {
382
382
  writeUint16(writer, channel.compression);
383
383
 
384
- if (channel.buffer) {
385
- writeBytes(writer, channel.buffer);
384
+ if (channel.data) {
385
+ writeBytes(writer, channel.data);
386
386
  }
387
387
  }
388
388
  }
@@ -635,12 +635,31 @@ function getMaskChannels(tempBuffer: Uint8Array, layerData: LayerChannelData, la
635
635
  compression = Compression.RleCompressed;
636
636
  }
637
637
 
638
- layerData.channels.push({ channelId: realMask ? ChannelID.RealUserMask : ChannelID.UserMask, compression, buffer, length: 2 + buffer.length });
638
+ layerData.channels.push({ id: realMask ? ChannelID.RealUserMask : ChannelID.UserMask, compression, data: buffer, length: 2 + buffer.length });
639
639
 
640
640
  layerData[realMask ? 'realMask' : 'mask'] = { top, left, right, bottom };
641
641
  }
642
642
 
643
+ function bounds(obj: { top?: number; left?: number; bottom?: number; right?: number; } | undefined) {
644
+ return obj ? {
645
+ top: obj.top || 0,
646
+ left: obj.left || 0,
647
+ right: obj.right || 0,
648
+ bottom: obj.bottom || 0,
649
+ } : undefined;
650
+ }
651
+
643
652
  function getChannels(tempBuffer: Uint8Array, layer: Layer, background: boolean, options: WriteOptions): LayerChannelData {
653
+ if (layer.rawData) {
654
+ return {
655
+ layer,
656
+ channels: layer.rawData.channels.map(c => ({ ...c, length: 2 + (c.data?.byteLength ?? 0) })),
657
+ ...bounds(layer)!,
658
+ mask: bounds(layer.mask),
659
+ realMask: bounds(layer.realMask),
660
+ };
661
+ }
662
+
644
663
  const layerData = getLayerChannels(tempBuffer, layer, background, options);
645
664
  if (layer.mask) getMaskChannels(tempBuffer, layerData, layer, layer.mask, options, false);
646
665
  if (layer.realMask) getMaskChannels(tempBuffer, layerData, layer, layer.realMask, options, true);
@@ -683,10 +702,10 @@ function getLayerChannels(tempBuffer: Uint8Array, layer: Layer, background: bool
683
702
  let right = (layer.right as any) | 0;
684
703
  let bottom = (layer.bottom as any) | 0;
685
704
  let channels: ChannelData[] = [
686
- { channelId: ChannelID.Transparency, compression: Compression.RawData, buffer: undefined, length: 2 },
687
- { channelId: ChannelID.Color0, compression: Compression.RawData, buffer: undefined, length: 2 },
688
- { channelId: ChannelID.Color1, compression: Compression.RawData, buffer: undefined, length: 2 },
689
- { channelId: ChannelID.Color2, compression: Compression.RawData, buffer: undefined, length: 2 },
705
+ { id: ChannelID.Transparency, compression: Compression.RawData, data: undefined, length: 2 },
706
+ { id: ChannelID.Color0, compression: Compression.RawData, data: undefined, length: 2 },
707
+ { id: ChannelID.Color1, compression: Compression.RawData, data: undefined, length: 2 },
708
+ { id: ChannelID.Color2, compression: Compression.RawData, data: undefined, length: 2 },
690
709
  ];
691
710
  let { width, height } = getLayerDimentions(layer);
692
711
 
@@ -699,22 +718,22 @@ function getLayerChannels(tempBuffer: Uint8Array, layer: Layer, background: bool
699
718
  right = left + width;
700
719
  bottom = top + height;
701
720
 
702
- let data = layer.imageData || layer.canvas!.getContext('2d')!.getImageData(0, 0, width, height);
721
+ let imageData = layer.imageData || layer.canvas!.getContext('2d')!.getImageData(0, 0, width, height);
703
722
 
704
723
  if (options.trimImageData) {
705
- const trimmed = trimData(data);
724
+ const trimmed = trimData(imageData);
706
725
 
707
- if (trimmed.left !== 0 || trimmed.top !== 0 || trimmed.right !== data.width || trimmed.bottom !== data.height) {
726
+ if (trimmed.left !== 0 || trimmed.top !== 0 || trimmed.right !== imageData.width || trimmed.bottom !== imageData.height) {
708
727
  left += trimmed.left;
709
728
  top += trimmed.top;
710
- right -= (data.width - trimmed.right);
711
- bottom -= (data.height - trimmed.bottom);
729
+ right -= (imageData.width - trimmed.right);
730
+ bottom -= (imageData.height - trimmed.bottom);
712
731
  width = right - left;
713
732
  height = bottom - top;
714
733
 
715
734
  if (!width || !height) return { layer, top, left, right, bottom, channels };
716
735
 
717
- data = cropImageData(data, trimmed.left, trimmed.top, width, height);
736
+ imageData = cropImageData(imageData, trimmed.left, trimmed.top, width, height);
718
737
  }
719
738
  }
720
739
 
@@ -724,28 +743,28 @@ function getLayerChannels(tempBuffer: Uint8Array, layer: Layer, background: bool
724
743
  ChannelID.Color2,
725
744
  ];
726
745
 
727
- if (!background || options.noBackground || layer.mask || hasAlpha(data) || (RAW_IMAGE_DATA && (layer as any).imageDataRaw?.['-1'])) {
746
+ if (!background || options.noBackground || layer.mask || hasAlpha(imageData) || (RAW_IMAGE_DATA && (layer as any).imageDataRaw?.['-1'])) {
728
747
  channelIds.unshift(ChannelID.Transparency);
729
748
  }
730
749
 
731
- channels = channelIds.map(channelId => {
732
- const offset = offsetForChannel(channelId, false); // TODO: psd.colorMode === ColorMode.CMYK);
733
- let buffer: Uint8Array;
750
+ channels = channelIds.map(id => {
751
+ const offset = offsetForChannel(id, false); // TODO: psd.colorMode === ColorMode.CMYK);
752
+ let data: Uint8Array;
734
753
  let compression: Compression;
735
754
 
736
755
  if (RAW_IMAGE_DATA && (layer as any).imageDataRaw) {
737
756
  // console.log('written raw layer image data');
738
- buffer = (layer as any).imageDataRaw[channelId];
739
- compression = (layer as any).imageDataRawCompression[channelId];
757
+ data = (layer as any).imageDataRaw[id];
758
+ compression = (layer as any).imageDataRawCompression[id];
740
759
  } else if (options.compress) {
741
- buffer = writeDataZipWithoutPrediction(data, [offset]);
760
+ data = writeDataZipWithoutPrediction(imageData, [offset]);
742
761
  compression = Compression.ZipWithoutPrediction;
743
762
  } else {
744
- buffer = writeDataRLE(tempBuffer, data, [offset], !!options.psb)!;
763
+ data = writeDataRLE(tempBuffer, imageData, [offset], !!options.psb)!;
745
764
  compression = Compression.RleCompressed;
746
765
  }
747
766
 
748
- return { channelId, compression, buffer, length: 2 + buffer.length };
767
+ return { id, compression, data, length: 2 + data.length };
749
768
  });
750
769
 
751
770
  return { layer, top, left, right, bottom, channels };
@@ -835,3 +854,78 @@ export function writeColor(writer: PsdWriter, color: Color | undefined) {
835
854
  writeZeros(writer, 6);
836
855
  }
837
856
  }
857
+
858
+ // ponytail: only round-trips RGB 8-bit patterns; source colorMode (16-bit/Indexed) is not preserved,
859
+ // since readPattern already converted everything to RGBA. Upgrade if pattern colorMode must survive write.
860
+ export function writePattern(writer: PsdWriter, pattern: PatternInfo) {
861
+ const width = pattern.bounds.w;
862
+ const height = pattern.bounds.h;
863
+ const pixelData: PixelData = { width, height, data: pattern.data };
864
+
865
+ writeUint32(writer, 0); // length, fixed up below
866
+ const pattsOffset = writer.offset;
867
+
868
+ writeUint32(writer, 1); // version
869
+ writeUint32(writer, ColorMode.RGB); // color mode - rgb only
870
+
871
+ writeInt16(writer, pattern.x);
872
+ writeInt16(writer, pattern.y);
873
+
874
+ writeUnicodeString(writer, pattern.name + '\0'); // name
875
+ writePascalString(writer, pattern.id, 1); // id
876
+
877
+ // virtual memory array list
878
+ writeUint32(writer, 3); // version
879
+ writeUint32(writer, 0); // length, fixed up below
880
+ const vlOffset = writer.offset;
881
+
882
+ const top = pattern.bounds.y;
883
+ const left = pattern.bounds.x;
884
+ const bottom = top + height;
885
+ const right = left + width;
886
+
887
+ writeUint32(writer, top);
888
+ writeUint32(writer, left);
889
+ writeUint32(writer, bottom);
890
+ writeUint32(writer, right);
891
+
892
+ writeUint32(writer, 24); // channels count
893
+
894
+ // channels: RGB at indices 0,1,2 and alpha at index 25
895
+ for (let i = 0; i < 24 + 2; i++) {
896
+ const offset = i < 3 ? i : (i === 25 ? 3 : -1);
897
+
898
+ if (offset < 0) {
899
+ writeUint32(writer, 0); // has
900
+ continue;
901
+ }
902
+
903
+ // worst-case RLE size for a single channel: width + 1 per scanline, plus scanline length headers
904
+ const buffer = new Uint8Array(width * height + 2 * height + 2 * width + 16);
905
+ // ponytail: pattern channels always use small (2-byte) RLE scanline headers, matching
906
+ // readPattern which reads them as non-large; `large` here only affects the header width.
907
+ const data = writeDataRLE(buffer, pixelData, [offset], false)!;
908
+
909
+ writeUint32(writer, 1); // has
910
+ writeUint32(writer, data.length + 4 + 16 + 2 + 1); // length
911
+ writeUint32(writer, 8); // pixelDepth
912
+ writeUint32(writer, top);
913
+ writeUint32(writer, left);
914
+ writeUint32(writer, bottom);
915
+ writeUint32(writer, right);
916
+ writeUint16(writer, 8); // pixelDepth2
917
+ writeUint8(writer, 1); // compressionMode - rle
918
+ writeBytes(writer, data);
919
+ }
920
+
921
+ const vlLength = writer.offset - vlOffset;
922
+ let pattsLength = writer.offset - pattsOffset;
923
+
924
+ while (pattsLength % 4) {
925
+ writeZeros(writer, 1);
926
+ pattsLength++;
927
+ }
928
+
929
+ writer.view.setUint32(vlOffset - 4, vlLength, false);
930
+ writer.view.setUint32(pattsOffset - 4, pattsLength, false);
931
+ }
package/tsconfig-es6.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "extends": "./tsconfig.json",
3
3
  "compilerOptions": {
4
- "module": "es6",
4
+ "module": "Node16",
5
+ "moduleResolution": "Node16",
5
6
  "outDir": "dist-es"
6
7
  }
7
8
  }
package/tsconfig.json CHANGED
@@ -1,17 +1,19 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "moduleResolution": "node",
4
- "target": "es5",
5
- "module": "commonjs",
3
+ "moduleResolution": "node16",
4
+ "target": "es2016",
5
+ "module": "node16",
6
6
  "lib": ["es2016", "dom"],
7
7
  "noUnusedLocals": true,
8
8
  "noUnusedParameters": true,
9
9
  "preserveConstEnums": true,
10
10
  "declaration": true,
11
11
  "useUnknownInCatchVariables": false,
12
+ "types": ["node", "mocha"],
12
13
  "strict": true,
13
14
  "sourceMap": true,
14
15
  "sourceRoot": "../src",
16
+ "rootDir": "src",
15
17
  "outDir": "dist"
16
18
  },
17
19
  "include": [