compressorjs 1.1.1 → 1.2.1

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.
@@ -1,11 +1,11 @@
1
1
  /*!
2
- * Compressor.js v1.1.1
2
+ * Compressor.js v1.2.1
3
3
  * https://fengyuanchen.github.io/compressorjs
4
4
  *
5
5
  * Copyright 2018-present Chen Fengyuan
6
6
  * Released under the MIT license
7
7
  *
8
- * Date: 2021-10-05T02:32:40.212Z
8
+ * Date: 2023-02-28T14:09:41.732Z
9
9
  */
10
10
 
11
11
  (function (global, factory) {
@@ -16,65 +16,49 @@
16
16
 
17
17
  function ownKeys(object, enumerableOnly) {
18
18
  var keys = Object.keys(object);
19
-
20
19
  if (Object.getOwnPropertySymbols) {
21
20
  var symbols = Object.getOwnPropertySymbols(object);
22
-
23
- if (enumerableOnly) {
24
- symbols = symbols.filter(function (sym) {
25
- return Object.getOwnPropertyDescriptor(object, sym).enumerable;
26
- });
27
- }
28
-
29
- keys.push.apply(keys, symbols);
21
+ enumerableOnly && (symbols = symbols.filter(function (sym) {
22
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
23
+ })), keys.push.apply(keys, symbols);
30
24
  }
31
-
32
25
  return keys;
33
26
  }
34
-
35
27
  function _objectSpread2(target) {
36
28
  for (var i = 1; i < arguments.length; i++) {
37
- var source = arguments[i] != null ? arguments[i] : {};
38
-
39
- if (i % 2) {
40
- ownKeys(Object(source), true).forEach(function (key) {
41
- _defineProperty(target, key, source[key]);
42
- });
43
- } else if (Object.getOwnPropertyDescriptors) {
44
- Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
45
- } else {
46
- ownKeys(Object(source)).forEach(function (key) {
47
- Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
48
- });
49
- }
29
+ var source = null != arguments[i] ? arguments[i] : {};
30
+ i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {
31
+ _defineProperty(target, key, source[key]);
32
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {
33
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
34
+ });
50
35
  }
51
-
52
36
  return target;
53
37
  }
54
-
55
38
  function _classCallCheck(instance, Constructor) {
56
39
  if (!(instance instanceof Constructor)) {
57
40
  throw new TypeError("Cannot call a class as a function");
58
41
  }
59
42
  }
60
-
61
43
  function _defineProperties(target, props) {
62
44
  for (var i = 0; i < props.length; i++) {
63
45
  var descriptor = props[i];
64
46
  descriptor.enumerable = descriptor.enumerable || false;
65
47
  descriptor.configurable = true;
66
48
  if ("value" in descriptor) descriptor.writable = true;
67
- Object.defineProperty(target, descriptor.key, descriptor);
49
+ Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor);
68
50
  }
69
51
  }
70
-
71
52
  function _createClass(Constructor, protoProps, staticProps) {
72
53
  if (protoProps) _defineProperties(Constructor.prototype, protoProps);
73
54
  if (staticProps) _defineProperties(Constructor, staticProps);
55
+ Object.defineProperty(Constructor, "prototype", {
56
+ writable: false
57
+ });
74
58
  return Constructor;
75
59
  }
76
-
77
60
  function _defineProperty(obj, key, value) {
61
+ key = _toPropertyKey(key);
78
62
  if (key in obj) {
79
63
  Object.defineProperty(obj, key, {
80
64
  value: value,
@@ -85,27 +69,36 @@
85
69
  } else {
86
70
  obj[key] = value;
87
71
  }
88
-
89
72
  return obj;
90
73
  }
91
-
92
74
  function _extends() {
93
- _extends = Object.assign || function (target) {
75
+ _extends = Object.assign ? Object.assign.bind() : function (target) {
94
76
  for (var i = 1; i < arguments.length; i++) {
95
77
  var source = arguments[i];
96
-
97
78
  for (var key in source) {
98
79
  if (Object.prototype.hasOwnProperty.call(source, key)) {
99
80
  target[key] = source[key];
100
81
  }
101
82
  }
102
83
  }
103
-
104
84
  return target;
105
85
  };
106
-
107
86
  return _extends.apply(this, arguments);
108
87
  }
88
+ function _toPrimitive(input, hint) {
89
+ if (typeof input !== "object" || input === null) return input;
90
+ var prim = input[Symbol.toPrimitive];
91
+ if (prim !== undefined) {
92
+ var res = prim.call(input, hint || "default");
93
+ if (typeof res !== "object") return res;
94
+ throw new TypeError("@@toPrimitive must return a primitive value.");
95
+ }
96
+ return (hint === "string" ? String : Number)(input);
97
+ }
98
+ function _toPropertyKey(arg) {
99
+ var key = _toPrimitive(arg, "string");
100
+ return typeof key === "symbol" ? key : String(key);
101
+ }
109
102
 
110
103
  var canvasToBlob = {exports: {}};
111
104
 
@@ -122,16 +115,13 @@
122
115
  * Based on stackoverflow user Stoive's code snippet:
123
116
  * http://stackoverflow.com/q/4998908
124
117
  */
125
-
126
118
  (function (module) {
127
119
  if (typeof window === 'undefined') {
128
120
  return;
129
121
  }
130
-
131
122
  (function (window) {
132
123
 
133
124
  var CanvasPrototype = window.HTMLCanvasElement && window.HTMLCanvasElement.prototype;
134
-
135
125
  var hasBlobConstructor = window.Blob && function () {
136
126
  try {
137
127
  return Boolean(new Blob());
@@ -139,7 +129,6 @@
139
129
  return false;
140
130
  }
141
131
  }();
142
-
143
132
  var hasArrayBufferViewSupport = hasBlobConstructor && window.Uint8Array && function () {
144
133
  try {
145
134
  return new Blob([new Uint8Array(100)]).size === 100;
@@ -147,52 +136,42 @@
147
136
  return false;
148
137
  }
149
138
  }();
150
-
151
139
  var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
152
140
  var dataURIPattern = /^data:((.*?)(;charset=.*?)?)(;base64)?,/;
153
-
154
141
  var dataURLtoBlob = (hasBlobConstructor || BlobBuilder) && window.atob && window.ArrayBuffer && window.Uint8Array && function (dataURI) {
155
- var matches, mediaType, isBase64, dataString, byteString, arrayBuffer, intArray, i, bb; // Parse the dataURI components as per RFC 2397
156
-
142
+ var matches, mediaType, isBase64, dataString, byteString, arrayBuffer, intArray, i, bb;
143
+ // Parse the dataURI components as per RFC 2397
157
144
  matches = dataURI.match(dataURIPattern);
158
-
159
145
  if (!matches) {
160
146
  throw new Error('invalid data URI');
161
- } // Default to text/plain;charset=US-ASCII
162
-
163
-
147
+ }
148
+ // Default to text/plain;charset=US-ASCII
164
149
  mediaType = matches[2] ? matches[1] : 'text/plain' + (matches[3] || ';charset=US-ASCII');
165
150
  isBase64 = !!matches[4];
166
151
  dataString = dataURI.slice(matches[0].length);
167
-
168
152
  if (isBase64) {
169
153
  // Convert base64 to raw binary data held in a string:
170
154
  byteString = atob(dataString);
171
155
  } else {
172
156
  // Convert base64/URLEncoded data component to raw binary:
173
157
  byteString = decodeURIComponent(dataString);
174
- } // Write the bytes of the string to an ArrayBuffer:
175
-
176
-
158
+ }
159
+ // Write the bytes of the string to an ArrayBuffer:
177
160
  arrayBuffer = new ArrayBuffer(byteString.length);
178
161
  intArray = new Uint8Array(arrayBuffer);
179
-
180
162
  for (i = 0; i < byteString.length; i += 1) {
181
163
  intArray[i] = byteString.charCodeAt(i);
182
- } // Write the ArrayBuffer (or ArrayBufferView) to a blob:
183
-
184
-
164
+ }
165
+ // Write the ArrayBuffer (or ArrayBufferView) to a blob:
185
166
  if (hasBlobConstructor) {
186
167
  return new Blob([hasArrayBufferViewSupport ? intArray : arrayBuffer], {
187
168
  type: mediaType
188
169
  });
189
170
  }
190
-
191
171
  bb = new BlobBuilder();
192
172
  bb.append(arrayBuffer);
193
173
  return bb.getBlob(mediaType);
194
174
  };
195
-
196
175
  if (window.HTMLCanvasElement && !CanvasPrototype.toBlob) {
197
176
  if (CanvasPrototype.mozGetAsFile) {
198
177
  CanvasPrototype.toBlob = function (callback, type, quality) {
@@ -227,7 +206,6 @@
227
206
  }
228
207
  }
229
208
  }
230
-
231
209
  if (module.exports) {
232
210
  module.exports = dataURLtoBlob;
233
211
  } else {
@@ -235,14 +213,12 @@
235
213
  }
236
214
  })(window);
237
215
  })(canvasToBlob);
238
-
239
216
  var toBlob = canvasToBlob.exports;
240
217
 
241
218
  var isBlob = function isBlob(value) {
242
219
  if (typeof Blob === 'undefined') {
243
220
  return false;
244
221
  }
245
-
246
222
  return value instanceof Blob || Object.prototype.toString.call(value) === '[object Blob]';
247
223
  };
248
224
 
@@ -253,59 +229,55 @@
253
229
  * @type {boolean}
254
230
  */
255
231
  strict: true,
256
-
257
232
  /**
258
233
  * Indicates if read the image's Exif Orientation information,
259
234
  * and then rotate or flip the image automatically.
260
235
  * @type {boolean}
261
236
  */
262
237
  checkOrientation: true,
263
-
238
+ /**
239
+ * Indicates if retain the image's Exif information after compressed.
240
+ * @type {boolean}
241
+ */
242
+ retainExif: false,
264
243
  /**
265
244
  * The max width of the output image.
266
245
  * @type {number}
267
246
  */
268
247
  maxWidth: Infinity,
269
-
270
248
  /**
271
249
  * The max height of the output image.
272
250
  * @type {number}
273
251
  */
274
252
  maxHeight: Infinity,
275
-
276
253
  /**
277
254
  * The min width of the output image.
278
255
  * @type {number}
279
256
  */
280
257
  minWidth: 0,
281
-
282
258
  /**
283
259
  * The min height of the output image.
284
260
  * @type {number}
285
261
  */
286
262
  minHeight: 0,
287
-
288
263
  /**
289
264
  * The width of the output image.
290
265
  * If not specified, the natural width of the source image will be used.
291
266
  * @type {number}
292
267
  */
293
268
  width: undefined,
294
-
295
269
  /**
296
270
  * The height of the output image.
297
271
  * If not specified, the natural height of the source image will be used.
298
272
  * @type {number}
299
273
  */
300
274
  height: undefined,
301
-
302
275
  /**
303
276
  * Sets how the size of the image should be resized to the container
304
277
  * specified by the `width` and `height` options.
305
278
  * @type {string}
306
279
  */
307
280
  resize: 'none',
308
-
309
281
  /**
310
282
  * The quality of the output image.
311
283
  * It must be a number between `0` and `1`,
@@ -314,28 +286,24 @@
314
286
  * @type {number}
315
287
  */
316
288
  quality: 0.8,
317
-
318
289
  /**
319
290
  * The mime type of the output image.
320
291
  * By default, the original mime type of the source image file will be used.
321
292
  * @type {string}
322
293
  */
323
294
  mimeType: 'auto',
324
-
325
295
  /**
326
296
  * Files whose file type is included in this list,
327
297
  * and whose file size exceeds the `convertSize` value will be converted to JPEGs.
328
298
  * @type {string|Array}
329
299
  */
330
300
  convertTypes: ['image/png'],
331
-
332
301
  /**
333
302
  * PNG files over this size (5 MB by default) will be converted to JPEGs.
334
303
  * To disable this, just set the value to `Infinity`.
335
304
  * @type {number}
336
305
  */
337
306
  convertSize: 5000000,
338
-
339
307
  /**
340
308
  * The hook function to execute before draw the image into the canvas for compression.
341
309
  * @type {Function}
@@ -347,7 +315,6 @@
347
315
  * }
348
316
  */
349
317
  beforeDraw: null,
350
-
351
318
  /**
352
319
  * The hook function to execute after drew the image into the canvas for compression.
353
320
  * @type {Function}
@@ -359,7 +326,6 @@
359
326
  * }
360
327
  */
361
328
  drew: null,
362
-
363
329
  /**
364
330
  * The hook function to execute when success to compress the image.
365
331
  * @type {Function}
@@ -370,7 +336,6 @@
370
336
  * }
371
337
  */
372
338
  success: null,
373
-
374
339
  /**
375
340
  * The hook function to execute when fail to compress the image.
376
341
  * @type {Function}
@@ -391,46 +356,44 @@
391
356
  * @param {*} value - The value to check.
392
357
  * @returns {boolean} Returns `true` if the given value is a positive number, else `false`.
393
358
  */
394
-
395
359
  var isPositiveNumber = function isPositiveNumber(value) {
396
360
  return value > 0 && value < Infinity;
397
361
  };
398
362
  var slice = Array.prototype.slice;
363
+
399
364
  /**
400
365
  * Convert array-like or iterable object to an array.
401
366
  * @param {*} value - The value to convert.
402
367
  * @returns {Array} Returns a new array.
403
368
  */
404
-
405
369
  function toArray(value) {
406
370
  return Array.from ? Array.from(value) : slice.call(value);
407
371
  }
408
372
  var REGEXP_IMAGE_TYPE = /^image\/.+$/;
373
+
409
374
  /**
410
375
  * Check if the given value is a mime type of image.
411
376
  * @param {*} value - The value to check.
412
377
  * @returns {boolean} Returns `true` if the given is a mime type of image, else `false`.
413
378
  */
414
-
415
379
  function isImageType(value) {
416
380
  return REGEXP_IMAGE_TYPE.test(value);
417
381
  }
382
+
418
383
  /**
419
384
  * Convert image type to extension.
420
385
  * @param {string} value - The image type to convert.
421
386
  * @returns {boolean} Returns the image extension.
422
387
  */
423
-
424
388
  function imageTypeToExtension(value) {
425
389
  var extension = isImageType(value) ? value.substr(6) : '';
426
-
427
390
  if (extension === 'jpeg') {
428
391
  extension = 'jpg';
429
392
  }
430
-
431
393
  return ".".concat(extension);
432
394
  }
433
395
  var fromCharCode = String.fromCharCode;
396
+
434
397
  /**
435
398
  * Get string from char code in data view.
436
399
  * @param {DataView} dataView - The data view for read.
@@ -438,83 +401,72 @@
438
401
  * @param {number} length - The read length.
439
402
  * @returns {string} The read result.
440
403
  */
441
-
442
404
  function getStringFromCharCode(dataView, start, length) {
443
405
  var str = '';
444
406
  var i;
445
407
  length += start;
446
-
447
408
  for (i = start; i < length; i += 1) {
448
409
  str += fromCharCode(dataView.getUint8(i));
449
410
  }
450
-
451
411
  return str;
452
412
  }
453
413
  var btoa = WINDOW.btoa;
414
+
454
415
  /**
455
416
  * Transform array buffer to Data URL.
456
417
  * @param {ArrayBuffer} arrayBuffer - The array buffer to transform.
457
418
  * @param {string} mimeType - The mime type of the Data URL.
458
419
  * @returns {string} The result Data URL.
459
420
  */
460
-
461
421
  function arrayBufferToDataURL(arrayBuffer, mimeType) {
462
422
  var chunks = [];
463
423
  var chunkSize = 8192;
464
424
  var uint8 = new Uint8Array(arrayBuffer);
465
-
466
425
  while (uint8.length > 0) {
467
426
  // XXX: Babel's `toConsumableArray` helper will throw error in IE or Safari 9
468
427
  // eslint-disable-next-line prefer-spread
469
428
  chunks.push(fromCharCode.apply(null, toArray(uint8.subarray(0, chunkSize))));
470
429
  uint8 = uint8.subarray(chunkSize);
471
430
  }
472
-
473
431
  return "data:".concat(mimeType, ";base64,").concat(btoa(chunks.join('')));
474
432
  }
433
+
475
434
  /**
476
435
  * Get orientation value from given array buffer.
477
436
  * @param {ArrayBuffer} arrayBuffer - The array buffer to read.
478
437
  * @returns {number} The read orientation value.
479
438
  */
480
-
481
439
  function resetAndGetOrientation(arrayBuffer) {
482
440
  var dataView = new DataView(arrayBuffer);
483
- var orientation; // Ignores range error when the image does not have correct Exif information
441
+ var orientation;
484
442
 
443
+ // Ignores range error when the image does not have correct Exif information
485
444
  try {
486
445
  var littleEndian;
487
446
  var app1Start;
488
- var ifdStart; // Only handle JPEG image (start by 0xFFD8)
447
+ var ifdStart;
489
448
 
449
+ // Only handle JPEG image (start by 0xFFD8)
490
450
  if (dataView.getUint8(0) === 0xFF && dataView.getUint8(1) === 0xD8) {
491
451
  var length = dataView.byteLength;
492
452
  var offset = 2;
493
-
494
453
  while (offset + 1 < length) {
495
454
  if (dataView.getUint8(offset) === 0xFF && dataView.getUint8(offset + 1) === 0xE1) {
496
455
  app1Start = offset;
497
456
  break;
498
457
  }
499
-
500
458
  offset += 1;
501
459
  }
502
460
  }
503
-
504
461
  if (app1Start) {
505
462
  var exifIDCode = app1Start + 4;
506
463
  var tiffOffset = app1Start + 10;
507
-
508
464
  if (getStringFromCharCode(dataView, exifIDCode, 4) === 'Exif') {
509
465
  var endianness = dataView.getUint16(tiffOffset);
510
466
  littleEndian = endianness === 0x4949;
511
-
512
- if (littleEndian || endianness === 0x4D4D
513
- /* bigEndian */
514
- ) {
467
+ if (littleEndian || endianness === 0x4D4D /* bigEndian */) {
515
468
  if (dataView.getUint16(tiffOffset + 2, littleEndian) === 0x002A) {
516
469
  var firstIFDOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
517
-
518
470
  if (firstIFDOffset >= 0x00000008) {
519
471
  ifdStart = tiffOffset + firstIFDOffset;
520
472
  }
@@ -522,25 +474,20 @@
522
474
  }
523
475
  }
524
476
  }
525
-
526
477
  if (ifdStart) {
527
478
  var _length = dataView.getUint16(ifdStart, littleEndian);
528
-
529
479
  var _offset;
530
-
531
480
  var i;
532
-
533
481
  for (i = 0; i < _length; i += 1) {
534
482
  _offset = ifdStart + i * 12 + 2;
535
-
536
- if (dataView.getUint16(_offset, littleEndian) === 0x0112
537
- /* Orientation */
538
- ) {
483
+ if (dataView.getUint16(_offset, littleEndian) === 0x0112 /* Orientation */) {
539
484
  // 8 is the offset of the current tag's value
540
- _offset += 8; // Get the original orientation value
485
+ _offset += 8;
541
486
 
542
- orientation = dataView.getUint16(_offset, littleEndian); // Override the orientation with its default value
487
+ // Get the original orientation value
488
+ orientation = dataView.getUint16(_offset, littleEndian);
543
489
 
490
+ // Override the orientation with its default value
544
491
  dataView.setUint16(_offset, 1, littleEndian);
545
492
  break;
546
493
  }
@@ -549,59 +496,56 @@
549
496
  } catch (e) {
550
497
  orientation = 1;
551
498
  }
552
-
553
499
  return orientation;
554
500
  }
501
+
555
502
  /**
556
503
  * Parse Exif Orientation value.
557
504
  * @param {number} orientation - The orientation to parse.
558
505
  * @returns {Object} The parsed result.
559
506
  */
560
-
561
507
  function parseOrientation(orientation) {
562
508
  var rotate = 0;
563
509
  var scaleX = 1;
564
510
  var scaleY = 1;
565
-
566
511
  switch (orientation) {
567
512
  // Flip horizontal
568
513
  case 2:
569
514
  scaleX = -1;
570
515
  break;
571
- // Rotate left 180°
572
516
 
517
+ // Rotate left 180°
573
518
  case 3:
574
519
  rotate = -180;
575
520
  break;
576
- // Flip vertical
577
521
 
522
+ // Flip vertical
578
523
  case 4:
579
524
  scaleY = -1;
580
525
  break;
581
- // Flip vertical and rotate right 90°
582
526
 
527
+ // Flip vertical and rotate right 90°
583
528
  case 5:
584
529
  rotate = 90;
585
530
  scaleY = -1;
586
531
  break;
587
- // Rotate right 90°
588
532
 
533
+ // Rotate right 90°
589
534
  case 6:
590
535
  rotate = 90;
591
536
  break;
592
- // Flip horizontal and rotate right 90°
593
537
 
538
+ // Flip horizontal and rotate right 90°
594
539
  case 7:
595
540
  rotate = 90;
596
541
  scaleX = -1;
597
542
  break;
598
- // Rotate left 90°
599
543
 
544
+ // Rotate left 90°
600
545
  case 8:
601
546
  rotate = -90;
602
547
  break;
603
548
  }
604
-
605
549
  return {
606
550
  rotate: rotate,
607
551
  scaleX: scaleX,
@@ -609,6 +553,7 @@
609
553
  };
610
554
  }
611
555
  var REGEXP_DECIMALS = /\.\d*(?:0|9){12}\d*$/;
556
+
612
557
  /**
613
558
  * Normalize decimal number.
614
559
  * Check out {@link https://0.30000000000000004.com/}
@@ -616,29 +561,26 @@
616
561
  * @param {number} [times=100000000000] - The times for normalizing.
617
562
  * @returns {number} Returns the normalized number.
618
563
  */
619
-
620
564
  function normalizeDecimalNumber(value) {
621
565
  var times = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 100000000000;
622
566
  return REGEXP_DECIMALS.test(value) ? Math.round(value * times) / times : value;
623
567
  }
568
+
624
569
  /**
625
570
  * Get the max sizes in a rectangle under the given aspect ratio.
626
571
  * @param {Object} data - The original sizes.
627
572
  * @param {string} [type='contain'] - The adjust type.
628
573
  * @returns {Object} The result sizes.
629
574
  */
630
-
631
575
  function getAdjustedSizes(_ref) {
632
576
  var aspectRatio = _ref.aspectRatio,
633
- height = _ref.height,
634
- width = _ref.width;
577
+ height = _ref.height,
578
+ width = _ref.width;
635
579
  var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'none';
636
580
  var isValidWidth = isPositiveNumber(width);
637
581
  var isValidHeight = isPositiveNumber(height);
638
-
639
582
  if (isValidWidth && isValidHeight) {
640
583
  var adjustedWidth = height * aspectRatio;
641
-
642
584
  if ((type === 'contain' || type === 'none') && adjustedWidth > width || type === 'cover' && adjustedWidth < width) {
643
585
  height = width / aspectRatio;
644
586
  } else {
@@ -649,23 +591,76 @@
649
591
  } else if (isValidHeight) {
650
592
  width = height * aspectRatio;
651
593
  }
652
-
653
594
  return {
654
595
  width: width,
655
596
  height: height
656
597
  };
657
598
  }
658
599
 
600
+ /**
601
+ * Get Exif information from the given array buffer.
602
+ * @param {ArrayBuffer} arrayBuffer - The array buffer to read.
603
+ * @returns {Array} The read Exif information.
604
+ */
605
+ function getExif(arrayBuffer) {
606
+ var array = toArray(new Uint8Array(arrayBuffer));
607
+ var length = array.length;
608
+ var segments = [];
609
+ var start = 0;
610
+ while (start + 3 < length) {
611
+ var value = array[start];
612
+ var next = array[start + 1];
613
+
614
+ // SOS (Start of Scan)
615
+ if (value === 0xFF && next === 0xDA) {
616
+ break;
617
+ }
618
+
619
+ // SOI (Start of Image)
620
+ if (value === 0xFF && next === 0xD8) {
621
+ start += 2;
622
+ } else {
623
+ var offset = array[start + 2] * 256 + array[start + 3];
624
+ var end = start + offset + 2;
625
+ var segment = array.slice(start, end);
626
+ segments.push(segment);
627
+ start = end;
628
+ }
629
+ }
630
+ return segments.reduce(function (exifArray, current) {
631
+ if (current[0] === 0xFF && current[1] === 0xE1) {
632
+ return exifArray.concat(current);
633
+ }
634
+ return exifArray;
635
+ }, []);
636
+ }
637
+
638
+ /**
639
+ * Insert Exif information into the given array buffer.
640
+ * @param {ArrayBuffer} arrayBuffer - The array buffer to transform.
641
+ * @param {Array} exifArray - The Exif information to insert.
642
+ * @returns {ArrayBuffer} The transformed array buffer.
643
+ */
644
+ function insertExif(arrayBuffer, exifArray) {
645
+ var array = toArray(new Uint8Array(arrayBuffer));
646
+ if (array[2] !== 0xFF || array[3] !== 0xE0) {
647
+ return arrayBuffer;
648
+ }
649
+ var app0Length = array[4] * 256 + array[5];
650
+ var newArrayBuffer = [0xFF, 0xD8].concat(exifArray, array.slice(4 + app0Length));
651
+ return new Uint8Array(newArrayBuffer);
652
+ }
653
+
659
654
  var ArrayBuffer$1 = WINDOW.ArrayBuffer,
660
- FileReader = WINDOW.FileReader;
655
+ FileReader = WINDOW.FileReader;
661
656
  var URL = WINDOW.URL || WINDOW.webkitURL;
662
657
  var REGEXP_EXTENSION = /\.\w+$/;
663
658
  var AnotherCompressor = WINDOW.Compressor;
659
+
664
660
  /**
665
661
  * Creates a new image compressor.
666
662
  * @class
667
663
  */
668
-
669
664
  var Compressor = /*#__PURE__*/function () {
670
665
  /**
671
666
  * The constructor of Compressor.
@@ -674,93 +669,87 @@
674
669
  */
675
670
  function Compressor(file, options) {
676
671
  _classCallCheck(this, Compressor);
677
-
678
672
  this.file = file;
673
+ this.exif = [];
679
674
  this.image = new Image();
680
675
  this.options = _objectSpread2(_objectSpread2({}, DEFAULTS), options);
681
676
  this.aborted = false;
682
677
  this.result = null;
683
678
  this.init();
684
679
  }
685
-
686
680
  _createClass(Compressor, [{
687
681
  key: "init",
688
682
  value: function init() {
689
683
  var _this = this;
690
-
691
684
  var file = this.file,
692
- options = this.options;
693
-
685
+ options = this.options;
694
686
  if (!isBlob(file)) {
695
687
  this.fail(new Error('The first argument must be a File or Blob object.'));
696
688
  return;
697
689
  }
698
-
699
690
  var mimeType = file.type;
700
-
701
691
  if (!isImageType(mimeType)) {
702
692
  this.fail(new Error('The first argument must be an image File or Blob object.'));
703
693
  return;
704
694
  }
705
-
706
695
  if (!URL || !FileReader) {
707
696
  this.fail(new Error('The current browser does not support image compression.'));
708
697
  return;
709
698
  }
710
-
711
699
  if (!ArrayBuffer$1) {
712
700
  options.checkOrientation = false;
701
+ options.retainExif = false;
713
702
  }
714
-
715
- if (URL && !options.checkOrientation) {
703
+ var isJPEGImage = mimeType === 'image/jpeg';
704
+ var checkOrientation = isJPEGImage && options.checkOrientation;
705
+ var retainExif = isJPEGImage && options.retainExif;
706
+ if (URL && !checkOrientation && !retainExif) {
716
707
  this.load({
717
708
  url: URL.createObjectURL(file)
718
709
  });
719
710
  } else {
720
711
  var reader = new FileReader();
721
- var checkOrientation = options.checkOrientation && mimeType === 'image/jpeg';
722
712
  this.reader = reader;
723
-
724
713
  reader.onload = function (_ref) {
725
714
  var target = _ref.target;
726
715
  var result = target.result;
727
716
  var data = {};
728
-
717
+ var orientation = 1;
729
718
  if (checkOrientation) {
730
719
  // Reset the orientation value to its default value 1
731
720
  // as some iOS browsers will render image with its orientation
732
- var orientation = resetAndGetOrientation(result);
721
+ orientation = resetAndGetOrientation(result);
722
+ if (orientation > 1) {
723
+ _extends(data, parseOrientation(orientation));
724
+ }
725
+ }
726
+ if (retainExif) {
727
+ _this.exif = getExif(result);
728
+ }
729
+ if (checkOrientation || retainExif) {
730
+ if (!URL
733
731
 
734
- if (orientation > 1 || !URL) {
735
- // Generate a new URL which has the default orientation value
732
+ // Generate a new URL with the default orientation value 1.
733
+ || orientation > 1) {
736
734
  data.url = arrayBufferToDataURL(result, mimeType);
737
-
738
- if (orientation > 1) {
739
- _extends(data, parseOrientation(orientation));
740
- }
741
735
  } else {
742
736
  data.url = URL.createObjectURL(file);
743
737
  }
744
738
  } else {
745
739
  data.url = result;
746
740
  }
747
-
748
741
  _this.load(data);
749
742
  };
750
-
751
743
  reader.onabort = function () {
752
744
  _this.fail(new Error('Aborted to read the image with FileReader.'));
753
745
  };
754
-
755
746
  reader.onerror = function () {
756
747
  _this.fail(new Error('Failed to read the image with FileReader.'));
757
748
  };
758
-
759
749
  reader.onloadend = function () {
760
750
  _this.reader = null;
761
751
  };
762
-
763
- if (checkOrientation) {
752
+ if (checkOrientation || retainExif) {
764
753
  reader.readAsArrayBuffer(file);
765
754
  } else {
766
755
  reader.readAsDataURL(file);
@@ -771,32 +760,27 @@
771
760
  key: "load",
772
761
  value: function load(data) {
773
762
  var _this2 = this;
774
-
775
763
  var file = this.file,
776
- image = this.image;
777
-
764
+ image = this.image;
778
765
  image.onload = function () {
779
766
  _this2.draw(_objectSpread2(_objectSpread2({}, data), {}, {
780
767
  naturalWidth: image.naturalWidth,
781
768
  naturalHeight: image.naturalHeight
782
769
  }));
783
770
  };
784
-
785
771
  image.onabort = function () {
786
772
  _this2.fail(new Error('Aborted to load the image.'));
787
773
  };
788
-
789
774
  image.onerror = function () {
790
775
  _this2.fail(new Error('Failed to load the image.'));
791
- }; // Match all browsers that use WebKit as the layout engine in iOS devices,
792
- // such as Safari for iOS, Chrome for iOS, and in-app browsers.
793
-
776
+ };
794
777
 
778
+ // Match all browsers that use WebKit as the layout engine in iOS devices,
779
+ // such as Safari for iOS, Chrome for iOS, and in-app browsers.
795
780
  if (WINDOW.navigator && /(?:iPad|iPhone|iPod).*?AppleWebKit/i.test(WINDOW.navigator.userAgent)) {
796
781
  // Fix the `The operation is insecure` error (#57)
797
782
  image.crossOrigin = 'anonymous';
798
783
  }
799
-
800
784
  image.alt = file.name;
801
785
  image.src = data.url;
802
786
  }
@@ -804,18 +788,17 @@
804
788
  key: "draw",
805
789
  value: function draw(_ref2) {
806
790
  var _this3 = this;
807
-
808
791
  var naturalWidth = _ref2.naturalWidth,
809
- naturalHeight = _ref2.naturalHeight,
810
- _ref2$rotate = _ref2.rotate,
811
- rotate = _ref2$rotate === void 0 ? 0 : _ref2$rotate,
812
- _ref2$scaleX = _ref2.scaleX,
813
- scaleX = _ref2$scaleX === void 0 ? 1 : _ref2$scaleX,
814
- _ref2$scaleY = _ref2.scaleY,
815
- scaleY = _ref2$scaleY === void 0 ? 1 : _ref2$scaleY;
792
+ naturalHeight = _ref2.naturalHeight,
793
+ _ref2$rotate = _ref2.rotate,
794
+ rotate = _ref2$rotate === void 0 ? 0 : _ref2$rotate,
795
+ _ref2$scaleX = _ref2.scaleX,
796
+ scaleX = _ref2$scaleX === void 0 ? 1 : _ref2$scaleX,
797
+ _ref2$scaleY = _ref2.scaleY,
798
+ scaleY = _ref2$scaleY === void 0 ? 1 : _ref2$scaleY;
816
799
  var file = this.file,
817
- image = this.image,
818
- options = this.options;
800
+ image = this.image,
801
+ options = this.options;
819
802
  var canvas = document.createElement('canvas');
820
803
  var context = canvas.getContext('2d');
821
804
  var is90DegreesRotated = Math.abs(rotate) % 180 === 90;
@@ -826,8 +809,7 @@
826
809
  var minHeight = Math.max(options.minHeight, 0) || 0;
827
810
  var aspectRatio = naturalWidth / naturalHeight;
828
811
  var width = options.width,
829
- height = options.height;
830
-
812
+ height = options.height;
831
813
  if (is90DegreesRotated) {
832
814
  var _ref3 = [maxHeight, maxWidth];
833
815
  maxWidth = _ref3[0];
@@ -839,36 +821,29 @@
839
821
  width = _ref5[0];
840
822
  height = _ref5[1];
841
823
  }
842
-
843
824
  if (resizable) {
844
825
  aspectRatio = width / height;
845
826
  }
846
-
847
827
  var _getAdjustedSizes = getAdjustedSizes({
848
828
  aspectRatio: aspectRatio,
849
829
  width: maxWidth,
850
830
  height: maxHeight
851
831
  }, 'contain');
852
-
853
832
  maxWidth = _getAdjustedSizes.width;
854
833
  maxHeight = _getAdjustedSizes.height;
855
-
856
834
  var _getAdjustedSizes2 = getAdjustedSizes({
857
835
  aspectRatio: aspectRatio,
858
836
  width: minWidth,
859
837
  height: minHeight
860
838
  }, 'cover');
861
-
862
839
  minWidth = _getAdjustedSizes2.width;
863
840
  minHeight = _getAdjustedSizes2.height;
864
-
865
841
  if (resizable) {
866
842
  var _getAdjustedSizes3 = getAdjustedSizes({
867
843
  aspectRatio: aspectRatio,
868
844
  width: width,
869
845
  height: height
870
846
  }, options.resize);
871
-
872
847
  width = _getAdjustedSizes3.width;
873
848
  height = _getAdjustedSizes3.height;
874
849
  } else {
@@ -877,13 +852,11 @@
877
852
  width: width,
878
853
  height: height
879
854
  });
880
-
881
855
  var _getAdjustedSizes4$wi = _getAdjustedSizes4.width;
882
856
  width = _getAdjustedSizes4$wi === void 0 ? naturalWidth : _getAdjustedSizes4$wi;
883
857
  var _getAdjustedSizes4$he = _getAdjustedSizes4.height;
884
858
  height = _getAdjustedSizes4$he === void 0 ? naturalHeight : _getAdjustedSizes4$he;
885
859
  }
886
-
887
860
  width = Math.floor(normalizeDecimalNumber(Math.min(Math.max(width, minWidth), maxWidth)));
888
861
  height = Math.floor(normalizeDecimalNumber(Math.min(Math.max(height, minHeight), maxHeight)));
889
862
  var destX = -width / 2;
@@ -891,13 +864,11 @@
891
864
  var destWidth = width;
892
865
  var destHeight = height;
893
866
  var params = [];
894
-
895
867
  if (resizable) {
896
868
  var srcX = 0;
897
869
  var srcY = 0;
898
870
  var srcWidth = naturalWidth;
899
871
  var srcHeight = naturalHeight;
900
-
901
872
  var _getAdjustedSizes5 = getAdjustedSizes({
902
873
  aspectRatio: aspectRatio,
903
874
  width: naturalWidth,
@@ -906,106 +877,124 @@
906
877
  contain: 'cover',
907
878
  cover: 'contain'
908
879
  }[options.resize]);
909
-
910
880
  srcWidth = _getAdjustedSizes5.width;
911
881
  srcHeight = _getAdjustedSizes5.height;
912
882
  srcX = (naturalWidth - srcWidth) / 2;
913
883
  srcY = (naturalHeight - srcHeight) / 2;
914
884
  params.push(srcX, srcY, srcWidth, srcHeight);
915
885
  }
916
-
917
886
  params.push(destX, destY, destWidth, destHeight);
918
-
919
887
  if (is90DegreesRotated) {
920
888
  var _ref6 = [height, width];
921
889
  width = _ref6[0];
922
890
  height = _ref6[1];
923
891
  }
924
-
925
892
  canvas.width = width;
926
893
  canvas.height = height;
927
-
928
894
  if (!isImageType(options.mimeType)) {
929
895
  options.mimeType = file.type;
930
896
  }
897
+ var fillStyle = 'transparent';
931
898
 
932
- var fillStyle = 'transparent'; // Converts PNG files over the `convertSize` to JPEGs.
933
-
899
+ // Converts PNG files over the `convertSize` to JPEGs.
934
900
  if (file.size > options.convertSize && options.convertTypes.indexOf(options.mimeType) >= 0) {
935
901
  options.mimeType = 'image/jpeg';
936
902
  }
937
-
938
- if (options.mimeType === 'image/jpeg') {
903
+ var isJPEGImage = options.mimeType === 'image/jpeg';
904
+ if (isJPEGImage) {
939
905
  fillStyle = '#fff';
940
- } // Override the default fill color (#000, black)
941
-
906
+ }
942
907
 
908
+ // Override the default fill color (#000, black)
943
909
  context.fillStyle = fillStyle;
944
910
  context.fillRect(0, 0, width, height);
945
-
946
911
  if (options.beforeDraw) {
947
912
  options.beforeDraw.call(this, context, canvas);
948
913
  }
949
-
950
914
  if (this.aborted) {
951
915
  return;
952
916
  }
953
-
954
917
  context.save();
955
918
  context.translate(width / 2, height / 2);
956
919
  context.rotate(rotate * Math.PI / 180);
957
920
  context.scale(scaleX, scaleY);
958
921
  context.drawImage.apply(context, [image].concat(params));
959
922
  context.restore();
960
-
961
923
  if (options.drew) {
962
924
  options.drew.call(this, context, canvas);
963
925
  }
964
-
965
926
  if (this.aborted) {
966
927
  return;
967
928
  }
968
-
969
- var done = function done(result) {
929
+ var callback = function callback(blob) {
970
930
  if (!_this3.aborted) {
971
- _this3.done({
972
- naturalWidth: naturalWidth,
973
- naturalHeight: naturalHeight,
974
- result: result
975
- });
931
+ var done = function done(result) {
932
+ return _this3.done({
933
+ naturalWidth: naturalWidth,
934
+ naturalHeight: naturalHeight,
935
+ result: result
936
+ });
937
+ };
938
+ if (blob && isJPEGImage && options.retainExif && _this3.exif && _this3.exif.length > 0) {
939
+ var next = function next(arrayBuffer) {
940
+ return done(toBlob(arrayBufferToDataURL(insertExif(arrayBuffer, _this3.exif), options.mimeType)));
941
+ };
942
+ if (blob.arrayBuffer) {
943
+ blob.arrayBuffer().then(next).catch(function () {
944
+ _this3.fail(new Error('Failed to read the compressed image with Blob.arrayBuffer().'));
945
+ });
946
+ } else {
947
+ var reader = new FileReader();
948
+ _this3.reader = reader;
949
+ reader.onload = function (_ref7) {
950
+ var target = _ref7.target;
951
+ next(target.result);
952
+ };
953
+ reader.onabort = function () {
954
+ _this3.fail(new Error('Aborted to read the compressed image with FileReader.'));
955
+ };
956
+ reader.onerror = function () {
957
+ _this3.fail(new Error('Failed to read the compressed image with FileReader.'));
958
+ };
959
+ reader.onloadend = function () {
960
+ _this3.reader = null;
961
+ };
962
+ reader.readAsArrayBuffer(blob);
963
+ }
964
+ } else {
965
+ done(blob);
966
+ }
976
967
  }
977
968
  };
978
-
979
969
  if (canvas.toBlob) {
980
- canvas.toBlob(done, options.mimeType, options.quality);
970
+ canvas.toBlob(callback, options.mimeType, options.quality);
981
971
  } else {
982
- done(toBlob(canvas.toDataURL(options.mimeType, options.quality)));
972
+ callback(toBlob(canvas.toDataURL(options.mimeType, options.quality)));
983
973
  }
984
974
  }
985
975
  }, {
986
976
  key: "done",
987
- value: function done(_ref7) {
988
- var naturalWidth = _ref7.naturalWidth,
989
- naturalHeight = _ref7.naturalHeight,
990
- result = _ref7.result;
977
+ value: function done(_ref8) {
978
+ var naturalWidth = _ref8.naturalWidth,
979
+ naturalHeight = _ref8.naturalHeight,
980
+ result = _ref8.result;
991
981
  var file = this.file,
992
- image = this.image,
993
- options = this.options;
994
-
995
- if (URL && !options.checkOrientation) {
982
+ image = this.image,
983
+ options = this.options;
984
+ if (URL && image.src.indexOf('blob:') === 0) {
996
985
  URL.revokeObjectURL(image.src);
997
986
  }
998
-
999
987
  if (result) {
1000
988
  // Returns original file if the result is greater than it and without size related options
1001
- if (options.strict && result.size > file.size && options.mimeType === file.type && !(options.width > naturalWidth || options.height > naturalHeight || options.minWidth > naturalWidth || options.minHeight > naturalHeight || options.maxWidth < naturalWidth || options.maxHeight < naturalHeight)) {
989
+ if (options.strict && !options.retainExif && result.size > file.size && options.mimeType === file.type && !(options.width > naturalWidth || options.height > naturalHeight || options.minWidth > naturalWidth || options.minHeight > naturalHeight || options.maxWidth < naturalWidth || options.maxHeight < naturalHeight)) {
1002
990
  result = file;
1003
991
  } else {
1004
992
  var date = new Date();
1005
993
  result.lastModified = date.getTime();
1006
994
  result.lastModifiedDate = date;
1007
- result.name = file.name; // Convert the extension to match its type
995
+ result.name = file.name;
1008
996
 
997
+ // Convert the extension to match its type
1009
998
  if (result.name && result.type !== file.type) {
1010
999
  result.name = result.name.replace(REGEXP_EXTENSION, imageTypeToExtension(result.type));
1011
1000
  }
@@ -1014,9 +1003,7 @@
1014
1003
  // Returns original file if the result is null in some cases.
1015
1004
  result = file;
1016
1005
  }
1017
-
1018
1006
  this.result = result;
1019
-
1020
1007
  if (options.success) {
1021
1008
  options.success.call(this, result);
1022
1009
  }
@@ -1025,7 +1012,6 @@
1025
1012
  key: "fail",
1026
1013
  value: function fail(err) {
1027
1014
  var options = this.options;
1028
-
1029
1015
  if (options.error) {
1030
1016
  options.error.call(this, err);
1031
1017
  } else {
@@ -1037,7 +1023,6 @@
1037
1023
  value: function abort() {
1038
1024
  if (!this.aborted) {
1039
1025
  this.aborted = true;
1040
-
1041
1026
  if (this.reader) {
1042
1027
  this.reader.abort();
1043
1028
  } else if (!this.image.complete) {
@@ -1048,29 +1033,28 @@
1048
1033
  }
1049
1034
  }
1050
1035
  }
1036
+
1051
1037
  /**
1052
1038
  * Get the no conflict compressor class.
1053
1039
  * @returns {Compressor} The compressor class.
1054
1040
  */
1055
-
1056
1041
  }], [{
1057
1042
  key: "noConflict",
1058
1043
  value: function noConflict() {
1059
1044
  window.Compressor = AnotherCompressor;
1060
1045
  return Compressor;
1061
1046
  }
1047
+
1062
1048
  /**
1063
1049
  * Change the default options.
1064
1050
  * @param {Object} options - The new default options.
1065
1051
  */
1066
-
1067
1052
  }, {
1068
1053
  key: "setDefaults",
1069
1054
  value: function setDefaults(options) {
1070
1055
  _extends(DEFAULTS, options);
1071
1056
  }
1072
1057
  }]);
1073
-
1074
1058
  return Compressor;
1075
1059
  }();
1076
1060