/** * @author j433866 [j433866@gmail.com] * @copyright Crown Copyright 2019 * @license Apache-2.0 */ import Operation from "../Operation"; import OperationError from "../errors/OperationError"; import { isImage } from "../lib/FileType"; import { toBase64 } from "../lib/Base64.mjs"; import { isWorkerEnvironment } from "../Utils"; import jimp from "jimp"; /** * Crop Image operation */ class CropImage extends Operation { /** * CropImage constructor */ constructor() { super(); this.name = "Crop Image"; this.module = "Image"; this.description = "Crops an image to the specified region, or automatically crops edges.

Autocrop
Automatically crops same-colour borders from the image.

Autocrop tolerance
A percentage value for the tolerance of colour difference between pixels.

Only autocrop frames
Only crop real frames (all sides must have the same border)

Symmetric autocrop
Force autocrop to be symmetric (top/bottom and left/right are cropped by the same amount)

Autocrop keep border
The number of pixels of border to leave around the image."; this.infoURL = "https://wikipedia.org/wiki/Cropping_(image)"; this.inputType = "ArrayBuffer"; this.outputType = "ArrayBuffer"; this.presentType = "html"; this.args = [ { name: "X Position", type: "number", value: 0, min: 0 }, { name: "Y Position", type: "number", value: 0, min: 0 }, { name: "Width", type: "number", value: 10, min: 1 }, { name: "Height", type: "number", value: 10, min: 1 }, { name: "Autocrop", type: "boolean", value: false }, { name: "Autocrop tolerance (%)", type: "number", value: 0.02, min: 0, max: 100, step: 0.01 }, { name: "Only autocrop frames", type: "boolean", value: true }, { name: "Symmetric autocrop", type: "boolean", value: false }, { name: "Autocrop keep border (px)", type: "number", value: 0, min: 0 } ]; } /** * @param {ArrayBuffer} input * @param {Object[]} args * @returns {byteArray} */ async run(input, args) { const [xPos, yPos, width, height, autocrop, autoTolerance, autoFrames, autoSymmetric, autoBorder] = args; if (!isImage(new Uint8Array(input))) { throw new OperationError("Invalid file type."); } let image; try { image = await jimp.read(input); } catch (err) { throw new OperationError(`Error loading image. (${err})`); } try { if (isWorkerEnvironment()) self.sendStatusMessage("Cropping image..."); if (autocrop) { image.autocrop({ tolerance: (autoTolerance / 100), cropOnlyFrames: autoFrames, cropSymmetric: autoSymmetric, leaveBorder: autoBorder }); } else { image.crop(xPos, yPos, width, height); } let imageBuffer; if (image.getMIME() === "image/gif") { imageBuffer = await image.getBufferAsync(jimp.MIME_PNG); } else { imageBuffer = await image.getBufferAsync(jimp.AUTO); } return imageBuffer.buffer; } catch (err) { throw new OperationError(`Error cropping image. (${err})`); } } /** * Displays the cropped image using HTML for web apps * @param {ArrayBuffer} data * @returns {html} */ present(data) { if (!data.byteLength) return ""; const dataArray = new Uint8Array(data); const type = isImage(dataArray); if (!type) { throw new OperationError("Invalid file type."); } return ``; } } export default CropImage;