-
Notifications
You must be signed in to change notification settings - Fork 429
/
index.js
127 lines (109 loc) · 3.4 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import toBlob from 'blueimp-canvas-to-blob';
import isBlob from 'is-blob';
import DEFAULTS from './defaults';
const URL = window.URL || window.webkitURL;
const FileReader = window.FileReader;
const REGEXP_MIME_TYPE_IMAGE = /^image\/.+$/;
/**
* Creates a new image compressor.
* @class
*/
export default class ImageCompressor {
/**
* The constructor of ImageCompressor.
* @param {File|Blob} file - The target image file for compressing.
* @param {Object} [options] - The options for compressing.
*/
constructor(file, options) {
this.result = null;
if (file) {
this.compress(file, options);
}
}
/**
* The main compress method.
* @param {File|Blob} file - The target image file for compressing.
* @param {Object} [options] - The options for compressing.
* @returns {Promise} - A Promise instance.
*/
compress(file, options) {
const image = new Image();
options = { ...DEFAULTS, ...options };
return new Promise((resolve, reject) => {
if (!isBlob(file)) {
reject('The first argument must be a File or Blob object.');
return;
}
if (!REGEXP_MIME_TYPE_IMAGE.test(file.type)) {
reject('The first argument must be an image File or Blob object.');
return;
}
if (URL) {
resolve(URL.createObjectURL(file));
} else if (FileReader) {
const reader = new FileReader();
reader.onload = e => resolve(e.file.result);
reader.onabort = reject;
reader.onerror = reject;
reader.readAsDataURL(file);
} else {
reject('The current browser does not support image compression.');
}
})
.then(url => new Promise((resolve, reject) => {
image.onload = () => {
resolve({
width: image.naturalWidth,
height: image.naturalHeight,
});
};
image.onabort = reject;
image.onerror = reject;
image.alt = file.name;
image.src = url;
}))
.then(({ width, height }) => new Promise((resolve) => {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
const aspectRatio = width / height;
let canvasWidth = width;
let canvasHeight = height;
if (options.width > 0) {
canvasWidth = options.width;
canvasHeight = canvasWidth / aspectRatio;
} else if (options.height > 0) {
canvasHeight = options.height;
canvasWidth = canvasHeight * aspectRatio;
}
canvas.width = canvasWidth;
canvas.height = canvasHeight;
context.drawImage(image, 0, 0, canvasWidth, canvasHeight);
if (canvas.toBlob) {
canvas.toBlob(resolve, file.type, options.quality);
} else {
resolve(toBlob(canvas.toDataURL(file.type, options.quality)));
}
}))
.then((result) => {
if (URL) {
URL.revokeObjectURL(image.src);
}
result.name = file.name;
// Returns original file if the result is large than it
if (result.size > file.size) {
result = file;
}
this.result = result;
if (options.success) {
options.success(result);
}
return Promise.resolve(result);
})
.catch((err) => {
if (!options.error) {
throw err;
}
options.error(new Error(err));
});
}
}