UNPKG

blueimp-load-image

Version:

JavaScript Load Image is a library to load images provided as File or Blob objects or via URL. It returns an optionally scaled, cropped or rotated HTML img or canvas element. It also provides methods to parse image metadata to extract IPTC and Exif tags a

328 lines (317 loc) 9.22 kB
/* * 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 } })