UNPKG

cyberchef

Version:

The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.

152 lines (139 loc) 4.71 kB
/** * @author j433866 [j433866@gmail.com] * @copyright Crown Copyright 2019 * @license Apache-2.0 */ import Operation from "../Operation.mjs"; import OperationError from "../errors/OperationError.mjs"; import { isImage } from "../lib/FileType.mjs"; import { toBase64 } from "../lib/Base64.mjs"; import { isWorkerEnvironment } from "../Utils.mjs"; import Jimp from "jimp/es/index.js"; /** * 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.<br><br><b><u>Autocrop</u></b><br>Automatically crops same-colour borders from the image.<br><br><u>Autocrop tolerance</u><br>A percentage value for the tolerance of colour difference between pixels.<br><br><u>Only autocrop frames</u><br>Only crop real frames (all sides must have the same border)<br><br><u>Symmetric autocrop</u><br>Force autocrop to be symmetric (top/bottom and left/right are cropped by the same amount)<br><br><u>Autocrop keep border</u><br>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(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 `<img src="data:${type};base64,${toBase64(dataArray)}">`; } } export default CropImage;