ag-psd 20.0.0 → 20.1.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ag-psd",
3
- "version": "20.0.0",
3
+ "version": "20.1.0",
4
4
  "description": "Library for reading and writing PSD files",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist-es/index.js",
@@ -34,20 +34,19 @@
34
34
  "author": "Agamnentzar",
35
35
  "license": "MIT",
36
36
  "devDependencies": {
37
- "@types/mocha": "^9.1.1",
37
+ "@types/mocha": "^10.0.6",
38
38
  "@types/node": "^18.11.18",
39
39
  "browserify": "^17.0.0",
40
40
  "canvas": "^2.11.0",
41
41
  "chai": "^4.3.7",
42
- "mocha": "^6.2.0",
42
+ "mocha": "^10.4.0",
43
+ "source-map-support": "^0.5.21",
43
44
  "tslint": "^6.1.3",
44
- "typescript": "^4.9.4",
45
- "source-map-support": "^0.5.21"
45
+ "typescript": "^4.9.4"
46
46
  },
47
47
  "dependencies": {
48
48
  "@types/base64-js": "^1.3.0",
49
- "@types/pako": "^2.0.0",
50
49
  "base64-js": "^1.5.1",
51
- "pako": "^2.1.0"
50
+ "zlib": "^1.0.5"
52
51
  }
53
52
  }
@@ -3351,6 +3351,16 @@ addHandler(
3351
3351
  },
3352
3352
  );
3353
3353
 
