UNPKG

9.22 kBJavaScriptView Raw
1/*
2 * JavaScript Load Image Scaling
3 * https://github.com/blueimp/JavaScript-Load-Image
4 *
5 * Copyright 2011, Sebastian Tschan
6 * https://blueimp.net
7 *
8 * Licensed under the MIT license:
9 * https://opensource.org/licenses/MIT
10 */
11
12/* global define, module, require */
13
14;(function (factory) {
15 'use strict'
16 if (typeof define === 'function' && define.amd) {
17 // Register as an anonymous AMD module:
18 define(['./load-image'], factory)
19 } else if (typeof module === 'object' && module.exports) {
20 factory(require('./load-image'))
21 } else {
22 // Browser globals:
23 factory(window.loadImage)
24 }
25})(function (loadImage) {
26 'use strict'
27
28 var originalTransform = loadImage.transform
29
30 loadImage.createCanvas = function (width, height, offscreen) {
31 if (offscreen && loadImage.global.OffscreenCanvas) {
32 return new OffscreenCanvas(width, height)
33 }
34 var canvas = document.createElement('canvas')
35 canvas.width = width
36 canvas.height = height
37 return canvas
38 }
39
40 loadImage.transform = function (img, options, callback, file, data) {
41 originalTransform.call(
42 loadImage,
43 loadImage.scale(img, options, data),
44 options,
45 callback,
46 file,
47 data
48 )
49 }
50
51 // Transform image coordinates, allows to override e.g.
52 // the canvas orientation based on the orientation option,
53 // gets canvas, options and data passed as arguments:
54 loadImage.transformCoordinates = function () {}
55
56 // Returns transformed options, allows to override e.g.
57 // maxWidth, maxHeight and crop options based on the aspectRatio.
58 // gets img, options, data passed as arguments:
59 loadImage.getTransformedOptions = function (img, options) {
60 var aspectRatio = options.aspectRatio
61 var newOptions
62 var i
63 var width
64 var height
65 if (!aspectRatio) {
66 return options
67 }
68 newOptions = {}
69 for (i in options) {
70 if (Object.prototype.hasOwnProperty.call(options, i)) {
71 newOptions[i] = options[i]
72 }
73 }
74 newOptions.crop = true
75 width = img.naturalWidth || img.width
76 height = img.naturalHeight || img.height
77 if (width / height > aspectRatio) {
78 newOptions.maxWidth = height * aspectRatio
79 newOptions.maxHeight = height
80 } else {
81 newOptions.maxWidth = width
82 newOptions.maxHeight = width / aspectRatio
83 }
84 return newOptions
85 }
86
87 // Canvas render method, allows to implement a different rendering algorithm:
88 loadImage.drawImage = function (
89 img,
90 canvas,
91 sourceX,
92 sourceY,
93 sourceWidth,
94 sourceHeight,
95 destWidth,
96 destHeight,
97 options
98 ) {
99 var ctx = canvas.getContext('2d')
100 if (options.imageSmoothingEnabled === false) {
101 ctx.msImageSmoothingEnabled = false
102 ctx.imageSmoothingEnabled = false
103 } else if (options.imageSmoothingQuality) {
104 ctx.imageSmoothingQuality = options.imageSmoothingQuality
105 }
106 ctx.drawImage(
107 img,
108 sourceX,
109 sourceY,
110 sourceWidth,
111 sourceHeight,
112 0,
113 0,
114 destWidth,
115 destHeight
116 )
117 return ctx
118 }
119
120 // Determines if the target image should be a canvas element:
121 loadImage.requiresCanvas = function (options) {
122 return options.canvas || options.crop || !!options.aspectRatio
123 }
124
125 // Scales and/or crops the given image (img or canvas HTML element)
126 // using the given options:
127 loadImage.scale = function (img, options, data) {
128 // eslint-disable-next-line no-param-reassign
129 options = options || {}
130 // eslint-disable-next-line no-param-reassign
131 data = data || {}
132 var useCanvas =
133 img.getContext ||
134 (loadImage.requiresCanvas(options) &&
135 !!loadImage.global.HTMLCanvasElement)
136 var width = img.naturalWidth || img.width
137 var height = img.naturalHeight || img.height
138 var destWidth = width
139 var destHeight = height
140 var maxWidth
141 var maxHeight
142 var minWidth
143 var minHeight
144 var sourceWidth
145 var sourceHeight
146 var sourceX
147 var sourceY
148 var pixelRatio
149 var downsamplingRatio
150 var tmp
151 var canvas
152 /**
153 * Scales up image dimensions
154 */
155 function scaleUp() {
156 var scale = Math.max(
157 (minWidth || destWidth) / destWidth,
158 (minHeight || destHeight) / destHeight
159 )
160 if (scale > 1) {
161 destWidth *= scale
162 destHeight *= scale
163 }
164 }
165 /**
166 * Scales down image dimensions
167 */
168 function scaleDown() {
169 var scale = Math.min(
170 (maxWidth || destWidth) / destWidth,
171 (maxHeight || destHeight) / destHeight
172 )
173 if (scale < 1) {
174 destWidth *= scale
175 destHeight *= scale
176 }
177 }
178 if (useCanvas) {
179 // eslint-disable-next-line no-param-reassign
180 options = loadImage.getTransformedOptions(img, options, data)
181 sourceX = options.left || 0
182 sourceY = options.top || 0
183 if (options.sourceWidth) {
184 sourceWidth = options.sourceWidth
185 if (options.right !== undefined && options.left === undefined) {
186 sourceX = width - sourceWidth - options.right
187 }
188 } else {
189 sourceWidth = width - sourceX - (options.right || 0)
190 }
191 if (options.sourceHeight) {
192 sourceHeight = options.sourceHeight
193 if (options.bottom !== undefined && options.top === undefined) {
194 sourceY = height - sourceHeight - options.bottom
195 }
196 } else {
197 sourceHeight = height - sourceY - (options.bottom || 0)
198 }
199 destWidth = sourceWidth
200 destHeight = sourceHeight
201 }
202 maxWidth = options.maxWidth
203 maxHeight = options.maxHeight
204 minWidth = options.minWidth
205 minHeight = options.minHeight
206 if (useCanvas && maxWidth && maxHeight && options.crop) {
207 destWidth = maxWidth
208 destHeight = maxHeight
209 tmp = sourceWidth / sourceHeight - maxWidth / maxHeight
210 if (tmp < 0) {
211 sourceHeight = (maxHeight * sourceWidth) / maxWidth
212 if (options.top === undefined && options.bottom === undefined) {
213 sourceY = (height - sourceHeight) / 2
214 }
215 } else if (tmp > 0) {
216 sourceWidth = (maxWidth * sourceHeight) / maxHeight
217 if (options.left === undefined && options.right === undefined) {
218 sourceX = (width - sourceWidth) / 2
219 }
220 }
221 } else {
222 if (options.contain || options.cover) {
223 minWidth = maxWidth = maxWidth || minWidth
224 minHeight = maxHeight = maxHeight || minHeight
225 }
226 if (options.cover) {
227 scaleDown()
228 scaleUp()
229 } else {
230 scaleUp()
231 scaleDown()
232 }
233 }
234 if (useCanvas) {
235 pixelRatio = options.pixelRatio
236 if (
237 pixelRatio > 1 &&
238 // Check if the image has not yet had the device pixel ratio applied:
239 !(
240 img.style.width &&
241 Math.floor(parseFloat(img.style.width, 10)) ===
242 Math.floor(width / pixelRatio)
243 )
244 ) {
245 destWidth *= pixelRatio
246 destHeight *= pixelRatio
247 }
248 // Check if workaround for Chromium orientation crop bug is required:
249 // https://bugs.chromium.org/p/chromium/issues/detail?id=1074354
250 if (
251 loadImage.orientationCropBug &&
252 !img.getContext &&
253 (sourceX || sourceY || sourceWidth !== width || sourceHeight !== height)
254 ) {
255 // Write the complete source image to an intermediate canvas first:
256 tmp = img
257 // eslint-disable-next-line no-param-reassign
258 img = loadImage.createCanvas(width, height, true)
259 loadImage.drawImage(
260 tmp,
261 img,
262 0,
263 0,
264 width,
265 height,
266 width,
267 height,
268 options
269 )
270 }
271 downsamplingRatio = options.downsamplingRatio
272 if (
273 downsamplingRatio > 0 &&
274 downsamplingRatio < 1 &&
275 destWidth < sourceWidth &&
276 destHeight < sourceHeight
277 ) {
278 while (sourceWidth * downsamplingRatio > destWidth) {
279 canvas = loadImage.createCanvas(
280 sourceWidth * downsamplingRatio,
281 sourceHeight * downsamplingRatio,
282 true
283 )
284 loadImage.drawImage(
285 img,
286 canvas,
287 sourceX,
288 sourceY,
289 sourceWidth,
290 sourceHeight,
291 canvas.width,
292 canvas.height,
293 options
294 )
295 sourceX = 0
296 sourceY = 0
297 sourceWidth = canvas.width
298 sourceHeight = canvas.height
299 // eslint-disable-next-line no-param-reassign
300 img = canvas
301 }
302 }
303 canvas = loadImage.createCanvas(destWidth, destHeight)
304 loadImage.transformCoordinates(canvas, options, data)
305 if (pixelRatio > 1) {
306 canvas.style.width = canvas.width / pixelRatio + 'px'
307 }
308 loadImage
309 .drawImage(
310 img,
311 canvas,
312 sourceX,
313 sourceY,
314 sourceWidth,
315 sourceHeight,
316 destWidth,
317 destHeight,
318 options
319 )
320 .setTransform(1, 0, 0, 1, 0, 0) // reset to the identity matrix
321 return canvas
322 }
323 img.width = destWidth
324 img.height = destHeight
325 return img
326 }
327})