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