3354
+ addHandler(
3355
+ 'Lr32',
3356
+ () => false,
3357
+ (reader, _target, _left, psd, options) => {
3358
+ readLayerInfo(reader, psd, options);
3359
+ },
3360
+ (_writer, _target) => {
3361
+ },
3362
+ );
3363
+
3354
3364
  addHandler(
3355
3365
  'LMsk',
3356
3366
  hasKey('userMask'),
@@ -4634,9 +4644,11 @@ addHandler(
4634
4644
  const data = readBytes(reader, left());
4635
4645
  target.engineData = fromByteArray(data);
4636
4646
  // const engineData = parseEngineData(data);
4647
+ // const engineData2 = decodeEngineData2(engineData);
4637
4648
  // console.log(require('util').inspect(engineData, false, 99, true));
4638
- // require('fs').writeFileSync('resources/engineData2Simple.txt', require('util').inspect(engineData, false, 99, false), 'utf8');
4639
- // require('fs').writeFileSync('test_data.json', JSON.stringify(ed, null, 2), 'utf8');
4649
+ // require('fs').writeFileSync('test_data.bin', data);
4650
+ // require('fs').writeFileSync('test_data.txt', require('util').inspect(engineData, false, 99, false), 'utf8');
4651
+ // require('fs').writeFileSync('test_data.json', JSON.stringify(engineData2, null, 2), 'utf8');
4640
4652
  },
4641
4653
  (writer, target) => {
4642
4654
  const buffer = toByteArray(target.engineData!);
@@ -0,0 +1,367 @@
1
+ /// Engine data 2 experiments
2
+ // /test/engineData2.json:1109 is character codes
3
+
4
+ interface KeysDict {
5
+ [key: string]: {
6
+ name?: string;
7
+ uproot?: boolean;
8
+ children?: KeysDict;
9
+ };
10
+ }
11
+
12
+ const keysColor: KeysDict = {
13
+ '0': {
14
+ uproot: true,
15
+ children: {
16
+ '0': { name: 'Type' },
17
+ '1': { name: 'Values' },
18
+ },
19
+ },
20
+ };
21
+
22
+ const keysStyleSheet: KeysDict = {
23
+ '0': { name: 'Font' },
24
+ '1': { name: 'FontSize' },
25
+ '2': { name: 'FauxBold' },
26
+ '3': { name: 'FauxItalic' },
27
+ '4': { name: 'AutoLeading' },
28
+ '5': { name: 'Leading' },
29
+ '6': { name: 'HorizontalScale' },
30
+ '7': { name: 'VerticalScale' },
31
+ '8': { name: 'Tracking' },
32
+ '9': { name: 'BaselineShift' },
33
+ // '10': ???
34
+ '11': { name: 'Kerning?' }, // different value than EngineData
35
+ '12': { name: 'FontCaps' },
36
+ '13': { name: 'FontBaseline' },
37
+
38
+ '15': { name: 'Strikethrough?' }, // number instead of bool
39
+ '16': { name: 'Underline?' }, // number instead of bool
40
+
41
+ '18': { name: 'Ligatures' },
42
+ '19': { name: 'DLigatures' },
43
+ // '20': ???
44
+ // '21': ???
45
+ // '22': ???
46
+ '23': { name: 'Fractions' }, // not present in EngineData
47
+ '24': { name: 'Ordinals' }, // not present in EngineData
48
+ // '25': ???
49
+ // '26': ???
50
+ // '27': ???
51
+ '28': { name: 'StylisticAlternates' }, // not present in EngineData
52
+ // '29': ???
53
+ '30': { name: 'OldStyle?' }, // OpenType > OldStyle, number instead of bool, not present in EngineData
54
+
55
+ '35': { name: 'BaselineDirection' },
56
+
57
+ '38': { name: 'Language' },
58
+
59
+ '52': { name: 'NoBreak' },
60
+ '53': { name: 'FillColor', children: keysColor },
61
+ '54': { name: 'StrokeColor?', children: keysColor },
62
+ '55': { children: { '99': { uproot: true } } },
63
+
64
+ // '68': ???
65
+
66
+ // '70': ???
67
+ // '71': ???
68
+ // '72': ???
69
+ // '73': ???
70
+
71
+ '79': { children: keysColor },
72
+
73
+ // '85': ???
74
+
75
+ // '87': ???
76
+ // '88': ???
77
+ };
78
+
79
+ const keysParagraph: KeysDict = {
80
+ '0': { name: 'Justification' },
81
+ '1': { name: 'FirstLineIndent' },
82
+ '2': { name: 'StartIndent' },
83
+ '3': { name: 'EndIndent' },
84
+ '4': { name: 'SpaceBefore' },
85
+ '5': { name: 'SpaceAfter' },
86
+
87
+ '7': { name: 'AutoLeading' },
88
+
89
+ '9': { name: 'AutoHyphenate' },
90
+ '10': { name: 'HyphenatedWordSize' },
91
+ '11': { name: 'PreHyphen' },
92
+ '12': { name: 'PostHyphen' },
93
+ '13': { name: 'ConsecutiveHyphens?' }, // different value than EngineData
94
+ '14': { name: 'Zone' },
95
+ '15': { name: 'HypenateCapitalizedWords' }, // not present in EngineData
96
+
97
+ '17': { name: 'WordSpacing' },
98
+ '18': { name: 'LetterSpacing' },
99
+ '19': { name: 'GlyphSpacing' },
100
+
101
+ '32': { name: 'StyleSheet', children: keysStyleSheet },
102
+ };
103
+
104
+ const keysStyleSheetData: KeysDict[''] = {
105
+ name: 'StyleSheetData',
106
+ children: keysStyleSheet,
107
+ };
108
+
109
+ const keysRoot: KeysDict = {
110
+ '0': {
111
+ name: 'ResourceDict',
112
+ children: {
113
+ '1': {
114
+ name: 'FontSet',
115
+ children: {
116
+ '0': {
117
+ uproot: true,
118
+ children: {
119
+ '0': {
120
+ uproot: true,
121
+ children: {
122
+ '0': {
123
+ uproot: true,
124
+ children: {
125
+ '0': { name: 'Name' },
126
+ '2': { name: 'FontType' },
127
+ },
128
+ },
129
+ },
130
+ }
131
+ },
132
+ },
133
+ },
134
+ },
135
+ '2': {
136
+ name: '2',
137
+ children: {},
138
+ },
139
+ '3': {
140
+ name: 'MojiKumiSet',
141
+ children: {
142
+ '0': {
143
+ uproot: true,
144
+ children: {
145
+ '0': {
146
+ uproot: true,
147
+ children: {
148
+ '0': { name: 'InternalName' },
149
+ },
150
+ },
151
+ },
152
+ },
153
+ },
154
+ },
155
+ '4': {
156
+ name: 'KinsokuSet',
157
+ children: {
158
+ '0': {
159
+ uproot: true,
160
+ children: {
161
+ '0': {
162
+ uproot: true,
163
+ children: {
164
+ '0': { name: 'Name' },
165
+ '5': {
166
+ uproot: true,
167
+ children: {
168
+ '0': { name: 'NoStart' },
169
+ '1': { name: 'NoEnd' },
170
+ '2': { name: 'Keep' },
171
+ '3': { name: 'Hanging' },
172
+ '4': { name: 'Name' },
173
+ },
174
+ },
175
+ },
176
+ },
177
+ },
178
+ },
179
+ },
180
+ },
181
+ '5': {
182
+ name: 'StyleSheetSet',
183
+ children: {
184
+ '0': {
185
+ uproot: true,
186
+ children: {
187
+ '0': {
188
+ uproot: true,
189
+ children: {
190
+ '0': { name: 'Name' },
191
+ '6': keysStyleSheetData,
192
+ },
193
+ },
194
+ },
195
+ },
196
+ },
197
+ },
198
+ '6': {
199
+ name: 'ParagraphSheetSet',
200
+ children: {
201
+ '0': {
202
+ uproot: true,
203
+ children: {
204
+ '0': {
205
+ uproot: true,
206
+ children: {
207
+ '0': { name: 'Name' },
208
+ '5': {
209
+ name: 'Properties',
210
+ children: keysParagraph,
211
+ },
212
+ '6': { name: 'DefaultStyleSheet' },
213
+ },
214
+ },
215
+ },
216
+ },
217
+ },
218
+ },
219
+ '8': {
220
+ name: '8',
221
+ children: {},
222
+ },
223
+ '9': {
224
+ name: 'Predefined',
225
+ children: {
226
+ '0': {
227
+ children: { '0': { uproot: true } },
228
+ },
229
+ '1': {
230
+ children: { '0': { uproot: true } },
231
+ },
232
+ },
233
+ },
234
+ },
235
+ },
236
+ '1': {
237
+ name: 'EngineDict',
238
+ children: {
239
+ '0': {
240
+ name: '0',
241
+ children: {
242
+ // 0: ???
243
+ // 1: ???
244
+ // 2: ???
245
+ '3': { name: 'SuperscriptSize' },
246
+ '4': { name: 'SuperscriptPosition' },
247
+ '5': { name: 'SubscriptSize' },
248
+ '6': { name: 'SubscriptPosition' },
249
+ '7': { name: 'SmallCapSize' },
250
+ '8': { name: 'UseFractionalGlyphWidths' }, // ???
251
+
252
+ '15': { children: { '0': { uproot: true } } },
253
+ // 16: ???
254
+ // 17: ???
255
+ },
256
+ },
257
+ '1': {
258
+ name: 'Editors?',
259
+ children: {
260
+ '0': {
261
+ name: 'Editor',
262
+ children: {
263
+ '0': { name: 'Text' },
264
+ '5': {
265
+ name: 'ParagraphRun',
266
+ children: {
267
+ '0': {
268
+ name: 'RunArray',
269
+ children: {
270
+ '0': {
271
+ name: 'ParagraphSheet',
272
+ children: {
273
+ '0': {
274
+ uproot: true,
275
+ children: {
276
+ '0': { name: '0' },
277
+ '5': {
278
+ name: '5',
279
+ children: keysParagraph,
280
+ },
281
+ '6': { name: '6' },
282
+ },
283
+ },
284
+ },
285
+ },
286
+ '1': { name: 'RunLength' },
287
+ },
288
+ },
289
+ },
290
+ },
291
+ '6': {
292
+ name: 'StyleRun',
293
+ children: {
294
+ '0': {
295
+ name: 'RunArray',
296
+ children: {
297
+ '0': {
298
+ name: 'StyleSheet',
299
+ children: {
300
+ '0': {
301
+ uproot: true,
302
+ children: {
303
+ '6': keysStyleSheetData,
304
+ },
305
+ },
306
+ },
307
+ },
308
+ '1': { name: 'RunLength' },
309
+ },
310
+ },
311
+ },
312
+ },
313
+ },
314
+ },
315
+ '1': {
316
+ name: 'FontVectorData ???',
317
+ // children: {
318
+ // '0': {},
319
+ // '2': {
320
+ // // '5'
321
+ // // '6'
322
+ // },
323
+ // }
324
+ },
325
+ },
326
+ },
327
+ '2': {
328
+ name: 'StyleSheet',
329
+ children: keysStyleSheet,
330
+ },
331
+ '3': {
332
+ name: 'ParagraphSheet',
333
+ children: keysParagraph,
334
+ },
335
+ },
336
+ },
337
+ };
338
+
339
+ function decodeObj(obj: any, keys: KeysDict): any {
340
+ if (obj === null) return obj;
341
+ if (Array.isArray(obj)) return obj.map(x => decodeObj(x, keys));
342
+ if (typeof obj !== 'object') return obj;
343
+
344
+ let result: any = {};
345
+
346
+ for (const key of Object.keys(obj)) {
347
+ if (keys[key]) {
348
+ if (keys[key].uproot) {
349
+ if (key !== '99') result = decodeObj(obj[key], keys[key].children ?? {});
350
+ if (obj['99']) result._type = obj['99'];
351
+ break;
352
+ } else {
353
+ result[keys[key].name || key] = decodeObj(obj[key], keys[key].children ?? {});
354
+ }
355
+ } else if (key === '99') {
356
+ result._type = obj[key];
357
+ } else {
358
+ result[key] = decodeObj(obj[key], {});
359
+ }
360
+ }
361
+
362
+ return result;
363
+ }
364
+
365
+ export function decodeEngineData2(data: any) {
366
+ return decodeObj(data, keysRoot);
367
+ }
package/src/helpers.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { fromByteArray } from 'base64-js';
2
- import { deflate } from 'pako';
2
+ import { deflateSync } from 'zlib';
3
3
  import { Layer, BlendMode, LayerColor, PixelData, PixelArray } from './psd';
4
4
 
5
5
  export const MOCK_HANDLERS = false;
@@ -166,7 +166,7 @@ export function hasAlpha(data: PixelData) {
166
166
  }
167
167
 
168
168
  export function resetImageData({ data }: PixelData) {
169
- const alpha = (data instanceof Uint32Array) ? (0xffffffff >>> 0) : ((data instanceof Uint16Array) ? 0xffff : 0xff);
169
+ const alpha = (data instanceof Float32Array) ? 1.0 : ((data instanceof Uint16Array) ? 0xffff : 0xff);
170
170
 
171
171
  for (let p = 0, size = data.length | 0; p < size; p = (p + 4) | 0) {
172
172
  data[p + 0] = 0;
@@ -186,10 +186,20 @@ export function imageDataToCanvas(pixelData: PixelData) {
186
186
  imageData = createImageData(pixelData.width, pixelData.height);
187
187
  const src = pixelData.data;
188
188
  const dst = imageData.data;
189
- const shift = (src instanceof Uint32Array) ? 24 : ((src instanceof Uint16Array) ? 8 : 0);
190
189
 
191
- for (let i = 0, size = src.length; i < size; i++) {
192
- dst[i] = src[i] >>> shift;
190
+ if (src instanceof Float32Array) {
191
+ for (let i = 0, size = src.length; i < size; i += 4) {
192
+ dst[i + 0] = Math.round(Math.pow(src[i + 0], 1.0 / 2.2) * 255);
193
+ dst[i + 1] = Math.round(Math.pow(src[i + 1], 1.0 / 2.2) * 255);
194
+ dst[i + 2] = Math.round(Math.pow(src[i + 2], 1.0 / 2.2) * 255);
195
+ dst[i + 3] = Math.round(src[i + 3] * 255);
196
+ }
197
+ } else {
198
+ const shift = (src instanceof Uint16Array) ? 8 : 0;
199
+
200
+ for (let i = 0, size = src.length; i < size; i++) {
201
+ dst[i] = src[i] >>> shift;
202
+ }
193
203
  }
194
204
  }
195
205
 
@@ -198,7 +208,7 @@ export function imageDataToCanvas(pixelData: PixelData) {
198
208
  }
199
209
 
200
210
  export function decodeBitmap(input: PixelArray, output: PixelArray, width: number, height: number) {
201
- if (input instanceof Uint32Array || input instanceof Uint16Array) throw new Error('Invalid bit depth');
211
+ if (!(input instanceof Uint8Array || input instanceof Uint8ClampedArray)) throw new Error('Invalid bit depth');
202
212
 
203
213
  for (let y = 0, p = 0, o = 0; y < height; y++) {
204
214
  for (let x = 0; x < width;) {
@@ -339,7 +349,7 @@ export function writeDataZipWithoutPrediction({ data, width, height }: PixelData
339
349
  channel[i] = data[o];
340
350
  }
341
351
 
342
- const buffer = deflate(channel);
352
+ const buffer = deflateSync(channel);
343
353
  buffers.push(buffer);
344
354
  totalLength += buffer.byteLength;
345
355
  }
@@ -98,8 +98,12 @@ addHandler(
98
98
  addHandler(
99
99
  1060,
100
100
  target => target.xmpMetadata !== undefined,
101
- (reader, target, left) => target.xmpMetadata = readUtf8String(reader, left()),
102
- (writer, target) => writeUtf8String(writer, target.xmpMetadata!),
101
+ (reader, target, left) => {
102
+ target.xmpMetadata = readUtf8String(reader, left());
103
+ },
104
+ (writer, target) => {
105
+ writeUtf8String(writer, target.xmpMetadata!);
106
+ },
103
107
  );
104
108
 
105
109
  const Inte = createEnum<RenderingIntent>('Inte', 'perceptual', {
package/src/psd.ts CHANGED
@@ -222,7 +222,7 @@ export interface LayerEffectsInfo {
222
222
  patternOverlay?: LayerEffectPatternOverlay; // not supported yet because of `Patt` section not implemented
223
223
  }
224
224
 
225
- export type PixelArray = Uint8ClampedArray | Uint8Array | Uint16Array | Uint32Array;
225
+ export type PixelArray = Uint8ClampedArray | Uint8Array | Uint16Array | Float32Array;
226
226
 
227
227
  export interface PixelData {
228
228
  data: PixelArray; // type depends on document bit depth
package/src/psdReader.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { inflate } from 'pako';
1
+ import { inflateSync } from 'zlib';
2
2
  import { Psd, Layer, ColorMode, SectionDividerType, LayerAdditionalInfo, ReadOptions, LayerMaskData, Color, PatternInfo, GlobalLayerMaskInfo, RGB, PixelData, PixelArray } from './psd';
3
3
  import { resetImageData, offsetForChannel, decodeBitmap, createImageData, toBlendMode, ChannelID, Compression, LayerMaskFlags, MaskParams, ColorSpace, RAW_IMAGE_DATA, largeAdditionalInfoKeys, imageDataToCanvas } from './helpers';
4
4
  import { infoHandlersMap } from './additionalInfo';
@@ -230,7 +230,16 @@ export function readPsd(reader: PsdReader, readOptions: ReadOptions = {}) {
230
230
 
231
231
  // color mode data
232
232
  readSection(reader, 1, left => {
233
- if (options.throwForMissingFeatures) throw new Error('Color mode data not supported');
233
+ if (!left()) return;
234
+
235
+ // const numbers: number[] = [];
236
+ // console.log('color mode', left());
237
+ // while (left()) {
238
+ // numbers.push(readUint32(reader));
239
+ // }
240
+ // console.log('color mode', numbers);
241
+
242
+ // if (options.throwForMissingFeatures) throw new Error('Color mode data not supported');
234
243
  skipBytes(reader, left());
235
244
  });
236
245
 
@@ -661,7 +670,7 @@ function createImageDataBitDepth(width: number, height: number, bitDepth: number
661
670
  } else if (bitDepth === 16) {
662
671
  return { width, height, data: new Uint16Array(width * height * 4) };
663
672
  } else if (bitDepth === 32) {
664
- return { width, height, data: new Uint32Array(width * height * 4) };
673
+ return { width, height, data: new Float32Array(width * height * 4) };
665
674
  } else {
666
675
  throw new Error(`Invalid bitDepth (${bitDepth})`);
667
676
  }
@@ -682,13 +691,15 @@ function readImageData(reader: PsdReader, psd: Psd, options: ReadOptionsExt) {
682
691
 
683
692
  switch (psd.colorMode) {
684
693
  case ColorMode.Bitmap: {
694
+ if (bitsPerChannel !== 1) throw new Error('Invalid bitsPerChannel for bitmap color mode');
695
+
685
696
  let bytes: Uint8Array;
686
697
 
687
698
  if (compression === Compression.RawData) {
688
699
  bytes = readBytes(reader, Math.ceil(psd.width / 8) * psd.height);
689
700
  } else if (compression === Compression.RleCompressed) {
690
701
  bytes = new Uint8Array(psd.width * psd.height);
691
- readDataRLE(reader, { data: bytes, width: psd.width, height: psd.height }, psd.width, psd.height, bitsPerChannel, 1, [0], options.large);
702
+ readDataRLE(reader, { data: bytes, width: psd.width, height: psd.height }, psd.width, psd.height, 8, 1, [0], options.large);
692
703
  } else {
693
704
  throw new Error(`Bitmap compression not supported: ${compression}`);
694
705
  }
@@ -828,11 +839,11 @@ function bytesToArray(bytes: Uint8Array, bitDepth: number) {
828
839
  }
829
840
  } else if (bitDepth === 32) {
830
841
  if (bytes.byteOffset % 4) {
831
- const result = new Uint32Array(bytes.byteLength / 4);
842
+ const result = new Float32Array(bytes.byteLength / 4);
832
843
  new Uint8Array(result.buffer, result.byteOffset, result.byteLength).set(bytes);
833
844
  return result;
834
845
  } else {
835
- return new Uint32Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / 4);
846
+ return new Float32Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / 4);
836
847
  }
837
848
  } else {
838
849
  throw new Error(`Invalid bitDepth (${bitDepth})`)
@@ -850,6 +861,20 @@ function copyChannelToPixelData(pixelData: PixelData, channel: PixelArray, offse
850
861
 
851
862
  function readDataRaw(reader: PsdReader, pixelData: PixelData | undefined, width: number, height: number, bitDepth: number, step: number, offset: number) {
852
863
  const buffer = readBytes(reader, width * height * Math.floor(bitDepth / 8));
864
+
865
+ if (bitDepth == 32) {
866
+ for (let i = 0; i < buffer.byteLength; i += 4) {
867
+ const a = buffer[i + 0];
868
+ const b = buffer[i + 1];
869
+ const c = buffer[i + 2];
870
+ const d = buffer[i + 3];
871
+ buffer[i + 0] = d;
872
+ buffer[i + 1] = c;
873
+ buffer[i + 2] = b;
874
+ buffer[i + 3] = a;
875
+ }
876
+ }
877
+
853
878
  const array = bytesToArray(buffer, bitDepth);
854
879
 
855
880
  if (pixelData && offset < step) {
@@ -869,7 +894,7 @@ function decodePredicted(data: Uint8Array | Uint16Array, width: number, height:
869
894
 
870
895
  export function readDataZip(reader: PsdReader, length: number, pixelData: PixelData | undefined, width: number, height: number, bitDepth: number, step: number, offset: number, prediction: boolean) {
871
896
  const compressed = readBytes(reader, length);
872
- const decompressed = inflate(compressed);
897
+ const decompressed = inflateSync(compressed);
873
898
 
874
899
  if (pixelData && offset < step) {
875
900
  const array = bytesToArray(decompressed, bitDepth);
@@ -881,8 +906,21 @@ export function readDataZip(reader: PsdReader, length: number, pixelData: PixelD
881
906
  if (prediction) decodePredicted(array as Uint16Array, width, height, 0x10000);
882
907
  copyChannelToPixelData(pixelData, array, offset, step);
883
908
  } else if (bitDepth === 32) {
884
- if (prediction) decodePredicted(decompressed, width, height, 0x100);
885
- copyChannelToPixelData(pixelData, array, offset, step);
909
+ if (prediction) decodePredicted(decompressed, width * 4, height, 0x100);
910
+
911
+ let di = offset;
912
+ const dst = new Uint32Array(pixelData.data.buffer, pixelData.data.byteOffset, pixelData.data.length);
913
+
914
+ for (let y = 0; y < height; y++) {
915
+ let a = width * 4 * y;
916
+
917
+ for (let x = 0; x < width; x++, a++, di += step) {
918
+ const b = a + width;
919
+ const c = b + width;
920
+ const d = c + width;
921
+ dst[di] = ((decompressed[a] << 24) | (decompressed[b] << 16) | (decompressed[c] << 8) | decompressed[d]) >>> 0;
922
+ }
923
+ }
886
924
  } else {
887
925
  throw new Error('Invalid bitDepth');
888
926
  }
package/src/utf8.ts CHANGED
@@ -87,6 +87,10 @@ export function encodeStringTo(buffer: Uint8Array | Buffer, offset: number, valu
87
87
  }
88
88
 
89
89
  export function encodeString(value: string): Uint8Array {
90
+ if (value.length > 1000 && typeof TextEncoder !== 'undefined') {
91
+ return (new TextEncoder()).encode(value);
92
+ }
93
+
90
94
  const buffer = new Uint8Array(stringLengthInBytes(value));
91
95
  encodeStringTo(buffer, 0, value);
92
96
  return buffer;
@@ -107,7 +111,11 @@ function continuationByte(buffer: Uint8Array, index: number): number {
107
111
  }
108
112
 
109
113
  export function decodeString(value: Uint8Array): string {
110
- let result = '';
114
+ if (value.byteLength > 1000 && typeof TextDecoder !== 'undefined') {
115
+ return (new TextDecoder()).decode(value);
116
+ }
117
+
118
+ let result: string[] = [];
111
119
 
112
120
  for (let i = 0; i < value.length;) {
113
121
  const byte1 = value[i++];
@@ -149,12 +157,12 @@ export function decodeString(value: Uint8Array): string {
149
157
 
150
158
  if (code > 0xffff) {
151
159
  code -= 0x10000;
152
- result += String.fromCharCode(code >>> 10 & 0x3ff | 0xd800);
160
+ result.push(String.fromCharCode(code >>> 10 & 0x3ff | 0xd800));
153
161
  code = 0xdc00 | code & 0x3ff;
154
162
  }
155
163
 
156
- result += String.fromCharCode(code);
164
+ result.push(String.fromCharCode(code));
157
165
  }
158
166
 
159
- return result;
167
+ return result.join('');
160
168
  }