ag-psd 32.0.0 → 34.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 (117) hide show
  1. package/.v8-cache/v24.7.0-x64-ef5a0af0/03e19709 +0 -0
  2. package/.v8-cache/v24.7.0-x64-ef5a0af0/05135617 +0 -0
  3. package/.v8-cache/v24.7.0-x64-ef5a0af0/1130885f +0 -0
  4. package/.v8-cache/v24.7.0-x64-ef5a0af0/226e2801 +0 -0
  5. package/.v8-cache/v24.7.0-x64-ef5a0af0/2a19133e +0 -0
  6. package/.v8-cache/v24.7.0-x64-ef5a0af0/4511bacf +0 -0
  7. package/.v8-cache/v24.7.0-x64-ef5a0af0/68416cb2 +0 -0
  8. package/.v8-cache/v24.7.0-x64-ef5a0af0/71df9cb3 +0 -0
  9. package/.v8-cache/v24.7.0-x64-ef5a0af0/7ea06cea +0 -0
  10. package/.v8-cache/v24.7.0-x64-ef5a0af0/87cf2209 +0 -0
  11. package/.v8-cache/v24.7.0-x64-ef5a0af0/932f0770 +0 -0
  12. package/.v8-cache/v24.7.0-x64-ef5a0af0/acc36e66 +0 -0
  13. package/.v8-cache/v24.7.0-x64-ef5a0af0/b3c2fab7 +0 -0
  14. package/.v8-cache/v24.7.0-x64-ef5a0af0/c0b789d2 +0 -0
  15. package/.v8-cache/v24.7.0-x64-ef5a0af0/c314aece +0 -0
  16. package/.v8-cache/v24.7.0-x64-ef5a0af0/cfc49f4f +0 -0
  17. package/.v8-cache/v24.7.0-x64-ef5a0af0/cff9434a +0 -0
  18. package/.v8-cache/v24.7.0-x64-ef5a0af0/d13d7610 +0 -0
  19. package/.v8-cache/v24.7.0-x64-ef5a0af0/dc86f000 +0 -0
  20. package/.v8-cache/v24.7.0-x64-ef5a0af0/e03e2acd +0 -0
  21. package/.v8-cache/v24.7.0-x64-ef5a0af0/e6745c2b +0 -0
  22. package/.v8-cache/v24.7.0-x64-ef5a0af0/e6b99945 +0 -0
  23. package/.v8-cache/v24.7.0-x64-ef5a0af0/eeeebdfe +0 -0
  24. package/.v8-cache/v24.7.0-x64-ef5a0af0/f6fd8125 +0 -0
  25. package/CHANGELOG.md +100 -0
  26. package/LICENSE +5 -0
  27. package/README.md +4 -7
  28. package/README_PSD.md +261 -84
  29. package/TODO.md +13 -84
  30. package/dist/abr.d.ts +11 -4
  31. package/dist/abr.js +362 -230
  32. package/dist/abr.js.map +1 -1
  33. package/dist/additionalInfo.d.ts +56 -2
  34. package/dist/additionalInfo.js +828 -361
  35. package/dist/additionalInfo.js.map +1 -1
  36. package/dist/ase.d.ts +6 -1
  37. package/dist/ase.js +61 -61
  38. package/dist/ase.js.map +1 -1
  39. package/dist/bundle.js +3321 -1364
  40. package/dist/descriptor.d.ts +28 -13
  41. package/dist/descriptor.js +295 -241
  42. package/dist/descriptor.js.map +1 -1
  43. package/dist/helpers.d.ts +7 -1
  44. package/dist/helpers.js +246 -4
  45. package/dist/helpers.js.map +1 -1
  46. package/dist/imageResources.d.ts +15 -3
  47. package/dist/imageResources.js +586 -144
  48. package/dist/imageResources.js.map +1 -1
  49. package/dist/index.d.ts +1 -0
  50. package/dist/index.js +1 -0
  51. package/dist/index.js.map +1 -1
  52. package/dist/jpeg.js +8 -8
  53. package/dist/jpeg.js.map +1 -1
  54. package/dist/psd.d.ts +292 -19
  55. package/dist/psd.js.map +1 -1
  56. package/dist/psdReader.d.ts +10 -0
  57. package/dist/psdReader.js +424 -216
  58. package/dist/psdReader.js.map +1 -1
  59. package/dist/psdWriter.d.ts +2 -0
  60. package/dist/psdWriter.js +373 -113
  61. package/dist/psdWriter.js.map +1 -1
  62. package/dist/text.d.ts +32 -1
  63. package/dist/text.js +75 -6
  64. package/dist/text.js.map +1 -1
  65. package/dist/utf8.js +0 -3
  66. package/dist/utf8.js.map +1 -1
  67. package/dist-es/abr.d.ts +11 -4
  68. package/dist-es/abr.js +362 -230
  69. package/dist-es/abr.js.map +1 -1
  70. package/dist-es/additionalInfo.d.ts +56 -2
  71. package/dist-es/additionalInfo.js +828 -361
  72. package/dist-es/additionalInfo.js.map +1 -1
  73. package/dist-es/ase.d.ts +6 -1
  74. package/dist-es/ase.js +61 -61
  75. package/dist-es/ase.js.map +1 -1
  76. package/dist-es/descriptor.d.ts +28 -13
  77. package/dist-es/descriptor.js +295 -241
  78. package/dist-es/descriptor.js.map +1 -1
  79. package/dist-es/helpers.d.ts +7 -1
  80. package/dist-es/helpers.js +246 -4
  81. package/dist-es/helpers.js.map +1 -1
  82. package/dist-es/imageResources.d.ts +15 -3
  83. package/dist-es/imageResources.js +586 -144
  84. package/dist-es/imageResources.js.map +1 -1
  85. package/dist-es/index.d.ts +1 -0
  86. package/dist-es/index.js +1 -0
  87. package/dist-es/index.js.map +1 -1
  88. package/dist-es/jpeg.js +8 -8
  89. package/dist-es/jpeg.js.map +1 -1
  90. package/dist-es/psd.d.ts +292 -19
  91. package/dist-es/psd.js.map +1 -1
  92. package/dist-es/psdReader.d.ts +10 -0
  93. package/dist-es/psdReader.js +424 -216
  94. package/dist-es/psdReader.js.map +1 -1
  95. package/dist-es/psdWriter.d.ts +2 -0
  96. package/dist-es/psdWriter.js +373 -113
  97. package/dist-es/psdWriter.js.map +1 -1
  98. package/dist-es/text.d.ts +32 -1
  99. package/dist-es/text.js +75 -6
  100. package/dist-es/text.js.map +1 -1
  101. package/dist-es/utf8.js +0 -3
  102. package/dist-es/utf8.js.map +1 -1
  103. package/package.json +2 -2
  104. package/perf.js +312 -9
  105. package/src/abr.ts +382 -235
  106. package/src/additionalInfo.ts +1071 -482
  107. package/src/ase.ts +66 -61
  108. package/src/descriptor.ts +291 -242
  109. package/src/helpers.ts +266 -3
  110. package/src/imageResources.ts +736 -169
  111. package/src/index.ts +1 -0
  112. package/src/jpeg.ts +8 -8
  113. package/src/psd.ts +271 -32
  114. package/src/psdReader.ts +440 -221
  115. package/src/psdWriter.ts +402 -110
  116. package/src/text.ts +93 -7
  117. package/src/utf8.ts +0 -4
