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