| // Copyright 2017 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import {assert} from 'chrome://resources/js/assert.js'; |
| |
| import {isImageOrientation} from './image_orientation.js'; |
| import type {LoadImageRequest} from './load_image_request.js'; |
| |
| /** |
| * Checks if the options on the request contain any image processing. |
| * |
| * @param width Source width. |
| * @param height Source height. |
| * @param request The request, containing resizing options. |
| * @return True if yes, false if not. |
| */ |
| export function shouldProcess( |
| width: number, height: number, request: LoadImageRequest): boolean { |
| const targetDimensions = resizeDimensions(width, height, request); |
| |
| // Dimensions has to be adjusted. |
| if (targetDimensions.width !== width || targetDimensions.height !== height) { |
| return true; |
| } |
| |
| // Orientation has to be adjusted. |
| if (isImageOrientation(request.orientation) && |
| !request.orientation.isIdentity()) { |
| return true; |
| } |
| |
| // No changes required. |
| return false; |
| } |
| |
| /** |
| * Calculates dimensions taking into account resize options, such as: |
| * - scale: for scaling, |
| * - maxWidth, maxHeight: for maximum dimensions, |
| * - width, height: for exact requested size. |
| * Returns the target size as hash array with width, height properties. |
| * |
| * @param width Source width. |
| * @param height Source height. |
| * @param request The request, containing resizing options. |
| * @return Dimensions. |
| */ |
| export function resizeDimensions( |
| width: number, height: number, |
| request: LoadImageRequest): {width: number, height: number} { |
| const scale = request.scale || 1; |
| assert(isImageOrientation(request.orientation)); |
| const targetDimensions = |
| request.orientation.getSizeAfterCancelling(width * scale, height * scale); |
| let targetWidth = targetDimensions.width; |
| let targetHeight = targetDimensions.height; |
| |
| if (request.maxWidth && targetWidth > request.maxWidth) { |
| const scale = request.maxWidth / targetWidth; |
| targetWidth *= scale; |
| targetHeight *= scale; |
| } |
| |
| if (request.maxHeight && targetHeight > request.maxHeight) { |
| const scale = request.maxHeight / targetHeight; |
| targetWidth *= scale; |
| targetHeight *= scale; |
| } |
| |
| if (request.width) { |
| targetWidth = request.width; |
| } |
| |
| if (request.height) { |
| targetHeight = request.height; |
| } |
| |
| targetWidth = Math.round(targetWidth); |
| targetHeight = Math.round(targetHeight); |
| |
| return {width: targetWidth, height: targetHeight}; |
| } |
| |
| /** |
| * Performs resizing and cropping of the source image into the target canvas. |
| * |
| * @param source Source image or canvas. |
| * @param target Target canvas. |
| * @param request The request, containing resizing options. |
| */ |
| export function resizeAndCrop( |
| source: HTMLCanvasElement|HTMLImageElement, target: HTMLCanvasElement, |
| request: LoadImageRequest) { |
| // Calculates copy parameters. |
| const copyParameters = calculateCopyParameters(source, request); |
| target.width = copyParameters.canvas.width; |
| target.height = copyParameters.canvas.height; |
| |
| // Apply. |
| const targetContext = target.getContext('2d')!; |
| targetContext.save(); |
| assert(isImageOrientation(request.orientation)); |
| request.orientation.cancelImageOrientation( |
| targetContext, copyParameters.target.width, copyParameters.target.height); |
| targetContext.drawImage( |
| source, copyParameters.source.x, copyParameters.source.y, |
| copyParameters.source.width, copyParameters.source.height, |
| copyParameters.target.x, copyParameters.target.y, |
| copyParameters.target.width, copyParameters.target.height); |
| targetContext.restore(); |
| } |
| |
| export interface CopyParameters { |
| source: {x: number, y: number, width: number, height: number}; |
| target: {x: number, y: number, width: number, height: number}; |
| canvas: {width: number, height: number}; |
| } |
| |
| /** |
| * Calculates copy parameters. |
| * |
| * @param source Source image or canvas. |
| * @param request The request, containing resizing options. |
| * @return Calculated copy parameters. |
| */ |
| export function calculateCopyParameters( |
| source: HTMLCanvasElement|HTMLImageElement, |
| request: LoadImageRequest): CopyParameters { |
| if (request.crop) { |
| // When an image is cropped, target should be a fixed size square. |
| assert(request.width); |
| assert(request.height); |
| assert(request.width === request.height); |
| |
| // The length of shorter edge becomes dimension of cropped area in the |
| // source. |
| const cropSourceDimension = Math.min(source.width, source.height); |
| |
| return { |
| source: { |
| x: Math.floor((source.width / 2) - (cropSourceDimension / 2)), |
| y: Math.floor((source.height / 2) - (cropSourceDimension / 2)), |
| width: cropSourceDimension, |
| height: cropSourceDimension, |
| }, |
| target: { |
| x: 0, |
| y: 0, |
| width: request.width!, |
| height: request.height!, |
| }, |
| canvas: { |
| width: request.width!, |
| height: request.height!, |
| }, |
| }; |
| } |
| |
| // Target dimension is calculated in the rotated(transformed) coordinate. |
| const targetCanvasDimensions = |
| resizeDimensions(source.width, source.height, request); |
| |
| assert(isImageOrientation(request.orientation)); |
| const targetDimensions = request.orientation.getSizeAfterCancelling( |
| targetCanvasDimensions.width, targetCanvasDimensions.height); |
| |
| return { |
| source: { |
| x: 0, |
| y: 0, |
| width: source.width, |
| height: source.height, |
| }, |
| target: { |
| x: 0, |
| y: 0, |
| width: targetDimensions.width, |
| height: targetDimensions.height, |
| }, |
| canvas: { |
| width: targetCanvasDimensions.width, |
| height: targetCanvasDimensions.height, |
| }, |
| }; |
| } |