Files
Chamilo/web/assets/blueimp-load-image/js/load-image-scale.js
2025-04-10 11:37:29 +02:00

328 lines
9.0 KiB
JavaScript

/*
* 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
}
})