@@ -30,13 +30,15 @@ exports.writePsd = writePsd;
30
30
  exports.writeColor = writeColor;
31
31
  exports.writePattern = writePattern;
32
32
  const helpers_1 = require("./helpers");
33
+ const pako_1 = require("pako");
33
34
  const additionalInfo_1 = require("./additionalInfo");
34
35
  const imageResources_1 = require("./imageResources");
36
+ const psdReader_1 = require("./psdReader");
35
37
  function createWriter(size = 4096) {
36
38
  const buffer = new ArrayBuffer(size);
37
39
  const view = new DataView(buffer);
38
40
  const offset = 0;
39
- return { buffer, view, offset, tempBuffer: undefined };
41
+ return { buffer, view, offset, tempBuffer: undefined, log: console.log };
40
42
  }
41
43
  function getWriterBuffer(writer) {
42
44
  return writer.buffer.slice(0, writer.offset);
@@ -201,10 +203,33 @@ function writeSection(writer, round, func, writeTotalLength = false, large = fal
201
203
  function verifyPixelData(data, name) {
202
204
  // check element size instead of instanceof, so arrays from other realms (iframes, workers, vm) are accepted
203
205
  const bytesPerElement = data && data.data.BYTES_PER_ELEMENT;
204
- if (bytesPerElement !== undefined && bytesPerElement !== 1) {
205
- throw new Error(`${name} has incorrect bitDepth (only 8-bit Uint8Array or Uint8ClampedArray data is supported for writing)`);
206
+ if (bytesPerElement !== undefined && bytesPerElement !== 1 && bytesPerElement !== 2 && !(data.data instanceof Float32Array)) {
207
+ throw new Error(`${name} has incorrect bitDepth (only Uint8Array, Uint8ClampedArray, Uint16Array and Float32Array data is supported for writing)`);
206
208
  }
207
209
  }
210
+ // supported bit depths for each color mode
211
+ const writeBitDepths = {
212
+ [0 /* ColorMode.Bitmap */]: [1],
213
+ [1 /* ColorMode.Grayscale */]: [8, 16, 32],
214
+ [2 /* ColorMode.Indexed */]: [8],
215
+ [3 /* ColorMode.RGB */]: [8, 16, 32],
216
+ [4 /* ColorMode.CMYK */]: [8, 16],
217
+ };
218
+ const colorModeNames = {
219
+ [0 /* ColorMode.Bitmap */]: 'Bitmap', [1 /* ColorMode.Grayscale */]: 'Grayscale', [2 /* ColorMode.Indexed */]: 'Indexed', [3 /* ColorMode.RGB */]: 'RGB',
220
+ [4 /* ColorMode.CMYK */]: 'CMYK', [7 /* ColorMode.Multichannel */]: 'Multichannel', [8 /* ColorMode.Duotone */]: 'Duotone', [9 /* ColorMode.Lab */]: 'Lab',
221
+ };
222
+ function colorChannelsCount(colorMode) {
223
+ return colorMode === 3 /* ColorMode.RGB */ ? 3 : (colorMode === 4 /* ColorMode.CMYK */ ? 4 : 1);
224
+ }
225
+ // HDR toning settings that Photoshop stores in color mode data of 32bit documents (default values of new document),
226
+ // Photoshop refuses to open 32bit documents without them
227
+ const hdrToningData = [
228
+ 104, 100, 114, 116, 0, 0, 0, 3, 62, 107, 133, 31, 0, 0, 0, 2, 0, 0, 0, 7, 0, 76, 0, 105, 0, 110, 0, 101, 0, 97, 0, 114, 0, 0,
229
+ 0, 2, 0, 2, 0, 0, 0, 0, 0, 255, 0, 255, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 65, 128, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 63, 128, 0, 0,
230
+ 104, 100, 114, 97, 0, 0, 0, 6, 0, 0, 0, 0, 65, 160, 0, 0, 65, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 128, 0, 0, 0, 0, 0, 0,
231
+ 0, 0,
232
+ ];
208
233
  function verifyBitCount(target) {
209
234
  var _a, _b, _c;
210
235
  (_a = target.children) === null || _a === void 0 ? void 0 : _a.forEach(verifyBitCount);
@@ -215,21 +240,37 @@ function verifyBitCount(target) {
215
240
  verifyPixelData((_c = target.realMask) === null || _c === void 0 ? void 0 : _c.imageData, 'realMask imageData');
216
241
  }
217
242
  function writePsd(writer, psd, options = {}) {
218
- var _a;
243
+ var _a, _b, _c, _d;
219
244
  if (!(+psd.width > 0 && +psd.height > 0))
220
245
  throw new Error('Invalid document size');
221
246
  if ((psd.width > 30000 || psd.height > 30000) && !options.psb)
222
247
  throw new Error('Document size is too large (max is 30000x30000, use PSB format instead)');
223
- const bitsPerChannel = (_a = psd.bitsPerChannel) !== null && _a !== void 0 ? _a : 8;
224
- if (bitsPerChannel !== 8)
225
- throw new Error('bitsPerChannel other than 8 are not supported for writing');
248
+ const colorMode = (_a = psd.colorMode) !== null && _a !== void 0 ? _a : 3 /* ColorMode.RGB */;
249
+ const bitsPerChannel = (_b = psd.bitsPerChannel) !== null && _b !== void 0 ? _b : (colorMode === 0 /* ColorMode.Bitmap */ ? 1 : 8);
250
+ const bitDepths = writeBitDepths[colorMode];
251
+ if (!bitDepths)
252
+ throw new Error(`${(_c = colorModeNames[colorMode]) !== null && _c !== void 0 ? _c : colorMode} color mode is not supported for writing`);
253
+ if (bitDepths.indexOf(bitsPerChannel) === -1)
254
+ throw new Error(`bitsPerChannel ${bitsPerChannel} is not supported for writing in ${colorModeNames[colorMode]} color mode`);
255
+ // Photoshop doesn't support layers in bitmap and indexed color modes
256
+ const layersAllowed = colorMode !== 0 /* ColorMode.Bitmap */ && colorMode !== 2 /* ColorMode.Indexed */;
257
+ if (!layersAllowed && ((_d = psd.children) === null || _d === void 0 ? void 0 : _d.length))
258
+ throw new Error(`Layers are not supported in ${colorModeNames[colorMode]} color mode`);
259
+ if (colorMode === 2 /* ColorMode.Indexed */ && !psd.palette)
260
+ throw new Error('Missing color palette for Indexed color mode');
261
+ if (options.log)
262
+ writer.log = options.log;
263
+ if (options.logMissingFeatures)
264
+ writer.logMissingFeatures = true;
226
265
  const layers = [];
227
266
  addChildren(layers, psd.children);
228
- if (!layers.length)
267
+ if (!layers.length && layersAllowed)
229
268
  layers.push({});
230
269
  verifyBitCount(psd);
231
270
  const imageResources = Object.assign({}, psd.imageResources);
232
- const opt = Object.assign(Object.assign({}, options), { layerIds: new Set(), layerToId: new Map() });
271
+ const opt = Object.assign(Object.assign({}, options), { layerIds: new Set(), layerToId: new Map(), colorMode, bitsPerChannel });
272
+ // 16 and 32 bit documents store layers in Lr16 / Lr32 section of global additional info
273
+ const layersInGlobalInfo = bitsPerChannel === 16 || bitsPerChannel === 32;
233
274
  if (opt.generateThumbnail) {
234
275
  imageResources.thumbnail = createThumbnail(psd);
235
276
  }
@@ -237,32 +278,38 @@ function writePsd(writer, psd, options = {}) {
237
278
  if (!imageData && psd.canvas) {
238
279
  imageData = psd.canvas.getContext('2d').getImageData(0, 0, psd.canvas.width, psd.canvas.height);
239
280
  }
281
+ if (!imageData && psd.rawCompositeData) { // read with `useRawData` option
282
+ imageData = (0, psdReader_1.getCompositeImageData)(psd);
283
+ }
240
284
  if (imageData && (psd.width !== imageData.width || psd.height !== imageData.height))
241
285
  throw new Error('Document canvas must have the same size as document');
242
- const globalAlpha = !!imageData && (0, helpers_1.hasAlpha)(imageData);
286
+ const globalAlpha = !!imageData && layersAllowed && (0, helpers_1.hasAlpha)(imageData);
243
287
  // only used for encoding a single layer channel at a time, composite image is encoded directly into the writer buffer
244
288
  writer.tempBuffer = new Uint8Array(getLargestLayerSize(psd.children, !!options.psb));
245
289
  // header
246
290
  writeSignature(writer, '8BPS');
247
291
  writeUint16(writer, options.psb ? 2 : 1); // version
248
292
  writeZeros(writer, 6);
249
- writeUint16(writer, globalAlpha ? 4 : 3); // channels
293
+ writeUint16(writer, colorChannelsCount(colorMode) + (globalAlpha ? 1 : 0)); // channels
250
294
  writeUint32(writer, psd.height);
251
295
  writeUint32(writer, psd.width);
252
296
  writeUint16(writer, bitsPerChannel); // bits per channel
253
- writeUint16(writer, 3 /* ColorMode.RGB */); // we only support saving RGB right now
297
+ writeUint16(writer, colorMode);
254
298
  // color mode data
255
299
  writeSection(writer, 1, () => {
256
- var _a, _b, _c;
257
- if (psd.palette) {
300
+ var _a, _b, _c, _d, _e, _f;
301
+ if (colorMode === 2 /* ColorMode.Indexed */) {
302
+ const palette = psd.palette;
258
303
  for (let i = 0; i < 256; i++)
259
- writeUint8(writer, ((_a = psd.palette[i]) === null || _a === void 0 ? void 0 : _a.r) || 0);
304
+ writeUint8(writer, (_b = (_a = palette[i]) === null || _a === void 0 ? void 0 : _a.r) !== null && _b !== void 0 ? _b : 0);
260
305
  for (let i = 0; i < 256; i++)
261
- writeUint8(writer, ((_b = psd.palette[i]) === null || _b === void 0 ? void 0 : _b.g) || 0);
306
+ writeUint8(writer, (_d = (_c = palette[i]) === null || _c === void 0 ? void 0 : _c.g) !== null && _d !== void 0 ? _d : 0);
262
307
  for (let i = 0; i < 256; i++)
263
- writeUint8(writer, ((_c = psd.palette[i]) === null || _c === void 0 ? void 0 : _c.b) || 0);
308
+ writeUint8(writer, (_f = (_e = palette[i]) === null || _e === void 0 ? void 0 : _e.b) !== null && _f !== void 0 ? _f : 0);
309
+ }
310
+ else if (bitsPerChannel === 32) {
311
+ writeBytes(writer, new Uint8Array(hdrToningData));
264
312
  }
265
- // TODO: other data?
266
313
  });
267
314
  // image resources
268
315
  imageResources.layersGroup = layers.map(l => l.linkGroup || 0);
@@ -272,27 +319,37 @@ function writePsd(writer, psd, options = {}) {
272
319
  const has = handler.has(imageResources);
273
320
  const count = has === false ? 0 : (has === true ? 1 : has);
274
321
  for (let i = 0; i < count; i++) {
322
+ const id = handler.keyCount > 1 ? handler.key + i : handler.key;
323
+ const name = handler.name ? handler.name(imageResources, i) : '';
275
324
  writeSignature(writer, '8BIM');
276
- writeUint16(writer, handler.key);
277
- writePascalString(writer, '', 2);
278
- writeSection(writer, 2, () => handler.write(writer, imageResources, i));
325
+ writeUint16(writer, id);
326
+ writePascalString(writer, name, 2);
327
+ writeSection(writer, 2, () => handler.write(writer, imageResources, i, psd));
279
328
  }
280
329
  }
281
330
  });
282
331
  // layer and mask info
283
332
  writeSection(writer, 2, () => {
284
- writeLayerInfo(writer, layers, psd, globalAlpha, opt);
333
+ if (layersInGlobalInfo || !layersAllowed) {
334
+ writeSection(writer, 4, () => { }, true, opt.psb); // empty layer info
335
+ }
336
+ else {
337
+ writeLayerInfo(writer, layers, psd, globalAlpha, opt);
338
+ }
285
339
  writeGlobalLayerMaskInfo(writer, psd.globalLayerMaskInfo);
340
+ if (layersInGlobalInfo) {
341
+ if (globalAlpha)
342
+ writeGlobalInfoSection(writer, bitsPerChannel === 16 ? 'Mt16' : 'Mt32', !!opt.psb, () => { });
343
+ writeGlobalInfoSection(writer, bitsPerChannel === 16 ? 'Lr16' : 'Lr32', !!opt.psb, () => {
344
+ writeLayerInfoData(writer, layers, psd, globalAlpha, opt);
345
+ });
346
+ }
286
347
  writeAdditionalLayerInfo(writer, psd, psd, opt);
287
348
  }, undefined, !!opt.psb);
288
349
  writer.tempBuffer = undefined;
289
350
  // image data
290
- writeUint16(writer, 1 /* Compression.RleCompressed */); // Photoshop doesn't support zip compression of composite image data
291
- if (helpers_1.RAW_IMAGE_DATA && psd.imageDataRaw) {
292
- console.log('writing raw image data');
293
- writeBytes(writer, psd.imageDataRaw);
294
- }
295
- else {
351
+ if (colorMode === 3 /* ColorMode.RGB */ && bitsPerChannel === 8 && (!imageData || is8bit(imageData))) {
352
+ writeUint16(writer, 1 /* Compression.RleCompressed */); // Photoshop doesn't support zip compression of composite image data
296
353
  const channels = globalAlpha ? [0, 1, 2, 3] : [0, 1, 2];
297
354
  const data = getCompositeData(imageData, psd.width, psd.height, globalAlpha);
298
355
  // encode directly into the writer buffer
@@ -301,6 +358,174 @@ function writePsd(writer, psd, options = {}) {
301
358
  const buffer = new Uint8Array(writer.buffer, writer.offset, maxSize);
302
359
  writer.offset += (0, helpers_1.writeDataRLE)(buffer, data, channels, !!options.psb).length;
303
360
  }
361
+ else {
362
+ writeCompositeImageData(writer, psd, imageData, colorMode, bitsPerChannel, globalAlpha, !!options.psb);
363
+ }
364
+ }
365
+ function writeGlobalInfoSection(writer, key, psb, func) {
366
+ writeSignature(writer, psb ? '8B64' : '8BIM');
367
+ writeSignature(writer, key);
368
+ writeSection(writer, 4, func, false, psb);
369
+ }
370
+ function is8bit(data) {
371
+ return data.data.BYTES_PER_ELEMENT === 1;
372
+ }
373
+ // converts image data (8, 16 or 32 bit RGBA data) to channels of the document color mode and bit depth
374
+ function getPlanarChannels(imageData, colorMode, bitsPerChannel, matte) {
375
+ const { data, width, height } = imageData;
376
+ const size = width * height;
377
+ const srcFloat = data instanceof Float32Array;
378
+ const srcMax = srcFloat ? 1 : (data instanceof Uint16Array ? 0xffff : 0xff);
379
+ const dstFloat = bitsPerChannel === 32;
380
+ const dstMax = dstFloat ? 1 : (bitsPerChannel === 16 ? 0xffff : 0xff);
381
+ const colorCount = colorChannelsCount(colorMode);
382
+ const create = () => dstFloat ? new Float32Array(size) : (bitsPerChannel === 16 ? new Uint16Array(size) : new Uint8Array(size));
383
+ const colors = [];
384
+ for (let i = 0; i < colorCount; i++)
385
+ colors.push(create());
386
+ const alpha = create();
387
+ // color values are gamma corrected when converting between float (linear) and integer values (same as imageDataToCanvas)
388
+ const toNormalized = (v) => srcFloat ? Math.pow((0, helpers_1.clamp)(v, 0, 1), 1 / 2.2) : v / srcMax;
389
+ const fromNormalized = (v) => dstFloat ? Math.pow(v, 2.2) : Math.round((0, helpers_1.clamp)(v, 0, 1) * dstMax);
390
+ const sameType = srcFloat === dstFloat && srcMax === dstMax;
391
+ const convertColor = (v) => sameType ? (dstFloat ? v : Math.round(v)) : fromNormalized(toNormalized(v));
392
+ const convertAlpha = (v) => sameType ? v : (dstFloat ? v / srcMax : Math.round((0, helpers_1.clamp)(v / srcMax, 0, 1) * dstMax));
393
+ const cmyk = [0, 0, 0, 0];
394
+ for (let i = 0, p = 0; i < size; i++, p += 4) {
395
+ const a = data[p + 3];
396
+ const alphaValue = convertAlpha(a);
397
+ alpha[i] = alphaValue;
398
+ // composite image colors are blended with white (or no ink) for documents with transparency
399
+ const blend = matte && a !== srcMax && a > 0 ? (0, helpers_1.clamp)(a / srcMax, 0, 1) : 1;
400
+ if (colorMode === 4 /* ColorMode.CMYK */) {
401
+ (0, helpers_1.rgbToCmykValues)(toNormalized(data[p]), toNormalized(data[p + 1]), toNormalized(data[p + 2]), cmyk);
402
+ for (let j = 0; j < 4; j++) {
403
+ colors[j][i] = Math.round((1 - (0, helpers_1.clamp)(cmyk[j] * blend, 0, 1)) * dstMax); // stored inverted (0 = 100% ink)
404
+ }
405
+ }
406
+ else {
407
+ for (let j = 0; j < colorCount; j++) {
408
+ let value;
409
+ if (colorMode === 3 /* ColorMode.RGB */) {
410
+ value = convertColor(data[p + j]);
411
+ }
412
+ else {
413
+ const r = data[p], g = data[p + 1], b = data[p + 2];
414
+ value = convertColor((r === g && g === b) ? r : (0.299 * r + 0.587 * g + 0.114 * b));
415
+ }
416
+ if (blend !== 1)
417
+ value = dstFloat ? value * blend + 1 - blend : Math.round(value * blend + dstMax * (1 - blend));
418
+ colors[j][i] = value;
419
+ }
420
+ }
421
+ }
422
+ return { colors, alpha };
423
+ }
424
+ function encodeChannel(values, width, height, options) {
425
+ if (!(values instanceof Uint8Array)) {
426
+ return { data: (0, helpers_1.writeDataZipWithPrediction)(values, width, height), compression: 3 /* Compression.ZipWithPrediction */ };
427
+ }
428
+ else if (options.compress) {
429
+ return { data: (0, pako_1.deflate)(values), compression: 2 /* Compression.ZipWithoutPrediction */ };
430
+ }
431
+ else {
432
+ return { data: (0, helpers_1.writeDataRLEBytes)(values, width, height, !!options.psb), compression: 1 /* Compression.RleCompressed */ };
433
+ }
434
+ }
435
+ function writeCompositeImageData(writer, psd, imageData, colorMode, bitsPerChannel, globalAlpha, psb) {
436
+ var _a;
437
+ const { width, height } = psd;
438
+ const data = imageData !== null && imageData !== void 0 ? imageData : { data: new Uint8Array(width * height * 4), width, height };
439
+ const parts = [];
440
+ if (colorMode === 0 /* ColorMode.Bitmap */ || colorMode === 2 /* ColorMode.Indexed */) {
441
+ const values = colorMode === 0 /* ColorMode.Bitmap */ ?
442
+ getBitmapData(data) :
443
+ getIndexedData(data, psd.palette, (_a = psd.imageResources) === null || _a === void 0 ? void 0 : _a.transparencyIndex);
444
+ const rowBytes = colorMode === 0 /* ColorMode.Bitmap */ ? Math.ceil(width / 8) : width;
445
+ if (colorMode === 0 /* ColorMode.Bitmap */) {
446
+ writeUint16(writer, 0 /* Compression.RawData */);
447
+ parts.push(values);
448
+ }
449
+ else {
450
+ writeUint16(writer, 1 /* Compression.RleCompressed */);
451
+ parts.push((0, helpers_1.writeDataRLEBytes)(values, rowBytes, height, psb));
452
+ }
453
+ }
454
+ else {
455
+ const { colors, alpha } = getPlanarChannels(data, colorMode, bitsPerChannel, globalAlpha);
456
+ const channels = globalAlpha ? [...colors, alpha] : colors;
457
+ if (bitsPerChannel === 8) {
458
+ // row byte counts for all channels are stored before data of all channels
459
+ const encoded = channels.map(c => (0, helpers_1.writeDataRLEBytes)(c, width, height, psb));
460
+ const countsSize = height * (psb ? 4 : 2);
461
+ writeUint16(writer, 1 /* Compression.RleCompressed */);
462
+ for (const e of encoded)
463
+ parts.push(e.subarray(0, countsSize));
464
+ for (const e of encoded)
465
+ parts.push(e.subarray(countsSize));
466
+ }
467
+ else {
468
+ writeUint16(writer, 0 /* Compression.RawData */); // Photoshop writes 16 and 32 bit composite image without compression
469
+ for (const c of channels)
470
+ parts.push((0, helpers_1.planarToBytes)(c));
471
+ }
472
+ }
473
+ for (const part of parts)
474
+ writeBytes(writer, part);
475
+ }
476
+ function getBitmapData({ data, width, height }) {
477
+ const rowBytes = Math.ceil(width / 8);
478
+ const result = new Uint8Array(rowBytes * height);
479
+ const max = data instanceof Float32Array ? 1 : (data instanceof Uint16Array ? 0xffff : 0xff);
480
+ for (let y = 0, p = 0; y < height; y++) {
481
+ for (let x = 0; x < width; x++, p += 4) {
482
+ const a = data[p + 3] / max;
483
+ const value = ((0.299 * data[p] + 0.587 * data[p + 1] + 0.114 * data[p + 2]) / max) * a + (1 - a); // blend with white
484
+ if (value < 0.5)
485
+ result[y * rowBytes + (x >> 3)] |= 0x80 >> (x & 7); // 1 = black
486
+ }
487
+ }
488
+ return result;
489
+ }
490
+ function getIndexedData({ data, width, height }, palette, transparencyIndex) {
491
+ const size = width * height;
492
+ const result = new Uint8Array(size);
493
+ const shift = data instanceof Uint16Array ? 8 : 0;
494
+ const cache = new Map();
495
+ for (let i = 0; i < palette.length && i < 256; i++) {
496
+ const key = (palette[i].r << 16) | (palette[i].g << 8) | palette[i].b;
497
+ if (i !== transparencyIndex && !cache.has(key))
498
+ cache.set(key, i);
499
+ }
500
+ for (let i = 0, p = 0; i < size; i++, p += 4) {
501
+ const read = (v) => data instanceof Float32Array ? Math.round(Math.pow((0, helpers_1.clamp)(v, 0, 1), 1 / 2.2) * 255) : (v >>> shift);
502
+ const a = data instanceof Float32Array ? data[p + 3] * 255 : (data[p + 3] >>> shift);
503
+ if (transparencyIndex !== undefined && transparencyIndex >= 0 && a < 128) {
504
+ result[i] = transparencyIndex;
505
+ continue;
506
+ }
507
+ const r = read(data[p]), g = read(data[p + 1]), b = read(data[p + 2]);
508
+ const key = (r << 16) | (g << 8) | b;
509
+ let index = cache.get(key);
510
+ if (index === undefined) {
511
+ // use closest color from the palette
512
+ let best = Infinity;
513
+ index = 0;
514
+ for (let j = 0; j < palette.length && j < 256; j++) {
515
+ if (j === transparencyIndex)
516
+ continue;
517
+ const dr = palette[j].r - r, dg = palette[j].g - g, db = palette[j].b - b;
518
+ const distance = dr * dr + dg * dg + db * db;
519
+ if (distance < best) {
520
+ best = distance;
521
+ index = j;
522
+ }
523
+ }
524
+ cache.set(key, index);
525
+ }
526
+ result[i] = index;
527
+ }
528
+ return result;
304
529
  }
305
530
  function getCompositeData(imageData, width, height, globalAlpha) {
306
531
  if (!imageData)
@@ -326,62 +551,68 @@ function getCompositeData(imageData, width, height, globalAlpha) {
326
551
  return dst ? { data: dst, width, height } : imageData;
327
552
  }
328
553
  function writeLayerInfo(writer, layers, psd, globalAlpha, options) {
329
- writeSection(writer, 4, () => {
330
- var _a;
331
- writeInt16(writer, globalAlpha ? -layers.length : layers.length);
332
- const layersData = layers.map((l, i) => getChannels(writer.tempBuffer, l, i === 0, options));
333
- // layer records
334
- for (const layerData of layersData) {
335
- const { layer, top, left, bottom, right, channels } = layerData;
336
- writeInt32(writer, top);
337
- writeInt32(writer, left);
338
- writeInt32(writer, bottom);
339
- writeInt32(writer, right);
340
- writeUint16(writer, channels.length);
341
- for (const c of channels) {
342
- writeInt16(writer, c.id);
343
- if (options.psb) {
344
- writeUint64(writer, c.length);
345
- }
346
- else {
347
- writeUint32(writer, c.length);
348
- }
554
+ writeSection(writer, 4, () => writeLayerInfoData(writer, layers, psd, globalAlpha, options), true, options.psb);
555
+ }
556
+ function writeLayerInfoData(writer, layers, psd, globalAlpha, options) {
557
+ var _a;
558
+ writeInt16(writer, globalAlpha ? -layers.length : layers.length);
559
+ const layersData = layers.map((l, i) => getChannels(writer, l, i === 0, options));
560
+ // layer records
561
+ for (const layerData of layersData) {
562
+ const { layer, top, left, bottom, right, channels } = layerData;
563
+ writeInt32(writer, top);
564
+ writeInt32(writer, left);
565
+ writeInt32(writer, bottom);
566
+ writeInt32(writer, right);
567
+ writeUint16(writer, channels.length);
568
+ for (const c of channels) {
569
+ writeInt16(writer, c.id);
570
+ if (options.psb) {
571
+ writeUint64(writer, c.length);
349
572
  }
350
- writeSignature(writer, '8BIM');
351
- writeSignature(writer, helpers_1.fromBlendMode[layer.blendMode] || 'norm');
352
- writeUint8(writer, Math.round((0, helpers_1.clamp)((_a = layer.opacity) !== null && _a !== void 0 ? _a : 1, 0, 1) * 255));
353
- writeUint8(writer, layer.clipping ? 1 : 0);
354
- let flags = 0x08; // 1 for Photoshop 5.0 and later, tells if bit 4 has useful information
355
- if (layer.transparencyProtected)
356
- flags |= 0x01;
357
- if (layer.hidden)
358
- flags |= 0x02;
359
- if (layer.vectorMask || (layer.sectionDivider && layer.sectionDivider.type !== 0 /* SectionDividerType.Other */) || layer.adjustment) {
360
- flags |= 0x10; // pixel data irrelevant to appearance of document
573
+ else {
574
+ writeUint32(writer, c.length);
361
575
  }
362
- if (layer.effectsOpen)
363
- flags |= 0x20;
364
- writeUint8(writer, flags);
365
- writeUint8(writer, 0); // filler
366
- writeSection(writer, 1, () => {
367
- writeLayerMaskData(writer, layer, layerData);
368
- writeLayerBlendingRanges(writer, layer);
369
- writePascalString(writer, (layer.name || '').substring(0, 255), 4);
370
- writeAdditionalLayerInfo(writer, layer, psd, options);
371
- });
372
576
  }
373
- // layer channel image data
374
- for (const layerData of layersData) {
375
- for (const channel of layerData.channels) {
376
- writeUint16(writer, channel.compression);
377
- if (channel.data) {
378
- writeBytes(writer, channel.data);
379
- }
577
+ writeSignature(writer, '8BIM');
578
+ writeSignature(writer, helpers_1.fromBlendMode[layer.blendMode] || 'norm');
579
+ writeUint8(writer, Math.round((0, helpers_1.clamp)((_a = layer.opacity) !== null && _a !== void 0 ? _a : 1, 0, 1) * 255));
580
+ writeUint8(writer, layer.clipping ? 1 : 0);
581
+ let flags = 0x08; // 1 for Photoshop 5.0 and later, tells if bit 4 has useful information
582
+ if (layer.transparencyProtected)
583
+ flags |= 0x01;
584
+ if (layer.hidden)
585
+ flags |= 0x02;
586
+ if (layer.vectorMask || (layer.sectionDivider && layer.sectionDivider.type !== 0 /* SectionDividerType.Other */) || layer.adjustment) {
587
+ flags |= 0x10; // pixel data irrelevant to appearance of document
588
+ }
589
+ if (layer.effectsOpen)
590
+ flags |= 0x20;
591
+ writeUint8(writer, flags);
592
+ writeUint8(writer, 0); // filler
593
+ writeSection(writer, 1, () => {
594
+ writeLayerMaskData(writer, layer, layerData);
595
+ writeLayerBlendingRanges(writer, layer);
596
+ writePascalString(writer, (layer.name || '').substring(0, 255), 4);
597
+ writeAdditionalLayerInfo(writer, layer, psd, options);
598
+ });
599
+ }
600
+ // layer channel image data
601
+ for (const layerData of layersData) {
602
+ for (const channel of layerData.channels) {
603
+ writeUint16(writer, channel.compression);
604
+ if (channel.data) {
605
+ writeBytes(writer, channel.data);
380
606
  }
381
607
  }
382
- }, true, options.psb);
608
+ }
609
+ }
610
+ // real mask is only stored separately if layer has both vector and pixel masks, otherwise it's stored as the main mask
611
+ function getMasks(layer) {
612
+ return layer.mask ? { mask: layer.mask, realMask: layer.realMask } : { mask: layer.realMask, realMask: undefined };
383
613
  }
384
- function writeLayerMaskData(writer, { mask, realMask }, layerData) {
614
+ function writeLayerMaskData(writer, layer, layerData) {
615
+ const { mask, realMask } = getMasks(layer);
385
616
  writeSection(writer, 4, () => {
386
617
  if (!mask && !realMask)
387
618
  return;
@@ -477,13 +708,13 @@ function writeAdditionalLayerInfo(writer, target, psd, options) {
477
708
  let key = handler.key;
478
709
  if (key === 'Txt2' && options.invalidateTextLayers)
479
710
  continue;
480
- if (key === 'vmsk' && options.psb)
481
- key = 'vsms';
711
+ if (key === 'vmsk' && additionalInfo_1.infoHandlersMap['vscg'].has(target))
712
+ key = 'vsms'; // Photoshop uses 'vsms' for layers with vector stroke
482
713
  if (handler.has(target)) {
483
714
  const large = options.psb && helpers_1.largeAdditionalInfoKeys.indexOf(key) !== -1;
484
715
  const writeTotalLength = key !== 'Txt2' && key !== 'cinf' && key !== 'extn' && key !== 'CAI ' && key !== 'OCIO';
485
716
  const fourBytes = key === 'levl' || key === 'Txt2' || key === 'luni' || key === 'vmsk' || key === 'artb' || key === 'artd' ||
486
- key === 'vogk' || key === 'SoLd' || key === 'lnk2' || key === 'vscg' || key === 'vsms' || key === 'GdFl' ||
717
+ key === 'vogk' || key === 'SoLd' || key === 'SoLE' || key === 'lnk2' || key === 'vscg' || key === 'vsms' || key === 'GdFl' ||
487
718
  key === 'lmfx' || key === 'lrFX' || key === 'cinf' || key === 'PlLd' || key === 'Anno' || key === 'CAI ' || key === 'OCIO' || key === 'GenI' || key === 'FEid' || key === 'curv' || key === 'CgEd' || key === 'vibA' || key === 'blwh' || key === 'grdm';
488
719
  writeSignature(writer, large ? '8B64' : '8BIM');
489
720
  writeSignature(writer, key);
@@ -576,7 +807,8 @@ function createThumbnail(psd) {
576
807
  }
577
808
  return canvas;
578
809
  }
579
- function getMaskChannels(tempBuffer, layerData, layer, mask, options, realMask) {
810
+ function getMaskChannels(tempBuffer, layerData, mask, options, realMask) {
811
+ var _a;
580
812
  let top = mask.top | 0;
581
813
  let left = mask.left | 0;
582
814
  let right = mask.right | 0;
@@ -593,14 +825,15 @@ function getMaskChannels(tempBuffer, layerData, layer, mask, options, realMask)
593
825
  bottom = top + height;
594
826
  let buffer;
595
827
  let compression;
596
- if (helpers_1.RAW_IMAGE_DATA && layer[realMask ? 'realMaskDataRaw' : 'maskDataRaw']) {
597
- buffer = layer[realMask ? 'realMaskDataRaw' : 'maskDataRaw'];
598
- compression = layer[realMask ? 'realMaskDataRawCompression' : 'maskDataRawCompression'];
599
- }
600
- else if (!imageData) {
828
+ const bitsPerChannel = (_a = options.bitsPerChannel) !== null && _a !== void 0 ? _a : 8;
829
+ if (!imageData) {
601
830
  buffer = new Uint8Array(0);
602
831
  compression = 1 /* Compression.RleCompressed */;
603
832
  }
833
+ else if (bitsPerChannel !== 8 || !is8bit(imageData)) {
834
+ const { colors } = getPlanarChannels(imageData, 3 /* ColorMode.RGB */, bitsPerChannel, false);
835
+ ({ data: buffer, compression } = encodeChannel(colors[0], width, height, options));
836
+ }
604
837
  else if (options.compress) {
605
838
  buffer = (0, helpers_1.writeDataZipWithoutPrediction)(imageData, [0]);
606
839
  compression = 2 /* Compression.ZipWithoutPrediction */;
@@ -620,15 +853,32 @@ function bounds(obj) {
620
853
  bottom: obj.bottom || 0,
621
854
  } : undefined;
622
855
  }
623
- function getChannels(tempBuffer, layer, background, options) {
856
+ function getChannels(writer, layer, background, options) {
857
+ var _a, _b;
858
+ let source = layer;
624
859
  if (layer.rawData) {
625
- return Object.assign(Object.assign({ layer, channels: layer.rawData.channels.map(c => { var _a, _b; return (Object.assign(Object.assign({}, c), { length: 2 + ((_b = (_a = c.data) === null || _a === void 0 ? void 0 : _a.byteLength) !== null && _b !== void 0 ? _b : 0) })); }) }, bounds(layer)), { mask: bounds(layer.mask), realMask: bounds(layer.realMask) });
860
+ const { colorMode, bitsPerChannel, large } = layer.rawData;
861
+ const opt = options;
862
+ if (large === !!options.psb && colorMode === ((_a = opt.colorMode) !== null && _a !== void 0 ? _a : 3 /* ColorMode.RGB */) && bitsPerChannel === ((_b = opt.bitsPerChannel) !== null && _b !== void 0 ? _b : 8)) {
863
+ // same mask mapping as in writeLayerMaskData
864
+ const { mask, realMask } = getMasks(layer);
865
+ return Object.assign(Object.assign({ layer, channels: layer.rawData.channels.map(c => { var _a, _b; return (Object.assign(Object.assign({}, c), { length: 2 + ((_b = (_a = c.data) === null || _a === void 0 ? void 0 : _a.byteLength) !== null && _b !== void 0 ? _b : 0) })); }) }, bounds(layer)), { mask: bounds(mask), realMask: bounds(realMask) });
866
+ }
867
+ // raw data is in different format than the one we're writing, decode it so it can be re-encoded
868
+ source = Object.assign(Object.assign({}, layer), { rawData: undefined, canvas: undefined, imageData: (0, psdReader_1.getLayerImageData)(layer), mask: layer.mask && Object.assign(Object.assign({}, layer.mask), { canvas: undefined, imageData: (0, psdReader_1.getLayerMaskImageData)(layer) }), realMask: layer.realMask && Object.assign(Object.assign({}, layer.realMask), { canvas: undefined, imageData: (0, psdReader_1.getLayerRealMaskImageData)(layer) }) });
869
+ // temp buffer is sized only for layers with image data, grow it and keep it for following layers
870
+ const size = getLargestLayerSize([Object.assign(Object.assign({}, source), { children: undefined })], !!options.psb);
871
+ if (writer.tempBuffer.byteLength < size)
872
+ writer.tempBuffer = new Uint8Array(size);
626
873
  }
627
- const layerData = getLayerChannels(tempBuffer, layer, background, options);
628
- if (layer.mask)
629
- getMaskChannels(tempBuffer, layerData, layer, layer.mask, options, false);
630
- if (layer.realMask)
631
- getMaskChannels(tempBuffer, layerData, layer, layer.realMask, options, true);
874
+ const tempBuffer = writer.tempBuffer;
875
+ const { mask, realMask } = getMasks(source);
876
+ const layerData = getLayerChannels(tempBuffer, source, background, options);
877
+ if (mask)
878
+ getMaskChannels(tempBuffer, layerData, mask, options, false);
879
+ if (realMask)
880
+ getMaskChannels(tempBuffer, layerData, realMask, options, true);
881
+ layerData.layer = layer;
632
882
  return layerData;
633
883
  }
634
884
  function getLayerDimentions({ canvas, imageData }) {
@@ -639,10 +889,8 @@ function getLayerDimentions({ canvas, imageData }) {
639
889
  return { width, height };
640
890
  }
641
891
  function cropImageData(data, left, top, width, height) {
642
- if (data.data instanceof Uint32Array || data.data instanceof Uint16Array) {
643
- throw new Error('imageData has incorrect bit depth');
644
- }
645
- const croppedData = (0, helpers_1.createImageData)(width, height);
892
+ const croppedData = is8bit(data) ? (0, helpers_1.createImageData)(width, height) :
893
+ { width, height, data: new data.data.constructor(width * height * 4) };
646
894
  const srcData = data.data;
647
895
  const dstData = croppedData.data;
648
896
  for (let y = 0; y < height; y++) {
@@ -658,7 +906,7 @@ function cropImageData(data, left, top, width, height) {
658
906
  return croppedData;
659
907
  }
660
908
  function getLayerChannels(tempBuffer, layer, background, options) {
661
- var _a;
909
+ var _a, _b;
662
910
  let top = layer.top | 0;
663
911
  let left = layer.left | 0;
664
912
  let right = layer.right | 0;
@@ -671,8 +919,11 @@ function getLayerChannels(tempBuffer, layer, background, options) {
671
919
  ];
672
920
  let { width, height } = getLayerDimentions(layer);
673
921
  if (!(layer.canvas || layer.imageData) || !width || !height) {
674
- right = left;
675
- bottom = top;
922
+ // layer without image data is empty, keep inverted (negative size) bounds from some files as they are
923
+ if (layer.right === undefined || right > left)
924
+ right = left;
925
+ if (layer.bottom === undefined || bottom > top)
926
+ bottom = top;
676
927
  return { layer, top, left, right, bottom, channels };
677
928
  }
678
929
  right = left + width;
@@ -697,19 +948,27 @@ function getLayerChannels(tempBuffer, layer, background, options) {
697
948
  1 /* ChannelID.Color1 */,
698
949
  2 /* ChannelID.Color2 */,
699
950
  ];
700
- if (!background || options.noBackground || layer.mask || (0, helpers_1.hasAlpha)(imageData) || (helpers_1.RAW_IMAGE_DATA && ((_a = layer.imageDataRaw) === null || _a === void 0 ? void 0 : _a['-1']))) {
951
+ if (!background || options.noBackground || layer.mask || (0, helpers_1.hasAlpha)(imageData)) {
701
952
  channelIds.unshift(-1 /* ChannelID.Transparency */);
702
953
  }
954
+ const colorMode = (_a = options.colorMode) !== null && _a !== void 0 ? _a : 3 /* ColorMode.RGB */;
955
+ const bitsPerChannel = (_b = options.bitsPerChannel) !== null && _b !== void 0 ? _b : 8;
956
+ if (colorMode !== 3 /* ColorMode.RGB */ || bitsPerChannel !== 8 || !is8bit(imageData)) {
957
+ const { colors, alpha } = getPlanarChannels(imageData, colorMode, bitsPerChannel, false);
958
+ const ids = channelIds[0] === -1 /* ChannelID.Transparency */ ? [-1 /* ChannelID.Transparency */] : [];
959
+ for (let i = 0; i < colors.length; i++)
960
+ ids.push(i);
961
+ channels = ids.map(id => {
962
+ const { data, compression } = encodeChannel(id === -1 /* ChannelID.Transparency */ ? alpha : colors[id], width, height, options);
963
+ return { id, compression, data, length: 2 + data.length };
964
+ });
965
+ return { layer, top, left, right, bottom, channels };
966
+ }
703
967
  channels = channelIds.map(id => {
704
- const offset = (0, helpers_1.offsetForChannel)(id, false); // TODO: psd.colorMode === ColorMode.CMYK);
968
+ const offset = (0, helpers_1.offsetForChannel)(id, false); // image data is always RGBA
705
969
  let data;
706
970
  let compression;
707
- if (helpers_1.RAW_IMAGE_DATA && layer.imageDataRaw) {
708
- // console.log('written raw layer image data');
709
- data = layer.imageDataRaw[id];
710
- compression = layer.imageDataRawCompression[id];
711
- }
712
- else if (options.compress) {
971
+ if (options.compress) {
713
972
  data = (0, helpers_1.writeDataZipWithoutPrediction)(imageData, [offset]);
714
973
  compression = 2 /* Compression.ZipWithoutPrediction */;
715
974
  }
@@ -790,11 +1049,12 @@ function writeColor(writer, color) {
790
1049
  writeUint16(writer, 0);
791
1050
  }
792
1051
  else if ('c' in color) {
1052
+ // 0 = 100% ink
793
1053
  writeUint16(writer, 2 /* ColorSpace.CMYK */);
794
- writeUint16(writer, Math.round(color.c * 257));
795
- writeUint16(writer, Math.round(color.m * 257));
796
- writeUint16(writer, Math.round(color.y * 257));
797
- writeUint16(writer, Math.round(color.k * 257));
1054
+ writeUint16(writer, 0xffff - Math.round((0, helpers_1.clamp)(color.c, 0, 255) * 257));
1055
+ writeUint16(writer, 0xffff - Math.round((0, helpers_1.clamp)(color.m, 0, 255) * 257));
1056
+ writeUint16(writer, 0xffff - Math.round((0, helpers_1.clamp)(color.y, 0, 255) * 257));
1057
+ writeUint16(writer, 0xffff - Math.round((0, helpers_1.clamp)(color.k, 0, 255) * 257));
798
1058
  }
799
1059
  else {
800
1060
  writeUint16(writer, 8 /* ColorSpace.Grayscale */);