/* * JavaScript Load Image Scaling * https://github.com/blueimp/JavaScript-Load-Image * * Copyright 2011, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: * https://opensource.org/licenses/MIT */ /* global define, module, require */ ;(function (factory) { 'use strict' if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: define(['./load-image'], factory) } else if (typeof module === 'object' && module.exports) { factory(require('./load-image')) } else { // Browser globals: factory(window.loadImage) } })(function (loadImage) { 'use strict' var originalTransform = loadImage.transform loadImage.createCanvas = function (width, height, offscreen) { if (offscreen && loadImage.global.OffscreenCanvas) { return new OffscreenCanvas(width, height) } var canvas = document.createElement('canvas') canvas.width = width canvas.height = height return canvas } loadImage.transform = function (img, options, callback, file, data) { originalTransform.call( loadImage, loadImage.scale(img, options, data), options, callback, file, data ) } // Transform image coordinates, allows to override e.g. // the canvas orientation based on the orientation option, // gets canvas, options and data passed as arguments: loadImage.transformCoordinates = function () {} // Returns transformed options, allows to override e.g. // maxWidth, maxHeight and crop options based on the aspectRatio. // gets img, options, data passed as arguments: loadImage.getTransformedOptions = function (img, options) { var aspectRatio = options.aspectRatio var newOptions var i var width var height if (!aspectRatio) { return options } newOptions = {} for (i in options) { if (Object.prototype.hasOwnProperty.call(options, i)) { newOptions[i] = options[i] } } newOptions.crop = true width = img.naturalWidth || img.width height = img.naturalHeight || img.height if (width / height > aspectRatio) { newOptions.maxWidth = height * aspectRatio newOptions.maxHeight = height } else { newOptions.maxWidth = width newOptions.maxHeight = width / aspectRatio } return newOptions } // Canvas render method, allows to implement a different rendering algorithm: loadImage.drawImage = function ( img, canvas, sourceX, sourceY, sourceWidth, sourceHeight, destWidth, destHeight, options ) { var ctx = canvas.getContext('2d') if (options.imageSmoothingEnabled === false) { ctx.msImageSmoothingEnabled = false ctx.imageSmoothingEnabled = false } else if (options.imageSmoothingQuality) { ctx.imageSmoothingQuality = options.imageSmoothingQuality } ctx.drawImage( img, sourceX, sourceY, sourceWidth, sourceHeight, 0, 0, destWidth, destHeight ) return ctx } // Determines if the target image should be a canvas element: loadImage.requiresCanvas = function (options) { return options.canvas || options.crop || !!options.aspectRatio } // Scales and/or crops the given image (img or canvas HTML element) // using the given options: loadImage.scale = function (img, options, data) { // eslint-disable-next-line no-param-reassign options = options || {} // eslint-disable-next-line no-param-reassign data = data || {} var useCanvas = img.getContext || (loadImage.requiresCanvas(options) && !!loadImage.global.HTMLCanvasElement) var width = img.naturalWidth || img.width var height = img.naturalHeight || img.height var destWidth = width var destHeight = height var maxWidth var maxHeight var minWidth var minHeight var sourceWidth var sourceHeight var sourceX var sourceY var pixelRatio var downsamplingRatio var tmp var canvas /** * Scales up image dimensions */ function scaleUp() { var scale = Math.max( (minWidth || destWidth) / destWidth, (minHeight || destHeight) / destHeight ) if (scale > 1) { destWidth *= scale destHeight *= scale } } /** * Scales down image dimensions */ function scaleDown() { var scale = Math.min( (maxWidth || destWidth) / destWidth, (maxHeight || destHeight) / destHeight ) if (scale < 1) { destWidth *= scale destHeight *= scale } } if (useCanvas) { // eslint-disable-next-line no-param-reassign options = loadImage.getTransformedOptions(img, options, data) sourceX = options.left || 0 sourceY = options.top || 0 if (options.sourceWidth) { sourceWidth = options.sourceWidth if (options.right !== undefined && options.left === undefined) { sourceX = width - sourceWidth - options.right } } else { sourceWidth = width - sourceX - (options.right || 0) } if (options.sourceHeight) { sourceHeight = options.sourceHeight if (options.bottom !== undefined && options.top === undefined) { sourceY = height - sourceHeight - options.bottom } } else { sourceHeight = height - sourceY - (options.bottom || 0) } destWidth = sourceWidth destHeight = sourceHeight } maxWidth = options.maxWidth maxHeight = options.maxHeight minWidth = options.minWidth minHeight = options.minHeight if (useCanvas && maxWidth && maxHeight && options.crop) { destWidth = maxWidth destHeight = maxHeight tmp = sourceWidth / sourceHeight - maxWidth / maxHeight if (tmp < 0) { sourceHeight = (maxHeight * sourceWidth) / maxWidth if (options.top === undefined && options.bottom === undefined) { sourceY = (height - sourceHeight) / 2 } } else if (tmp > 0) { sourceWidth = (maxWidth * sourceHeight) / maxHeight if (options.left === undefined && options.right === undefined) { sourceX = (width - sourceWidth) / 2 } } } else { if (options.contain || options.cover) { minWidth = maxWidth = maxWidth || minWidth minHeight = maxHeight = maxHeight || minHeight } if (options.cover) { scaleDown() scaleUp() } else { scaleUp() scaleDown() } } if (useCanvas) { pixelRatio = options.pixelRatio if ( pixelRatio > 1 && // Check if the image has not yet had the device pixel ratio applied: !( img.style.width && Math.floor(parseFloat(img.style.width, 10)) === Math.floor(width / pixelRatio) ) ) { destWidth *= pixelRatio destHeight *= pixelRatio } // Check if workaround for Chromium orientation crop bug is required: // https://bugs.chromium.org/p/chromium/issues/detail?id=1074354 if ( loadImage.orientationCropBug && !img.getContext && (sourceX || sourceY || sourceWidth !== width || sourceHeight !== height) ) { // Write the complete source image to an intermediate canvas first: tmp = img // eslint-disable-next-line no-param-reassign img = loadImage.createCanvas(width, height, true) loadImage.drawImage( tmp, img, 0, 0, width, height, width, height, options ) } downsamplingRatio = options.downsamplingRatio if ( downsamplingRatio > 0 && downsamplingRatio < 1 && destWidth < sourceWidth && destHeight < sourceHeight ) { while (sourceWidth * downsamplingRatio > destWidth) { canvas = loadImage.createCanvas( sourceWidth * downsamplingRatio, sourceHeight * downsamplingRatio, true ) loadImage.drawImage( img, canvas, sourceX, sourceY, sourceWidth, sourceHeight, canvas.width, canvas.height, options ) sourceX = 0 sourceY = 0 sourceWidth = canvas.width sourceHeight = canvas.height // eslint-disable-next-line no-param-reassign img = canvas } } canvas = loadImage.createCanvas(destWidth, destHeight) loadImage.transformCoordinates(canvas, options, data) if (pixelRatio > 1) { canvas.style.width = canvas.width / pixelRatio + 'px' } loadImage .drawImage( img, canvas, sourceX, sourceY, sourceWidth, sourceHeight, destWidth, destHeight, options ) .setTransform(1, 0, 0, 1, 0, 0) // reset to the identity matrix return canvas } img.width = destWidth img.height = destHeight return img } })