refactor(Multimedia): centralize Jimp configuration and enable WebP output

- Creates src/core/lib/Jimp.mjs to centralize Jimp instance with WebP support\n- Updates all image operations to use the centralized Jimp wrapper\n- Enables WEBP as an output format in 'Convert Image Format' operation\n- Adds quality support for WebP output
This commit is contained in:
Reuben Percival 2026-03-15 09:17:00 +00:00
parent 84ccd2f867
commit e24006d809
No known key found for this signature in database
GPG Key ID: C7D5099A6D762DFB
24 changed files with 58 additions and 41 deletions

21
src/core/lib/Jimp.mjs Normal file
View File

@ -0,0 +1,21 @@
/**
* Jimp image library with additional plugins.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2024
* @license Apache-2.0
*/
import { Jimp as BaseJimp, JimpMime, PNGFilterType, ResizeStrategy, EdgeAction } from "jimp";
import webp from "@jimp/wasm-webp";
/**
* Configure Jimp with WebP support
*/
const Jimp = new BaseJimp({
plugins: [webp],
formats: [webp]
});
export { Jimp, JimpMime, PNGFilterType, ResizeStrategy, EdgeAction };
export default Jimp;

View File

@ -16,7 +16,7 @@ import {
measureText, measureText,
measureTextHeight, measureTextHeight,
loadFont, loadFont,
} from "jimp"; } from "../lib/Jimp.mjs";
/** /**
* Add Text To Image operation * Add Text To Image operation

View File

@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
import { isWorkerEnvironment } from "../Utils.mjs"; import { isWorkerEnvironment } from "../Utils.mjs";
import { isImage } from "../lib/FileType.mjs"; import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs"; import { toBase64 } from "../lib/Base64.mjs";
import { Jimp, JimpMime } from "jimp"; import { Jimp, JimpMime } from "../lib/Jimp.mjs";
/** /**
* Blur Image operation * Blur Image operation

View File

@ -15,7 +15,7 @@ import {
ResizeStrategy, ResizeStrategy,
HorizontalAlign, HorizontalAlign,
VerticalAlign, VerticalAlign,
} from "jimp"; } from "../lib/Jimp.mjs";
/** /**
* Contain Image operation * Contain Image operation

View File

@ -8,16 +8,7 @@ import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs"; import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs"; import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs"; import { toBase64 } from "../lib/Base64.mjs";
import { Jimp as BaseJimp, JimpMime, PNGFilterType } from "jimp"; import { Jimp, JimpMime, PNGFilterType } from "../lib/Jimp.mjs";
import webp from "@jimp/wasm-webp";
/**
* Configure Jimp with WebP support
*/
const Jimp = new BaseJimp({
plugins: [webp],
formats: [webp]
});
function canTranscodeViaCanvas() { function canTranscodeViaCanvas() {
return ( return (
@ -31,7 +22,7 @@ function canTranscodeViaCanvas() {
} }
async function transcodeViaCanvas(input, inputMime, outputMime, quality) { async function transcodeViaCanvas(input, inputMime, outputMime, quality) {
const {Blob: BlobCtor, createImageBitmap: createImageBitmapFn, OffscreenCanvas: OffscreenCanvasCtor, document} = const { Blob: BlobCtor, createImageBitmap: createImageBitmapFn, OffscreenCanvas: OffscreenCanvasCtor, document } =
globalThis; globalThis;
const inputBytes = input instanceof ArrayBuffer ? new Uint8Array(input) : input; const inputBytes = input instanceof ArrayBuffer ? new Uint8Array(input) : input;
@ -52,7 +43,7 @@ async function transcodeViaCanvas(input, inputMime, outputMime, quality) {
const ctx = canvas.getContext("2d"); const ctx = canvas.getContext("2d");
if (!ctx) throw new Error("Unable to initialise canvas context"); if (!ctx) throw new Error("Unable to initialise canvas context");
if (outputMime === "image/jpeg") { if (outputMime === "image/jpeg" || outputMime === "image/webp") {
ctx.fillStyle = "#ffffff"; ctx.fillStyle = "#ffffff";
ctx.fillRect(0, 0, bitmap.width, bitmap.height); ctx.fillRect(0, 0, bitmap.width, bitmap.height);
} }
@ -98,7 +89,7 @@ class ConvertImageFormat extends Operation {
this.name = "Convert Image Format"; this.name = "Convert Image Format";
this.module = "Image"; this.module = "Image";
this.description = this.description =
"Converts an image between different formats. Supported output formats:<br><ul><li>Joint Photographic Experts Group (JPEG)</li><li>Portable Network Graphics (PNG)</li><li>Bitmap (BMP)</li><li>Tagged Image File Format (TIFF)</li></ul><br>Note: GIF and WebP files are supported for input, but cannot be outputted."; "Converts an image between different formats. Supported output formats:<br><ul><li>Joint Photographic Experts Group (JPEG)</li><li>Portable Network Graphics (PNG)</li><li>Bitmap (BMP)</li><li>Tagged Image File Format (TIFF)</li><li>WebP</li></ul><br>Note: GIF files are supported for input, but cannot be outputted.";
this.infoURL = "https://wikipedia.org/wiki/Image_file_formats"; this.infoURL = "https://wikipedia.org/wiki/Image_file_formats";
this.inputType = "ArrayBuffer"; this.inputType = "ArrayBuffer";
this.outputType = "ArrayBuffer"; this.outputType = "ArrayBuffer";
@ -107,10 +98,10 @@ class ConvertImageFormat extends Operation {
{ {
name: "Output Format", name: "Output Format",
type: "option", type: "option",
value: ["JPEG", "PNG", "BMP", "TIFF"], value: ["JPEG", "PNG", "BMP", "TIFF", "WEBP"],
}, },
{ {
name: "JPEG Quality", name: "Quality (JPEG/WebP)",
type: "number", type: "number",
value: 80, value: 80,
min: 1, min: 1,
@ -137,12 +128,13 @@ class ConvertImageFormat extends Operation {
* @returns {byteArray} * @returns {byteArray}
*/ */
async run(input, args) { async run(input, args) {
const [format, jpegQuality, pngFilterType, pngDeflateLevel] = args; const [format, quality, pngFilterType, pngDeflateLevel] = args;
const formatMap = { const formatMap = {
JPEG: JimpMime.jpeg, JPEG: JimpMime.jpeg,
PNG: JimpMime.png, PNG: JimpMime.png,
BMP: JimpMime.bmp, BMP: JimpMime.bmp,
TIFF: JimpMime.tiff, TIFF: JimpMime.tiff,
WEBP: "image/webp",
}; };
const pngFilterMap = { const pngFilterMap = {
@ -167,8 +159,11 @@ class ConvertImageFormat extends Operation {
canTranscodeViaCanvas() canTranscodeViaCanvas()
) { ) {
try { try {
const outputMime = mime === JimpMime.jpeg ? "image/jpeg" : "image/png"; let outputMime;
const quality = outputMime === "image/jpeg" ? jpegQuality : undefined; if (mime === JimpMime.jpeg) outputMime = "image/jpeg";
else if (mime === "image/webp") outputMime = "image/webp";
else outputMime = "image/png";
return await transcodeViaCanvas(input, inputMime, outputMime, quality); return await transcodeViaCanvas(input, inputMime, outputMime, quality);
} catch (err) { } catch (err) {
// If canvas fails, we can fall back to Jimp // If canvas fails, we can fall back to Jimp
@ -185,8 +180,9 @@ class ConvertImageFormat extends Operation {
let buffer; let buffer;
switch (mime) { switch (mime) {
case JimpMime.jpeg: case JimpMime.jpeg:
case "image/webp":
buffer = await image.getBuffer(mime, { buffer = await image.getBuffer(mime, {
quality: jpegQuality, quality: quality,
}); });
break; break;
case JimpMime.png: case JimpMime.png:

View File

@ -15,7 +15,7 @@ import {
ResizeStrategy, ResizeStrategy,
HorizontalAlign, HorizontalAlign,
VerticalAlign, VerticalAlign,
} from "jimp"; } from "../lib/Jimp.mjs";
/** /**
* Cover Image operation * Cover Image operation

View File

@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs"; import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs"; import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs"; import { isWorkerEnvironment } from "../Utils.mjs";
import { Jimp, JimpMime } from "jimp"; import { Jimp, JimpMime } from "../lib/Jimp.mjs";
/** /**
* Crop Image operation * Crop Image operation

View File

@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs"; import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs"; import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs"; import { isWorkerEnvironment } from "../Utils.mjs";
import { Jimp, JimpMime } from "jimp"; import { Jimp, JimpMime } from "../lib/Jimp.mjs";
/** /**
* Image Dither operation * Image Dither operation

View File

@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
import Utils from "../Utils.mjs"; import Utils from "../Utils.mjs";
import { fromBinary } from "../lib/Binary.mjs"; import { fromBinary } from "../lib/Binary.mjs";
import { isImage } from "../lib/FileType.mjs"; import { isImage } from "../lib/FileType.mjs";
import { Jimp } from "jimp"; import { Jimp } from "../lib/Jimp.mjs";
/** /**
* Extract LSB operation * Extract LSB operation

View File

@ -7,7 +7,7 @@
import Operation from "../Operation.mjs"; import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs"; import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs"; import { isImage } from "../lib/FileType.mjs";
import { Jimp } from "jimp"; import { Jimp } from "../lib/Jimp.mjs";
import { RGBA_DELIM_OPTIONS } from "../lib/Delim.mjs"; import { RGBA_DELIM_OPTIONS } from "../lib/Delim.mjs";

View File

@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs"; import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs"; import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs"; import { isWorkerEnvironment } from "../Utils.mjs";
import { Jimp, JimpMime } from "jimp"; import { Jimp, JimpMime } from "../lib/Jimp.mjs";
/** /**
* Flip Image operation * Flip Image operation

View File

@ -10,7 +10,7 @@ import Utils from "../Utils.mjs";
import { isImage } from "../lib/FileType.mjs"; import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs"; import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs"; import { isWorkerEnvironment } from "../Utils.mjs";
import { Jimp, JimpMime, ResizeStrategy, rgbaToInt } from "jimp"; import { Jimp, JimpMime, ResizeStrategy, rgbaToInt } from "../lib/Jimp.mjs";
/** /**
* Generate Image operation * Generate Image operation

View File

@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs"; import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs"; import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs"; import { isWorkerEnvironment } from "../Utils.mjs";
import { Jimp, JimpMime } from "jimp"; import { Jimp, JimpMime } from "../lib/Jimp.mjs";
/** /**
* Image Brightness / Contrast operation * Image Brightness / Contrast operation

View File

@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs"; import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs"; import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs"; import { isWorkerEnvironment } from "../Utils.mjs";
import { Jimp, JimpMime } from "jimp"; import { Jimp, JimpMime } from "../lib/Jimp.mjs";
/** /**
* Image Filter operation * Image Filter operation

View File

@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs"; import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs"; import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs"; import { isWorkerEnvironment } from "../Utils.mjs";
import { Jimp, JimpMime } from "jimp"; import { Jimp, JimpMime } from "../lib/Jimp.mjs";
/** /**
* Image Hue/Saturation/Lightness operation * Image Hue/Saturation/Lightness operation

View File

@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs"; import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs"; import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs"; import { isWorkerEnvironment } from "../Utils.mjs";
import { Jimp, JimpMime } from "jimp"; import { Jimp, JimpMime } from "../lib/Jimp.mjs";
/** /**
* Image Opacity operation * Image Opacity operation

View File

@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs"; import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs"; import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs"; import { isWorkerEnvironment } from "../Utils.mjs";
import { Jimp, JimpMime } from "jimp"; import { Jimp, JimpMime } from "../lib/Jimp.mjs";
/** /**
* Invert Image operation * Invert Image operation

View File

@ -8,7 +8,7 @@ import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs"; import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs"; import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs"; import { toBase64 } from "../lib/Base64.mjs";
import { Jimp, JimpMime } from "jimp"; import { Jimp, JimpMime } from "../lib/Jimp.mjs";
/** /**
* Normalise Image operation * Normalise Image operation

View File

@ -10,7 +10,7 @@ import Utils from "../Utils.mjs";
import { isImage } from "../lib/FileType.mjs"; import { isImage } from "../lib/FileType.mjs";
import { runHash } from "../lib/Hash.mjs"; import { runHash } from "../lib/Hash.mjs";
import { toBase64 } from "../lib/Base64.mjs"; import { toBase64 } from "../lib/Base64.mjs";
import { Jimp } from "jimp"; import { Jimp } from "../lib/Jimp.mjs";
/** /**
* Randomize Colour Palette operation * Randomize Colour Palette operation

View File

@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs"; import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs"; import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs"; import { isWorkerEnvironment } from "../Utils.mjs";
import { Jimp, JimpMime, ResizeStrategy } from "jimp"; import { Jimp, JimpMime, ResizeStrategy } from "../lib/Jimp.mjs";
/** /**
* Resize Image operation * Resize Image operation

View File

@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs"; import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs"; import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs"; import { isWorkerEnvironment } from "../Utils.mjs";
import { Jimp, JimpMime } from "jimp"; import { Jimp, JimpMime } from "../lib/Jimp.mjs";
/** /**
* Rotate Image operation * Rotate Image operation

View File

@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs"; import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs"; import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs"; import { isWorkerEnvironment } from "../Utils.mjs";
import { Jimp, JimpMime } from "jimp"; import { Jimp, JimpMime } from "../lib/Jimp.mjs";
/** /**
* Sharpen Image operation * Sharpen Image operation

View File

@ -8,7 +8,7 @@ import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs"; import OperationError from "../errors/OperationError.mjs";
import Utils from "../Utils.mjs"; import Utils from "../Utils.mjs";
import { isImage } from "../lib/FileType.mjs"; import { isImage } from "../lib/FileType.mjs";
import { Jimp, JimpMime } from "jimp"; import { Jimp, JimpMime } from "../lib/Jimp.mjs";
/** /**
* Split Colour Channels operation * Split Colour Channels operation

View File

@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
import Utils from "../Utils.mjs"; import Utils from "../Utils.mjs";
import { isImage } from "../lib/FileType.mjs"; import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs"; import { toBase64 } from "../lib/Base64.mjs";
import { Jimp } from "jimp"; import { Jimp } from "../lib/Jimp.mjs";
/** /**
* View Bit Plane operation * View Bit Plane operation