pica 8.0.0 → 9.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.
package/README.md CHANGED
@@ -130,7 +130,6 @@ taken from source and destination objects.
130
130
  - __options__ - quality (number) or object:
131
131
  - __quality__ (deprecated, use `.filter` instead) - 0..3.
132
132
  - __filter__ - filter name (Default - `mks2013`). See [resize_filter_info.js](https://github.com/nodeca/pica/blob/master/lib/mm_resize/resize_filter_info.js) for details. `mks2013` does both resize and sharpening, it's optimal and not recommended to change.
133
- - __alpha__ - use alpha channel. Default = `false`.
134
133
  - __unsharpAmount__ - >=0. Default = `0` (off). Usually
135
134
  value between 100 to 200 is good. Note, `mks2013` filter already does
136
135
  optimal sharpening.
@@ -171,7 +170,6 @@ binary data (for example, if you decode jpeg files "manually").
171
170
  - __toHeight__ - output height, >=0, in pixels.
172
171
  - __quality__ (deprecated, use `.filter` instead) - 0..3.
173
172
  - __filter__ - filter name (Default - `mks2013`). See [resize_filter_info.js](https://github.com/nodeca/pica/blob/master/lib/mm_resize/resize_filter_info.js) for details. `mks2013` does both resize and sharpening, it's optimal and not recommended to change.
174
- - __alpha__ - use alpha channel. Default = `false`.
175
173
  - __unsharpAmount__ - >=0. Default = `0` (off). Usually
176
174
  value between 100 to 200 is good. Note, `mks2013` filter already does
177
175
  optimal sharpening.
package/dist/pica.js CHANGED
@@ -13,8 +13,6 @@ https://github.com/nodeca/pica
13
13
  //
14
14
  'use strict';
15
15
 
16
- var inherits = _dereq_('inherits');
17
-
18
16
  var Multimath = _dereq_('multimath');
19
17
 
20
18
  var mm_unsharp_mask = _dereq_('./mm_unsharp_mask');
@@ -37,7 +35,8 @@ function MathLib(requested_features) {
37
35
  this.use(mm_resize);
38
36
  }
39
37
 
40
- inherits(MathLib, Multimath);
38
+ MathLib.prototype = Object.create(Multimath.prototype);
39
+ MathLib.prototype.constructor = MathLib;
41
40
 
42
41
  MathLib.prototype.resizeAndUnsharp = function resizeAndUnsharp(options, cache) {
43
42
  var result = this.resize(options, cache);
@@ -51,7 +50,7 @@ MathLib.prototype.resizeAndUnsharp = function resizeAndUnsharp(options, cache) {
51
50
 
52
51
  module.exports = MathLib;
53
52
 
54
- },{"./mm_resize":4,"./mm_unsharp_mask":9,"inherits":19,"multimath":20}],2:[function(_dereq_,module,exports){
53
+ },{"./mm_resize":4,"./mm_unsharp_mask":9,"multimath":19}],2:[function(_dereq_,module,exports){
55
54
  // Resize convolvers, pure JS implementation
56
55
  //
57
56
  'use strict'; // Precision of fixed FP values
@@ -59,18 +58,23 @@ module.exports = MathLib;
59
58
 
60
59
  function clampTo8(i) {
61
60
  return i < 0 ? 0 : i > 255 ? 255 : i;
62
- } // Convolve image in horizontal directions and transpose output. In theory,
63
- // transpose allow:
61
+ }
62
+
63
+ function clampNegative(i) {
64
+ return i >= 0 ? i : 0;
65
+ } // Convolve image data in horizontal direction. Can be used for:
66
+ //
67
+ // 1. bitmap with premultiplied alpha
68
+ // 2. bitmap without alpha (all values 255)
64
69
  //
65
- // - use the same convolver for both passes (this fails due different
66
- // types of input array and temporary buffer)
67
- // - making vertical pass by horisonltal lines inprove CPU cache use.
70
+ // Notes:
68
71
  //
69
- // But in real life this doesn't work :)
72
+ // - output is transposed
73
+ // - output resolution is ~15 bits per channel(for better precision).
70
74
  //
71
75
 
72
76
 
73
- function convolveHorizontally(src, dest, srcW, srcH, destW, filters) {
77
+ function convolveHor(src, dest, srcW, srcH, destW, filters) {
74
78
  var r, g, b, a;
75
79
  var filterPtr, filterShift, filterSize;
76
80
  var srcPtr, srcY, destX, filterVal;
@@ -96,39 +100,26 @@ function convolveHorizontally(src, dest, srcW, srcH, destW, filters) {
96
100
  g = g + filterVal * src[srcPtr + 1] | 0;
97
101
  r = r + filterVal * src[srcPtr] | 0;
98
102
  srcPtr = srcPtr + 4 | 0;
99
- } // Bring this value back in range. All of the filter scaling factors
100
- // are in fixed point with FIXED_FRAC_BITS bits of fractional part.
101
- //
102
- // (!) Add 1/2 of value before clamping to get proper rounding. In other
103
- // case brightness loss will be noticeable if you resize image with white
104
- // border and place it on white background.
103
+ } // Store 15 bits between passes for better precision
104
+ // Instead of shift to 14 (FIXED_FRAC_BITS), shift to 7 only
105
105
  //
106
106
 
107
107
 
108
- dest[destOffset + 3] = clampTo8(a + (1 << 13) >> 14
109
- /*FIXED_FRAC_BITS*/
110
- );
111
- dest[destOffset + 2] = clampTo8(b + (1 << 13) >> 14
112
- /*FIXED_FRAC_BITS*/
113
- );
114
- dest[destOffset + 1] = clampTo8(g + (1 << 13) >> 14
115
- /*FIXED_FRAC_BITS*/
116
- );
117
- dest[destOffset] = clampTo8(r + (1 << 13) >> 14
118
- /*FIXED_FRAC_BITS*/
119
- );
108
+ dest[destOffset + 3] = clampNegative(a >> 7);
109
+ dest[destOffset + 2] = clampNegative(b >> 7);
110
+ dest[destOffset + 1] = clampNegative(g >> 7);
111
+ dest[destOffset] = clampNegative(r >> 7);
120
112
  destOffset = destOffset + srcH * 4 | 0;
121
113
  }
122
114
 
123
115
  destOffset = (srcY + 1) * 4 | 0;
124
116
  srcOffset = (srcY + 1) * srcW * 4 | 0;
125
117
  }
126
- } // Technically, convolvers are the same. But input array and temporary
127
- // buffer can be of different type (especially, in old browsers). So,
128
- // keep code in separate functions to avoid deoptimizations & speed loss.
118
+ } // Supplementary method for `convolveHor()`
119
+ //
129
120
 
130
121
 
131
- function convolveVertically(src, dest, srcW, srcH, destW, filters) {
122
+ function convolveVert(src, dest, srcW, srcH, destW, filters) {
132
123
  var r, g, b, a;
133
124
  var filterPtr, filterShift, filterSize;
134
125
  var srcPtr, srcY, destX, filterVal;
@@ -154,27 +145,134 @@ function convolveVertically(src, dest, srcW, srcH, destW, filters) {
154
145
  g = g + filterVal * src[srcPtr + 1] | 0;
155
146
  r = r + filterVal * src[srcPtr] | 0;
156
147
  srcPtr = srcPtr + 4 | 0;
157
- } // Bring this value back in range. All of the filter scaling factors
158
- // are in fixed point with FIXED_FRAC_BITS bits of fractional part.
148
+ } // Sync with premultiplied version for exact result match
149
+
150
+
151
+ r >>= 7;
152
+ g >>= 7;
153
+ b >>= 7;
154
+ a >>= 7; // Bring this value back in range + round result.
159
155
  //
160
- // (!) Add 1/2 of value before clamping to get proper rounding. In other
161
- // case brightness loss will be noticeable if you resize image with white
162
- // border and place it on white background.
156
+
157
+ dest[destOffset + 3] = clampTo8(a + (1 << 13) >> 14);
158
+ dest[destOffset + 2] = clampTo8(b + (1 << 13) >> 14);
159
+ dest[destOffset + 1] = clampTo8(g + (1 << 13) >> 14);
160
+ dest[destOffset] = clampTo8(r + (1 << 13) >> 14);
161
+ destOffset = destOffset + srcH * 4 | 0;
162
+ }
163
+
164
+ destOffset = (srcY + 1) * 4 | 0;
165
+ srcOffset = (srcY + 1) * srcW * 4 | 0;
166
+ }
167
+ } // Premultiply & convolve image data in horizontal direction. Can be used for:
168
+ //
169
+ // - Any bitmap data, extracted with `.getImageData()` method (with
170
+ // non-premultiplied alpha)
171
+ //
172
+ // For images without alpha channel this method is slower than `convolveHor()`
173
+ //
174
+
175
+
176
+ function convolveHorWithPre(src, dest, srcW, srcH, destW, filters) {
177
+ var r, g, b, a, alpha;
178
+ var filterPtr, filterShift, filterSize;
179
+ var srcPtr, srcY, destX, filterVal;
180
+ var srcOffset = 0,
181
+ destOffset = 0; // For each row
182
+
183
+ for (srcY = 0; srcY < srcH; srcY++) {
184
+ filterPtr = 0; // Apply precomputed filters to each destination row point
185
+
186
+ for (destX = 0; destX < destW; destX++) {
187
+ // Get the filter that determines the current output pixel.
188
+ filterShift = filters[filterPtr++];
189
+ filterSize = filters[filterPtr++];
190
+ srcPtr = srcOffset + filterShift * 4 | 0;
191
+ r = g = b = a = 0; // Apply the filter to the row to get the destination pixel r, g, b, a
192
+
193
+ for (; filterSize > 0; filterSize--) {
194
+ filterVal = filters[filterPtr++]; // Use reverse order to workaround deopts in old v8 (node v.10)
195
+ // Big thanks to @mraleph (Vyacheslav Egorov) for the tip.
196
+
197
+ alpha = src[srcPtr + 3];
198
+ a = a + filterVal * alpha | 0;
199
+ b = b + filterVal * src[srcPtr + 2] * alpha | 0;
200
+ g = g + filterVal * src[srcPtr + 1] * alpha | 0;
201
+ r = r + filterVal * src[srcPtr] * alpha | 0;
202
+ srcPtr = srcPtr + 4 | 0;
203
+ } // Premultiply is (* alpha / 255).
204
+ // Postpone division for better performance
205
+
206
+
207
+ b = b / 255 | 0;
208
+ g = g / 255 | 0;
209
+ r = r / 255 | 0; // Store 15 bits between passes for better precision
210
+ // Instead of shift to 14 (FIXED_FRAC_BITS), shift to 7 only
163
211
  //
164
212
 
213
+ dest[destOffset + 3] = clampNegative(a >> 7);
214
+ dest[destOffset + 2] = clampNegative(b >> 7);
215
+ dest[destOffset + 1] = clampNegative(g >> 7);
216
+ dest[destOffset] = clampNegative(r >> 7);
217
+ destOffset = destOffset + srcH * 4 | 0;
218
+ }
165
219
 
166
- dest[destOffset + 3] = clampTo8(a + (1 << 13) >> 14
167
- /*FIXED_FRAC_BITS*/
168
- );
169
- dest[destOffset + 2] = clampTo8(b + (1 << 13) >> 14
170
- /*FIXED_FRAC_BITS*/
171
- );
172
- dest[destOffset + 1] = clampTo8(g + (1 << 13) >> 14
173
- /*FIXED_FRAC_BITS*/
174
- );
175
- dest[destOffset] = clampTo8(r + (1 << 13) >> 14
176
- /*FIXED_FRAC_BITS*/
177
- );
220
+ destOffset = (srcY + 1) * 4 | 0;
221
+ srcOffset = (srcY + 1) * srcW * 4 | 0;
222
+ }
223
+ } // Supplementary method for `convolveHorWithPre()`
224
+ //
225
+
226
+
227
+ function convolveVertWithPre(src, dest, srcW, srcH, destW, filters) {
228
+ var r, g, b, a;
229
+ var filterPtr, filterShift, filterSize;
230
+ var srcPtr, srcY, destX, filterVal;
231
+ var srcOffset = 0,
232
+ destOffset = 0; // For each row
233
+
234
+ for (srcY = 0; srcY < srcH; srcY++) {
235
+ filterPtr = 0; // Apply precomputed filters to each destination row point
236
+
237
+ for (destX = 0; destX < destW; destX++) {
238
+ // Get the filter that determines the current output pixel.
239
+ filterShift = filters[filterPtr++];
240
+ filterSize = filters[filterPtr++];
241
+ srcPtr = srcOffset + filterShift * 4 | 0;
242
+ r = g = b = a = 0; // Apply the filter to the row to get the destination pixel r, g, b, a
243
+
244
+ for (; filterSize > 0; filterSize--) {
245
+ filterVal = filters[filterPtr++]; // Use reverse order to workaround deopts in old v8 (node v.10)
246
+ // Big thanks to @mraleph (Vyacheslav Egorov) for the tip.
247
+
248
+ a = a + filterVal * src[srcPtr + 3] | 0;
249
+ b = b + filterVal * src[srcPtr + 2] | 0;
250
+ g = g + filterVal * src[srcPtr + 1] | 0;
251
+ r = r + filterVal * src[srcPtr] | 0;
252
+ srcPtr = srcPtr + 4 | 0;
253
+ } // Downscale to leave room for un-premultiply
254
+
255
+
256
+ r >>= 7;
257
+ g >>= 7;
258
+ b >>= 7;
259
+ a >>= 7; // Un-premultiply
260
+
261
+ a = clampTo8(a + (1 << 13) >> 14);
262
+
263
+ if (a > 0) {
264
+ r = r * 255 / a | 0;
265
+ g = g * 255 / a | 0;
266
+ b = b * 255 / a | 0;
267
+ } // Bring this value back in range + round result.
268
+ // Shift value = FIXED_FRAC_BITS + 7
269
+ //
270
+
271
+
272
+ dest[destOffset + 3] = a;
273
+ dest[destOffset + 2] = clampTo8(b + (1 << 13) >> 14);
274
+ dest[destOffset + 1] = clampTo8(g + (1 << 13) >> 14);
275
+ dest[destOffset] = clampTo8(r + (1 << 13) >> 14);
178
276
  destOffset = destOffset + srcH * 4 | 0;
179
277
  }
180
278
 
@@ -184,8 +282,10 @@ function convolveVertically(src, dest, srcW, srcH, destW, filters) {
184
282
  }
185
283
 
186
284
  module.exports = {
187
- convolveHorizontally: convolveHorizontally,
188
- convolveVertically: convolveVertically
285
+ convolveHor: convolveHor,
286
+ convolveVert: convolveVert,
287
+ convolveHorWithPre: convolveHorWithPre,
288
+ convolveVertWithPre: convolveVertWithPre
189
289
  };
190
290
 
191
291
  },{}],3:[function(_dereq_,module,exports){
@@ -194,7 +294,7 @@ module.exports = {
194
294
  'use strict';
195
295
  /* eslint-disable max-len */
196
296
 
197
- module.exports = 'AGFzbQEAAAAADAZkeWxpbmsAAAAAAAEXA2AAAGAGf39/f39/AGAHf39/f39/fwACDwEDZW52Bm1lbW9yeQIAAAMEAwABAgYGAX8AQQALB1cFEV9fd2FzbV9jYWxsX2N0b3JzAAAIY29udm9sdmUAAQpjb252b2x2ZUhWAAIMX19kc29faGFuZGxlAwAYX193YXNtX2FwcGx5X2RhdGFfcmVsb2NzAAAK7AMDAwABC8YDAQ9/AkAgA0UNACAERQ0AA0AgDCENQQAhE0EAIQcDQCAHQQJqIQYCfyAHQQF0IAVqIgcuAQIiFEUEQEGAwAAhCEGAwAAhCUGAwAAhCkGAwAAhCyAGDAELIBIgBy4BAGohCEEAIQsgFCEHQQAhDiAGIQlBACEPQQAhEANAIAUgCUEBdGouAQAiESAAIAhBAnRqKAIAIgpBGHZsIBBqIRAgCkH/AXEgEWwgC2ohCyAKQRB2Qf8BcSARbCAPaiEPIApBCHZB/wFxIBFsIA5qIQ4gCEEBaiEIIAlBAWohCSAHQQFrIgcNAAsgC0GAQGshCCAOQYBAayEJIA9BgEBrIQogEEGAQGshCyAGIBRqCyEHIAEgDUECdGogCUEOdSIGQf8BIAZB/wFIGyIGQQAgBkEAShtBCHRBgP4DcSAKQQ51IgZB/wEgBkH/AUgbIgZBACAGQQBKG0EQdEGAgPwHcSALQQ51IgZB/wEgBkH/AUgbIgZBACAGQQBKG0EYdHJyIAhBDnUiBkH/ASAGQf8BSBsiBkEAIAZBAEobcjYCACADIA1qIQ0gE0EBaiITIARHDQALIAxBAWoiDCACbCESIAMgDEcNAAsLCx4AQQAgAiADIAQgBSAAEAEgAkEAIAQgBSAGIAEQAQs=';
297
+ module.exports = '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';
198
298
 
199
299
  },{}],4:[function(_dereq_,module,exports){
200
300
  'use strict';
@@ -211,9 +311,23 @@ module.exports = {
211
311
 
212
312
  var createFilters = _dereq_('./resize_filter_gen');
213
313
 
214
- var convolveHorizontally = _dereq_('./convolve').convolveHorizontally;
314
+ var _require = _dereq_('./convolve'),
315
+ convolveHor = _require.convolveHor,
316
+ convolveVert = _require.convolveVert,
317
+ convolveHorWithPre = _require.convolveHorWithPre,
318
+ convolveVertWithPre = _require.convolveVertWithPre;
215
319
 
216
- var convolveVertically = _dereq_('./convolve').convolveVertically;
320
+ function hasAlpha(src, width, height) {
321
+ var ptr = 3,
322
+ len = width * height * 4 | 0;
323
+
324
+ while (ptr < len) {
325
+ if (src[ptr] !== 255) return true;
326
+ ptr = ptr + 4 | 0;
327
+ }
328
+
329
+ return false;
330
+ }
217
331
 
218
332
  function resetAlpha(dst, width, height) {
219
333
  var ptr = 3,
@@ -236,20 +350,20 @@ module.exports = function resize(options) {
236
350
  var offsetX = options.offsetX || 0;
237
351
  var offsetY = options.offsetY || 0;
238
352
  var dest = options.dest || new Uint8Array(destW * destH * 4);
239
- var alpha = options.alpha || false;
240
353
  var filter = typeof options.filter === 'undefined' ? 'mks2013' : options.filter;
241
354
  var filtersX = createFilters(filter, srcW, destW, scaleX, offsetX),
242
355
  filtersY = createFilters(filter, srcH, destH, scaleY, offsetY);
243
- var tmp = new Uint8Array(destW * srcH * 4); // To use single function we need src & tmp of the same type.
244
- // But src can be CanvasPixelArray, and tmp - Uint8Array. So, keep
245
- // vertical and horizontal passes separately to avoid deoptimization.
356
+ var tmp = new Uint16Array(destW * srcH * 4); // Autodetect if alpha channel exists, and use appropriate method
246
357
 
247
- convolveHorizontally(src, tmp, srcW, srcH, destW, filtersX);
248
- convolveVertically(tmp, dest, srcH, destW, destH, filtersY); // That's faster than doing checks in convolver.
249
- // !!! Note, canvas data is not premultipled. We don't need other
250
- // alpha corrections.
358
+ if (hasAlpha(src, srcW, srcH)) {
359
+ convolveHorWithPre(src, tmp, srcW, srcH, destW, filtersX);
360
+ convolveVertWithPre(tmp, dest, srcH, destW, destH, filtersY);
361
+ } else {
362
+ convolveHor(src, tmp, srcW, srcH, destW, filtersX);
363
+ convolveVert(tmp, dest, srcH, destW, destH, filtersY);
364
+ resetAlpha(dest, destW, destH);
365
+ }
251
366
 
252
- if (!alpha) resetAlpha(dest, destW, destH);
253
367
  return dest;
254
368
  };
255
369
 
@@ -473,6 +587,18 @@ module.exports = {
473
587
 
474
588
  var createFilters = _dereq_('./resize_filter_gen');
475
589
 
590
+ function hasAlpha(src, width, height) {
591
+ var ptr = 3,
592
+ len = width * height * 4 | 0;
593
+
594
+ while (ptr < len) {
595
+ if (src[ptr] !== 255) return true;
596
+ ptr = ptr + 4 | 0;
597
+ }
598
+
599
+ return false;
600
+ }
601
+
476
602
  function resetAlpha(dst, width, height) {
477
603
  var ptr = 3,
478
604
  len = width * height * 4 | 0;
@@ -517,16 +643,18 @@ module.exports = function resize_wasm(options) {
517
643
  var offsetX = options.offsetX || 0.0;
518
644
  var offsetY = options.offsetY || 0.0;
519
645
  var dest = options.dest || new Uint8Array(destW * destH * 4);
520
- var alpha = options.alpha || false;
521
646
  var filter = typeof options.filter === 'undefined' ? 'mks2013' : options.filter;
522
647
  var filtersX = createFilters(filter, srcW, destW, scaleX, offsetX),
523
648
  filtersY = createFilters(filter, srcH, destH, scaleY, offsetY); // destination is 0 too.
524
649
 
525
- var src_offset = 0; // buffer between convolve passes
650
+ var src_offset = 0;
651
+ var src_size = Math.max(src.byteLength, dest.byteLength); // buffer between convolve passes
526
652
 
527
- var tmp_offset = this.__align(src_offset + Math.max(src.byteLength, dest.byteLength));
653
+ var tmp_offset = this.__align(src_offset + src_size);
528
654
 
529
- var filtersX_offset = this.__align(tmp_offset + srcH * destW * 4);
655
+ var tmp_size = srcH * destW * 4 * 2; // 2 bytes per channel
656
+
657
+ var filtersX_offset = this.__align(tmp_offset + tmp_size);
530
658
 
531
659
  var filtersY_offset = this.__align(filtersX_offset + filtersX.byteLength);
532
660
 
@@ -545,22 +673,24 @@ module.exports = function resize_wasm(options) {
545
673
  // speed difference is not significant vs direct .set()
546
674
 
547
675
  copyInt16asLE(filtersX, mem, filtersX_offset);
548
- copyInt16asLE(filtersY, mem, filtersY_offset); //
549
- // Now call webassembly method
676
+ copyInt16asLE(filtersY, mem, filtersY_offset); // Now call webassembly method
550
677
  // emsdk does method names with '_'
551
678
 
552
679
  var fn = instance.exports.convolveHV || instance.exports._convolveHV;
553
- fn(filtersX_offset, filtersY_offset, tmp_offset, srcW, srcH, destW, destH); //
680
+
681
+ if (hasAlpha(src, srcW, srcH)) {
682
+ fn(filtersX_offset, filtersY_offset, tmp_offset, srcW, srcH, destW, destH, 1);
683
+ } else {
684
+ fn(filtersX_offset, filtersY_offset, tmp_offset, srcW, srcH, destW, destH, 0);
685
+ resetAlpha(dest, destW, destH);
686
+ } //
554
687
  // Copy data back to typed array
555
688
  //
556
689
  // 32-bit copy is much faster in chrome
557
690
 
558
- var dest32 = new Uint32Array(dest.buffer);
559
- dest32.set(new Uint32Array(this.__memory.buffer, 0, destH * destW)); // That's faster than doing checks in convolver.
560
- // !!! Note, canvas data is not premultipled. We don't need other
561
- // alpha corrections.
562
691
 
563
- if (!alpha) resetAlpha(dest, destW, destH);
692
+ var dest32 = new Uint32Array(dest.buffer);
693
+ dest32.set(new Uint32Array(this.__memory.buffer, 0, destH * destW));
564
694
  return dest;
565
695
  };
566
696
 
@@ -1149,9 +1279,7 @@ module.exports = function () {
1149
1279
 
1150
1280
  if (!tileOpts.src && tileOpts.srcBitmap) {
1151
1281
  var canvas = new OffscreenCanvas(tileOpts.width, tileOpts.height);
1152
- var ctx = canvas.getContext('2d', {
1153
- alpha: Boolean(tileOpts.alpha)
1154
- });
1282
+ var ctx = canvas.getContext('2d');
1155
1283
  ctx.drawImage(tileOpts.srcBitmap, 0, 0);
1156
1284
  tileOpts.src = ctx.getImageData(0, 0, tileOpts.width, tileOpts.height).data;
1157
1285
  canvas.width = canvas.height = 0;
@@ -1172,9 +1300,7 @@ module.exports = function () {
1172
1300
 
1173
1301
  var _canvas = new OffscreenCanvas(tileOpts.toWidth, tileOpts.toHeight);
1174
1302
 
1175
- var _ctx = _canvas.getContext('2d', {
1176
- alpha: Boolean(tileOpts.alpha)
1177
- });
1303
+ var _ctx = _canvas.getContext('2d');
1178
1304
 
1179
1305
  _ctx.putImageData(toImageData, 0, 0);
1180
1306
 
@@ -1313,35 +1439,6 @@ function blurMono16(src, width, height, radius) {
1313
1439
  module.exports = blurMono16;
1314
1440
 
1315
1441
  },{}],19:[function(_dereq_,module,exports){
1316
- if (typeof Object.create === 'function') {
1317
- // implementation from standard node.js 'util' module
1318
- module.exports = function inherits(ctor, superCtor) {
1319
- if (superCtor) {
1320
- ctor.super_ = superCtor
1321
- ctor.prototype = Object.create(superCtor.prototype, {
1322
- constructor: {
1323
- value: ctor,
1324
- enumerable: false,
1325
- writable: true,
1326
- configurable: true
1327
- }
1328
- })
1329
- }
1330
- };
1331
- } else {
1332
- // old school shim for old browsers
1333
- module.exports = function inherits(ctor, superCtor) {
1334
- if (superCtor) {
1335
- ctor.super_ = superCtor
1336
- var TempCtor = function () {}
1337
- TempCtor.prototype = superCtor.prototype
1338
- ctor.prototype = new TempCtor()
1339
- ctor.prototype.constructor = ctor
1340
- }
1341
- }
1342
- }
1343
-
1344
- },{}],20:[function(_dereq_,module,exports){
1345
1442
  'use strict';
1346
1443
 
1347
1444
 
@@ -1500,7 +1597,7 @@ MultiMath.prototype.__align = function align(number, base) {
1500
1597
 
1501
1598
  module.exports = MultiMath;
1502
1599
 
1503
- },{"./lib/base64decode":21,"./lib/wa_detect":22,"object-assign":23}],21:[function(_dereq_,module,exports){
1600
+ },{"./lib/base64decode":20,"./lib/wa_detect":21,"object-assign":22}],20:[function(_dereq_,module,exports){
1504
1601
  // base64 decode str -> Uint8Array, to load WA modules
1505
1602
  //
1506
1603
  'use strict';
@@ -1548,7 +1645,7 @@ module.exports = function base64decode(str) {
1548
1645
  return out;
1549
1646
  };
1550
1647
 
1551
- },{}],22:[function(_dereq_,module,exports){
1648
+ },{}],21:[function(_dereq_,module,exports){
1552
1649
  // Detect WebAssembly support.
1553
1650
  // - Check global WebAssembly object
1554
1651
  // - Try to load simple module (can be disabled via CSP)
@@ -1587,7 +1684,7 @@ module.exports = function hasWebAssembly() {
1587
1684
  return wa;
1588
1685
  };
1589
1686
 
1590
- },{}],23:[function(_dereq_,module,exports){
1687
+ },{}],22:[function(_dereq_,module,exports){
1591
1688
  /*
1592
1689
  object-assign
1593
1690
  (c) Sindre Sorhus
@@ -1679,7 +1776,7 @@ module.exports = shouldUseNative() ? Object.assign : function (target, source) {
1679
1776
  return to;
1680
1777
  };
1681
1778
 
1682
- },{}],24:[function(_dereq_,module,exports){
1779
+ },{}],23:[function(_dereq_,module,exports){
1683
1780
  var bundleFn = arguments[3];
1684
1781
  var sources = arguments[4];
1685
1782
  var cache = arguments[5];
@@ -1825,7 +1922,6 @@ var DEFAULT_PICA_OPTS = {
1825
1922
  };
1826
1923
  var DEFAULT_RESIZE_OPTS = {
1827
1924
  filter: 'mks2013',
1828
- alpha: false,
1829
1925
  unsharpAmount: 0,
1830
1926
  unsharpRadius: 0.0,
1831
1927
  unsharpThreshold: 0
@@ -2044,9 +2140,7 @@ Pica.prototype.__extractTileData = function (tile, from, opts, stageEnv, extract
2044
2140
 
2045
2141
 
2046
2142
  if (utils.isCanvas(from)) {
2047
- if (!stageEnv.srcCtx) stageEnv.srcCtx = from.getContext('2d', {
2048
- alpha: Boolean(opts.alpha)
2049
- }); // If input is Canvas - extract region data directly
2143
+ if (!stageEnv.srcCtx) stageEnv.srcCtx = from.getContext('2d'); // If input is Canvas - extract region data directly
2050
2144
 
2051
2145
  this.debug('Get tile pixel data');
2052
2146
  extractTo.src = stageEnv.srcCtx.getImageData(tile.x, tile.y, tile.width, tile.height).data;
@@ -2060,9 +2154,7 @@ Pica.prototype.__extractTileData = function (tile, from, opts, stageEnv, extract
2060
2154
 
2061
2155
  this.debug('Draw tile imageBitmap/image to temporary canvas');
2062
2156
  var tmpCanvas = this.options.createCanvas(tile.width, tile.height);
2063
- var tmpCtx = tmpCanvas.getContext('2d', {
2064
- alpha: Boolean(opts.alpha)
2065
- });
2157
+ var tmpCtx = tmpCanvas.getContext('2d');
2066
2158
  tmpCtx.globalCompositeOperation = 'copy';
2067
2159
  tmpCtx.drawImage(stageEnv.srcImageBitmap || from, tile.x, tile.y, tile.width, tile.height, 0, 0, tile.width, tile.height);
2068
2160
  this.debug('Get tile pixel data');
@@ -2136,7 +2228,6 @@ Pica.prototype.__tileAndResize = function (from, to, opts) {
2136
2228
  offsetX: tile.offsetX,
2137
2229
  offsetY: tile.offsetY,
2138
2230
  filter: opts.filter,
2139
- alpha: opts.alpha,
2140
2231
  unsharpAmount: opts.unsharpAmount,
2141
2232
  unsharpRadius: opts.unsharpRadius,
2142
2233
  unsharpThreshold: opts.unsharpThreshold
@@ -2161,9 +2252,7 @@ Pica.prototype.__tileAndResize = function (from, to, opts) {
2161
2252
 
2162
2253
 
2163
2254
  return Promise.resolve().then(function () {
2164
- stageEnv.toCtx = to.getContext('2d', {
2165
- alpha: Boolean(opts.alpha)
2166
- });
2255
+ stageEnv.toCtx = to.getContext('2d');
2167
2256
  if (utils.isCanvas(from)) return null;
2168
2257
 
2169
2258
  if (utils.isImageBitmap(from)) {
@@ -2284,9 +2373,7 @@ Pica.prototype.__processStages = function (stages, from, to, opts) {
2284
2373
  Pica.prototype.__resizeViaCreateImageBitmap = function (from, to, opts) {
2285
2374
  var _this5 = this;
2286
2375
 
2287
- var toCtx = to.getContext('2d', {
2288
- alpha: Boolean(opts.alpha)
2289
- });
2376
+ var toCtx = to.getContext('2d');
2290
2377
  this.debug('Resize via createImageBitmap()');
2291
2378
  return createImageBitmap(from, {
2292
2379
  resizeWidth: opts.toWidth,
@@ -2309,9 +2396,7 @@ Pica.prototype.__resizeViaCreateImageBitmap = function (from, to, opts) {
2309
2396
 
2310
2397
  var tmpCanvas = _this5.options.createCanvas(opts.toWidth, opts.toHeight);
2311
2398
 
2312
- var tmpCtx = tmpCanvas.getContext('2d', {
2313
- alpha: Boolean(opts.alpha)
2314
- });
2399
+ var tmpCtx = tmpCanvas.getContext('2d');
2315
2400
  tmpCtx.drawImage(imageBitmap, 0, 0);
2316
2401
  imageBitmap.close();
2317
2402
  var iData = tmpCtx.getImageData(0, 0, opts.toWidth, opts.toHeight);
@@ -2461,5 +2546,5 @@ Pica.prototype.debug = function () {};
2461
2546
 
2462
2547
  module.exports = Pica;
2463
2548
 
2464
- },{"./lib/mathlib":1,"./lib/mm_resize/resize_filter_info":7,"./lib/pool":13,"./lib/stepper":14,"./lib/tiler":15,"./lib/utils":16,"./lib/worker":17,"object-assign":23,"webworkify":24}]},{},[])("/index.js")
2549
+ },{"./lib/mathlib":1,"./lib/mm_resize/resize_filter_info":7,"./lib/pool":13,"./lib/stepper":14,"./lib/tiler":15,"./lib/utils":16,"./lib/worker":17,"object-assign":22,"webworkify":23}]},{},[])("/index.js")
2465
2550
  });