From 21a8d0320190644148072e45ed46610fbb14824e Mon Sep 17 00:00:00 2001 From: j433866 Date: Thu, 7 Mar 2019 13:21:26 +0000 Subject: [PATCH 01/27] Move parsing and generation of QR codes to lib folder. Also rewrote QR code parsing to be more readable and actually error out properly. --- src/core/lib/QRCode.mjs | 90 ++++++++++++++++++++++++++ src/core/operations/GenerateQRCode.mjs | 26 +------- src/core/operations/ParseQRCode.mjs | 60 ++--------------- 3 files changed, 96 insertions(+), 80 deletions(-) create mode 100644 src/core/lib/QRCode.mjs diff --git a/src/core/lib/QRCode.mjs b/src/core/lib/QRCode.mjs new file mode 100644 index 00000000..bf134367 --- /dev/null +++ b/src/core/lib/QRCode.mjs @@ -0,0 +1,90 @@ +/** + * QR code resources + * + * @author j433866 [j433866@gmail.com] + * @copyright Crown Copyright 2019 + * @license Apache-2.0 + */ + +import OperationError from "../errors/OperationError"; +import jsQR from "jsqr"; +import qr from "qr-image"; +import jimp from "jimp"; + +/** + * Parses a QR code image from an image + * + * @param {byteArray} input + * @param {boolean} normalise + * @returns {string} + */ +export async function parseQrCode(input, normalise) { + let image; + try { + image = await jimp.read(Buffer.from(input)); + } catch (err) { + throw new OperationError(`Error opening image. (${err})`); + } + + try { + if (normalise) { + image.rgba(false); + image.background(0xFFFFFFFF); + image.normalize(); + image.greyscale(); + } + } catch (err) { + throw new OperationError(`Error normalising iamge. (${err})`); + } + + const qrData = jsQR(image.bitmap.data, image.getWidth(), image.getHeight()); + if (qrData) { + return qrData.data; + } else { + throw new OperationError("Could not read a QR code from the image."); + } +} + +/** + * Generates a QR code from the input string + * + * @param {string} input + * @param {string} format + * @param {number} moduleSize + * @param {number} margin + * @param {string} errorCorrection + * @returns {byteArray} + */ +export function generateQrCode(input, format, moduleSize, margin, errorCorrection) { + const formats = ["SVG", "EPS", "PDF", "PNG"]; + if (!formats.includes(format.toUpperCase())) { + throw new OperationError("Unsupported QR code format."); + } + + let qrImage; + try { + qrImage = qr.imageSync(input, { + type: format, + size: moduleSize, + margin: margin, + "ec_level": errorCorrection.charAt(0).toUpperCase() + }); + } catch (err) { + throw new OperationError(`Error generating QR code. (${err})`); + } + + if (!qrImage) { + throw new OperationError("Error generating QR code."); + } + + switch (format) { + case "SVG": + case "EPS": + case "PDF": + return [...Buffer.from(qrImage)]; + case "PNG": + return [...qrImage]; + default: + throw new OperationError("Unsupported QR code format."); + } +} diff --git a/src/core/operations/GenerateQRCode.mjs b/src/core/operations/GenerateQRCode.mjs index edab6d40..4e1983e5 100644 --- a/src/core/operations/GenerateQRCode.mjs +++ b/src/core/operations/GenerateQRCode.mjs @@ -6,7 +6,7 @@ import Operation from "../Operation"; import OperationError from "../errors/OperationError"; -import qr from "qr-image"; +import { generateQrCode } from "../lib/QRCode"; import { toBase64 } from "../lib/Base64"; import Magic from "../lib/Magic"; import Utils from "../Utils"; @@ -62,29 +62,7 @@ class GenerateQRCode extends Operation { run(input, args) { const [format, size, margin, errorCorrection] = args; - // Create new QR image from the input data, and convert it to a buffer - const qrImage = qr.imageSync(input, { - type: format, - size: size, - margin: margin, - "ec_level": errorCorrection.charAt(0).toUpperCase() - }); - - if (qrImage == null) { - throw new OperationError("Error generating QR code."); - } - - switch (format) { - case "SVG": - case "EPS": - case "PDF": - return [...Buffer.from(qrImage)]; - case "PNG": - // Return the QR image buffer as a byte array - return [...qrImage]; - default: - throw new OperationError("Unsupported QR code format."); - } + return generateQrCode(input, format, size, margin, errorCorrection); } /** diff --git a/src/core/operations/ParseQRCode.mjs b/src/core/operations/ParseQRCode.mjs index 75a24d55..816b6e75 100644 --- a/src/core/operations/ParseQRCode.mjs +++ b/src/core/operations/ParseQRCode.mjs @@ -7,8 +7,7 @@ import Operation from "../Operation"; import OperationError from "../errors/OperationError"; import Magic from "../lib/Magic"; -import jsqr from "jsqr"; -import jimp from "jimp"; +import { parseQrCode } from "../lib/QRCode"; /** * Parse QR Code operation @@ -42,64 +41,13 @@ class ParseQRCode extends Operation { * @returns {string} */ async run(input, args) { - const type = Magic.magicFileType(input); const [normalise] = args; + const type = Magic.magicFileType(input); - // Make sure that the input is an image - if (type && type.mime.indexOf("image") === 0) { - let image = input; - - if (normalise) { - // Process the image to be easier to read by jsqr - // Disables the alpha channel - // Sets the image default background to white - // Normalises the image colours - // Makes the image greyscale - // Converts image to a JPEG - image = await new Promise((resolve, reject) => { - jimp.read(Buffer.from(input)) - .then(image => { - image - .rgba(false) - .background(0xFFFFFFFF) - .normalize() - .greyscale() - .getBuffer(jimp.MIME_JPEG, (error, result) => { - resolve(result); - }); - }) - .catch(err => { - reject(new OperationError("Error reading the image file.")); - }); - }); - } - - if (image instanceof OperationError) { - throw image; - } - - return new Promise((resolve, reject) => { - jimp.read(Buffer.from(image)) - .then(image => { - if (image.bitmap != null) { - const qrData = jsqr(image.bitmap.data, image.getWidth(), image.getHeight()); - if (qrData != null) { - resolve(qrData.data); - } else { - reject(new OperationError("Couldn't read a QR code from the image.")); - } - } else { - reject(new OperationError("Error reading the image file.")); - } - }) - .catch(err => { - reject(new OperationError("Error reading the image file.")); - }); - }); - } else { + if (!type || type.mime.indexOf("image") !== 0) { throw new OperationError("Invalid file type."); } - + return await parseQrCode(input, normalise); } } From 11451ac6b9f42e22a446d6c5e5e95259895dbed3 Mon Sep 17 00:00:00 2001 From: j433866 Date: Thu, 7 Mar 2019 13:35:37 +0000 Subject: [PATCH 02/27] Add image format pattern. ("borrowed" from RenderImage) --- src/core/operations/ParseQRCode.mjs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/core/operations/ParseQRCode.mjs b/src/core/operations/ParseQRCode.mjs index 816b6e75..d929500b 100644 --- a/src/core/operations/ParseQRCode.mjs +++ b/src/core/operations/ParseQRCode.mjs @@ -33,6 +33,14 @@ class ParseQRCode extends Operation { "value": false } ]; + this.patterns = [ + { + "match": "^(?:\\xff\\xd8\\xff|\\x89\\x50\\x4e\\x47|\\x47\\x49\\x46|.{8}\\x57\\x45\\x42\\x50|\\x42\\x4d)", + "flags": "", + "args": [false], + "useful": true + } + ]; } /** From 3e428c044ac6e6bc13b232d8fdb91f0c36875a78 Mon Sep 17 00:00:00 2001 From: j433866 Date: Fri, 8 Mar 2019 13:38:59 +0000 Subject: [PATCH 03/27] Add min values to operation args --- src/core/operations/GenerateQRCode.mjs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/core/operations/GenerateQRCode.mjs b/src/core/operations/GenerateQRCode.mjs index 4e1983e5..d88eee15 100644 --- a/src/core/operations/GenerateQRCode.mjs +++ b/src/core/operations/GenerateQRCode.mjs @@ -38,12 +38,14 @@ class GenerateQRCode extends Operation { { "name": "Module size (px)", "type": "number", - "value": 5 + "value": 5, + "min": 1 }, { "name": "Margin (num modules)", "type": "number", - "value": 2 + "value": 2, + "min": 0 }, { "name": "Error correction", From dfbc1beccd21467e2fc72e9d8fa67421c7c8a4ed Mon Sep 17 00:00:00 2001 From: j433866 Date: Tue, 12 Mar 2019 16:24:43 +0000 Subject: [PATCH 04/27] Add sharpen image operation --- src/core/config/Categories.json | 3 +- src/core/operations/SharpenImage.mjs | 161 +++++++++++++++++++++++++++ 2 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 src/core/operations/SharpenImage.mjs diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 115e8436..2edc50ab 100755 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -374,7 +374,8 @@ "Image Filter", "Contain Image", "Cover Image", - "Image Hue/Saturation/Lightness" + "Image Hue/Saturation/Lightness", + "Sharpen Image" ] }, { diff --git a/src/core/operations/SharpenImage.mjs b/src/core/operations/SharpenImage.mjs new file mode 100644 index 00000000..db0e7bb7 --- /dev/null +++ b/src/core/operations/SharpenImage.mjs @@ -0,0 +1,161 @@ +/** + * @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"; +import jimp from "jimp"; + +/** + * Sharpen Image operation + */ +class SharpenImage extends Operation { + + /** + * SharpenImage constructor + */ + constructor() { + super(); + + this.name = "Sharpen Image"; + this.module = "Image"; + this.description = "Sharpens an image (Unsharp mask)"; + this.infoURL = "https://wikipedia.org/wiki/Unsharp_masking"; + this.inputType = "byteArray"; + this.outputType = "byteArray"; + this.presentType = "html"; + this.args = [ + { + name: "Radius", + type: "number", + value: 2, + min: 1 + }, + { + name: "Amount", + type: "number", + value: 1, + min: 0, + step: 0.1 + }, + { + name: "Threshold", + type: "number", + value: 10, + min: 0, + max: 100 + } + ]; + } + + /** + * @param {byteArray} input + * @param {Object[]} args + * @returns {byteArray} + */ + async run(input, args) { + const [radius, amount, threshold] = args; + + if (!isImage(input)){ + throw new OperationError("Invalid file type."); + } + + let image; + try { + image = await jimp.read(Buffer.from(input)); + } catch (err) { + throw new OperationError(`Error loading image. (${err})`); + } + + try { + if (ENVIRONMENT_IS_WORKER()) + self.sendStatusMessage("Sharpening image... (Cloning image)"); + const blurImage = image.clone(); + const blurMask = image.clone(); + + if (ENVIRONMENT_IS_WORKER()) + self.sendStatusMessage("Sharpening image... (Blurring cloned image)"); + blurImage.gaussian(radius); + + if (ENVIRONMENT_IS_WORKER()) + self.sendStatusMessage("Sharpening image... (Creating unsharp mask)"); + blurMask.scan(0, 0, blurMask.bitmap.width, blurMask.bitmap.height, function(x, y, idx) { + const blurRed = blurImage.bitmap.data[idx]; + const blurGreen = blurImage.bitmap.data[idx + 1]; + const blurBlue = blurImage.bitmap.data[idx + 2]; + + const normalRed = this.bitmap.data[idx]; + const normalGreen = this.bitmap.data[idx + 1]; + const normalBlue = this.bitmap.data[idx + 2]; + + // Subtract blurred pixel value from normal image + this.bitmap.data[idx] = (normalRed > blurRed) ? normalRed - blurRed : 0; + this.bitmap.data[idx + 1] = (normalGreen > blurGreen) ? normalGreen - blurGreen : 0; + this.bitmap.data[idx + 2] = (normalBlue > blurBlue) ? normalBlue - blurBlue : 0; + }); + + if (ENVIRONMENT_IS_WORKER()) + self.sendStatusMessage("Sharpening image... (Merging with unsharp mask)"); + image.scan(0, 0, image.bitmap.width, image.bitmap.height, function(x, y, idx) { + let maskRed = blurMask.bitmap.data[idx]; + let maskGreen = blurMask.bitmap.data[idx + 1]; + let maskBlue = blurMask.bitmap.data[idx + 2]; + + const normalRed = this.bitmap.data[idx]; + const normalGreen = this.bitmap.data[idx + 1]; + const normalBlue = this.bitmap.data[idx + 2]; + + // Calculate luminance + const maskLuminance = (0.2126 * maskRed + 0.7152 * maskGreen + 0.0722 * maskBlue); + const normalLuminance = (0.2126 * normalRed + 0.7152 * normalGreen + 0.0722 * normalBlue); + + let luminanceDiff; + if (maskLuminance > normalLuminance) { + luminanceDiff = maskLuminance - normalLuminance; + } else { + luminanceDiff = normalLuminance - maskLuminance; + } + + // Scale mask colours by amount + maskRed = maskRed * amount; + maskGreen = maskGreen * amount; + maskBlue = maskBlue * amount; + + // Only change pixel value if the difference is higher than threshold + if ((luminanceDiff / 255) * 100 >= threshold) { + this.bitmap.data[idx] = (normalRed + maskRed) <= 255 ? normalRed + maskRed : 255; + this.bitmap.data[idx + 1] = (normalGreen + maskGreen) <= 255 ? normalGreen + maskGreen : 255; + this.bitmap.data[idx + 2] = (normalBlue + maskBlue) <= 255 ? normalBlue + maskBlue : 255; + } + }); + + const imageBuffer = await image.getBufferAsync(jimp.AUTO); + return [...imageBuffer]; + } catch (err) { + throw new OperationError(`Error sharpening image. (${err})`); + } + } + + /** + * Displays the sharpened image using HTML for web apps + * @param {byteArray} data + * @returns {html} + */ + present(data) { + if (!data.length) return ""; + + const type = isImage(data); + if (!type) { + throw new OperationError("Invalid image type."); + } + + return ``; + } + +} + +export default SharpenImage; From e95b7075b98508e1da7a454d299b3d001e661719 Mon Sep 17 00:00:00 2001 From: j433866 Date: Tue, 12 Mar 2019 16:29:20 +0000 Subject: [PATCH 05/27] Add convert image format operation --- src/core/config/Categories.json | 3 +- src/core/operations/ConvertImageFormat.mjs | 142 +++++++++++++++++++++ 2 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 src/core/operations/ConvertImageFormat.mjs diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 2edc50ab..92f74212 100755 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -375,7 +375,8 @@ "Contain Image", "Cover Image", "Image Hue/Saturation/Lightness", - "Sharpen Image" + "Sharpen Image", + "Convert image format" ] }, { diff --git a/src/core/operations/ConvertImageFormat.mjs b/src/core/operations/ConvertImageFormat.mjs new file mode 100644 index 00000000..c8152908 --- /dev/null +++ b/src/core/operations/ConvertImageFormat.mjs @@ -0,0 +1,142 @@ +/** + * @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"; +import jimp from "jimp"; + +/** + * Convert Image Format operation + */ +class ConvertImageFormat extends Operation { + + /** + * ConvertImageFormat constructor + */ + constructor() { + super(); + + this.name = "Convert image format"; + this.module = "Image"; + this.description = "Converts an image between different formats. Supported formats:
  • Joint Photographic Experts Group (JPEG)
  • Portable Network Graphics (PNG)
  • Bitmap (BMP)
  • Tagged Image File Format (TIFF)

Note: GIF files are supported for input, but cannot be outputted."; + this.infoURL = "https://wikipedia.org/wiki/Image_file_formats"; + this.inputType = "byteArray"; + this.outputType = "byteArray"; + this.presentType = "html"; + this.args = [ + { + name: "Output Format", + type: "option", + value: [ + "JPEG", + "PNG", + "BMP", + "TIFF" + ] + }, + { + name: "JPEG Quality", + type: "number", + value: 80, + min: 1, + max: 100 + }, + { + name: "PNG Filter Type", + type: "option", + value: [ + "Auto", + "None", + "Sub", + "Up", + "Average", + "Paeth" + ] + }, + { + name: "PNG Deflate Level", + type: "number", + value: 9, + min: 0, + max: 9 + } + ]; + } + + /** + * @param {byteArray} input + * @param {Object[]} args + * @returns {byteArray} + */ + async run(input, args) { + const [format, jpegQuality, pngFilterType, pngDeflateLevel] = args; + const formatMap = { + "JPEG": jimp.MIME_JPEG, + "PNG": jimp.MIME_PNG, + "BMP": jimp.MIME_BMP, + "TIFF": jimp.MIME_TIFF + }; + + const pngFilterMap = { + "Auto": jimp.PNG_FILTER_AUTO, + "None": jimp.PNG_FILTER_NONE, + "Sub": jimp.PNG_FILTER_SUB, + "Up": jimp.PNG_FILTER_UP, + "Average": jimp.PNG_FILTER_AVERAGE, + "Paeth": jimp.PNG_FILTER_PATH // Incorrect spelling in Jimp library + }; + + const mime = formatMap[format]; + + if (!isImage(input)) { + throw new OperationError("Invalid file format."); + } + let image; + try { + image = await jimp.read(Buffer.from(input)); + } catch (err) { + throw new OperationError(`Error opening image file. (${err})`); + } + try { + switch (format) { + case "JPEG": + image.quality(jpegQuality); + break; + case "PNG": + image.filterType(pngFilterMap[pngFilterType]); + image.deflateLevel(pngDeflateLevel); + break; + } + + const imageBuffer = await image.getBufferAsync(mime); + return [...imageBuffer]; + } catch (err) { + throw new OperationError(`Error converting image format. (${err})`); + } + } + + /** + * Displays the converted image using HTML for web apps + * + * @param {byteArray} data + * @returns {html} + */ + present(data) { + if (!data.length) return ""; + + const type = isImage(data); + if (!type) { + throw new OperationError("Invalid image type."); + } + + return ``; + } + +} + +export default ConvertImageFormat; From bb7487c4763ea10cb015d00a5089ab8a6c0727b4 Mon Sep 17 00:00:00 2001 From: j433866 Date: Wed, 13 Mar 2019 09:20:13 +0000 Subject: [PATCH 06/27] Change to use new FileType library --- src/core/operations/ParseQRCode.mjs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/core/operations/ParseQRCode.mjs b/src/core/operations/ParseQRCode.mjs index d929500b..63646b79 100644 --- a/src/core/operations/ParseQRCode.mjs +++ b/src/core/operations/ParseQRCode.mjs @@ -6,7 +6,7 @@ import Operation from "../Operation"; import OperationError from "../errors/OperationError"; -import Magic from "../lib/Magic"; +import { isImage } from "../lib/FileType.mjs"; import { parseQrCode } from "../lib/QRCode"; /** @@ -50,9 +50,8 @@ class ParseQRCode extends Operation { */ async run(input, args) { const [normalise] = args; - const type = Magic.magicFileType(input); - if (!type || type.mime.indexOf("image") !== 0) { + if (!isImage(input)) { throw new OperationError("Invalid file type."); } return await parseQrCode(input, normalise); From 4fafa39e54ce8c1fd4c78b01339a16fc8da29a7a Mon Sep 17 00:00:00 2001 From: j433866 Date: Wed, 13 Mar 2019 13:09:02 +0000 Subject: [PATCH 07/27] Fix magic library to better handle operation error --- src/core/lib/Magic.mjs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/core/lib/Magic.mjs b/src/core/lib/Magic.mjs index f0b55857..d66b6f93 100644 --- a/src/core/lib/Magic.mjs +++ b/src/core/lib/Magic.mjs @@ -312,6 +312,11 @@ class Magic { return; } + // If the recipe returned an empty buffer, do not continue + if (_buffersEqual(output, new ArrayBuffer())) { + return; + } + const magic = new Magic(output, this.opPatterns), speculativeResults = await magic.speculativeExecution( depth-1, extLang, intensive, [...recipeConfig, opConfig], op.useful, crib); @@ -395,7 +400,12 @@ class Magic { const recipe = new Recipe(recipeConfig); try { await recipe.execute(dish); - return dish.get(Dish.ARRAY_BUFFER); + // Return an empty buffer if the recipe did not run to completion + if (recipe.lastRunOp === recipe.opList[recipe.opList.length - 1]) { + return dish.get(Dish.ARRAY_BUFFER); + } else { + return new ArrayBuffer(); + } } catch (err) { // If there are errors, return an empty buffer return new ArrayBuffer(); From 8e74acbf3e56a2e00b7f9abac6559bd91352d929 Mon Sep 17 00:00:00 2001 From: j433866 Date: Mon, 18 Mar 2019 09:43:37 +0000 Subject: [PATCH 08/27] Add opaque background option --- src/core/operations/ContainImage.mjs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/core/operations/ContainImage.mjs b/src/core/operations/ContainImage.mjs index c6df81ef..4cb7cfdf 100644 --- a/src/core/operations/ContainImage.mjs +++ b/src/core/operations/ContainImage.mjs @@ -72,6 +72,11 @@ class ContainImage extends Operation { "Bezier" ], defaultIndex: 1 + }, + { + name: "Opaque background", + type: "boolean", + value: true } ]; } @@ -82,7 +87,7 @@ class ContainImage extends Operation { * @returns {byteArray} */ async run(input, args) { - const [width, height, hAlign, vAlign, alg] = args; + const [width, height, hAlign, vAlign, alg, opaqueBg] = args; const resizeMap = { "Nearest Neighbour": jimp.RESIZE_NEAREST_NEIGHBOR, @@ -115,6 +120,13 @@ class ContainImage extends Operation { if (ENVIRONMENT_IS_WORKER()) self.sendStatusMessage("Containing image..."); image.contain(width, height, alignMap[hAlign] | alignMap[vAlign], resizeMap[alg]); + + if (opaqueBg) { + const newImage = await jimp.read(width, height, 0x000000FF); + newImage.blit(image, 0, 0); + image = newImage; + } + const imageBuffer = await image.getBufferAsync(jimp.AUTO); return [...imageBuffer]; } catch (err) { From ce72acdd613cd281da622e0c3bfe71338ee06f51 Mon Sep 17 00:00:00 2001 From: j433866 Date: Tue, 19 Mar 2019 13:53:09 +0000 Subject: [PATCH 09/27] Add 'add text to image' operation. Included variants of the Roboto fonts as bitmap fonts for jimp. Changed webpack config to import the font files. --- src/core/config/Categories.json | 3 +- src/core/operations/AddTextToImage.mjs | 257 +++++++++ .../static/fonts/bmfonts/Roboto72White.fnt | 485 +++++++++++++++++ .../static/fonts/bmfonts/Roboto72White.png | Bin 0 -> 52730 bytes .../fonts/bmfonts/RobotoBlack72White.fnt | 488 +++++++++++++++++ .../fonts/bmfonts/RobotoBlack72White.png | Bin 0 -> 50192 bytes .../fonts/bmfonts/RobotoMono72White.fnt | 103 ++++ .../fonts/bmfonts/RobotoMono72White.png | Bin 0 -> 52580 bytes .../fonts/bmfonts/RobotoSlab72White.fnt | 492 ++++++++++++++++++ .../fonts/bmfonts/RobotoSlab72White.png | Bin 0 -> 54282 bytes webpack.config.js | 2 +- 11 files changed, 1828 insertions(+), 2 deletions(-) create mode 100644 src/core/operations/AddTextToImage.mjs create mode 100644 src/web/static/fonts/bmfonts/Roboto72White.fnt create mode 100644 src/web/static/fonts/bmfonts/Roboto72White.png create mode 100644 src/web/static/fonts/bmfonts/RobotoBlack72White.fnt create mode 100644 src/web/static/fonts/bmfonts/RobotoBlack72White.png create mode 100644 src/web/static/fonts/bmfonts/RobotoMono72White.fnt create mode 100644 src/web/static/fonts/bmfonts/RobotoMono72White.png create mode 100644 src/web/static/fonts/bmfonts/RobotoSlab72White.fnt create mode 100644 src/web/static/fonts/bmfonts/RobotoSlab72White.png diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 92f74212..4bd40aa4 100755 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -376,7 +376,8 @@ "Cover Image", "Image Hue/Saturation/Lightness", "Sharpen Image", - "Convert image format" + "Convert Image Format", + "Add Text To Image" ] }, { diff --git a/src/core/operations/AddTextToImage.mjs b/src/core/operations/AddTextToImage.mjs new file mode 100644 index 00000000..f8ee3485 --- /dev/null +++ b/src/core/operations/AddTextToImage.mjs @@ -0,0 +1,257 @@ +/** + * @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"; +import jimp from "jimp"; + +/** + * Add Text To Image operation + */ +class AddTextToImage extends Operation { + + /** + * AddTextToImage constructor + */ + constructor() { + super(); + + this.name = "Add Text To Image"; + this.module = "Image"; + this.description = "Adds text onto an image.

Text can be horizontally or vertically aligned, or the position can be manually specified.
Variants of the Roboto font face are available in any size or colour.

Note: This may cause a degradation in image quality, especially when using font sizes larger than 72."; + this.infoURL = ""; + this.inputType = "byteArray"; + this.outputType = "byteArray"; + this.presentType = "html"; + this.args = [ + { + name: "Text", + type: "string", + value: "" + }, + { + name: "Horizontal align", + type: "option", + value: ["None", "Left", "Center", "Right"] + }, + { + name: "Vertical align", + type: "option", + value: ["None", "Top", "Middle", "Bottom"] + }, + { + name: "X position", + type: "number", + value: 0 + }, + { + name: "Y position", + type: "number", + value: 0 + }, + { + name: "Size", + type: "number", + value: 32, + min: 8 + }, + { + name: "Font face", + type: "option", + value: [ + "Roboto", + "Roboto Black", + "Roboto Mono", + "Roboto Slab" + ] + }, + { + name: "Red", + type: "number", + value: 255, + min: 0, + max: 255 + }, + { + name: "Green", + type: "number", + value: 255, + min: 0, + max: 255 + }, + { + name: "Blue", + type: "number", + value: 255, + min: 0, + max: 255 + }, + { + name: "Alpha", + type: "number", + value: 255, + min: 0, + max: 255 + } + ]; + } + + /** + * @param {byteArray} input + * @param {Object[]} args + * @returns {byteArray} + */ + async run(input, args) { + const text = args[0], + hAlign = args[1], + vAlign = args[2], + size = args[5], + fontFace = args[6], + red = args[7], + green = args[8], + blue = args[9], + alpha = args[10]; + + let xPos = args[3], + yPos = args[4]; + + if (!isImage(input)) { + throw new OperationError("Invalid file type."); + } + + let image; + try { + image = await jimp.read(Buffer.from(input)); + } catch (err) { + throw new OperationError(`Error loading image. (${err})`); + } + try { + if (ENVIRONMENT_IS_WORKER()) + self.sendStatusMessage("Adding text to image..."); + + const fontsMap = { + "Roboto": await import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/Roboto72White.fnt"), + "Roboto Black": await import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoBlack72White.fnt"), + "Roboto Mono": await import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoMono72White.fnt"), + "Roboto Slab": await import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoSlab72White.fnt") + }; + + // Make Webpack load the png font images + await import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/Roboto72White.png"); + await import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoSlab72White.png"); + await import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoMono72White.png"); + await import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoBlack72White.png"); + + const font = fontsMap[fontFace]; + + // LoadFont needs an absolute url, so append the font name to self.docURL + const jimpFont = await jimp.loadFont(self.docURL + "/" + font.default); + + jimpFont.pages.forEach(function(page) { + if (page.bitmap) { + // Adjust the RGB values of the image pages to change the font colour. + const pageWidth = page.bitmap.width; + const pageHeight = page.bitmap.height; + for (let ix = 0; ix < pageWidth; ix++) { + for (let iy = 0; iy < pageHeight; iy++) { + const idx = (iy * pageWidth + ix) << 2; + + const newRed = page.bitmap.data[idx] - (255 - red); + const newGreen = page.bitmap.data[idx + 1] - (255 - green); + const newBlue = page.bitmap.data[idx + 2] - (255 - blue); + const newAlpha = page.bitmap.data[idx + 3] - (255 - alpha); + + // Make sure the bitmap values don't go below 0 as that makes jimp very unhappy + page.bitmap.data[idx] = (newRed > 0) ? newRed : 0; + page.bitmap.data[idx + 1] = (newGreen > 0) ? newGreen : 0; + page.bitmap.data[idx + 2] = (newBlue > 0) ? newBlue : 0; + page.bitmap.data[idx + 3] = (newAlpha > 0) ? newAlpha : 0; + } + } + } + }); + + // Scale the image to a factor of 72, so we can print the text at any size + const scaleFactor = 72 / size; + if (size !== 72) { + // Use bicubic for decreasing size + if (size > 72) { + image.scale(scaleFactor, jimp.RESIZE_BICUBIC); + } else { + image.scale(scaleFactor, jimp.RESIZE_BILINEAR); + } + } + + // If using the alignment options, calculate the pixel values AFTER the image has been scaled + switch (hAlign) { + case "Left": + xPos = 0; + break; + case "Center": + xPos = (image.getWidth() / 2) - (jimp.measureText(jimpFont, text) / 2); + break; + case "Right": + xPos = image.getWidth() - jimp.measureText(jimpFont, text); + break; + default: + // Adjust x position for the scaled image + xPos = xPos * scaleFactor; + } + + switch (vAlign) { + case "Top": + yPos = 0; + break; + case "Middle": + yPos = (image.getHeight() / 2) - (jimp.measureTextHeight(jimpFont, text) / 2); + break; + case "Bottom": + yPos = image.getHeight() - jimp.measureTextHeight(jimpFont, text); + break; + default: + // Adjust y position for the scaled image + yPos = yPos * scaleFactor; + } + + image.print(jimpFont, xPos, yPos, text); + + if (size !== 72) { + if (size > 72) { + image.scale(1 / scaleFactor, jimp.RESIZE_BILINEAR); + } else { + image.scale(1 / scaleFactor, jimp.RESIZE_BICUBIC); + } + } + + const imageBuffer = await image.getBufferAsync(jimp.AUTO); + return [...imageBuffer]; + } catch (err) { + throw new OperationError(`Error adding text to image. (${err})`); + } + } + + /** + * Displays the blurred image using HTML for web apps + * + * @param {byteArray} data + * @returns {html} + */ + present(data) { + if (!data.length) return ""; + + const type = isImage(data); + if (!type) { + throw new OperationError("Invalid file type."); + } + + return ``; + } + +} + +export default AddTextToImage; diff --git a/src/web/static/fonts/bmfonts/Roboto72White.fnt b/src/web/static/fonts/bmfonts/Roboto72White.fnt new file mode 100644 index 00000000..fd186892 --- /dev/null +++ b/src/web/static/fonts/bmfonts/Roboto72White.fnt @@ -0,0 +1,485 @@ +info face="Roboto" size=72 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=1,1,1,1 spacing=-2,-2 +common lineHeight=85 base=67 scaleW=512 scaleH=512 pages=1 packed=0 +page id=0 file="images/Roboto72White.png" +chars count=98 +char id=0 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=66 xadvance=0 page=0 chnl=0 +char id=10 x=0 y=0 width=70 height=99 xoffset=2 yoffset=-11 xadvance=74 page=0 chnl=0 +char id=32 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=66 xadvance=18 page=0 chnl=0 +char id=33 x=493 y=99 width=10 height=55 xoffset=5 yoffset=14 xadvance=19 page=0 chnl=0 +char id=34 x=446 y=319 width=16 height=19 xoffset=4 yoffset=12 xadvance=23 page=0 chnl=0 +char id=35 x=204 y=265 width=41 height=54 xoffset=3 yoffset=14 xadvance=44 page=0 chnl=0 +char id=36 x=269 y=0 width=35 height=69 xoffset=3 yoffset=6 xadvance=40 page=0 chnl=0 +char id=37 x=31 y=155 width=48 height=56 xoffset=3 yoffset=13 xadvance=53 page=0 chnl=0 +char id=38 x=79 y=155 width=43 height=56 xoffset=3 yoffset=13 xadvance=45 page=0 chnl=0 +char id=39 x=503 y=99 width=7 height=19 xoffset=3 yoffset=12 xadvance=13 page=0 chnl=0 +char id=40 x=70 y=0 width=21 height=78 xoffset=4 yoffset=7 xadvance=25 page=0 chnl=0 +char id=41 x=91 y=0 width=22 height=78 xoffset=-1 yoffset=7 xadvance=25 page=0 chnl=0 +char id=42 x=342 y=319 width=32 height=32 xoffset=-1 yoffset=14 xadvance=31 page=0 chnl=0 +char id=43 x=242 y=319 width=37 height=40 xoffset=2 yoffset=23 xadvance=41 page=0 chnl=0 +char id=44 x=433 y=319 width=13 height=21 xoffset=-1 yoffset=58 xadvance=14 page=0 chnl=0 +char id=45 x=27 y=360 width=19 height=8 xoffset=0 yoffset=41 xadvance=19 page=0 chnl=0 +char id=46 x=17 y=360 width=10 height=11 xoffset=4 yoffset=58 xadvance=19 page=0 chnl=0 +char id=47 x=355 y=0 width=30 height=58 xoffset=-1 yoffset=14 xadvance=30 page=0 chnl=0 +char id=48 x=449 y=99 width=34 height=56 xoffset=3 yoffset=13 xadvance=40 page=0 chnl=0 +char id=49 x=474 y=211 width=22 height=54 xoffset=5 yoffset=14 xadvance=40 page=0 chnl=0 +char id=50 x=195 y=155 width=37 height=55 xoffset=2 yoffset=13 xadvance=41 page=0 chnl=0 +char id=51 x=379 y=99 width=35 height=56 xoffset=2 yoffset=13 xadvance=40 page=0 chnl=0 +char id=52 x=128 y=265 width=39 height=54 xoffset=1 yoffset=14 xadvance=41 page=0 chnl=0 +char id=53 x=232 y=155 width=35 height=55 xoffset=4 yoffset=14 xadvance=40 page=0 chnl=0 +char id=54 x=267 y=155 width=35 height=55 xoffset=4 yoffset=14 xadvance=41 page=0 chnl=0 +char id=55 x=167 y=265 width=37 height=54 xoffset=2 yoffset=14 xadvance=41 page=0 chnl=0 +char id=56 x=414 y=99 width=35 height=56 xoffset=3 yoffset=13 xadvance=40 page=0 chnl=0 +char id=57 x=302 y=155 width=34 height=55 xoffset=3 yoffset=13 xadvance=41 page=0 chnl=0 +char id=58 x=495 y=265 width=10 height=41 xoffset=4 yoffset=28 xadvance=18 page=0 chnl=0 +char id=59 x=496 y=211 width=13 height=52 xoffset=0 yoffset=28 xadvance=15 page=0 chnl=0 +char id=60 x=279 y=319 width=31 height=35 xoffset=2 yoffset=27 xadvance=37 page=0 chnl=0 +char id=61 x=402 y=319 width=31 height=23 xoffset=4 yoffset=31 xadvance=39 page=0 chnl=0 +char id=62 x=310 y=319 width=32 height=35 xoffset=4 yoffset=27 xadvance=38 page=0 chnl=0 +char id=63 x=0 y=155 width=31 height=56 xoffset=2 yoffset=13 xadvance=34 page=0 chnl=0 +char id=64 x=210 y=0 width=59 height=69 xoffset=3 yoffset=15 xadvance=65 page=0 chnl=0 +char id=65 x=336 y=155 width=49 height=54 xoffset=-1 yoffset=14 xadvance=47 page=0 chnl=0 +char id=66 x=385 y=155 width=37 height=54 xoffset=5 yoffset=14 xadvance=45 page=0 chnl=0 +char id=67 x=0 y=99 width=42 height=56 xoffset=3 yoffset=13 xadvance=46 page=0 chnl=0 +char id=68 x=422 y=155 width=39 height=54 xoffset=5 yoffset=14 xadvance=47 page=0 chnl=0 +char id=69 x=461 y=155 width=35 height=54 xoffset=5 yoffset=14 xadvance=41 page=0 chnl=0 +char id=70 x=0 y=211 width=34 height=54 xoffset=5 yoffset=14 xadvance=40 page=0 chnl=0 +char id=71 x=42 y=99 width=42 height=56 xoffset=3 yoffset=13 xadvance=49 page=0 chnl=0 +char id=72 x=34 y=211 width=41 height=54 xoffset=5 yoffset=14 xadvance=51 page=0 chnl=0 +char id=73 x=496 y=155 width=9 height=54 xoffset=5 yoffset=14 xadvance=19 page=0 chnl=0 +char id=74 x=122 y=155 width=34 height=55 xoffset=1 yoffset=14 xadvance=40 page=0 chnl=0 +char id=75 x=75 y=211 width=41 height=54 xoffset=5 yoffset=14 xadvance=45 page=0 chnl=0 +char id=76 x=116 y=211 width=33 height=54 xoffset=5 yoffset=14 xadvance=39 page=0 chnl=0 +char id=77 x=149 y=211 width=53 height=54 xoffset=5 yoffset=14 xadvance=63 page=0 chnl=0 +char id=78 x=202 y=211 width=41 height=54 xoffset=5 yoffset=14 xadvance=51 page=0 chnl=0 +char id=79 x=84 y=99 width=43 height=56 xoffset=3 yoffset=13 xadvance=49 page=0 chnl=0 +char id=80 x=243 y=211 width=39 height=54 xoffset=5 yoffset=14 xadvance=45 page=0 chnl=0 +char id=81 x=304 y=0 width=44 height=64 xoffset=3 yoffset=13 xadvance=49 page=0 chnl=0 +char id=82 x=282 y=211 width=40 height=54 xoffset=5 yoffset=14 xadvance=45 page=0 chnl=0 +char id=83 x=127 y=99 width=39 height=56 xoffset=2 yoffset=13 xadvance=43 page=0 chnl=0 +char id=84 x=322 y=211 width=42 height=54 xoffset=1 yoffset=14 xadvance=44 page=0 chnl=0 +char id=85 x=156 y=155 width=39 height=55 xoffset=4 yoffset=14 xadvance=47 page=0 chnl=0 +char id=86 x=364 y=211 width=47 height=54 xoffset=-1 yoffset=14 xadvance=46 page=0 chnl=0 +char id=87 x=411 y=211 width=63 height=54 xoffset=1 yoffset=14 xadvance=64 page=0 chnl=0 +char id=88 x=0 y=265 width=44 height=54 xoffset=1 yoffset=14 xadvance=45 page=0 chnl=0 +char id=89 x=44 y=265 width=45 height=54 xoffset=-1 yoffset=14 xadvance=43 page=0 chnl=0 +char id=90 x=89 y=265 width=39 height=54 xoffset=2 yoffset=14 xadvance=43 page=0 chnl=0 +char id=91 x=161 y=0 width=16 height=72 xoffset=4 yoffset=7 xadvance=19 page=0 chnl=0 +char id=92 x=385 y=0 width=30 height=58 xoffset=0 yoffset=14 xadvance=30 page=0 chnl=0 +char id=93 x=177 y=0 width=16 height=72 xoffset=0 yoffset=7 xadvance=20 page=0 chnl=0 +char id=94 x=374 y=319 width=28 height=28 xoffset=1 yoffset=14 xadvance=30 page=0 chnl=0 +char id=95 x=46 y=360 width=34 height=8 xoffset=0 yoffset=65 xadvance=34 page=0 chnl=0 +char id=96 x=0 y=360 width=17 height=13 xoffset=1 yoffset=11 xadvance=22 page=0 chnl=0 +char id=97 x=268 y=265 width=34 height=42 xoffset=3 yoffset=27 xadvance=39 page=0 chnl=0 +char id=98 x=415 y=0 width=34 height=57 xoffset=4 yoffset=12 xadvance=40 page=0 chnl=0 +char id=99 x=302 y=265 width=34 height=42 xoffset=2 yoffset=27 xadvance=38 page=0 chnl=0 +char id=100 x=449 y=0 width=34 height=57 xoffset=2 yoffset=12 xadvance=40 page=0 chnl=0 +char id=101 x=336 y=265 width=34 height=42 xoffset=2 yoffset=27 xadvance=38 page=0 chnl=0 +char id=102 x=483 y=0 width=25 height=57 xoffset=1 yoffset=11 xadvance=26 page=0 chnl=0 +char id=103 x=166 y=99 width=34 height=56 xoffset=2 yoffset=27 xadvance=40 page=0 chnl=0 +char id=104 x=200 y=99 width=32 height=56 xoffset=4 yoffset=12 xadvance=40 page=0 chnl=0 +char id=105 x=483 y=99 width=10 height=55 xoffset=4 yoffset=13 xadvance=18 page=0 chnl=0 +char id=106 x=193 y=0 width=17 height=71 xoffset=-4 yoffset=13 xadvance=17 page=0 chnl=0 +char id=107 x=232 y=99 width=34 height=56 xoffset=4 yoffset=12 xadvance=37 page=0 chnl=0 +char id=108 x=266 y=99 width=9 height=56 xoffset=4 yoffset=12 xadvance=17 page=0 chnl=0 +char id=109 x=439 y=265 width=56 height=41 xoffset=4 yoffset=27 xadvance=64 page=0 chnl=0 +char id=110 x=0 y=319 width=32 height=41 xoffset=4 yoffset=27 xadvance=40 page=0 chnl=0 +char id=111 x=370 y=265 width=37 height=42 xoffset=2 yoffset=27 xadvance=41 page=0 chnl=0 +char id=112 x=275 y=99 width=34 height=56 xoffset=4 yoffset=27 xadvance=40 page=0 chnl=0 +char id=113 x=309 y=99 width=34 height=56 xoffset=2 yoffset=27 xadvance=41 page=0 chnl=0 +char id=114 x=32 y=319 width=21 height=41 xoffset=4 yoffset=27 xadvance=25 page=0 chnl=0 +char id=115 x=407 y=265 width=32 height=42 xoffset=2 yoffset=27 xadvance=37 page=0 chnl=0 +char id=116 x=245 y=265 width=23 height=51 xoffset=0 yoffset=18 xadvance=25 page=0 chnl=0 +char id=117 x=53 y=319 width=32 height=41 xoffset=4 yoffset=28 xadvance=40 page=0 chnl=0 +char id=118 x=85 y=319 width=35 height=40 xoffset=0 yoffset=28 xadvance=35 page=0 chnl=0 +char id=119 x=120 y=319 width=54 height=40 xoffset=0 yoffset=28 xadvance=54 page=0 chnl=0 +char id=120 x=174 y=319 width=36 height=40 xoffset=0 yoffset=28 xadvance=36 page=0 chnl=0 +char id=121 x=343 y=99 width=36 height=56 xoffset=-1 yoffset=28 xadvance=34 page=0 chnl=0 +char id=122 x=210 y=319 width=32 height=40 xoffset=2 yoffset=28 xadvance=35 page=0 chnl=0 +char id=123 x=113 y=0 width=24 height=73 xoffset=1 yoffset=9 xadvance=25 page=0 chnl=0 +char id=124 x=348 y=0 width=7 height=63 xoffset=5 yoffset=14 xadvance=17 page=0 chnl=0 +char id=125 x=137 y=0 width=24 height=73 xoffset=-1 yoffset=9 xadvance=24 page=0 chnl=0 +char id=126 x=462 y=319 width=42 height=16 xoffset=4 yoffset=38 xadvance=50 page=0 chnl=0 +char id=127 x=0 y=0 width=70 height=99 xoffset=2 yoffset=-11 xadvance=74 page=0 chnl=0 +kernings count=382 +kerning first=70 second=74 amount=-9 +kerning first=34 second=97 amount=-2 +kerning first=34 second=101 amount=-2 +kerning first=34 second=113 amount=-2 +kerning first=34 second=99 amount=-2 +kerning first=70 second=99 amount=-1 +kerning first=88 second=113 amount=-1 +kerning first=84 second=46 amount=-8 +kerning first=84 second=119 amount=-2 +kerning first=87 second=97 amount=-1 +kerning first=90 second=117 amount=-1 +kerning first=39 second=97 amount=-2 +kerning first=69 second=111 amount=-1 +kerning first=87 second=41 amount=1 +kerning first=76 second=86 amount=-6 +kerning first=121 second=34 amount=1 +kerning first=40 second=86 amount=1 +kerning first=85 second=65 amount=-1 +kerning first=89 second=89 amount=1 +kerning first=72 second=65 amount=1 +kerning first=104 second=39 amount=-4 +kerning first=114 second=102 amount=1 +kerning first=89 second=42 amount=-2 +kerning first=114 second=34 amount=1 +kerning first=84 second=115 amount=-4 +kerning first=84 second=71 amount=-1 +kerning first=89 second=101 amount=-2 +kerning first=89 second=45 amount=-2 +kerning first=122 second=99 amount=-1 +kerning first=78 second=88 amount=1 +kerning first=68 second=89 amount=-2 +kerning first=122 second=103 amount=-1 +kerning first=78 second=84 amount=-1 +kerning first=86 second=103 amount=-2 +kerning first=89 second=67 amount=-1 +kerning first=89 second=79 amount=-1 +kerning first=75 second=111 amount=-1 +kerning first=111 second=120 amount=-1 +kerning first=87 second=44 amount=-4 +kerning first=91 second=74 amount=-1 +kerning first=120 second=111 amount=-1 +kerning first=84 second=111 amount=-3 +kerning first=102 second=113 amount=-1 +kerning first=80 second=88 amount=-1 +kerning first=66 second=84 amount=-1 +kerning first=65 second=87 amount=-2 +kerning first=86 second=100 amount=-2 +kerning first=122 second=100 amount=-1 +kerning first=75 second=118 amount=-1 +kerning first=70 second=118 amount=-1 +kerning first=73 second=88 amount=1 +kerning first=70 second=121 amount=-1 +kerning first=65 second=34 amount=-4 +kerning first=39 second=101 amount=-2 +kerning first=75 second=101 amount=-1 +kerning first=84 second=99 amount=-3 +kerning first=84 second=65 amount=-3 +kerning first=112 second=39 amount=-1 +kerning first=76 second=39 amount=-12 +kerning first=78 second=65 amount=1 +kerning first=88 second=45 amount=-2 +kerning first=65 second=121 amount=-2 +kerning first=34 second=111 amount=-2 +kerning first=89 second=85 amount=-3 +kerning first=114 second=99 amount=-1 +kerning first=86 second=125 amount=1 +kerning first=70 second=111 amount=-1 +kerning first=89 second=120 amount=-1 +kerning first=90 second=119 amount=-1 +kerning first=120 second=99 amount=-1 +kerning first=89 second=117 amount=-1 +kerning first=82 second=89 amount=-2 +kerning first=75 second=117 amount=-1 +kerning first=34 second=34 amount=-4 +kerning first=89 second=110 amount=-1 +kerning first=88 second=101 amount=-1 +kerning first=107 second=103 amount=-1 +kerning first=34 second=115 amount=-3 +kerning first=98 second=39 amount=-1 +kerning first=70 second=65 amount=-6 +kerning first=70 second=46 amount=-8 +kerning first=98 second=34 amount=-1 +kerning first=70 second=84 amount=1 +kerning first=114 second=100 amount=-1 +kerning first=88 second=79 amount=-1 +kerning first=39 second=113 amount=-2 +kerning first=114 second=103 amount=-1 +kerning first=77 second=65 amount=1 +kerning first=120 second=103 amount=-1 +kerning first=114 second=121 amount=1 +kerning first=89 second=100 amount=-2 +kerning first=80 second=65 amount=-5 +kerning first=121 second=111 amount=-1 +kerning first=84 second=74 amount=-8 +kerning first=122 second=111 amount=-1 +kerning first=114 second=118 amount=1 +kerning first=102 second=41 amount=1 +kerning first=122 second=113 amount=-1 +kerning first=89 second=122 amount=-1 +kerning first=89 second=38 amount=-1 +kerning first=81 second=89 amount=-1 +kerning first=114 second=111 amount=-1 +kerning first=46 second=34 amount=-6 +kerning first=84 second=112 amount=-4 +kerning first=112 second=34 amount=-1 +kerning first=76 second=34 amount=-12 +kerning first=102 second=125 amount=1 +kerning first=39 second=115 amount=-3 +kerning first=76 second=118 amount=-5 +kerning first=86 second=99 amount=-2 +kerning first=84 second=84 amount=1 +kerning first=86 second=65 amount=-3 +kerning first=87 second=101 amount=-1 +kerning first=67 second=125 amount=-1 +kerning first=120 second=113 amount=-1 +kerning first=118 second=46 amount=-4 +kerning first=88 second=103 amount=-1 +kerning first=111 second=122 amount=-1 +kerning first=77 second=84 amount=-1 +kerning first=114 second=46 amount=-4 +kerning first=34 second=39 amount=-4 +kerning first=114 second=44 amount=-4 +kerning first=69 second=84 amount=1 +kerning first=89 second=46 amount=-7 +kerning first=97 second=39 amount=-2 +kerning first=34 second=100 amount=-2 +kerning first=70 second=100 amount=-1 +kerning first=84 second=120 amount=-3 +kerning first=90 second=118 amount=-1 +kerning first=70 second=114 amount=-1 +kerning first=34 second=112 amount=-1 +kerning first=109 second=34 amount=-4 +kerning first=86 second=113 amount=-2 +kerning first=88 second=71 amount=-1 +kerning first=66 second=89 amount=-2 +kerning first=102 second=103 amount=-1 +kerning first=88 second=67 amount=-1 +kerning first=39 second=110 amount=-1 +kerning first=75 second=110 amount=-1 +kerning first=88 second=117 amount=-1 +kerning first=89 second=118 amount=-1 +kerning first=97 second=118 amount=-1 +kerning first=87 second=65 amount=-2 +kerning first=73 second=89 amount=-1 +kerning first=89 second=74 amount=-3 +kerning first=102 second=101 amount=-1 +kerning first=86 second=111 amount=-2 +kerning first=65 second=119 amount=-1 +kerning first=84 second=100 amount=-3 +kerning first=104 second=34 amount=-4 +kerning first=86 second=41 amount=1 +kerning first=111 second=34 amount=-5 +kerning first=40 second=89 amount=1 +kerning first=121 second=39 amount=1 +kerning first=68 second=90 amount=-1 +kerning first=114 second=113 amount=-1 +kerning first=68 second=88 amount=-1 +kerning first=98 second=120 amount=-1 +kerning first=110 second=34 amount=-4 +kerning first=119 second=44 amount=-4 +kerning first=119 second=46 amount=-4 +kerning first=118 second=44 amount=-4 +kerning first=84 second=114 amount=-3 +kerning first=86 second=97 amount=-2 +kerning first=68 second=86 amount=-1 +kerning first=86 second=93 amount=1 +kerning first=97 second=34 amount=-2 +kerning first=34 second=65 amount=-4 +kerning first=84 second=118 amount=-3 +kerning first=76 second=84 amount=-10 +kerning first=107 second=99 amount=-1 +kerning first=121 second=46 amount=-4 +kerning first=123 second=85 amount=-1 +kerning first=65 second=63 amount=-2 +kerning first=89 second=44 amount=-7 +kerning first=80 second=118 amount=1 +kerning first=112 second=122 amount=-1 +kerning first=79 second=65 amount=-1 +kerning first=80 second=121 amount=1 +kerning first=118 second=34 amount=1 +kerning first=87 second=45 amount=-2 +kerning first=69 second=100 amount=-1 +kerning first=87 second=103 amount=-1 +kerning first=112 second=120 amount=-1 +kerning first=68 second=44 amount=-4 +kerning first=86 second=45 amount=-1 +kerning first=39 second=34 amount=-4 +kerning first=68 second=46 amount=-4 +kerning first=65 second=89 amount=-3 +kerning first=69 second=118 amount=-1 +kerning first=88 second=99 amount=-1 +kerning first=87 second=46 amount=-4 +kerning first=47 second=47 amount=-8 +kerning first=73 second=65 amount=1 +kerning first=123 second=74 amount=-1 +kerning first=69 second=102 amount=-1 +kerning first=87 second=111 amount=-1 +kerning first=39 second=112 amount=-1 +kerning first=89 second=116 amount=-1 +kerning first=70 second=113 amount=-1 +kerning first=77 second=88 amount=1 +kerning first=84 second=32 amount=-1 +kerning first=90 second=103 amount=-1 +kerning first=65 second=86 amount=-3 +kerning first=75 second=112 amount=-1 +kerning first=39 second=109 amount=-1 +kerning first=75 second=81 amount=-1 +kerning first=89 second=115 amount=-2 +kerning first=84 second=83 amount=-1 +kerning first=89 second=87 amount=1 +kerning first=114 second=101 amount=-1 +kerning first=116 second=111 amount=-1 +kerning first=90 second=100 amount=-1 +kerning first=84 second=122 amount=-2 +kerning first=68 second=84 amount=-1 +kerning first=32 second=84 amount=-1 +kerning first=84 second=117 amount=-3 +kerning first=74 second=65 amount=-1 +kerning first=107 second=101 amount=-1 +kerning first=75 second=109 amount=-1 +kerning first=80 second=46 amount=-11 +kerning first=89 second=93 amount=1 +kerning first=89 second=65 amount=-3 +kerning first=87 second=117 amount=-1 +kerning first=89 second=81 amount=-1 +kerning first=39 second=103 amount=-2 +kerning first=86 second=101 amount=-2 +kerning first=86 second=117 amount=-1 +kerning first=84 second=113 amount=-3 +kerning first=34 second=110 amount=-1 +kerning first=89 second=84 amount=1 +kerning first=84 second=110 amount=-4 +kerning first=39 second=99 amount=-2 +kerning first=88 second=121 amount=-1 +kerning first=65 second=39 amount=-4 +kerning first=110 second=39 amount=-4 +kerning first=75 second=67 amount=-1 +kerning first=88 second=118 amount=-1 +kerning first=86 second=114 amount=-1 +kerning first=80 second=74 amount=-7 +kerning first=84 second=97 amount=-4 +kerning first=82 second=84 amount=-3 +kerning first=91 second=85 amount=-1 +kerning first=102 second=99 amount=-1 +kerning first=66 second=86 amount=-1 +kerning first=120 second=101 amount=-1 +kerning first=102 second=93 amount=1 +kerning first=75 second=100 amount=-1 +kerning first=84 second=79 amount=-1 +kerning first=111 second=121 amount=-1 +kerning first=75 second=121 amount=-1 +kerning first=81 second=87 amount=-1 +kerning first=107 second=113 amount=-1 +kerning first=120 second=100 amount=-1 +kerning first=90 second=79 amount=-1 +kerning first=89 second=114 amount=-1 +kerning first=122 second=101 amount=-1 +kerning first=111 second=118 amount=-1 +kerning first=82 second=86 amount=-1 +kerning first=67 second=84 amount=-1 +kerning first=70 second=101 amount=-1 +kerning first=89 second=83 amount=-1 +kerning first=114 second=97 amount=-1 +kerning first=70 second=97 amount=-1 +kerning first=89 second=102 amount=-1 +kerning first=78 second=89 amount=-1 +kerning first=70 second=44 amount=-8 +kerning first=44 second=39 amount=-6 +kerning first=84 second=45 amount=-8 +kerning first=89 second=121 amount=-1 +kerning first=84 second=86 amount=1 +kerning first=87 second=99 amount=-1 +kerning first=98 second=122 amount=-1 +kerning first=89 second=112 amount=-1 +kerning first=89 second=103 amount=-2 +kerning first=88 second=81 amount=-1 +kerning first=102 second=34 amount=1 +kerning first=109 second=39 amount=-4 +kerning first=81 second=84 amount=-2 +kerning first=121 second=97 amount=-1 +kerning first=89 second=99 amount=-2 +kerning first=89 second=125 amount=1 +kerning first=81 second=86 amount=-1 +kerning first=114 second=116 amount=2 +kerning first=114 second=119 amount=1 +kerning first=84 second=44 amount=-8 +kerning first=102 second=39 amount=1 +kerning first=44 second=34 amount=-6 +kerning first=34 second=109 amount=-1 +kerning first=75 second=119 amount=-2 +kerning first=76 second=65 amount=1 +kerning first=84 second=81 amount=-1 +kerning first=76 second=121 amount=-5 +kerning first=69 second=101 amount=-1 +kerning first=89 second=111 amount=-2 +kerning first=80 second=90 amount=-1 +kerning first=89 second=97 amount=-3 +kerning first=89 second=109 amount=-1 +kerning first=90 second=99 amount=-1 +kerning first=89 second=86 amount=1 +kerning first=79 second=88 amount=-1 +kerning first=70 second=103 amount=-1 +kerning first=34 second=103 amount=-2 +kerning first=84 second=67 amount=-1 +kerning first=76 second=79 amount=-2 +kerning first=89 second=41 amount=1 +kerning first=65 second=118 amount=-2 +kerning first=75 second=71 amount=-1 +kerning first=76 second=87 amount=-5 +kerning first=77 second=89 amount=-1 +kerning first=90 second=113 amount=-1 +kerning first=79 second=89 amount=-2 +kerning first=118 second=111 amount=-1 +kerning first=118 second=97 amount=-1 +kerning first=88 second=100 amount=-1 +kerning first=90 second=121 amount=-1 +kerning first=89 second=113 amount=-2 +kerning first=84 second=87 amount=1 +kerning first=39 second=111 amount=-2 +kerning first=80 second=44 amount=-11 +kerning first=39 second=100 amount=-2 +kerning first=75 second=113 amount=-1 +kerning first=88 second=111 amount=-1 +kerning first=84 second=89 amount=1 +kerning first=84 second=103 amount=-3 +kerning first=70 second=117 amount=-1 +kerning first=67 second=41 amount=-1 +kerning first=89 second=71 amount=-1 +kerning first=121 second=44 amount=-4 +kerning first=97 second=121 amount=-1 +kerning first=87 second=113 amount=-1 +kerning first=73 second=84 amount=-1 +kerning first=84 second=101 amount=-3 +kerning first=75 second=99 amount=-1 +kerning first=65 second=85 amount=-1 +kerning first=76 second=67 amount=-2 +kerning first=76 second=81 amount=-2 +kerning first=75 second=79 amount=-1 +kerning first=39 second=65 amount=-4 +kerning first=76 second=117 amount=-2 +kerning first=65 second=84 amount=-5 +kerning first=90 second=101 amount=-1 +kerning first=84 second=121 amount=-3 +kerning first=69 second=99 amount=-1 +kerning first=114 second=39 amount=1 +kerning first=84 second=109 amount=-4 +kerning first=76 second=119 amount=-3 +kerning first=76 second=85 amount=-2 +kerning first=65 second=116 amount=-1 +kerning first=76 second=71 amount=-2 +kerning first=79 second=90 amount=-1 +kerning first=107 second=100 amount=-1 +kerning first=90 second=111 amount=-1 +kerning first=79 second=44 amount=-4 +kerning first=75 second=45 amount=-2 +kerning first=40 second=87 amount=1 +kerning first=79 second=86 amount=-1 +kerning first=102 second=100 amount=-1 +kerning first=72 second=89 amount=-1 +kerning first=72 second=88 amount=1 +kerning first=79 second=46 amount=-4 +kerning first=76 second=89 amount=-8 +kerning first=68 second=65 amount=-1 +kerning first=79 second=84 amount=-1 +kerning first=87 second=100 amount=-1 +kerning first=75 second=103 amount=-1 +kerning first=90 second=67 amount=-1 +kerning first=69 second=103 amount=-1 +kerning first=90 second=71 amount=-1 +kerning first=86 second=44 amount=-8 +kerning first=69 second=121 amount=-1 +kerning first=87 second=114 amount=-1 +kerning first=118 second=39 amount=1 +kerning first=46 second=39 amount=-6 +kerning first=72 second=84 amount=-1 +kerning first=86 second=46 amount=-8 +kerning first=69 second=113 amount=-1 +kerning first=69 second=119 amount=-1 +kerning first=39 second=39 amount=-4 +kerning first=69 second=117 amount=-1 +kerning first=111 second=39 amount=-5 +kerning first=90 second=81 amount=-1 diff --git a/src/web/static/fonts/bmfonts/Roboto72White.png b/src/web/static/fonts/bmfonts/Roboto72White.png new file mode 100644 index 0000000000000000000000000000000000000000..423a3a7e942054465e40a69e813b5e1fcf993fbb GIT binary patch literal 52730 zcmZs?1z6MT{|3A+)R1;`cX!u2 zJ?H#?=e+NGU0fGj+xR~B^Lg&)llQ`(Xetxlro9aS00>o86m$RpEXr0Qzt2pQCIMQ7J*{nN8Zw1eKYr{;PhK-_s283+OsO=gh91-*w>pcpORiYH#2 zaruj0Pw?DqXkPNJe7yg4AG#}zW1KPfGWE2U+ypvbz8v7hn;ohpz4wFbx-GoPbKWHF zl!;4hyG>v}SL#$!II3psO}-mQeO@Nr^L1uVmF-c`$YAiP9uudd{p z>W1kix@p4hIKfMwAN(@xwO~(3FML8=i6f3t&F$b#+g2R3vA&z_`v1=!PSU7&82Gh z4wt`SFEYpibrb)s$!zwFP?VS-5y^?!m9r`s04n*h(|yjUw6CspX)8*+X|Oj(-lT{l z0t(vx6;%1fB^z#?aT*ctG!r1X7m#);!GluMUW1hG8NUu*umR?4+qIMnh$m2*Fk7a4 zDpGoCZKpR$@GDc4hIZmikh&-!X0jm%$<`%UcDYP`BX(+!M zuUUcpLIR}sgmvHyI%|-AZ$3S_k{{w)!yl0*0uP1qr0m(BHxPt^NXWGtIe8!11vW9% zqoTIT+ST&p zTPp=^`RjG!w!g7HuOs;3$d>~cJDu`Ku!GUph_0J8N+P)#eR(roW>>SMg1l& zNXhHd-5XmnaRBlnw~#C6ZWB1k1t7^POsvI%!IWa>qk<4bBR!Yn)`xP zSpEfO?Md}}0S0OsC}`$WK39*SXw8tX#v!f1-Ehn1`~U2|*JH0`0XdU?T9em9Mf-`S z^oNWcDsOZ6_D)9839yOdrI~rYZx44C$@(iDwDOm3>(ig)P3gP%zmATbJ`(7G0ZsU= zP3)-M)5Q5uYsjv_RR(#0MsFVx+>oSUpzroI-A%~iV_vrUr8ep2A9#~+olhvjldo&d z&3i-)Qwl7gw=U&Yk2Iep-XX)+fDasW~iF*hux6sVJ+*=Y2lDUx(p4hClIM zRd%O#q9^3U8K*N^zTv3>JD&F+*|AtEo(PMNV|TeSGA4aH^2^s?clMGYONV3(@>D4W z`^7PI!|V_A&#Lo(^9R5v1C3IDE+s!oO5z8{Y+&|c+gN8-Io?vY@yyp7w?cqSvCdVY z__RNKCyrW0w+KDtT>}4YSv*LmXTe-R#;MMnH>t|9;xu6M^(g~SiAljBrOKo_u?e3P z+=x)KAxut?V2lumIpvlUe~Pq=nGXgGFm9bNsVf$q5Y?)VAOlo0{^JGho3D6VDpX&(eE z`-)<-^0x|=EKSxlJr*IcEFCEveN*zWnoHsp<19%`q(2KU6Y%8xhmJATUPR6|ZoPW< z2It)d?7Js}>U=A6pe%cphMt;^nru|lAIszSdaUjlC47{CCr-GAUBH8$~- zMYhBjQ{@G&ps#4E-YxVk-4(U7Ha8LRXCfX#E48;nv73(DlsSxD29cTXgfG_Zh5E@P zR{-5rBNZe~0l`!%-ce`+=ISJ4^N8Y5u;N&pPs)do-LlH9tglHdzB|fslQ+hb^MF!r zq1f>_xj%NT!2k4^YGVGb4~$<|PJJ)k*}xq>9-+jLVyYO22Qu+G&Om!5*pJD&^=Oul)mxd# zPx!_sTHW5xzWDoc1YOJo8PEfq>VdICuN;hYbXzad!adAX4HZ`dtgzx%v z-dJT#rbu&0wNQ!aNyP_Ix9ld|&0yKYjX$TpzXX`w^e4vsU@)=4N`zB}OgX(*H*35n ze$(nZMa>-aglq>b2$0oOLc4UM;KDP)2oah#5_1B&A0&4$KIM zD2{6bH&HVt+!M!~B!*oT%5iK=kD;L56lA8+sBzDF<5i}H z`omWWT(2Dry3?ddZDq6ZP0KC|va5M=8(#j6#exBFKCe~?>`la$8~bU!YZB|hNgV2S zCSEhL+Sa^#;@a73m>lR(l}=ew1T0J&7dvJampd6*>{eQXm~LC*H#l@f;Gh&5VjgoO zcqyn&JizdLz%}T4dCa9Zre&pOz`9YbH+<|@+S8BW7bjsHdJ2+rk^UohzCR|8c3z|& z@Mr%V#PT}-4o~6SRd1$IEO6tqWt~BkHo`v+zyHa7`Rb4dnV04adQUN4SZY?)j{qtL zuy+utw62m9A#0K4_o{=vddD6< z0Hl@tnkV!{#;EIEGg_$D>%x=mF$7#T_UVGp+uUN;=8Gttg>s@FK7P&@6D<3Aq5KK=^-#fiS@LlG}dTdLq>31$Kd z2mE+JnlWopfr$-Bl35!-Jj*v^^N5t@*aeVWPQ5JuEG(95Bg_s-HTQm1Tc$3rX_Mm3 z_MMd(C@wgiU5~=lB`1M0H5)m*+`Eb7b_sRx)^`FPRT-CARx9UJ7$p}bZ53y#4JXSYyQ-)Iznw{G5WXMm?%iE{nN{or&L8YO~K zwr=ZAW2QJWJ}}ZTALOX2=NK}uiMaDCD1~Cnk*Wu)0c!bqjMQ!?ZsEW_cj?h4Q;GB1 z6s6XCV)})z6UDG|1HOjJwRN61ghyqd7#-3l>d&3{_%qF|$z5wDX3zQ@?JD~MZYf;s zUL{TAPWkNse4q5n*zD-Ah^yrrH7fh&NR5KTEYY20J}$m?fE2!J|~S7So~=v;lX{i~U~ zglNr85;qiwy*kTJ5+b5R*YORylNr%_+-dG!f^8LKH-BMC=;c0A`?%Yds;>@b(w!ql zGlfP_LTemlNiBek=FVV&`YD7+(!-p}aa^wJze38D+<1A*8Pc>I9y2Ki>q~IvGO*E8 z;zLWAKLwg~L_*3F2Wrnz36u!zl3Gbm{;_y$tI*o5+n9qUq1mCF!^;q&TetLv$h>KD zj`})Hu$!pi+g!%o!Qzoy`r(l^vVA={+&X%S3)a~hq=VidMYW0qf4!XxnjzThgzXm< zE&ZY72(qIMEGIm&d@I?*tV{UuMTGdoM?Wb2w58pDh#3l+<@ixVG^9$lBIV_!p=J;h z(@VuY2_L*aU;o3o9i$1JGdkL>PFOmMovT#CHwZzZB@Cw1FSYjs(sDBoDKSR=?0Ms? zRA|)P?lVRJU5hDuc7*PCU1v^BY-;~;>*)i0x9ypU1|iUv;gtUBZm9E{Tgssv@}ttP zF%cR+j#I%9xKU84*L(lL);`uA@ajipWSYZIIOBCmMG`7@D&K@n{uKM+|HYg+fLD2_ zwThmV0_C|9>(@%lL$rOFosz-%N>LIisCX;~n_R|kuTzwG znw$VWv5SUB9hGr>`4!he^VNrq89I&s-8u{x{@CJIGLDPuO|qNPs-ywP0{r|jznFwz z@KrV^#y0}uSW-HiYDO*h9gDArhv~5> zPv$jRjqfRgxKLplD%wY{ZAF&Hf#-PxsbiR{1Blf76|!)0TAJPhM*+wF3=#=H6l{`~ zKc~qr4G}MQH{r07{8HqRZ8MI&p~d*I@jiMCJ%E%<>xJ`D2|Wqfb*<>ymqjpa3h+2I zU{XV{#FrSe3ec=#gmXbOgpXC7HC3>SZuRH;{32h%;MUANqWlK_p~%t+SqU|K`P0o! zG-?PJl~-52IaT%dE7F1M?4m3=LFij_M4S|fa{IzHvS2b z*$etBp>GT}-lrmzRv%MA)%RCh>=3^Nc9$*|2Bj1JHsB{@}h|q8=$O?BN;x zPB`vR&~xR6o;ARrw*jU?)ow~lA`o9#Qv)M1h3a2+yFgVkh;xJDSf(^7(9T?Cep`CJ zI_D!n9}C8R;IH*^7e`coF53EDD3tfKI(~^2e@gx+Gr{7F`NEA`2F&;m4KXLnuU>^L z1{fGCIJFO!`4L-a2Xp2>?`6@AYGU59tRnD{nW#WB>DZd#W~4DB`)OjXcjfL*-^&u1 z(Q|ZkS-G*(7|^RB0dXIbXk`0~!>a(k4TGdSPo%+p z>pEoxbz8TNcFXDfL>9_oP=})ca(;Lo3u;QB#7X6RX;{U^L>m31xqr$dx~^R|HL!;ue-7K-JA?iTYo-<|Rpjr4=`}v7RNT?(?$w07PI?p` zgLa>SI9%PGD@cs6{9t4B?IVvN&&+;R@Pa{3#Rw+xC-%Z5{x)FbM8IU3@<+?Ks@_yg zGLUYe@F{5DNf!F~gGI+nDDnia~5f@SYqkWXK^)=Tl{oyLGSuH z{XbyJ7+>Uvb801V!1Rkw_~P@DryUx7YvgjaQpg|z8|CD?)DsbQ8qzYYyS7#K* zfPYf}Y2ZQ=dDu(&)x!+LgILjIb&OTTd&QD)MazRS)V4KKwUyM4fmm>P{^h_S@_Zw=&a~0R z-R(XQy_?gYI^)HE)i6qBM^`s0tJQ3l-VHfdVS~+`v5s7~?W*JK?YfPT>ej;cS+A)) zoI&u1?|);nD=ZSMS4mW7y8n(V7sB44_=uIte#;^7A8^|oV8D#$ZhykCyW)<>e0p#- zoE{KEj5`w;4`jtVtS8KU_bxkdzLsGP0tAi%bB{1F@Y~)RO3|*~P;KHa-TKigL>S1F zIOy?LH{=l+mt3vN>gs=)>1gVW#d?gu8B3(pQ(YR(I^4 zuO#V}OQDmQbPCD*8U+8MB~o3f+)`k=zO2edl{NJ&e63sftI+FE4=Usg=LBj$B!TJb zbs#kO``}wkP>5TF9e^g!NtU|-;~-yKgok{wBu9n#Na};N**5K-{jTR{R6a()`}eGP zP#YXu$_YeDA#UQ@x~-ax`o&ZtRgMx2aA;m(rI@z5idi+>}S(kapRg}!tb`)>}ByGp}B=n;xaauKwFRE zLrVUW78@|*`k_;XFZ2n){DK%D)@<=^;r2`*PACLLJ_(Etgp)H7n^At|88Bp8# zcG4?jvDEt#%=fUNX0>@L^S+EP@$3cedb}}e`)%P`wVHuF)DSv{_TG}gJV=pX)W=KS z>x^Iyl>X=RPcyHw7p<*(-jsO=w|qb7FHe9uIon8xj~O?#?E|1IR=g{$)R0aI>rp5T zjG=)*g7u|`niJ5Kk1^$yr#hzYCO@+3gkN}w11sXD%kXwdbAuet9Howgng7L0_U!Tx zY?+_GSlfiXvTxnt2A^VTPIc|dh^i7gn_hycezZ2(>^<_O`D&ApbyfTDec` zvVX4lZwLAP=U6kiFClc3tVP5A3d_w24OySb;`!RS&k--h9^EqfZ+S+N@NgfYNP6axy}#T!DEs=LBZ256H@9WVznxIB>GA>-WoJRa zlkPG>1x`L9JX^(=E|IUPmPJ_~=>NI#$`b&ScH zVN?cx`epFb<529zCey8t$pw$pcPP|n6LrSde>apH1GS&+zf%KWGy-?&c~Dy{|FZGz z>=1L9bu`2bQAlad9ATAApaS@A`R>_POKP-dxT{fHF9K)l1ux+hK-qU?O8vI(#GMaI zLA(UG{d$G}GPAQYgrvD_$=hP*mjjOjjUE?4wUB_^==j(n1w;)of?M`s*~)7m%!czl zUMFJ>VDnJgwDLf14Kh0!u?!l2G1sJSJJF`r0I?u7Tl}GGVD!7a{Aiadc;O&1+9vCl zD{a2=zsL-1Ai5tkozleNpMx%M56sJkKCde!suUe4%`UQ5DzD|!f}?P#W)t=P+WnAa)U7KO7H?mo9SJW)8oltdo`+q8C?A9@6so2Q)1+Z1X~2))ZjMyQ01;r-{q0z9kY&qA<6dtsNk8(T zFf>iMPtQ;@<>|@o{A-p_$vQ&nY^fCkjk>XySy zk(EsgA6^E0D%k$z>ITyW@pfjhBJCd6*(pVXp3vVNRw39%q&+YUeY^%CnZ%C}oQxer zq{uc%T70-e;Cs*DxzjCsz8-}p3G=lF=TUi!s;)QMjTEpPHv=s=Q!LYTum!w&9|F7!9 z>?2bWf@!DZDZ6=SgKy35+;IB>+O@y07DymP_fi1_6+L4{OWOs|A086KKhFg22>Mpp zdZJb@001e9gsCi1@*3WOvRkl|!K=Z%LCnyCYRBOAm}TzWARlPge%=dG(&tWu0i4%D zbfi1l6(1}_`Fm>uX!DYK7lxN4mV=$$bpNhfpSAT^;`i%~2?`4=SeKSFJVtPEMr;;R zFx-+~9Hr2x5ME%|6M)ELdM_kWGE}_(G%^5vUlehwARh$YV-06YNB*#)cczc6J`Qpr zVuONuB179&pPrnDCoUPyrXfy-)e$EQUNyF!F{7czAe`ivcw>2YS7e#WofnBMWLzPC z#v4znLeu#aYT1t*SuPlRLKVio_z0bX@y36V^zzZ?;G&qfC#6%PRtab~3FH+fF+Gh} zx1hu?|F@BPRWhPZ`x0haSk-cLsC(gliRg6_=sv!l+Tf|_%AtJ^+pbnBmIx(pqXm_ZA7o+3mnsvWBiOCtPTlTeOB5bjt`%G4;*$?VwK?W zeOS12Cp?gVINa3%+@vm&K35^mCUzwmD3$ebaxq1`au^b(`GmdzesXz{6;8miCO){7=gAPcoCm5nTXZs>rdVX z#bZ{?LE{bu-){O4RnJ}V9;h0OP;=}&#^WLUkCpkrv+d&+SYluU$0+Ch(e2v+mH>tI zP4|z<5HmZ&t+aOUHRr;uqkCVWM+k{tFT+$j@y^s4Tm00aZPGaYE_8lX7QFlcX5c?N ziErS4rT?aTJNM}hZW$ge&Ssa=FBELZd`o-S09G5(sk(Ii=Hn*!Y>H*5pLbK!UwtI* zY;exBw&Cp`F}a=5;#)tyl0L30E%6mDau;(*W4Rbamw~H48;0xxYfaAx#x~dlH#VL=plO;mP|dOAeGcM_56A2t|ikQF;?|*sT*{w z98Y_bt(tSD>=YKG{pzjorS3NezRVmnK-N(4jggekXH7!f))^EZ24x_QzxdFUT7;~S zX>Pw@Hu=GzMRsEHcvcIS0T>!6 z%$X_=UI^NPX$LE^4XrTKKTg8>Gat}pdgKzZr0{e{rOb$9=!?%+W1NQGm=xEYHVVC~ z7ZWXuSJLb&4i%Ef{mD(!q06vfqCfsUw%l{D3|_|d+Rm_w6169T^UX0SWg3M$+){#{ zCMaZq2UDkX#&o*pK$!8y^TDXxyBTJ|QX!HIfPQ>4YvRQkuC+-!H!Epp^?gztxARdY zYM_uqUT#tWm8ykEFQqsZi61gEsE=YnBT&?i{w9qkEYH6UBepQz#*U*Qe()$eDQ`N? zqTJ{(_xzF!$AB@Ng*`-BJD*0^F$g5Mbrdt|b@PbBlU~y5vS4OHaFrD^gxO>g<_Ruw zHKC0OV>2X;?w&q1{B>Vwj55>NdC0B1C)WMpz(Y!<<+fQ|J-fQn&%QWrIcW5~zbofs z55VZzDw`InjynzNC$o-RoX=mBfMq>RXTTz;r{?BgIFXxXe8M#3g2(z`3$mjtakqW% zPxieRodY2oRq7uW|LBaCu#hsReB&`%nhLVUC!!;IApgRDsP5MnkdU`M_T@uS@k3pm z)_}ggs>%|DCN4!LNR_Rr&wSmBq3j;_0{CFrpk+$fuC zXw}$Hkxx7?bg(cKGOKcl?c&kfLT?w1v)P_0n^zu$*wozGt7qFQ z!4bKQg5~^f*}f98R=_Td#tfOaWf4yo_j2b!BgCRNy3Say!Q7j`)YmU2*rJj;@$;kG zT&ja?srYGUb-HvlQ-sa8I$KZFOlo?XTm2pFCiJDmOK*8SQG=HFhV;3C0YX@O@dr?y z@#zDC?K__jB(>@N$!%&V_U@x$GyXnc3=>gI#Prn#iZ;EViRcMEC-6wiL~98=Pze?t2E$DY00OGI^)nKA>TZ4z-&Zf z15R`W0&()--pP4vWFLo|`TqJ_cV8HsdmC%GT-UtuoNt-bv}RQRHKqr7)_w?xXj|`Vw|GuKg60gsD%NCw&BaC+G zpJnGb&=Ypx?9!nerFm=}G+iZruiFVpuS;{LMobgCR65tylF|fCgo`yNs)I$4are2{ z-)jOMW?p?-6o&D(GAs?dm~P`eoVUcf8D1ko&cI!%K(N7#k50|eOgYq}5Z%4dUx%g+IuaPYA7GRU#bOnzn}4aHT+QWYm1X3d^9@_f zu9kyeoAcCXZ_Y|KsLMt8d(y|bt$04BAiRi>*_omSjF#xPE@DxZS(}V#{!zDg#7hU| zoU_>h^f&pf=K7>64t)&iGhV9(qbWH;2FBw+dO)M+H&A7OV6SdqJ-CIA%i`a(& z_G>4rn_9MFrp{918Ni^Qq-(dAeP|EiZtkDH(4ZHN%?xKKiC6iwSmB{U`brCHz zSe@8Nfqq@%lnikZyw1L69qh8+xWmvD2C$HWDsv9K^KbR!doU3_HQ>UWLu7uac>qbz zpg;7sShz35qZzgWGpT8hJibj||afF{bihpt#kMS^#-P?V$mTLK1?Pv=I zn6TEdEHV<&i#X2;5h3K&$u`0b(7Y!efJrSEtI^T>PIs8T6@|#Ah~V{N5y@5;Ia@t( z#Md5~$O$&Wf|X|mYBh%#+_ihQbYhwVf)!qx#JRp*xin;3!4~Jg&c8K-kp3+w?b974 zDhgbE08N8QGQb|s81C3m^}r-E{jvmSvZL-a%5{rjRAA8XLJtv5Twylb9yqZwZ~%)P zDI9tsi2=&r1H|A%240ZOyY&#Zk(ToY(_==#fY7PY{g0yq_o=BHvOmnxOFq369J_W& z6*5KTyLB`CuqE{F*yqBy7|g%g1#cyYhdG!OX(Abkke_mSzon#Yy%lzLf-r6E|H#uo zz^Ci&-(Wt75x=^%65UNxSblSlU&Lp#nOOD9mk7FX>hZ< zi}Bu-gfsVOKOy4Z=k?d(Bx5Y1+0M${VxhZ#z|&XrnSzmlZM>eu^-sHNLogBL_xgWc zZB}?Yp>kQD;7+jg=S2}`6C@E#oMc9qDbOUoY;*4K#kcWCfzDk1-|RtBO?IfscYpBD zBK?5kfbGsCbtZp|B*0_g-;X#*9Q@ruc=hrxYlBX(HvwM2Mtv8rjD(Tx-oGp`+X%z- zHWhqNIa{36y?-kH_6V4FCaFq6v)E^n^9!E26%EvX@9hH115nTJ)J5AAaI`bh{;wyL z1WGeoUplQgQLX$7!bn?^*o_C|Upv_K|M&YR;{Sf|jQ79RzWO)59nXJnq3PgX=DSGy zmm#Ki{$A>DBK!^T_s6dTu;{RMW>?ZrpL6*Sg_p!1yu5B)XiG{v{l(?~+4b>9kh>iC zP-etV(>FU+TK&?2t8uoCj>{kJYV;oD?tdKKC%LES;@G#-cy3a$bD()izw(ijXz)Cj zOX{YLD&tgNbi+3{)m>_%Enjrx+1M9Chqs6t?|Dz7J&dyXXL!cS=*ur|{FlUUis^oA z6bD!-g_fd0cXbvN0?psUt@5dS%qmoij-CeeK zG8YJ4{H+=>3O)LZ*y!kz*aPbK{zoVV@%jsb@nYn@vgNS+i$n|+!Mtpnd>mbeDF|O0RPV3Ni_;bsAG@saBho-O2 zzD$SPO52KxUOEcL!5O{#_A+-k(8DhxRh-nIH-M)OTMgV=4BB-ckrv8kGkb;lkr}Yj z*7W=#ffqW!@Ny>FwurQk2q#WUm0@*Z+IwCohqvS1z}~&%o!i9fdRF(EbVc&CzCEhI z50jv^!yg#FLDcKdnaiiQzq~@+; z>o%M1MS1L5PYDJ*+7F6%g5i37=9ifeyX~1ddeRC)-vED zF&bbE@La@(iDn@tH$Pp}w);QdG z;24p->l(PdAOrrMEq3_r!yYka#@)gO{caaY24`bxMr{u&Pr&RKE6EnhU_#Kt)wY-@ zy+cN%M)N1&;p#2Y`Ll{hYW&B?0V zn(3%JpmF=$+RBaHo}b&4XSrmPNeqUYR#%wq<`q12BK{O_0!GBJ!#0bs+fXD^I>Lf=KcQf_ej3*I2h{ZV^oCMpw97RAd?{9S4MIRyS1+23mib zV@jO*K@S^9JV_`!OG5}<|^F|9(E zP8v+73}iTyKW4J#W+12|LXH^S^h8Dn6T%5@eqJx&%o_2f0&-i)`g$`kBBk3^o6&kcRT*th;nR(g{>y;x+w+#!F3AL;sAM*>}f4A*|S+c zKl?^zSRLbwf$%3TIMiNolKMTg#bHTv&E!t%+rWVEinUueBflz1rC3+ELF!&|FYX(E z?fEFNrHfUhtt<>8!mGcqzWru=F_i=QwAZYJwv^LwC`4m|*59NzTr8b480f?Y$NSIW zL}6#~&G4cIq&5ex$d`Q6j4(kSn$gsKSq9qN`#70N>3E1AdY4(7oZve%(W$x%{Qd8rK7w6UFr zLvOEzvFPRNq0>Zn5^m&m0$%85oGe$4-ImVU^zZ~+E0`<-q$TJMX#}b-vF{V@W}6q| zyJcPL=U~1FaqTiUr{q-|($o5Y{NxT0biS^rO2ROt{N@cngyC2$@6HK>yG}Atf?d=5 z4y)(9YIvZ+m#*mn9BXbYV?=09;Ru_Um&N{z&u;viVgM7*DInVVw;o|}lBT~}-i!NYN6lZXs2{6LDd}W0(o-Jc;(xJD8}cKNU+mh;;i1__`g?V& zCqo{XlI$*Oz|E$e75F~=5+kwC+)QLSPaC~(V{4&YKSgY;k z2qOiR1Dz;b2?uE1pQyYg5PD7CW*-G)sp#q*p!`Y1|6z0NTU2f+$$#9k(8BZiVQm&p zBI*Jf5~B)zYt|-itoSo~KVjB;62aM^$W&5=>q5V%QP*Brns`LffIPWLN&iq&wo}-- zngYHg#FQc&S(Z`sO(|8K%#4PL9uiZ?JA(AkGmM-B@J z%{$HIGxOyp_uUMdt-<8@kVwS%<_tcb)tNtD=6{X~858!@KOXmya&pVC8km}}8i}7% z$fYhKNTC$Ed}BmYJa8WUeOLUvDY0lENb-VUblG8}i|iGswGWk;Ht<%J5|kB}GKT2j z);Vz8tAyD@x#P(l7--O0Ux%EwSDn9Xdbk3zDlH33^e>F(+p~8iiD1e03~4scj^%;b zsR=0}Z6QFKiVtbo zm67!Xq7WnS?4SHVxdjJW8&O7gM%S_jC$D@#5(*Yz?n1$5x`}TG4tx&RW02plfQfEO zbG4&aWy^{~*RCd19)3~|kQ}3i4CvU|L2Z;?-O5t^fZ0m{UhCbgK@|m48veLSG48~v z`$RGoltDwuw`J+VUvbb(-+Sp1-Mh-sqVBXo)4ckiq-)OEjdi$PE~)cfse7bpLfv#me#c5YN$IuQY60F=Hvk~BF?M6n*K-_oI{7oe#gXugD_FRxf zG$%6N-atj%EL)!3Tb)2^ZvuL1t6C(Y^yoF|n?azsd#}(xr@TqR@ zo!8xT0{Ww8pw%Gzu_6m{LTHPLiluUfq~63G-Rpu#D<5SNEb2BTHw0q}6~4wClQI{= z$P3mnLMQl@ltn3oXRdvK=BM$RtO#9rE^)|&i{*-qCAdO@(~`k}hJ)`aXHbb)pLB`Y zk=-v2V{XzQ+NHnpl2>e+V+@f9Yrnuj(swsd^n|2UIzx{S~%h~ zIxN*(HQMZ>;wMCNpdsTbQ67$x<{-td2l}JcI_!C#yIb?G-YZcvBy>khLCX;LN-wo( z0^_W!$IJMWwdH2RXM3KYdR!Woq6h-s&b2HgH=o5*Odc zVh$1Te0-D_Onqc9^#6xb`*2k`F}i9@`fi1ziB*q;IAb;xN%`E)DSWGmz)`1g5VQgs zkcz>~Q7n-0C1|oSbK73{gnWqYO5z|HVLw||cbw2Z+5Zb?Mrp`Pq(%{mU@We;z^pUT zw+}^lF}F7q+iFRJ(*0mf7KFvHNFRf3MvJXrg}W1Z%<9Q!mOLm%S;VhHp4_M{3O%y- zII)c?YG8SXC-T&^45)ic^l2@Hpf0$`K_=}w!;>2lE4M#}{veXs-nw&-!CsU+?!JLB zpHLsstBM3|=tD;c+>ZIKsRI}1VI+Id3ZN7h8D?1AIq4y2m>)3qHltJN{P9%b@tA*0)A|9ma_Xx!V zAL_hb<(QbbQO#W#I*xfsE&91jLOe38O~90?u5zR;`Zlp!k=SQzifr}{TklpIGxEfA z$rJbh<@}mGMK1OPg=8U-z_`jWE13^`m;;Q&fFGSqRhBe@i0Fjf|dbxw`S!8Ttp(%%oI%3p^nIX|T z14kJ{NIzD=(m}Lt0RGPGJV3U-a6=cvk;?4-i-YbZtvBhKb2WSO28#=B$HO~4h& zDT@jZgR4riQA7MR{VE3DS{M_n5LH-K36A@R9)K$-DFx2mG4$uC8{ta$3vk}1POKMS zUPE}q)3tgI`XBB|d4p%HbJUgBy06^EM5LHv3C+5hKSD_j;Nlqa=7&b z(eCT&T2H_IRYO8}R7DcHr{I;6Y$y1~rfVGHi%ZgEVoK~uKQR<09TQ}kReBf9wKvCY zY*)ws#rl?01Th>I*$Dx$enVVRVg%~E>S1aq6U^5bt8#g(l0-6^TW5IwqQT>_T;@wz z0;aF(+H1j&mgkIzx}t}tUTOI$AeIk<)HXB<#ic4A8UR0w?JQ8WeyI@92yG-_^@}4D zbKYt_W_o1ag{6gd+Tog~>r2wsu&aR6FwoFpre5ribv0M356j5~#7qmraE0trXx}6DVI$HPaQ>Y zz=_ChMWaYHt_d-CSL#%n8W-7?M5JL|@2=|Jo@4Iw52E*lc3s#$|1^G-phhP@Iwl<7 zsDj5Z@Vyw2g(c!n7_LzGssc7e;h;J^BUn(DvOq9CVEOlTI)o(!N2^PV3zvb+>xFi+ z4U5*eE!uG;4X7b(_em9$@h3=c9o|nVBgX@3;YZ9y`5KRYDHYpG`9E+>gyF6eTaOJ> z)wskTV39`7*Q!5Vvk}8a((loG8S*h4zNIx2jTE+xAt^a;JjYIV%qX zMCL6T^}|H4xp1+vg_u4?U~5TpID_F?_6MrKU6rNC=*TD$OV9nSKccbYP2Tb*Am+G* z=TixB>Ih(l^u)L(6D}|9`-jvY)?vSBYRJYmSR4gJ1~^SUWY{XzC0td*Z|z(;CS`dd zwkpKo`E$^N2lqry*`s3WnV6n=UuRP7Cp9jV{kwbvjA~X-`Akdg+Y+cnTnqn_(FSVK zIN?(JrQ&-Uh4j5%_p}_o_`x{fI03ZK;f!(Md%1>(>G)T8f%K55Vt6^S0`kCINx5Aq zwM@K=hUyeZ!J9ZaKXOP8Fw?>e%pOJJpE6f~hlfBAO| z59<8`5{@OE>sE^RLB;Iw2PI8eCugdHLx)w@uN~S4>)~O-Q2IyF+%Ff~utt~l=|}I_ zgcIq1+G7#j84E3svan+(W&KXB-G!@Le2*SC_nq0I>nCsHf~ZMh^@&{5k{8t82U8lW z^&Gvw?|T=0;(*D`x45FU4Ph=N-)}HcLE%}ko(g!wBIMb4DdBKyXO7lyK9KGjgl?1o zv$v|GV+*8xq_f$|17lRZqfmb{A)cekUv~{7OIx_3$32PgdEzQ6gqj3h&xF5ifK2UNPPAiBcPEv#7HibdN6J~?5PL%jT&R?$UO#L zGa|1i7wEXd@T`8Ls(g1U#-;wD0_-E7iz@NXnk(%n5j6{ zLq`1YPy`^<-#AQKU?bbKJHc&15=$o|-B4V?AL--R+;br3uvn}&ejgiJ+0yxGXE|Do z7@S$p*~*uAKr5}T)(x1x3etf~s(-qlHE)72UKG@7Zf1;386w!VzF#Fwz z95DXLqnlI+6F24)raEn&WT1}|iDEghu)d_YzGIsyv9Von+LAT|hI=9ClNfvu7);LV zIgm$#Z*R>PmHUS%=M-w$nNjae_WpkkjMMFS`$csHh<~4=jDU%hDTN)$D-gCoA2LmK z^4Prl!FX1-+**fLeA|vz8Z{;{Z@Z8+S!_Sg?j+bI-S~>wrubdNjt*!iOsOCUiIT_V z)&SWbh`%TH!)MeGbe}tbfH9r`0!Q;t9Ym5|#=DPkAM<{zm+MvTSa^okUzUVH-qJuu zH*SVqp5t8-t~{4uUoj#sKOpW{OL5uWNX~wcErO$uA^u);Ur+tU|F~x8gLL`gRt8=~ zh>UPlCxMVScQ#Q~w8!k4o(GvR>GZ0>a0(VDphD*7|cwP<2%4CPR_S%6yw5unqb;R0zNjj>aSK12QFC zjHwk?WK0$-T#md^Y)lgV)RWsJF!#|>zv5b7^FpvjI9wg+d@SvXtS}sDO z4Oq^>TJAERmx->6;?6P4wY>u|bNhyaii>={jgdT$OVKqy%ewGIsh zAnOXy(s}~-<5RnZ=xE+JnIu`n6{lnWkQ_n%fKKL#e^bw>4Rg2o#{WarSB6E|K5qj{ zcL>s*!b;cDT>=s!-5rukEh*g~ozkFybV#RkcP%B|NGbI$PyPPympzXCbkBXw%sJ=G zH8b}B{_odE-@9Uq2UToLJf(+fAcIhF8~w07Tm`=cETl-6z1!PqE_I_loCOFEY&K^P z<8J{>f7787jQzs6Fwx zj`+9KZ-L#+*Nm@KiU{l^F#Etl2@)P3wNb39wvPw>iKxW#>kKoFrl+|@nI^QbmRURR z`ti!_1&h&(f;PDO;BV`0Rn#KUC}3p)qz2~v4ik#%Fxu+3`&GUCI5h#tKGZQ-D(?_M zT;|;KB;nFac9I`vria7`sTT6T)=PhudenVxs8zzuYIyq!IP#s$%SXuNKzNTqXNf8+ z_v$Z-OHtjjMJ!Xqy~GNU%ChsI4mv^X7=2VT*$Z=hW$qa<0ViC-NQA+yxy60 zv+SP*D`xo=3&4rrG|m!$xM0`xgk;%j6X*gMeOjVLJ!W<(zK8;7Jo)b?)y$GK!@MhC zmkU>QT%hTveMOAnBdel^F0|Tb%#7&hy|j4F5c2)( zf#;=Q+1*StNF>k$2WFhO5i*zpgCi;5Q4*4R&SVr1!DsLro~n{$*!WB6KiiB^;Qva- zA*1l&4TJEvY*iHL@#Pg zC#>X!tMh}=(pr}Z^>hM&-(vqA5)V@^HO5v9D5PB0eAQdLRH>1LR+!Skt6)(0gD>I- z>7R&~W6W!>Jx&vz^TwXGpKvRmT)o819t{AeD!;;_@If`$o%)Q+IT;e3*FjTwu$idS z+8_!!*BtSk#zThX^Wd%O3WsFCWgW+o!Igs|MvGkQ=Y|nOSv?7(uXP;#xM-`ee_Tvk z4O0@IzYth*>wV~A)Hmn_{WQ&X;3(KK#51i0RX-)?SqW*gl9U5*DXhFA;IGlnIR&W| zSzSw=By)hS^owkUOuaMV?!6Kcw@21k+T(re)#lMg39tQGC@^m#0mlBU*CZCkg8^e) zc?GlZaGdh%xXcY^vH&k~vDe#<@89m1;*F1$(L+D-0RV*VueEnsel1^3=^bnP_%0A!ngxejh$&h4T9nD3=CrAyPd~4r2$9joFN-N^gG=J9(0;!R z_iL3H8e>OllfTy>3JH z-6AmocWqL8P`mcNHO+zlx2(IA(@(#C0e06V1RWh}uerH93~)BGJjFi*)GMp)ca2fg zcj{O+N?HzF0=%ot(*8V1MAuoPP%l~3ZC6#NPfFhiDx&xntE7$EFCt|+fhPg3KtReu8;kyQQ!R&K3WXgfQHv#K z$H(T|TcM&L8q%4XLUx~gKYEU(3ro|p$N+-rBi`2ppau{ejBV?GOkevJb|ft>pfJZL zQxql`dir9wSw)s0{v|7r?U$eVra|F$@zlpXYyi2G-Un7^>X$uMtj}qs316+nOZ$(_ z@eF&$)UJsikmE(-p~k$478(eRMdfDnFoS{HEHWkDceXR->miT(oCsT^kUZ9Fu{MCC z6#g5fgyM$20p0ty3Pxv4-xjdn2mC1jq@6_71gL|z*s~C z(^w*5u5OeBRKAGqqXWCqvc230O#;Wz!U`zTpmWJnyb9xzCwQf>$~svgR;Qdmp#O{X znJ~lwqd_ z?JRv{201A?wndFy5%X?DH)#5On?k6O7Vi|I{u*Nc1$Z&SG^IsN<16n2`IRNw|l?ph&T?!8rgz6-U<|-;y+iBKGhoxFs4Nn z6bfU)(qfa30u9L~^$iMc-GRnB$(<$UtpvEo6;{}AJXIFh#=Sw!X{B3X zaG=0N&-KCucOUTrrGF?8TY zR@an67upW1w0^{VPZHAjB5!x+a<1llFdZ`L~3I#5ri|#cV&l!EY;hTkXpY_%p z3)30IcMES;%wG^8dw0u>C;dWkrZv8sJ7^YXLcJrcdLrXig*b%r(~ClkLsdSU6N~J@ z;TyH94;|8O()_@y#DlVKgAFrH;ld^R;JW+TxDkEQdNNl>I;nY*kFCw}zVC0*#`M-w zJmgGpfVubLVk=xh;@Cne!GIDDf!LC| z$P<^Jq+$|q>+BRD>88(t?CZ%iIpP>9MDT47vA_o|#wg{Nz2L{f2F&~;3o&8yk&j`h%&$Nn zcUa6PXkw^tKuH1u4tn>a_Tne<){%M~gQj;TcG4lb*>@Fg9MQxxdl(%W4@TSugK9oD zub-3HqLhul-?1d3C&rL|*P6JyA?=IoI0KaB4|ZexUIc!UNG^M~xBGBfKqBRPJj{HC zA&N5&y9jb!41rgyC?Boi3ljB#6T7pFM5Jlq-wys(ZHx7YE;gr<#8BqEbdU^p6&@;g zLLx}Q&2SQf7ylL>x8ZPd@u0kJ^JP)FYhR?6w7=-<)GmC|EQLCnwSw7dYxon7*~M4? zz}l&{7``e=q;%DDl_Uuis}s6}PiUeWn}ZBq07GU^ zbmC+C`e2!z+$Np+ToHJ}N^#CzZN@_I4G_s0ktClJDwryY+Z6GRxz{X61()W6=(GX_ z_31^9SAj}!zmB^#`$SHf!9p`SV?8a;;^uMVdR(6uO_w-XicBlGvO+wV`i}@~DG3a| z*1kV71p^Mlqa2;cEt1BMduDtQZq9@VOV|jwh8L=Sz=yu!oX_(}kbG3x+8)B8YK(n0ZiR6LR~=Pp@)qi-i1s zBx?^P3>r5A zKJ0fT4^drXeBbaKTUmH9OQxLBEd7K=*+Tu7vi2sW(A5@s)N_z zYyCfc5G#QlG8o~iP4jb?bh)R!I&cm8e_L-D--U|0kL1i`H%mBOsU$s!Iy(FJr#Va> z>N!!$Pc^OaWNsh#_6%8fNvwteNP6~!K}?zGeGW4b;c&vUM?uJ8KdT8~3leqSx!cMJ zb)rfB@FcR9YYn%SOIc_#RVO1Spih0Qr~^2JvB!oi&i)HXFH1X8a5zNt{(6l=DwV$} zLI&@8TQiM?NT$N2XDr9p??<81SiT1UMa#QYOf7p*Md-Pgv-1MVc{_<6#LvbK^ zp(`Wh6w3B}7uHcvue&TJJ^yyrLmU9CwTo*m_;xo-A}*b4=@Rnuo|d{b?pTlqJz*QJ z;&#>f2ZH-MVYb~u#`_cPX*nTNCk3qA6pE#{IDW%x@xSl`v1#(RZtJpo?&IXA(gDeT z-4pt5uxt9)Aq#H<%wd)6!g7c}a;y@^uVow4_+IP`!ObvuBEXzbp+lJ-cSH{6`G*Yy z*|i`K%;j%JuXk@KeIcL&0oR}u_7ruDKa@ZHB$W0hAS<~@XcxpQyPP<>XKNE5J9O^i z|7mCYr;F~nBTlF%ln#Nm_kvvTGes;fO0ejMA;F`-30n|(QaM@P+3v95Po6LcZhIW| z#dp-iKO}hFa?BWm3u(uyIvqK(hBKDcBqhB?A5?KF8dm^u)xmv#ZC8UAv#%&HAJq z&Ed8*%au5?*=|Kg4}(jWPY{l{ic4;uD>pB}*nGGi>r2F)Zt49CcGU5pSy(&-1B~`Q2AIklzODRXdWE;B68lP~!5PQqt=w zEU6Gs^bZhJRHZ`a5=qQLLrmzovy<~p%(c>5^0n5aY{q=)C~ZN}BD}cE8zO->NOFso zI8mK`^A-Vo;58i`C=y0;4acIYl1&Rnc0+CNgJnQgfR~XI)|1kZ_t!Vp6oVtw!%mgY zTLid`xUvF0;7_HawosTlvBL0`*Aw5*8zS%mGn`U%u`RntFd`h%+|~``Ht8??z3J!{ zrF7xwDL;}lb*SYQqzbUH2I;9AF3W&%FgsXw*XX6BV-w)+q+DX1ETDi^Zq_i%0LG(n zxg5-~e6Pa@f9BuTFGS-t>!wHGmt;8$iU#4uYmBh8TUdno1Uss5uLfI+Uqcx!q&E9+ z0}r+y?TM=M!90H{cL#2L zc@1x(YeV|Yo!(e)%LPUhZy4DeLxwn?lgwu;Xs`J2n^uo>#QC_P--0+Ozr&@6ff0e_ zPMB}5onEzi$fK4qP|(dY7notxD&<;RK^$Jrig4KbG9^R>?pYuTU<~sL*-A?8p%h{t zsZ`Iatf=X6bL$cnpt`(1^EjSGPeTeZ5$rqdfbHZ1^{LFp(DP$>+BfLO?Fj(a19e-% z7n*suI2Asia5-3!c(oIAl(%i)5gp>AI_uuW6IK+YlbDlS`+0FKS$6Bh1kfeaDya~= z*~S_qtZZ9n3|9RPmj3~he`JSF_;nEZ3ptD>euQ?p&o-G$7fhen=_vHVfwn;F98^!u zn@)~{Y*?>-iq#fEhSSIWeg@OwlJPP6tA~^`E|RlkNxN}kAPvuG4nhTlgL{DM=;6Y= zF0dZHh`5}f*OBO<*a=r_o>-ZCBbQ5i*@Rx#^0B=4_BBi8esKXqMl1D_RubM>^6s#H zZlyMDbZjh8+HDq)qAPM=lVri8u?pxJ@VFT5uFi6Hl2EQ6#}Q-R$-uBJ<0`P=jHKRe ztHjh+VtJ(+Kl*VJ?V#CNJ4l9auuo4^d@8rz?7pJRjt4iV&K)V)PwD8&$|*4dRbRT@Skm8+03c4i4=GM{6+K_h->6;7PQNi{g>;IWID{ow!&mcu zg1;g4i>U~c9p(-OYkaxC(4QKGwX{EsX7apx=!8C_2=RBEEpcZxq>Oj zK}n?rY#RqUS?;z}1)Kj*O5j1XGjR%R)>bY5U`U2HzE6%`f=MuBdRpjoIjNpAmo%BTpJHZ?sYABUgD?hrLZX#txZK)!!2}MJJ^|b zR;SFRa7{F$JUbVZT~(GW!n6^V!^T) zcW;goH}#jr&EvV>v?R)BUdAhvR(;I=5 zfn#19*T2Pk#8*DN%8mv#zx>iHvQR_oUB#Co-&;FCzYEm-18fUN4sgXRcaV1UGW)T@ zSxEeURcxigVUPXYFd_SG*x81NzxaYyu{F0m!Op(!P&0>?@YLLj6N&<{hLlk^srfhWg z#H`c;L#no=VRJ}4ZNdFJ4!nx6A=xr+LYcR%6=_LD>UmXe;pH-E zfiQc!_GBU{HlMVcLad47*l4R87R7|vu%)tpRN&mTqs0+DS2);k zuw+3MDpFtZzoU{29#;deHTWmpd*4^ELa?q!?cH?wmI7V^UB%_Qa*y+SnSxPCw*Uu`i%%_1=y~-@oYpPYca$f?-q#s>y*gn4W92DB z4U7My(gvloxZeI(331k@;W=faJi2}|KI@p#n@f|Ly6c^gPOV{>Or{JQ4$zVyP}8-|Hg}mo(W>cOuLD~2(vbl9LVUB)`+!EG;O%Xt*j}oIXhE>-a>O* z6~L5ScNLuS%b$|Z`DE0dP<)-BWw z&Y=EAc&Bm~Z!{?zlZ7N=tAY0Iv-x6W-H2!poO*J`2JSq&d8vG$Tzg{L2KW6}{Y3-q zM7hw@CX_nhe`0T9yun=a%dc3DLV!^n4vw*Y$9zC9nwLO)U(aPSeV9OSKLSNTy;ALz zI~1>nbT8aWZv>H2@98@nw%!*RX=YYkIqrXB-LbN80p(e1IkKf3fe@0Ds4VgLs@>15 zJyH>WIB4GI_*yArULsB1dp>Y^`7Dn0Z^vCq(Ft43R7h5Xiukc1Dh2BX-j%c{V-^~D%h&ZY& z6cy2*eC((Uq9kYbgGMZ$UH)8UbD8w^2YS!4%%YLJhBSLK=KY{Zu7io}u;~kltZtzQ z64d261hzau^&6nYG6LVNS$ushV(>)G;%$<22ZPFisqvsb>44=2?0H?r`dHJyJ%7-8 zInjuf{8n;t2s+u@@G%DA!8&fL`;&gP`Au%psUG{=*w`d5-Bt?ePFQ4_9~8+UX~0SX zn&{TFn}L(uLSYcu(3(h$lV4C7xQTk0&1*3*wtw3K5nt|(PU&O*C=lX-8)W-)dn3;P zxia_~gK3_AWiM^&BW`^db88Dy+Bp}Hjg^x5Brg#n%x(Ya@AOT-$CdT1gJ~!S+xe z*(=-qcvZ`*cJu4!%A)auANCc^NchjT&xx+;iETd&9nYJR+zsCBeIC3ZBVLy#tnC8Y zPk=tAV<(!Nz7#5OV29#i^RFCRH@E3mvqyrhi?)4Phsn>zpee4G>twKRRn)FqcXI%O zwqKc+)cKqaxx^?7ibk@b*F zO=0iAd6pd7bQb6ua94ehb!^ynuM@GKiJQA2mI);S`NZfL6lO( zr@rJ^kMf@rrHvi6aI%`Cge7R`PWr`hj~t9Vs~8WxVB;e0JPQw$fa8Shz_YeH4(!rQ zJZ=h%@|f=+@AMgejf+k$6p*Ff4@;OMY^J2{8hTdC5pWA3yRQ#R=cCaW`iRS>wq#WB zpQZG6>YkXF)ftn#MtFph*+elC2(WkB!dH_IIOz?6YI@mtyZuQiNNNxjjiCow3>Q(v zhOdj-lwesivP*XkyKlxxh~FltYASuArVMbFT}lJjaPbz$$7~hvTp1k2@pGmp_)%yI z`)HK%pfmujg6{kF_V<^DM+rV}1isQ71T(f83FxgpLNM%fmZpD|)>V<*M3bq{B{0xp zv*{wd`OaBv&??o=lQGv@84ifCy?tLmC$)o_KVH*7Qd2Z9mOM3A)Esu$omprw4SnbZ z(#Tsc6R>8Z0b2y&v>T%We&*1&Xt+wP;=w8j8q61k+0;zJjF|7Lbjc6Zrj zW?3()&q-75>)08@&LE~9o=i<$+E$678ol3&8)*%9pyP`K*yM|LY!j@o7A?@p9Ms|B zCLN7`jQ6~l@J2nw$JQn~wRT9WvZ@=4iE0dpV7)?Z_5Vf> z&yYzF^(W!48|7GFZqwpT3d|aC=ufT*DzGfvwUS&m`TB=GT61mt|C3~~aE8(w)f)g$Y^QOZ@i7}LciCR0 z6`YD$jU4ip4PV1@7yc=#{HKr$wA-pOUH(#zsu}LXuz?=^gUkRuQcWSPTP|+}g!A73 z;b4(;j>AS_5Cee0X3bEEm4c0lxZy`&Z7Qr8-zvfV9N!;Uq693+1DL?v43> z(V?3R_9~rGMXjMO@x^S5P^)!}Bv?~s2ZdxmrV&vchNu7!K099fuT5AuPnkrE$5FId z>t@!e-fLug=7jeKUCZ5p4qxZ<20v|U`5aMBG;sVwx`L0$opNoCn+s0D4PCIhGv=_P z=Pc>U+c_*R=>%E2FX8FC_nM5UL1bCmraqEQb8Y`6>E01VjC{iYDBCtK4T`mGo`=(1 zbmen1(xW?n@K%>%OD+{@;G)hiQF`Ro@_ebp(J4HGss<5rHS{b+D~I>bNzjD{5?;Nz z_qlT9;e`1h><=;jP1W>p&dF#udjl$LuQOip+uAbZaE7M70;(>G8N&Mp z!L-X(gXCkEZ?L!Ti)JhcCy3;#6JG3f8ySop51ckYcVi-YCWUbx7Y$B(43wcFJfqQm zmGcI*4TOJHJT_mb5L-0rEyq)UA<`}pSB&RRZS=h;^$7?nn8A%=MnO+~okOB%g4;;U z576%b?tBYWO^t((Z1v1w?1I#AxkD=WA_r@%mF%L zkU%FEUORnDcpEi{A*#(Iw6qWtXl?{^vzyEP_YFj8JR@93yeal*8|vCX6kQnfESQN$ z-I%gvCM1ea2zGB6BT%3fm{OCcPRx5k>kUrEi@1fsKCY zQVqM$x`X2^JnJ}~^AH{_p^Ph8%U(@NwuZq{K}(K(u_hR{{^w={vdpHGbh`05se!HF zxT;Cak>qOxMMeXz6#+-9q>Weaqgq$W;;?n-ZOlviRFB9w7732Lpkt;Eo~qeNTiANK zK$A-Nm<`A`wP~qtPT#T((t5&wD8B$rw*sn-j_Go2J=UUHV=+Io+@L#jO6Hi=g4
DJ*`trAiv3hD_b^$+XeDqKt`D1&GH5qx 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%0Dy&l2@60*gnqhoo4E%7d;zi&Vj6A+ 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 Kkt&xk4*EZn*WASb literal 0 HcmV?d00001 diff --git a/src/web/static/fonts/bmfonts/RobotoMono72White.fnt b/src/web/static/fonts/bmfonts/RobotoMono72White.fnt new file mode 100644 index 00000000..f280314d --- /dev/null +++ b/src/web/static/fonts/bmfonts/RobotoMono72White.fnt @@ -0,0 +1,103 @@ +info face="Roboto Mono" size=72 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=1,1,1,1 spacing=-2,-2 +common lineHeight=96 base=76 scaleW=512 scaleH=512 pages=1 packed=0 +page id=0 file="images/RobotoMono72White.png" +chars count=98 +char id=0 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=75 xadvance=0 page=0 chnl=0 +char id=10 x=0 y=0 width=45 height=99 xoffset=-1 yoffset=-2 xadvance=43 page=0 chnl=0 +char id=32 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=75 xadvance=43 page=0 chnl=0 +char id=33 x=498 y=99 width=10 height=55 xoffset=16 yoffset=23 xadvance=43 page=0 chnl=0 +char id=34 x=434 y=319 width=20 height=19 xoffset=11 yoffset=21 xadvance=43 page=0 chnl=0 +char id=35 x=175 y=265 width=41 height=54 xoffset=1 yoffset=23 xadvance=43 page=0 chnl=0 +char id=36 x=200 y=0 width=35 height=69 xoffset=5 yoffset=15 xadvance=43 page=0 chnl=0 +char id=37 x=0 y=155 width=42 height=56 xoffset=1 yoffset=22 xadvance=44 page=0 chnl=0 +char id=38 x=42 y=155 width=41 height=56 xoffset=3 yoffset=22 xadvance=44 page=0 chnl=0 +char id=39 x=502 y=211 width=7 height=19 xoffset=16 yoffset=21 xadvance=43 page=0 chnl=0 +char id=40 x=45 y=0 width=21 height=78 xoffset=12 yoffset=16 xadvance=44 page=0 chnl=0 +char id=41 x=66 y=0 width=22 height=78 xoffset=9 yoffset=16 xadvance=43 page=0 chnl=0 +char id=42 x=256 y=319 width=37 height=37 xoffset=4 yoffset=32 xadvance=43 page=0 chnl=0 +char id=43 x=219 y=319 width=37 height=40 xoffset=3 yoffset=32 xadvance=43 page=0 chnl=0 +char id=44 x=421 y=319 width=13 height=22 xoffset=11 yoffset=67 xadvance=43 page=0 chnl=0 +char id=45 x=17 y=360 width=29 height=8 xoffset=7 yoffset=49 xadvance=44 page=0 chnl=0 +char id=46 x=496 y=319 width=12 height=13 xoffset=16 yoffset=65 xadvance=43 page=0 chnl=0 +char id=47 x=319 y=0 width=31 height=58 xoffset=7 yoffset=23 xadvance=43 page=0 chnl=0 +char id=48 x=431 y=99 width=35 height=56 xoffset=4 yoffset=22 xadvance=43 page=0 chnl=0 +char id=49 x=36 y=265 width=23 height=54 xoffset=6 yoffset=23 xadvance=44 page=0 chnl=0 +char id=50 x=189 y=155 width=37 height=55 xoffset=2 yoffset=22 xadvance=44 page=0 chnl=0 +char id=51 x=361 y=99 width=35 height=56 xoffset=2 yoffset=22 xadvance=43 page=0 chnl=0 +char id=52 x=59 y=265 width=39 height=54 xoffset=2 yoffset=23 xadvance=44 page=0 chnl=0 +char id=53 x=226 y=155 width=35 height=55 xoffset=5 yoffset=23 xadvance=43 page=0 chnl=0 +char id=54 x=261 y=155 width=35 height=55 xoffset=4 yoffset=23 xadvance=43 page=0 chnl=0 +char id=55 x=98 y=265 width=37 height=54 xoffset=3 yoffset=23 xadvance=44 page=0 chnl=0 +char id=56 x=396 y=99 width=35 height=56 xoffset=5 yoffset=22 xadvance=43 page=0 chnl=0 +char id=57 x=296 y=155 width=34 height=55 xoffset=4 yoffset=22 xadvance=43 page=0 chnl=0 +char id=58 x=490 y=211 width=12 height=43 xoffset=18 yoffset=35 xadvance=43 page=0 chnl=0 +char id=59 x=486 y=0 width=14 height=55 xoffset=16 yoffset=35 xadvance=43 page=0 chnl=0 +char id=60 x=293 y=319 width=32 height=35 xoffset=5 yoffset=36 xadvance=43 page=0 chnl=0 +char id=61 x=388 y=319 width=33 height=23 xoffset=5 yoffset=41 xadvance=43 page=0 chnl=0 +char id=62 x=325 y=319 width=33 height=35 xoffset=5 yoffset=36 xadvance=43 page=0 chnl=0 +char id=63 x=466 y=99 width=32 height=56 xoffset=6 yoffset=22 xadvance=43 page=0 chnl=0 +char id=64 x=135 y=265 width=40 height=54 xoffset=1 yoffset=23 xadvance=42 page=0 chnl=0 +char id=65 x=330 y=155 width=42 height=54 xoffset=1 yoffset=23 xadvance=43 page=0 chnl=0 +char id=66 x=372 y=155 width=35 height=54 xoffset=5 yoffset=23 xadvance=43 page=0 chnl=0 +char id=67 x=448 y=0 width=38 height=56 xoffset=3 yoffset=22 xadvance=43 page=0 chnl=0 +char id=68 x=407 y=155 width=37 height=54 xoffset=4 yoffset=23 xadvance=43 page=0 chnl=0 +char id=69 x=444 y=155 width=34 height=54 xoffset=5 yoffset=23 xadvance=43 page=0 chnl=0 +char id=70 x=0 y=211 width=34 height=54 xoffset=6 yoffset=23 xadvance=44 page=0 chnl=0 +char id=71 x=0 y=99 width=38 height=56 xoffset=3 yoffset=22 xadvance=44 page=0 chnl=0 +char id=72 x=34 y=211 width=36 height=54 xoffset=4 yoffset=23 xadvance=43 page=0 chnl=0 +char id=73 x=478 y=155 width=33 height=54 xoffset=5 yoffset=23 xadvance=43 page=0 chnl=0 +char id=74 x=83 y=155 width=36 height=55 xoffset=2 yoffset=23 xadvance=43 page=0 chnl=0 +char id=75 x=70 y=211 width=38 height=54 xoffset=5 yoffset=23 xadvance=43 page=0 chnl=0 +char id=76 x=108 y=211 width=34 height=54 xoffset=6 yoffset=23 xadvance=43 page=0 chnl=0 +char id=77 x=142 y=211 width=36 height=54 xoffset=4 yoffset=23 xadvance=43 page=0 chnl=0 +char id=78 x=178 y=211 width=35 height=54 xoffset=4 yoffset=23 xadvance=43 page=0 chnl=0 +char id=79 x=38 y=99 width=38 height=56 xoffset=3 yoffset=22 xadvance=43 page=0 chnl=0 +char id=80 x=213 y=211 width=36 height=54 xoffset=6 yoffset=23 xadvance=43 page=0 chnl=0 +char id=81 x=242 y=0 width=40 height=64 xoffset=2 yoffset=22 xadvance=43 page=0 chnl=0 +char id=82 x=249 y=211 width=36 height=54 xoffset=5 yoffset=23 xadvance=43 page=0 chnl=0 +char id=83 x=76 y=99 width=38 height=56 xoffset=3 yoffset=22 xadvance=44 page=0 chnl=0 +char id=84 x=285 y=211 width=40 height=54 xoffset=2 yoffset=23 xadvance=44 page=0 chnl=0 +char id=85 x=119 y=155 width=36 height=55 xoffset=4 yoffset=23 xadvance=43 page=0 chnl=0 +char id=86 x=325 y=211 width=41 height=54 xoffset=1 yoffset=23 xadvance=43 page=0 chnl=0 +char id=87 x=366 y=211 width=42 height=54 xoffset=1 yoffset=23 xadvance=43 page=0 chnl=0 +char id=88 x=408 y=211 width=41 height=54 xoffset=2 yoffset=23 xadvance=43 page=0 chnl=0 +char id=89 x=449 y=211 width=41 height=54 xoffset=1 yoffset=23 xadvance=43 page=0 chnl=0 +char id=90 x=0 y=265 width=36 height=54 xoffset=3 yoffset=23 xadvance=43 page=0 chnl=0 +char id=91 x=88 y=0 width=16 height=72 xoffset=14 yoffset=16 xadvance=43 page=0 chnl=0 +char id=92 x=350 y=0 width=30 height=58 xoffset=7 yoffset=23 xadvance=43 page=0 chnl=0 +char id=93 x=104 y=0 width=17 height=72 xoffset=13 yoffset=16 xadvance=44 page=0 chnl=0 +char id=94 x=358 y=319 width=30 height=30 xoffset=7 yoffset=23 xadvance=43 page=0 chnl=0 +char id=95 x=46 y=360 width=34 height=8 xoffset=4 yoffset=74 xadvance=43 page=0 chnl=0 +char id=96 x=0 y=360 width=17 height=12 xoffset=13 yoffset=22 xadvance=43 page=0 chnl=0 +char id=97 x=251 y=265 width=35 height=42 xoffset=4 yoffset=36 xadvance=43 page=0 chnl=0 +char id=98 x=380 y=0 width=34 height=57 xoffset=5 yoffset=21 xadvance=43 page=0 chnl=0 +char id=99 x=286 y=265 width=35 height=42 xoffset=4 yoffset=36 xadvance=43 page=0 chnl=0 +char id=100 x=414 y=0 width=34 height=57 xoffset=4 yoffset=21 xadvance=43 page=0 chnl=0 +char id=101 x=321 y=265 width=36 height=42 xoffset=4 yoffset=36 xadvance=43 page=0 chnl=0 +char id=102 x=282 y=0 width=37 height=58 xoffset=4 yoffset=19 xadvance=43 page=0 chnl=0 +char id=103 x=114 y=99 width=34 height=56 xoffset=4 yoffset=36 xadvance=43 page=0 chnl=0 +char id=104 x=148 y=99 width=34 height=56 xoffset=5 yoffset=21 xadvance=43 page=0 chnl=0 +char id=105 x=155 y=155 width=34 height=55 xoffset=6 yoffset=22 xadvance=43 page=0 chnl=0 +char id=106 x=121 y=0 width=26 height=71 xoffset=6 yoffset=22 xadvance=44 page=0 chnl=0 +char id=107 x=182 y=99 width=36 height=56 xoffset=5 yoffset=21 xadvance=43 page=0 chnl=0 +char id=108 x=218 y=99 width=34 height=56 xoffset=6 yoffset=21 xadvance=43 page=0 chnl=0 +char id=109 x=428 y=265 width=39 height=41 xoffset=2 yoffset=36 xadvance=43 page=0 chnl=0 +char id=110 x=467 y=265 width=34 height=41 xoffset=5 yoffset=36 xadvance=43 page=0 chnl=0 +char id=111 x=357 y=265 width=37 height=42 xoffset=3 yoffset=36 xadvance=43 page=0 chnl=0 +char id=112 x=252 y=99 width=34 height=56 xoffset=5 yoffset=36 xadvance=43 page=0 chnl=0 +char id=113 x=286 y=99 width=34 height=56 xoffset=4 yoffset=36 xadvance=43 page=0 chnl=0 +char id=114 x=0 y=319 width=29 height=41 xoffset=11 yoffset=36 xadvance=44 page=0 chnl=0 +char id=115 x=394 y=265 width=34 height=42 xoffset=5 yoffset=36 xadvance=43 page=0 chnl=0 +char id=116 x=216 y=265 width=35 height=51 xoffset=4 yoffset=27 xadvance=43 page=0 chnl=0 +char id=117 x=29 y=319 width=33 height=41 xoffset=5 yoffset=37 xadvance=43 page=0 chnl=0 +char id=118 x=62 y=319 width=39 height=40 xoffset=2 yoffset=37 xadvance=43 page=0 chnl=0 +char id=119 x=101 y=319 width=43 height=40 xoffset=0 yoffset=37 xadvance=43 page=0 chnl=0 +char id=120 x=144 y=319 width=40 height=40 xoffset=2 yoffset=37 xadvance=43 page=0 chnl=0 +char id=121 x=320 y=99 width=41 height=56 xoffset=1 yoffset=37 xadvance=43 page=0 chnl=0 +char id=122 x=184 y=319 width=35 height=40 xoffset=5 yoffset=37 xadvance=44 page=0 chnl=0 +char id=123 x=147 y=0 width=26 height=71 xoffset=10 yoffset=19 xadvance=43 page=0 chnl=0 +char id=124 x=235 y=0 width=7 height=68 xoffset=18 yoffset=23 xadvance=43 page=0 chnl=0 +char id=125 x=173 y=0 width=27 height=71 xoffset=10 yoffset=19 xadvance=44 page=0 chnl=0 +char id=126 x=454 y=319 width=42 height=16 xoffset=1 yoffset=47 xadvance=44 page=0 chnl=0 +char id=127 x=0 y=0 width=45 height=99 xoffset=-1 yoffset=-2 xadvance=43 page=0 chnl=0 +kernings count=0 diff --git a/src/web/static/fonts/bmfonts/RobotoMono72White.png b/src/web/static/fonts/bmfonts/RobotoMono72White.png new file mode 100644 index 0000000000000000000000000000000000000000..ed192363be386b4fc5f532b629a71b37802323fe GIT binary patch literal 52580 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 I*(&&d0pzTe1^@s6 literal 0 HcmV?d00001 diff --git a/src/web/static/fonts/bmfonts/RobotoSlab72White.fnt b/src/web/static/fonts/bmfonts/RobotoSlab72White.fnt new file mode 100644 index 00000000..71e1b131 --- /dev/null +++ b/src/web/static/fonts/bmfonts/RobotoSlab72White.fnt @@ -0,0 +1,492 @@ +info face="Roboto Slab Regular" size=72 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=1,1,1,1 spacing=-2,-2 +common lineHeight=96 base=76 scaleW=512 scaleH=512 pages=1 packed=0 +page id=0 file="images/RobotoSlab72White.png" +chars count=98 +char id=0 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=75 xadvance=0 page=0 chnl=0 +char id=10 x=0 y=0 width=70 height=98 xoffset=0 yoffset=-1 xadvance=70 page=0 chnl=0 +char id=32 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=75 xadvance=18 page=0 chnl=0 +char id=33 x=497 y=156 width=9 height=54 xoffset=4 yoffset=23 xadvance=17 page=0 chnl=0 +char id=34 x=191 y=362 width=19 height=20 xoffset=5 yoffset=20 xadvance=28 page=0 chnl=0 +char id=35 x=406 y=266 width=41 height=54 xoffset=1 yoffset=23 xadvance=43 page=0 chnl=0 +char id=36 x=212 y=0 width=35 height=69 xoffset=2 yoffset=15 xadvance=39 page=0 chnl=0 +char id=37 x=174 y=156 width=48 height=56 xoffset=2 yoffset=22 xadvance=52 page=0 chnl=0 +char id=38 x=222 y=156 width=44 height=56 xoffset=2 yoffset=22 xadvance=46 page=0 chnl=0 +char id=39 x=210 y=362 width=8 height=20 xoffset=5 yoffset=20 xadvance=17 page=0 chnl=0 +char id=40 x=70 y=0 width=21 height=77 xoffset=3 yoffset=17 xadvance=23 page=0 chnl=0 +char id=41 x=91 y=0 width=21 height=77 xoffset=-1 yoffset=17 xadvance=23 page=0 chnl=0 +char id=42 x=100 y=362 width=31 height=33 xoffset=1 yoffset=23 xadvance=33 page=0 chnl=0 +char id=43 x=0 y=362 width=37 height=40 xoffset=2 yoffset=32 xadvance=41 page=0 chnl=0 +char id=44 x=492 y=320 width=13 height=21 xoffset=-1 yoffset=67 xadvance=14 page=0 chnl=0 +char id=45 x=287 y=362 width=19 height=8 xoffset=4 yoffset=50 xadvance=27 page=0 chnl=0 +char id=46 x=278 y=362 width=9 height=9 xoffset=4 yoffset=68 xadvance=17 page=0 chnl=0 +char id=47 x=470 y=0 width=30 height=58 xoffset=-1 yoffset=23 xadvance=29 page=0 chnl=0 +char id=48 x=139 y=156 width=35 height=56 xoffset=3 yoffset=22 xadvance=41 page=0 chnl=0 +char id=49 x=305 y=266 width=25 height=54 xoffset=3 yoffset=23 xadvance=30 page=0 chnl=0 +char id=50 x=357 y=156 width=36 height=55 xoffset=2 yoffset=22 xadvance=40 page=0 chnl=0 +char id=51 x=0 y=156 width=34 height=56 xoffset=2 yoffset=22 xadvance=39 page=0 chnl=0 +char id=52 x=330 y=266 width=39 height=54 xoffset=1 yoffset=23 xadvance=42 page=0 chnl=0 +char id=53 x=393 y=156 width=33 height=55 xoffset=2 yoffset=23 xadvance=37 page=0 chnl=0 +char id=54 x=34 y=156 width=35 height=56 xoffset=3 yoffset=22 xadvance=40 page=0 chnl=0 +char id=55 x=369 y=266 width=37 height=54 xoffset=2 yoffset=23 xadvance=40 page=0 chnl=0 +char id=56 x=69 y=156 width=35 height=56 xoffset=2 yoffset=22 xadvance=39 page=0 chnl=0 +char id=57 x=104 y=156 width=35 height=56 xoffset=2 yoffset=22 xadvance=41 page=0 chnl=0 +char id=58 x=500 y=0 width=9 height=40 xoffset=4 yoffset=37 xadvance=15 page=0 chnl=0 +char id=59 x=447 y=266 width=13 height=52 xoffset=0 yoffset=37 xadvance=15 page=0 chnl=0 +char id=60 x=37 y=362 width=31 height=35 xoffset=2 yoffset=39 xadvance=36 page=0 chnl=0 +char id=61 x=160 y=362 width=31 height=23 xoffset=4 yoffset=40 xadvance=39 page=0 chnl=0 +char id=62 x=68 y=362 width=32 height=35 xoffset=3 yoffset=39 xadvance=37 page=0 chnl=0 +char id=63 x=480 y=98 width=31 height=55 xoffset=1 yoffset=22 xadvance=33 page=0 chnl=0 +char id=64 x=247 y=0 width=60 height=68 xoffset=1 yoffset=25 xadvance=64 page=0 chnl=0 +char id=65 x=426 y=156 width=51 height=54 xoffset=1 yoffset=23 xadvance=53 page=0 chnl=0 +char id=66 x=0 y=212 width=44 height=54 xoffset=1 yoffset=23 xadvance=47 page=0 chnl=0 +char id=67 x=191 y=98 width=42 height=56 xoffset=1 yoffset=22 xadvance=46 page=0 chnl=0 +char id=68 x=44 y=212 width=46 height=54 xoffset=1 yoffset=23 xadvance=50 page=0 chnl=0 +char id=69 x=90 y=212 width=42 height=54 xoffset=1 yoffset=23 xadvance=46 page=0 chnl=0 +char id=70 x=132 y=212 width=42 height=54 xoffset=1 yoffset=23 xadvance=44 page=0 chnl=0 +char id=71 x=233 y=98 width=43 height=56 xoffset=1 yoffset=22 xadvance=49 page=0 chnl=0 +char id=72 x=174 y=212 width=52 height=54 xoffset=1 yoffset=23 xadvance=55 page=0 chnl=0 +char id=73 x=477 y=156 width=20 height=54 xoffset=1 yoffset=23 xadvance=22 page=0 chnl=0 +char id=74 x=266 y=156 width=39 height=55 xoffset=1 yoffset=23 xadvance=41 page=0 chnl=0 +char id=75 x=226 y=212 width=48 height=54 xoffset=1 yoffset=23 xadvance=50 page=0 chnl=0 +char id=76 x=274 y=212 width=39 height=54 xoffset=1 yoffset=23 xadvance=42 page=0 chnl=0 +char id=77 x=313 y=212 width=64 height=54 xoffset=1 yoffset=23 xadvance=66 page=0 chnl=0 +char id=78 x=377 y=212 width=52 height=54 xoffset=1 yoffset=23 xadvance=54 page=0 chnl=0 +char id=79 x=276 y=98 width=47 height=56 xoffset=2 yoffset=22 xadvance=51 page=0 chnl=0 +char id=80 x=429 y=212 width=43 height=54 xoffset=1 yoffset=23 xadvance=45 page=0 chnl=0 +char id=81 x=307 y=0 width=48 height=64 xoffset=2 yoffset=22 xadvance=51 page=0 chnl=0 +char id=82 x=0 y=266 width=46 height=54 xoffset=1 yoffset=23 xadvance=48 page=0 chnl=0 +char id=83 x=323 y=98 width=38 height=56 xoffset=3 yoffset=22 xadvance=43 page=0 chnl=0 +char id=84 x=46 y=266 width=45 height=54 xoffset=0 yoffset=23 xadvance=45 page=0 chnl=0 +char id=85 x=305 y=156 width=52 height=55 xoffset=1 yoffset=23 xadvance=54 page=0 chnl=0 +char id=86 x=91 y=266 width=50 height=54 xoffset=1 yoffset=23 xadvance=52 page=0 chnl=0 +char id=87 x=141 y=266 width=67 height=54 xoffset=0 yoffset=23 xadvance=67 page=0 chnl=0 +char id=88 x=208 y=266 width=49 height=54 xoffset=1 yoffset=23 xadvance=51 page=0 chnl=0 +char id=89 x=257 y=266 width=48 height=54 xoffset=1 yoffset=23 xadvance=50 page=0 chnl=0 +char id=90 x=472 y=212 width=38 height=54 xoffset=2 yoffset=23 xadvance=42 page=0 chnl=0 +char id=91 x=180 y=0 width=16 height=72 xoffset=5 yoffset=16 xadvance=21 page=0 chnl=0 +char id=92 x=0 y=98 width=31 height=58 xoffset=0 yoffset=23 xadvance=30 page=0 chnl=0 +char id=93 x=196 y=0 width=16 height=72 xoffset=-1 yoffset=16 xadvance=19 page=0 chnl=0 +char id=94 x=131 y=362 width=29 height=28 xoffset=1 yoffset=23 xadvance=30 page=0 chnl=0 +char id=95 x=306 y=362 width=34 height=8 xoffset=3 yoffset=74 xadvance=40 page=0 chnl=0 +char id=96 x=260 y=362 width=18 height=12 xoffset=1 yoffset=22 xadvance=20 page=0 chnl=0 +char id=97 x=0 y=320 width=36 height=42 xoffset=3 yoffset=36 xadvance=41 page=0 chnl=0 +char id=98 x=363 y=0 width=41 height=58 xoffset=-2 yoffset=20 xadvance=42 page=0 chnl=0 +char id=99 x=36 y=320 width=34 height=42 xoffset=2 yoffset=36 xadvance=39 page=0 chnl=0 +char id=100 x=404 y=0 width=40 height=58 xoffset=2 yoffset=20 xadvance=43 page=0 chnl=0 +char id=101 x=70 y=320 width=34 height=42 xoffset=2 yoffset=36 xadvance=39 page=0 chnl=0 +char id=102 x=444 y=0 width=26 height=58 xoffset=1 yoffset=19 xadvance=25 page=0 chnl=0 +char id=103 x=31 y=98 width=34 height=57 xoffset=2 yoffset=36 xadvance=40 page=0 chnl=0 +char id=104 x=65 y=98 width=44 height=57 xoffset=1 yoffset=20 xadvance=46 page=0 chnl=0 +char id=105 x=109 y=98 width=20 height=57 xoffset=2 yoffset=20 xadvance=23 page=0 chnl=0 +char id=106 x=112 y=0 width=18 height=73 xoffset=-2 yoffset=20 xadvance=20 page=0 chnl=0 +char id=107 x=129 y=98 width=42 height=57 xoffset=1 yoffset=20 xadvance=44 page=0 chnl=0 +char id=108 x=171 y=98 width=20 height=57 xoffset=1 yoffset=20 xadvance=22 page=0 chnl=0 +char id=109 x=171 y=320 width=66 height=41 xoffset=1 yoffset=36 xadvance=68 page=0 chnl=0 +char id=110 x=237 y=320 width=44 height=41 xoffset=1 yoffset=36 xadvance=46 page=0 chnl=0 +char id=111 x=104 y=320 width=36 height=42 xoffset=2 yoffset=36 xadvance=40 page=0 chnl=0 +char id=112 x=361 y=98 width=40 height=56 xoffset=1 yoffset=36 xadvance=43 page=0 chnl=0 +char id=113 x=401 y=98 width=39 height=56 xoffset=2 yoffset=36 xadvance=40 page=0 chnl=0 +char id=114 x=484 y=266 width=27 height=41 xoffset=2 yoffset=36 xadvance=30 page=0 chnl=0 +char id=115 x=140 y=320 width=31 height=42 xoffset=3 yoffset=36 xadvance=36 page=0 chnl=0 +char id=116 x=460 y=266 width=24 height=51 xoffset=1 yoffset=27 xadvance=26 page=0 chnl=0 +char id=117 x=281 y=320 width=43 height=41 xoffset=0 yoffset=37 xadvance=44 page=0 chnl=0 +char id=118 x=324 y=320 width=39 height=40 xoffset=0 yoffset=37 xadvance=40 page=0 chnl=0 +char id=119 x=363 y=320 width=57 height=40 xoffset=1 yoffset=37 xadvance=59 page=0 chnl=0 +char id=120 x=420 y=320 width=40 height=40 xoffset=1 yoffset=37 xadvance=42 page=0 chnl=0 +char id=121 x=440 y=98 width=40 height=56 xoffset=0 yoffset=37 xadvance=41 page=0 chnl=0 +char id=122 x=460 y=320 width=32 height=40 xoffset=3 yoffset=37 xadvance=38 page=0 chnl=0 +char id=123 x=130 y=0 width=25 height=73 xoffset=1 yoffset=18 xadvance=25 page=0 chnl=0 +char id=124 x=355 y=0 width=8 height=63 xoffset=4 yoffset=23 xadvance=16 page=0 chnl=0 +char id=125 x=155 y=0 width=25 height=73 xoffset=-1 yoffset=18 xadvance=25 page=0 chnl=0 +char id=126 x=218 y=362 width=42 height=16 xoffset=3 yoffset=47 xadvance=49 page=0 chnl=0 +char id=127 x=0 y=0 width=70 height=98 xoffset=0 yoffset=-1 xadvance=70 page=0 chnl=0 +kernings count=389 +kerning first=86 second=45 amount=-1 +kerning first=114 second=46 amount=-4 +kerning first=40 second=87 amount=1 +kerning first=70 second=99 amount=-1 +kerning first=84 second=110 amount=-3 +kerning first=114 second=116 amount=1 +kerning first=39 second=65 amount=-4 +kerning first=104 second=34 amount=-1 +kerning first=89 second=71 amount=-1 +kerning first=107 second=113 amount=-1 +kerning first=78 second=88 amount=1 +kerning first=109 second=39 amount=-1 +kerning first=120 second=100 amount=-1 +kerning first=84 second=100 amount=-3 +kerning first=68 second=90 amount=-1 +kerning first=68 second=44 amount=-4 +kerning first=84 second=103 amount=-3 +kerning first=34 second=97 amount=-2 +kerning first=70 second=97 amount=-1 +kerning first=76 second=81 amount=-2 +kerning first=73 second=89 amount=-1 +kerning first=84 second=44 amount=-8 +kerning first=68 second=65 amount=-3 +kerning first=97 second=34 amount=-2 +kerning first=111 second=121 amount=-1 +kerning first=79 second=90 amount=-1 +kerning first=75 second=121 amount=-1 +kerning first=75 second=118 amount=-1 +kerning first=111 second=118 amount=-1 +kerning first=89 second=65 amount=-9 +kerning first=75 second=71 amount=-4 +kerning first=39 second=99 amount=-2 +kerning first=75 second=99 amount=-1 +kerning first=90 second=121 amount=-1 +kerning first=44 second=39 amount=-6 +kerning first=89 second=46 amount=-7 +kerning first=89 second=74 amount=-7 +kerning first=34 second=103 amount=-2 +kerning first=70 second=103 amount=-1 +kerning first=112 second=39 amount=-1 +kerning first=122 second=113 amount=-1 +kerning first=86 second=113 amount=-2 +kerning first=68 second=84 amount=-1 +kerning first=89 second=110 amount=-1 +kerning first=34 second=100 amount=-2 +kerning first=68 second=86 amount=-1 +kerning first=87 second=45 amount=-2 +kerning first=39 second=34 amount=-4 +kerning first=114 second=100 amount=-1 +kerning first=84 second=81 amount=-1 +kerning first=70 second=101 amount=-1 +kerning first=68 second=89 amount=-2 +kerning first=88 second=117 amount=-1 +kerning first=112 second=34 amount=-1 +kerning first=76 second=67 amount=-2 +kerning first=76 second=34 amount=-5 +kerning first=88 second=111 amount=-1 +kerning first=66 second=86 amount=-1 +kerning first=66 second=89 amount=-2 +kerning first=122 second=101 amount=-1 +kerning first=86 second=101 amount=-2 +kerning first=76 second=121 amount=-5 +kerning first=84 second=119 amount=-2 +kerning first=84 second=112 amount=-3 +kerning first=87 second=111 amount=-1 +kerning first=69 second=118 amount=-1 +kerning first=65 second=117 amount=-2 +kerning first=65 second=89 amount=-9 +kerning first=72 second=89 amount=-1 +kerning first=119 second=44 amount=-4 +kerning first=69 second=121 amount=-1 +kerning first=84 second=109 amount=-3 +kerning first=84 second=122 amount=-2 +kerning first=89 second=99 amount=-2 +kerning first=76 second=118 amount=-5 +kerning first=90 second=99 amount=-1 +kerning first=90 second=103 amount=-1 +kerning first=79 second=89 amount=-2 +kerning first=90 second=79 amount=-1 +kerning first=84 second=115 amount=-4 +kerning first=76 second=65 amount=1 +kerning first=90 second=100 amount=-1 +kerning first=118 second=46 amount=-4 +kerning first=87 second=117 amount=-1 +kerning first=118 second=34 amount=1 +kerning first=69 second=103 amount=-1 +kerning first=97 second=121 amount=-1 +kerning first=39 second=111 amount=-2 +kerning first=72 second=88 amount=1 +kerning first=76 second=87 amount=-5 +kerning first=69 second=119 amount=-1 +kerning first=121 second=97 amount=-1 +kerning first=75 second=45 amount=-8 +kerning first=65 second=86 amount=-9 +kerning first=46 second=34 amount=-6 +kerning first=76 second=84 amount=-10 +kerning first=116 second=111 amount=-1 +kerning first=87 second=113 amount=-1 +kerning first=69 second=100 amount=-1 +kerning first=97 second=118 amount=-1 +kerning first=65 second=85 amount=-2 +kerning first=90 second=71 amount=-1 +kerning first=68 second=46 amount=-4 +kerning first=65 second=79 amount=-3 +kerning first=98 second=122 amount=-1 +kerning first=86 second=41 amount=1 +kerning first=84 second=118 amount=-3 +kerning first=70 second=118 amount=-1 +kerning first=121 second=111 amount=-1 +kerning first=81 second=87 amount=-1 +kerning first=70 second=100 amount=-1 +kerning first=102 second=93 amount=1 +kerning first=114 second=101 amount=-1 +kerning first=88 second=45 amount=-2 +kerning first=39 second=103 amount=-2 +kerning first=75 second=103 amount=-1 +kerning first=88 second=101 amount=-1 +kerning first=89 second=103 amount=-2 +kerning first=110 second=39 amount=-1 +kerning first=89 second=89 amount=1 +kerning first=87 second=65 amount=-2 +kerning first=119 second=46 amount=-4 +kerning first=34 second=34 amount=-4 +kerning first=88 second=79 amount=-2 +kerning first=79 second=86 amount=-1 +kerning first=76 second=119 amount=-3 +kerning first=75 second=111 amount=-1 +kerning first=65 second=116 amount=-4 +kerning first=86 second=65 amount=-9 +kerning first=70 second=84 amount=1 +kerning first=75 second=117 amount=-1 +kerning first=80 second=65 amount=-9 +kerning first=34 second=112 amount=-1 +kerning first=102 second=99 amount=-1 +kerning first=118 second=97 amount=-1 +kerning first=89 second=81 amount=-1 +kerning first=118 second=111 amount=-1 +kerning first=102 second=101 amount=-1 +kerning first=114 second=44 amount=-4 +kerning first=90 second=119 amount=-1 +kerning first=75 second=81 amount=-4 +kerning first=88 second=121 amount=-1 +kerning first=34 second=110 amount=-1 +kerning first=86 second=100 amount=-2 +kerning first=122 second=100 amount=-1 +kerning first=89 second=67 amount=-1 +kerning first=90 second=118 amount=-1 +kerning first=84 second=84 amount=1 +kerning first=121 second=34 amount=1 +kerning first=91 second=74 amount=-1 +kerning first=88 second=113 amount=-1 +kerning first=77 second=88 amount=1 +kerning first=75 second=119 amount=-2 +kerning first=114 second=104 amount=-1 +kerning first=68 second=88 amount=-2 +kerning first=121 second=44 amount=-4 +kerning first=81 second=89 amount=-1 +kerning first=102 second=39 amount=1 +kerning first=74 second=65 amount=-2 +kerning first=114 second=118 amount=1 +kerning first=84 second=46 amount=-8 +kerning first=111 second=34 amount=-1 +kerning first=88 second=71 amount=-2 +kerning first=88 second=99 amount=-1 +kerning first=84 second=74 amount=-8 +kerning first=39 second=109 amount=-1 +kerning first=98 second=34 amount=-1 +kerning first=86 second=114 amount=-1 +kerning first=88 second=81 amount=-2 +kerning first=70 second=74 amount=-11 +kerning first=89 second=83 amount=-1 +kerning first=87 second=41 amount=1 +kerning first=89 second=97 amount=-3 +kerning first=89 second=87 amount=1 +kerning first=67 second=125 amount=-1 +kerning first=89 second=93 amount=1 +kerning first=80 second=118 amount=1 +kerning first=107 second=100 amount=-1 +kerning first=114 second=34 amount=1 +kerning first=89 second=109 amount=-1 +kerning first=89 second=45 amount=-2 +kerning first=70 second=44 amount=-8 +kerning first=34 second=39 amount=-4 +kerning first=88 second=67 amount=-2 +kerning first=70 second=46 amount=-8 +kerning first=102 second=41 amount=1 +kerning first=89 second=117 amount=-1 +kerning first=89 second=111 amount=-4 +kerning first=89 second=115 amount=-4 +kerning first=114 second=102 amount=1 +kerning first=89 second=125 amount=1 +kerning first=89 second=121 amount=-1 +kerning first=114 second=108 amount=-1 +kerning first=47 second=47 amount=-8 +kerning first=65 second=63 amount=-2 +kerning first=75 second=67 amount=-4 +kerning first=87 second=100 amount=-1 +kerning first=111 second=104 amount=-1 +kerning first=111 second=107 amount=-1 +kerning first=75 second=109 amount=-1 +kerning first=87 second=114 amount=-1 +kerning first=111 second=120 amount=-1 +kerning first=69 second=99 amount=-1 +kerning first=65 second=84 amount=-6 +kerning first=39 second=97 amount=-2 +kerning first=121 second=46 amount=-4 +kerning first=89 second=85 amount=-3 +kerning first=75 second=79 amount=-4 +kerning first=107 second=99 amount=-1 +kerning first=102 second=100 amount=-1 +kerning first=102 second=103 amount=-1 +kerning first=75 second=110 amount=-1 +kerning first=39 second=110 amount=-1 +kerning first=69 second=84 amount=1 +kerning first=84 second=111 amount=-3 +kerning first=120 second=111 amount=-1 +kerning first=84 second=114 amount=-3 +kerning first=112 second=120 amount=-1 +kerning first=79 second=84 amount=-1 +kerning first=84 second=117 amount=-3 +kerning first=89 second=79 amount=-1 +kerning first=75 second=113 amount=-1 +kerning first=39 second=113 amount=-2 +kerning first=80 second=44 amount=-11 +kerning first=79 second=88 amount=-2 +kerning first=98 second=39 amount=-1 +kerning first=65 second=118 amount=-4 +kerning first=65 second=34 amount=-4 +kerning first=88 second=103 amount=-1 +kerning first=77 second=89 amount=-1 +kerning first=39 second=101 amount=-2 +kerning first=75 second=101 amount=-1 +kerning first=88 second=100 amount=-1 +kerning first=78 second=65 amount=-3 +kerning first=87 second=44 amount=-4 +kerning first=67 second=41 amount=-1 +kerning first=86 second=93 amount=1 +kerning first=84 second=83 amount=-1 +kerning first=102 second=113 amount=-1 +kerning first=34 second=111 amount=-2 +kerning first=70 second=111 amount=-1 +kerning first=86 second=99 amount=-2 +kerning first=84 second=86 amount=1 +kerning first=122 second=99 amount=-1 +kerning first=84 second=89 amount=1 +kerning first=70 second=114 amount=-1 +kerning first=86 second=74 amount=-8 +kerning first=89 second=38 amount=-1 +kerning first=87 second=97 amount=-1 +kerning first=76 second=86 amount=-9 +kerning first=40 second=86 amount=1 +kerning first=90 second=113 amount=-1 +kerning first=39 second=39 amount=-4 +kerning first=111 second=39 amount=-1 +kerning first=90 second=117 amount=-1 +kerning first=89 second=41 amount=1 +kerning first=65 second=121 amount=-4 +kerning first=89 second=100 amount=-2 +kerning first=89 second=42 amount=-2 +kerning first=76 second=117 amount=-2 +kerning first=69 second=111 amount=-1 +kerning first=46 second=39 amount=-6 +kerning first=118 second=39 amount=1 +kerning first=91 second=85 amount=-1 +kerning first=80 second=90 amount=-1 +kerning first=90 second=81 amount=-1 +kerning first=69 second=117 amount=-1 +kerning first=76 second=39 amount=-5 +kerning first=90 second=67 amount=-1 +kerning first=87 second=103 amount=-1 +kerning first=84 second=120 amount=-3 +kerning first=89 second=101 amount=-2 +kerning first=102 second=125 amount=1 +kerning first=76 second=85 amount=-2 +kerning first=79 second=65 amount=-3 +kerning first=65 second=71 amount=-3 +kerning first=79 second=44 amount=-4 +kerning first=97 second=39 amount=-2 +kerning first=90 second=101 amount=-1 +kerning first=65 second=87 amount=-5 +kerning first=79 second=46 amount=-4 +kerning first=87 second=99 amount=-1 +kerning first=34 second=101 amount=-2 +kerning first=40 second=89 amount=1 +kerning first=76 second=89 amount=-8 +kerning first=69 second=113 amount=-1 +kerning first=120 second=103 amount=-1 +kerning first=69 second=101 amount=-1 +kerning first=69 second=102 amount=-1 +kerning first=104 second=39 amount=-1 +kerning first=80 second=121 amount=1 +kerning first=86 second=46 amount=-8 +kerning first=65 second=81 amount=-3 +kerning first=86 second=44 amount=-8 +kerning first=120 second=99 amount=-1 +kerning first=98 second=120 amount=-1 +kerning first=39 second=115 amount=-3 +kerning first=121 second=39 amount=1 +kerning first=88 second=118 amount=-1 +kerning first=84 second=65 amount=-6 +kerning first=65 second=39 amount=-4 +kerning first=84 second=79 amount=-1 +kerning first=65 second=119 amount=-4 +kerning first=70 second=117 amount=-1 +kerning first=75 second=100 amount=-1 +kerning first=86 second=111 amount=-2 +kerning first=122 second=111 amount=-1 +kerning first=81 second=84 amount=-2 +kerning first=107 second=103 amount=-1 +kerning first=118 second=44 amount=-4 +kerning first=87 second=46 amount=-4 +kerning first=87 second=101 amount=-1 +kerning first=70 second=79 amount=-2 +kerning first=87 second=74 amount=-2 +kerning first=123 second=74 amount=-1 +kerning first=76 second=71 amount=-2 +kerning first=39 second=100 amount=-2 +kerning first=80 second=88 amount=-1 +kerning first=84 second=121 amount=-3 +kerning first=112 second=122 amount=-1 +kerning first=84 second=71 amount=-1 +kerning first=89 second=86 amount=1 +kerning first=84 second=113 amount=-3 +kerning first=120 second=113 amount=-1 +kerning first=89 second=44 amount=-7 +kerning first=84 second=99 amount=-3 +kerning first=34 second=113 amount=-2 +kerning first=80 second=46 amount=-11 +kerning first=86 second=117 amount=-1 +kerning first=110 second=34 amount=-1 +kerning first=80 second=74 amount=-7 +kerning first=120 second=101 amount=-1 +kerning first=73 second=88 amount=1 +kerning first=108 second=111 amount=-1 +kerning first=34 second=115 amount=-3 +kerning first=89 second=113 amount=-2 +kerning first=82 second=86 amount=-3 +kerning first=114 second=39 amount=1 +kerning first=34 second=109 amount=-1 +kerning first=84 second=101 amount=-3 +kerning first=70 second=121 amount=-1 +kerning first=123 second=85 amount=-1 +kerning first=122 second=103 amount=-1 +kerning first=86 second=97 amount=-2 +kerning first=82 second=89 amount=-4 +kerning first=66 second=84 amount=-1 +kerning first=84 second=97 amount=-4 +kerning first=86 second=103 amount=-2 +kerning first=70 second=113 amount=-1 +kerning first=84 second=87 amount=1 +kerning first=75 second=112 amount=-1 +kerning first=114 second=111 amount=-1 +kerning first=39 second=112 amount=-1 +kerning first=107 second=101 amount=-1 +kerning first=82 second=84 amount=-3 +kerning first=114 second=121 amount=1 +kerning first=34 second=99 amount=-2 +kerning first=70 second=81 amount=-2 +kerning first=111 second=122 amount=-1 +kerning first=84 second=67 amount=-1 +kerning first=111 second=108 amount=-1 +kerning first=89 second=84 amount=1 +kerning first=76 second=79 amount=-2 +kerning first=85 second=65 amount=-2 +kerning first=44 second=34 amount=-6 +kerning first=65 second=67 amount=-3 +kerning first=109 second=34 amount=-1 +kerning first=114 second=103 amount=-1 +kerning first=78 second=89 amount=-1 +kerning first=89 second=114 amount=-1 +kerning first=89 second=112 amount=-1 +kerning first=34 second=65 amount=-4 +kerning first=70 second=65 amount=-11 +kerning first=81 second=86 amount=-1 +kerning first=114 second=119 amount=1 +kerning first=89 second=102 amount=-1 +kerning first=84 second=45 amount=-8 +kerning first=86 second=125 amount=1 +kerning first=70 second=67 amount=-2 +kerning first=89 second=116 amount=-1 +kerning first=102 second=34 amount=1 +kerning first=114 second=99 amount=-1 +kerning first=67 second=84 amount=-1 +kerning first=114 second=113 amount=-1 +kerning first=89 second=122 amount=-1 +kerning first=89 second=118 amount=-1 +kerning first=70 second=71 amount=-2 +kerning first=114 second=107 amount=-1 +kerning first=89 second=120 amount=-1 diff --git a/src/web/static/fonts/bmfonts/RobotoSlab72White.png b/src/web/static/fonts/bmfonts/RobotoSlab72White.png new file mode 100644 index 0000000000000000000000000000000000000000..5aa1bf064c4d545993bd838050b81ccf624a5c64 GIT binary patch literal 54282 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 Date: Tue, 19 Mar 2019 13:54:26 +0000 Subject: [PATCH 10/27] Add new implementation of gaussian blur. Changed SharpenImage to use the new algorithm. --- src/core/lib/ImageManipulation.mjs | 252 +++++++++++++++++++++++++++ src/core/operations/BlurImage.mjs | 7 +- src/core/operations/SharpenImage.mjs | 5 +- 3 files changed, 260 insertions(+), 4 deletions(-) create mode 100644 src/core/lib/ImageManipulation.mjs diff --git a/src/core/lib/ImageManipulation.mjs b/src/core/lib/ImageManipulation.mjs new file mode 100644 index 00000000..1f1b85ae --- /dev/null +++ b/src/core/lib/ImageManipulation.mjs @@ -0,0 +1,252 @@ +/** + * Image manipulation resources + * + * @author j433866 [j433866@gmail.com] + * @copyright Crown Copyright 2019 + * @license Apache-2.0 + */ + +import OperationError from "../errors/OperationError"; + +/** + * Gaussian blurs an image. + * + * @param {jimp} input + * @param {int} radius + * @param {boolean} fast + * @returns {jimp} + */ +export function gaussianBlur (input, radius) { + try { + // From http://blog.ivank.net/fastest-gaussian-blur.html + const boxes = boxesForGauss(radius, 3); + for (let i = 0; i < 3; i++) { + input = boxBlur(input, (boxes[i] - 1) / 2); + } + } catch (err) { + log.error(err); + throw new OperationError(`Error blurring image. (${err})`); + } + + return input; +} + +/** + * + * @param {int} radius + * @param {int} numBoxes + * @returns {Array} + */ +function boxesForGauss(radius, numBoxes) { + const idealWidth = Math.sqrt((12 * radius * radius / numBoxes) + 1); + + let wl = Math.floor(idealWidth); + + if (wl % 2 === 0) { + wl--; + } + + const wu = wl + 2; + + const mIdeal = (12 * radius * radius - numBoxes * wl * wl - 4 * numBoxes * wl - 3 * numBoxes) / (-4 * wl - 4); + const m = Math.round(mIdeal); + + const sizes = []; + for (let i = 0; i < numBoxes; i++) { + sizes.push(i < m ? wl : wu); + } + return sizes; +} + +/** + * Applies a box blur effect to the image + * + * @param {jimp} source + * @param {number} radius + * @returns {jimp} + */ +function boxBlur (source, radius) { + const width = source.bitmap.width; + const height = source.bitmap.height; + let output = source.clone(); + output = boxBlurH(source, output, width, height, radius); + source = boxBlurV(output, source, width, height, radius); + + return source; +} + +/** + * Applies the horizontal blur + * + * @param {jimp} source + * @param {jimp} output + * @param {number} width + * @param {number} height + * @param {number} radius + * @returns {jimp} + */ +function boxBlurH (source, output, width, height, radius) { + const iarr = 1 / (radius + radius + 1); + for (let i = 0; i < height; i++) { + let ti = 0, + li = ti, + ri = ti + radius; + const idx = source.getPixelIndex(ti, i); + const firstValRed = source.bitmap.data[idx], + firstValGreen = source.bitmap.data[idx + 1], + firstValBlue = source.bitmap.data[idx + 2], + firstValAlpha = source.bitmap.data[idx + 3]; + + const lastIdx = source.getPixelIndex(width - 1, i), + lastValRed = source.bitmap.data[lastIdx], + lastValGreen = source.bitmap.data[lastIdx + 1], + lastValBlue = source.bitmap.data[lastIdx + 2], + lastValAlpha = source.bitmap.data[lastIdx + 3]; + + let red = (radius + 1) * firstValRed; + let green = (radius + 1) * firstValGreen; + let blue = (radius + 1) * firstValBlue; + let alpha = (radius + 1) * firstValAlpha; + + for (let j = 0; j < radius; j++) { + const jIdx = source.getPixelIndex(ti + j, i); + red += source.bitmap.data[jIdx]; + green += source.bitmap.data[jIdx + 1]; + blue += source.bitmap.data[jIdx + 2]; + alpha += source.bitmap.data[jIdx + 3]; + } + + for (let j = 0; j <= radius; j++) { + const jIdx = source.getPixelIndex(ri++, i); + red += source.bitmap.data[jIdx] - firstValRed; + green += source.bitmap.data[jIdx + 1] - firstValGreen; + blue += source.bitmap.data[jIdx + 2] - firstValBlue; + alpha += source.bitmap.data[jIdx + 3] - firstValAlpha; + + const tiIdx = source.getPixelIndex(ti++, i); + output.bitmap.data[tiIdx] = Math.round(red * iarr); + output.bitmap.data[tiIdx + 1] = Math.round(green * iarr); + output.bitmap.data[tiIdx + 2] = Math.round(blue * iarr); + output.bitmap.data[tiIdx + 3] = Math.round(alpha * iarr); + } + + for (let j = radius + 1; j < width - radius; j++) { + const riIdx = source.getPixelIndex(ri++, i); + const liIdx = source.getPixelIndex(li++, i); + red += source.bitmap.data[riIdx] - source.bitmap.data[liIdx]; + green += source.bitmap.data[riIdx + 1] - source.bitmap.data[liIdx + 1]; + blue += source.bitmap.data[riIdx + 2] - source.bitmap.data[liIdx + 2]; + alpha += source.bitmap.data[riIdx + 3] - source.bitmap.data[liIdx + 3]; + + const tiIdx = source.getPixelIndex(ti++, i); + output.bitmap.data[tiIdx] = Math.round(red * iarr); + output.bitmap.data[tiIdx + 1] = Math.round(green * iarr); + output.bitmap.data[tiIdx + 2] = Math.round(blue * iarr); + output.bitmap.data[tiIdx + 3] = Math.round(alpha * iarr); + } + + for (let j = width - radius; j < width; j++) { + const liIdx = source.getPixelIndex(li++, i); + red += lastValRed - source.bitmap.data[liIdx]; + green += lastValGreen - source.bitmap.data[liIdx + 1]; + blue += lastValBlue - source.bitmap.data[liIdx + 2]; + alpha += lastValAlpha - source.bitmap.data[liIdx + 3]; + + const tiIdx = source.getPixelIndex(ti++, i); + output.bitmap.data[tiIdx] = Math.round(red * iarr); + output.bitmap.data[tiIdx + 1] = Math.round(green * iarr); + output.bitmap.data[tiIdx + 2] = Math.round(blue * iarr); + output.bitmap.data[tiIdx + 3] = Math.round(alpha * iarr); + } + } + return output; +} + +/** + * Applies the vertical blur + * + * @param {jimp} source + * @param {jimp} output + * @param {int} width + * @param {int} height + * @param {int} radius + * @returns {jimp} + */ +function boxBlurV (source, output, width, height, radius) { + const iarr = 1 / (radius + radius + 1); + for (let i = 0; i < width; i++) { + let ti = 0, + li = ti, + ri = ti + radius; + + const idx = source.getPixelIndex(i, ti); + + const firstValRed = source.bitmap.data[idx], + firstValGreen = source.bitmap.data[idx + 1], + firstValBlue = source.bitmap.data[idx + 2], + firstValAlpha = source.bitmap.data[idx + 3]; + + const lastIdx = source.getPixelIndex(i, height - 1), + lastValRed = source.bitmap.data[lastIdx], + lastValGreen = source.bitmap.data[lastIdx + 1], + lastValBlue = source.bitmap.data[lastIdx + 2], + lastValAlpha = source.bitmap.data[lastIdx + 3]; + + let red = (radius + 1) * firstValRed; + let green = (radius + 1) * firstValGreen; + let blue = (radius + 1) * firstValBlue; + let alpha = (radius + 1) * firstValAlpha; + + for (let j = 0; j < radius; j++) { + const jIdx = source.getPixelIndex(i, ti + j); + red += source.bitmap.data[jIdx]; + green += source.bitmap.data[jIdx + 1]; + blue += source.bitmap.data[jIdx + 2]; + alpha += source.bitmap.data[jIdx + 3]; + } + + for (let j = 0; j <= radius; j++) { + const riIdx = source.getPixelIndex(i, ri++); + red += source.bitmap.data[riIdx] - firstValRed; + green += source.bitmap.data[riIdx + 1] - firstValGreen; + blue += source.bitmap.data[riIdx + 2] - firstValBlue; + alpha += source.bitmap.data[riIdx + 3] - firstValAlpha; + + const tiIdx = source.getPixelIndex(i, ti++); + output.bitmap.data[tiIdx] = Math.round(red * iarr); + output.bitmap.data[tiIdx + 1] = Math.round(green * iarr); + output.bitmap.data[tiIdx + 2] = Math.round(blue * iarr); + output.bitmap.data[tiIdx + 3] = Math.round(alpha * iarr); + } + + for (let j = radius + 1; j < height - radius; j++) { + const riIdx = source.getPixelIndex(i, ri++); + const liIdx = source.getPixelIndex(i, li++); + red += source.bitmap.data[riIdx] - source.bitmap.data[liIdx]; + green += source.bitmap.data[riIdx + 1] - source.bitmap.data[liIdx + 1]; + blue += source.bitmap.data[riIdx + 2] - source.bitmap.data[liIdx + 2]; + alpha += source.bitmap.data[riIdx + 3] - source.bitmap.data[liIdx + 3]; + + const tiIdx = source.getPixelIndex(i, ti++); + output.bitmap.data[tiIdx] = Math.round(red * iarr); + output.bitmap.data[tiIdx + 1] = Math.round(green * iarr); + output.bitmap.data[tiIdx + 2] = Math.round(blue * iarr); + output.bitmap.data[tiIdx + 3] = Math.round(alpha * iarr); + } + + for (let j = height - radius; j < height; j++) { + const liIdx = source.getPixelIndex(i, li++); + red += lastValRed - source.bitmap.data[liIdx]; + green += lastValGreen - source.bitmap.data[liIdx + 1]; + blue += lastValBlue - source.bitmap.data[liIdx + 2]; + alpha += lastValAlpha - source.bitmap.data[liIdx + 3]; + + const tiIdx = source.getPixelIndex(i, ti++); + output.bitmap.data[tiIdx] = Math.round(red * iarr); + output.bitmap.data[tiIdx + 1] = Math.round(green * iarr); + output.bitmap.data[tiIdx + 2] = Math.round(blue * iarr); + output.bitmap.data[tiIdx + 3] = Math.round(alpha * iarr); + } + } + return output; +} diff --git a/src/core/operations/BlurImage.mjs b/src/core/operations/BlurImage.mjs index e1a52710..e0b5c919 100644 --- a/src/core/operations/BlurImage.mjs +++ b/src/core/operations/BlurImage.mjs @@ -9,6 +9,7 @@ import OperationError from "../errors/OperationError"; import { isImage } from "../lib/FileType"; import { toBase64 } from "../lib/Base64"; import jimp from "jimp"; +import { gaussianBlur } from "../lib/ImageManipulation"; /** * Blur Image operation @@ -64,12 +65,14 @@ class BlurImage extends Operation { try { switch (blurType){ case "Fast": + if (ENVIRONMENT_IS_WORKER()) + self.sendStatusMessage("Fast blurring image..."); image.blur(blurAmount); break; case "Gaussian": if (ENVIRONMENT_IS_WORKER()) - self.sendStatusMessage("Gaussian blurring image. This may take a while..."); - image.gaussian(blurAmount); + self.sendStatusMessage("Gaussian blurring image..."); + image = gaussianBlur(image, blurAmount); break; } diff --git a/src/core/operations/SharpenImage.mjs b/src/core/operations/SharpenImage.mjs index db0e7bb7..3ef1912e 100644 --- a/src/core/operations/SharpenImage.mjs +++ b/src/core/operations/SharpenImage.mjs @@ -8,6 +8,7 @@ import Operation from "../Operation"; import OperationError from "../errors/OperationError"; import { isImage } from "../lib/FileType"; import { toBase64 } from "../lib/Base64"; +import { gaussianBlur } from "../lib/ImageManipulation"; import jimp from "jimp"; /** @@ -74,12 +75,12 @@ class SharpenImage extends Operation { try { if (ENVIRONMENT_IS_WORKER()) self.sendStatusMessage("Sharpening image... (Cloning image)"); - const blurImage = image.clone(); const blurMask = image.clone(); if (ENVIRONMENT_IS_WORKER()) self.sendStatusMessage("Sharpening image... (Blurring cloned image)"); - blurImage.gaussian(radius); + const blurImage = gaussianBlur(image.clone(), radius, 3); + if (ENVIRONMENT_IS_WORKER()) self.sendStatusMessage("Sharpening image... (Creating unsharp mask)"); From b312e179047d3f6bd374226eec975248e5833f41 Mon Sep 17 00:00:00 2001 From: j433866 Date: Tue, 19 Mar 2019 13:54:39 +0000 Subject: [PATCH 11/27] Change title to title case --- src/core/operations/ConvertImageFormat.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/operations/ConvertImageFormat.mjs b/src/core/operations/ConvertImageFormat.mjs index c8152908..5900fbbc 100644 --- a/src/core/operations/ConvertImageFormat.mjs +++ b/src/core/operations/ConvertImageFormat.mjs @@ -21,7 +21,7 @@ class ConvertImageFormat extends Operation { constructor() { super(); - this.name = "Convert image format"; + this.name = "Convert Image Format"; this.module = "Image"; this.description = "Converts an image between different formats. Supported formats:

  • Joint Photographic Experts Group (JPEG)
  • Portable Network Graphics (PNG)
  • Bitmap (BMP)
  • Tagged Image File Format (TIFF)

Note: GIF files are supported for input, but cannot be outputted."; this.infoURL = "https://wikipedia.org/wiki/Image_file_formats"; From 6a01e4039423e3583f2af5816d3ef9fb219f9d31 Mon Sep 17 00:00:00 2001 From: j433866 Date: Wed, 20 Mar 2019 11:20:34 +0000 Subject: [PATCH 12/27] Fix bug where GIF input would error on output. Also minor corrections to jsdocs in ImageManipulation --- src/core/lib/ImageManipulation.mjs | 13 +++++------ src/core/operations/AddTextToImage.mjs | 7 +++++- src/core/operations/BlurImage.mjs | 7 +++++- src/core/operations/ContainImage.mjs | 7 +++++- src/core/operations/CoverImage.mjs | 7 +++++- src/core/operations/CropImage.mjs | 7 +++++- src/core/operations/DitherImage.mjs | 8 ++++++- src/core/operations/FlipImage.mjs | 7 +++++- .../operations/ImageBrightnessContrast.mjs | 7 +++++- src/core/operations/ImageFilter.mjs | 7 +++++- .../ImageHueSaturationLightness.mjs | 8 ++++++- src/core/operations/ImageOpacity.mjs | 7 +++++- src/core/operations/InvertImage.mjs | 8 ++++++- src/core/operations/NormaliseImage.mjs | 22 +++++++++++++++---- src/core/operations/ResizeImage.mjs | 7 +++++- src/core/operations/RotateImage.mjs | 8 ++++++- src/core/operations/SharpenImage.mjs | 7 +++++- 17 files changed, 118 insertions(+), 26 deletions(-) diff --git a/src/core/lib/ImageManipulation.mjs b/src/core/lib/ImageManipulation.mjs index 1f1b85ae..54c1bafc 100644 --- a/src/core/lib/ImageManipulation.mjs +++ b/src/core/lib/ImageManipulation.mjs @@ -12,7 +12,7 @@ import OperationError from "../errors/OperationError"; * Gaussian blurs an image. * * @param {jimp} input - * @param {int} radius + * @param {number} radius * @param {boolean} fast * @returns {jimp} */ @@ -24,7 +24,6 @@ export function gaussianBlur (input, radius) { input = boxBlur(input, (boxes[i] - 1) / 2); } } catch (err) { - log.error(err); throw new OperationError(`Error blurring image. (${err})`); } @@ -33,8 +32,8 @@ export function gaussianBlur (input, radius) { /** * - * @param {int} radius - * @param {int} numBoxes + * @param {number} radius + * @param {number} numBoxes * @returns {Array} */ function boxesForGauss(radius, numBoxes) { @@ -167,9 +166,9 @@ function boxBlurH (source, output, width, height, radius) { * * @param {jimp} source * @param {jimp} output - * @param {int} width - * @param {int} height - * @param {int} radius + * @param {number} width + * @param {number} height + * @param {number} radius * @returns {jimp} */ function boxBlurV (source, output, width, height, radius) { diff --git a/src/core/operations/AddTextToImage.mjs b/src/core/operations/AddTextToImage.mjs index f8ee3485..68a28c8f 100644 --- a/src/core/operations/AddTextToImage.mjs +++ b/src/core/operations/AddTextToImage.mjs @@ -228,7 +228,12 @@ class AddTextToImage extends Operation { } } - const imageBuffer = await image.getBufferAsync(jimp.AUTO); + let imageBuffer; + if (image.getMIME() === "image/gif") { + imageBuffer = await image.getBufferAsync(jimp.MIME_PNG); + } else { + imageBuffer = await image.getBufferAsync(jimp.AUTO); + } return [...imageBuffer]; } catch (err) { throw new OperationError(`Error adding text to image. (${err})`); diff --git a/src/core/operations/BlurImage.mjs b/src/core/operations/BlurImage.mjs index e0b5c919..68c8dbd6 100644 --- a/src/core/operations/BlurImage.mjs +++ b/src/core/operations/BlurImage.mjs @@ -76,7 +76,12 @@ class BlurImage extends Operation { break; } - const imageBuffer = await image.getBufferAsync(jimp.AUTO); + let imageBuffer; + if (image.getMIME() === "image/gif") { + imageBuffer = await image.getBufferAsync(jimp.MIME_PNG); + } else { + imageBuffer = await image.getBufferAsync(jimp.AUTO); + } return [...imageBuffer]; } catch (err) { throw new OperationError(`Error blurring image. (${err})`); diff --git a/src/core/operations/ContainImage.mjs b/src/core/operations/ContainImage.mjs index 4cb7cfdf..e16d3d58 100644 --- a/src/core/operations/ContainImage.mjs +++ b/src/core/operations/ContainImage.mjs @@ -127,7 +127,12 @@ class ContainImage extends Operation { image = newImage; } - const imageBuffer = await image.getBufferAsync(jimp.AUTO); + let imageBuffer; + if (image.getMIME() === "image/gif") { + imageBuffer = await image.getBufferAsync(jimp.MIME_PNG); + } else { + imageBuffer = await image.getBufferAsync(jimp.AUTO); + } return [...imageBuffer]; } catch (err) { throw new OperationError(`Error containing image. (${err})`); diff --git a/src/core/operations/CoverImage.mjs b/src/core/operations/CoverImage.mjs index 07466308..492938ff 100644 --- a/src/core/operations/CoverImage.mjs +++ b/src/core/operations/CoverImage.mjs @@ -115,7 +115,12 @@ class CoverImage extends Operation { if (ENVIRONMENT_IS_WORKER()) self.sendStatusMessage("Covering image..."); image.cover(width, height, alignMap[hAlign] | alignMap[vAlign], resizeMap[alg]); - const imageBuffer = await image.getBufferAsync(jimp.AUTO); + let imageBuffer; + if (image.getMIME() === "image/gif") { + imageBuffer = await image.getBufferAsync(jimp.MIME_PNG); + } else { + imageBuffer = await image.getBufferAsync(jimp.AUTO); + } return [...imageBuffer]; } catch (err) { throw new OperationError(`Error covering image. (${err})`); diff --git a/src/core/operations/CropImage.mjs b/src/core/operations/CropImage.mjs index efbf29f9..fd04a907 100644 --- a/src/core/operations/CropImage.mjs +++ b/src/core/operations/CropImage.mjs @@ -116,7 +116,12 @@ class CropImage extends Operation { image.crop(xPos, yPos, width, height); } - const imageBuffer = await image.getBufferAsync(jimp.AUTO); + let imageBuffer; + if (image.getMIME() === "image/gif") { + imageBuffer = await image.getBufferAsync(jimp.MIME_PNG); + } else { + imageBuffer = await image.getBufferAsync(jimp.AUTO); + } return [...imageBuffer]; } catch (err) { throw new OperationError(`Error cropping image. (${err})`); diff --git a/src/core/operations/DitherImage.mjs b/src/core/operations/DitherImage.mjs index 13011837..3e603016 100644 --- a/src/core/operations/DitherImage.mjs +++ b/src/core/operations/DitherImage.mjs @@ -51,7 +51,13 @@ class DitherImage extends Operation { if (ENVIRONMENT_IS_WORKER()) self.sendStatusMessage("Applying dither to image..."); image.dither565(); - const imageBuffer = await image.getBufferAsync(jimp.AUTO); + + let imageBuffer; + if (image.getMIME() === "image/gif") { + imageBuffer = await image.getBufferAsync(jimp.MIME_PNG); + } else { + imageBuffer = await image.getBufferAsync(jimp.AUTO); + } return [...imageBuffer]; } catch (err) { throw new OperationError(`Error applying dither to image. (${err})`); diff --git a/src/core/operations/FlipImage.mjs b/src/core/operations/FlipImage.mjs index 593809e9..cebba0e0 100644 --- a/src/core/operations/FlipImage.mjs +++ b/src/core/operations/FlipImage.mjs @@ -66,7 +66,12 @@ class FlipImage extends Operation { break; } - const imageBuffer = await image.getBufferAsync(jimp.AUTO); + let imageBuffer; + if (image.getMIME() === "image/gif") { + imageBuffer = await image.getBufferAsync(jimp.MIME_PNG); + } else { + imageBuffer = await image.getBufferAsync(jimp.AUTO); + } return [...imageBuffer]; } catch (err) { throw new OperationError(`Error flipping image. (${err})`); diff --git a/src/core/operations/ImageBrightnessContrast.mjs b/src/core/operations/ImageBrightnessContrast.mjs index 27a30cff..f47134a2 100644 --- a/src/core/operations/ImageBrightnessContrast.mjs +++ b/src/core/operations/ImageBrightnessContrast.mjs @@ -75,7 +75,12 @@ class ImageBrightnessContrast extends Operation { image.contrast(contrast / 100); } - const imageBuffer = await image.getBufferAsync(jimp.AUTO); + let imageBuffer; + if (image.getMIME() === "image/gif") { + imageBuffer = await image.getBufferAsync(jimp.MIME_PNG); + } else { + imageBuffer = await image.getBufferAsync(jimp.AUTO); + } return [...imageBuffer]; } catch (err) { throw new OperationError(`Error adjusting image brightness or contrast. (${err})`); diff --git a/src/core/operations/ImageFilter.mjs b/src/core/operations/ImageFilter.mjs index aca34042..6c1a5a65 100644 --- a/src/core/operations/ImageFilter.mjs +++ b/src/core/operations/ImageFilter.mjs @@ -66,7 +66,12 @@ class ImageFilter extends Operation { image.sepia(); } - const imageBuffer = await image.getBufferAsync(jimp.AUTO); + let imageBuffer; + if (image.getMIME() === "image/gif") { + imageBuffer = await image.getBufferAsync(jimp.MIME_PNG); + } else { + imageBuffer = await image.getBufferAsync(jimp.AUTO); + } return [...imageBuffer]; } catch (err) { throw new OperationError(`Error applying filter to image. (${err})`); diff --git a/src/core/operations/ImageHueSaturationLightness.mjs b/src/core/operations/ImageHueSaturationLightness.mjs index bca73c30..4bdd9fa7 100644 --- a/src/core/operations/ImageHueSaturationLightness.mjs +++ b/src/core/operations/ImageHueSaturationLightness.mjs @@ -102,7 +102,13 @@ class ImageHueSaturationLightness extends Operation { } ]); } - const imageBuffer = await image.getBufferAsync(jimp.AUTO); + + let imageBuffer; + if (image.getMIME() === "image/gif") { + imageBuffer = await image.getBufferAsync(jimp.MIME_PNG); + } else { + imageBuffer = await image.getBufferAsync(jimp.AUTO); + } return [...imageBuffer]; } catch (err) { throw new OperationError(`Error adjusting image hue / saturation / lightness. (${err})`); diff --git a/src/core/operations/ImageOpacity.mjs b/src/core/operations/ImageOpacity.mjs index 999ad176..afa370ff 100644 --- a/src/core/operations/ImageOpacity.mjs +++ b/src/core/operations/ImageOpacity.mjs @@ -61,7 +61,12 @@ class ImageOpacity extends Operation { self.sendStatusMessage("Changing image opacity..."); image.opacity(opacity / 100); - const imageBuffer = await image.getBufferAsync(jimp.MIME_PNG); + let imageBuffer; + if (image.getMIME() === "image/gif") { + imageBuffer = await image.getBufferAsync(jimp.MIME_PNG); + } else { + imageBuffer = await image.getBufferAsync(jimp.AUTO); + } return [...imageBuffer]; } catch (err) { throw new OperationError(`Error changing image opacity. (${err})`); diff --git a/src/core/operations/InvertImage.mjs b/src/core/operations/InvertImage.mjs index ed97523f..7c7a4d09 100644 --- a/src/core/operations/InvertImage.mjs +++ b/src/core/operations/InvertImage.mjs @@ -51,7 +51,13 @@ class InvertImage extends Operation { if (ENVIRONMENT_IS_WORKER()) self.sendStatusMessage("Inverting image..."); image.invert(); - const imageBuffer = await image.getBufferAsync(jimp.AUTO); + + let imageBuffer; + if (image.getMIME() === "image/gif") { + imageBuffer = await image.getBufferAsync(jimp.MIME_PNG); + } else { + imageBuffer = await image.getBufferAsync(jimp.AUTO); + } return [...imageBuffer]; } catch (err) { throw new OperationError(`Error inverting image. (${err})`); diff --git a/src/core/operations/NormaliseImage.mjs b/src/core/operations/NormaliseImage.mjs index bb5113a7..c49cc977 100644 --- a/src/core/operations/NormaliseImage.mjs +++ b/src/core/operations/NormaliseImage.mjs @@ -41,12 +41,26 @@ class NormaliseImage extends Operation { throw new OperationError("Invalid file type."); } - const image = await jimp.read(Buffer.from(input)); + let image; + try { + image = await jimp.read(Buffer.from(input)); + } catch (err) { + throw new OperationError(`Error opening image file. (${err})`); + } - image.normalize(); + try { + image.normalize(); - const imageBuffer = await image.getBufferAsync(jimp.AUTO); - return [...imageBuffer]; + let imageBuffer; + if (image.getMIME() === "image/gif") { + imageBuffer = await image.getBufferAsync(jimp.MIME_PNG); + } else { + imageBuffer = await image.getBufferAsync(jimp.AUTO); + } + return [...imageBuffer]; + } catch (err) { + throw new OperationError(`Error normalising image. (${err})`); + } } /** diff --git a/src/core/operations/ResizeImage.mjs b/src/core/operations/ResizeImage.mjs index 48a5d54a..11266ba8 100644 --- a/src/core/operations/ResizeImage.mjs +++ b/src/core/operations/ResizeImage.mjs @@ -110,7 +110,12 @@ class ResizeImage extends Operation { image.resize(width, height, resizeMap[resizeAlg]); } - const imageBuffer = await image.getBufferAsync(jimp.AUTO); + let imageBuffer; + if (image.getMIME() === "image/gif") { + imageBuffer = await image.getBufferAsync(jimp.MIME_PNG); + } else { + imageBuffer = await image.getBufferAsync(jimp.AUTO); + } return [...imageBuffer]; } catch (err) { throw new OperationError(`Error resizing image. (${err})`); diff --git a/src/core/operations/RotateImage.mjs b/src/core/operations/RotateImage.mjs index 34497863..16330c44 100644 --- a/src/core/operations/RotateImage.mjs +++ b/src/core/operations/RotateImage.mjs @@ -59,7 +59,13 @@ class RotateImage extends Operation { if (ENVIRONMENT_IS_WORKER()) self.sendStatusMessage("Rotating image..."); image.rotate(degrees); - const imageBuffer = await image.getBufferAsync(jimp.AUTO); + + let imageBuffer; + if (image.getMIME() === "image/gif") { + imageBuffer = await image.getBufferAsync(jimp.MIME_PNG); + } else { + imageBuffer = await image.getBufferAsync(jimp.AUTO); + } return [...imageBuffer]; } catch (err) { throw new OperationError(`Error rotating image. (${err})`); diff --git a/src/core/operations/SharpenImage.mjs b/src/core/operations/SharpenImage.mjs index 3ef1912e..de2f3603 100644 --- a/src/core/operations/SharpenImage.mjs +++ b/src/core/operations/SharpenImage.mjs @@ -134,7 +134,12 @@ class SharpenImage extends Operation { } }); - const imageBuffer = await image.getBufferAsync(jimp.AUTO); + let imageBuffer; + if (image.getMIME() === "image/gif") { + imageBuffer = await image.getBufferAsync(jimp.MIME_PNG); + } else { + imageBuffer = await image.getBufferAsync(jimp.AUTO); + } return [...imageBuffer]; } catch (err) { throw new OperationError(`Error sharpening image. (${err})`); From c2496fe63e9e8a495ad7209ca1fcd9709589fc72 Mon Sep 17 00:00:00 2001 From: j433866 Date: Mon, 1 Apr 2019 09:00:41 +0100 Subject: [PATCH 13/27] Change to use Promise.all --- src/core/operations/AddTextToImage.mjs | 34 ++++++++++++++++++-------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/core/operations/AddTextToImage.mjs b/src/core/operations/AddTextToImage.mjs index 68a28c8f..56c455b6 100644 --- a/src/core/operations/AddTextToImage.mjs +++ b/src/core/operations/AddTextToImage.mjs @@ -134,18 +134,32 @@ class AddTextToImage extends Operation { if (ENVIRONMENT_IS_WORKER()) self.sendStatusMessage("Adding text to image..."); - const fontsMap = { - "Roboto": await import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/Roboto72White.fnt"), - "Roboto Black": await import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoBlack72White.fnt"), - "Roboto Mono": await import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoMono72White.fnt"), - "Roboto Slab": await import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoSlab72White.fnt") - }; + const fontsMap = {}; + const fonts = [ + import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/Roboto72White.fnt"), + import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoBlack72White.fnt"), + import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoMono72White.fnt"), + import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoSlab72White.fnt") + ]; + + await Promise.all(fonts) + .then(fonts => { + fontsMap.Roboto = fonts[0]; + fontsMap["Roboto Black"] = fonts[1]; + fontsMap["Roboto Mono"] = fonts[2]; + fontsMap["Roboto Slab"] = fonts[3] + }); + // Make Webpack load the png font images - await import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/Roboto72White.png"); - await import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoSlab72White.png"); - await import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoMono72White.png"); - await import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoBlack72White.png"); + const fontImages = [ + import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/Roboto72White.png"), + import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoSlab72White.png"), + import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoMono72White.png"), + import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoBlack72White.png") + ]; + + await Promise.all(fontImages); const font = fontsMap[fontFace]; From e44a22e143520fcef46054b593c117440003a71d Mon Sep 17 00:00:00 2001 From: j433866 Date: Mon, 1 Apr 2019 10:54:46 +0100 Subject: [PATCH 14/27] Change ops to use ArrayBuffer instead of byteArray --- src/core/operations/AddTextToImage.mjs | 23 ++++++++++--------- src/core/operations/BlurImage.mjs | 21 +++++++++-------- src/core/operations/ContainImage.mjs | 21 +++++++++-------- src/core/operations/ConvertImageFormat.mjs | 23 ++++++++++--------- src/core/operations/CoverImage.mjs | 21 +++++++++-------- src/core/operations/CropImage.mjs | 21 +++++++++-------- src/core/operations/DitherImage.mjs | 21 +++++++++-------- src/core/operations/FlipImage.mjs | 21 +++++++++-------- .../operations/ImageBrightnessContrast.mjs | 21 +++++++++-------- src/core/operations/ImageFilter.mjs | 21 +++++++++-------- .../ImageHueSaturationLightness.mjs | 21 +++++++++-------- src/core/operations/ImageOpacity.mjs | 21 +++++++++-------- src/core/operations/InvertImage.mjs | 21 +++++++++-------- src/core/operations/NormaliseImage.mjs | 21 +++++++++-------- src/core/operations/ParseQRCode.mjs | 8 +++---- src/core/operations/ResizeImage.mjs | 21 +++++++++-------- src/core/operations/RotateImage.mjs | 21 +++++++++-------- src/core/operations/SharpenImage.mjs | 23 ++++++++++--------- 18 files changed, 194 insertions(+), 177 deletions(-) diff --git a/src/core/operations/AddTextToImage.mjs b/src/core/operations/AddTextToImage.mjs index 56c455b6..99ea7bd0 100644 --- a/src/core/operations/AddTextToImage.mjs +++ b/src/core/operations/AddTextToImage.mjs @@ -25,8 +25,8 @@ class AddTextToImage extends Operation { this.module = "Image"; this.description = "Adds text onto an image.

Text can be horizontally or vertically aligned, or the position can be manually specified.
Variants of the Roboto font face are available in any size or colour.

Note: This may cause a degradation in image quality, especially when using font sizes larger than 72."; this.infoURL = ""; - this.inputType = "byteArray"; - this.outputType = "byteArray"; + this.inputType = "ArrayBuffer"; + this.outputType = "ArrayBuffer"; this.presentType = "html"; this.args = [ { @@ -102,7 +102,7 @@ class AddTextToImage extends Operation { } /** - * @param {byteArray} input + * @param {ArrayBuffer} input * @param {Object[]} args * @returns {byteArray} */ @@ -120,13 +120,13 @@ class AddTextToImage extends Operation { let xPos = args[3], yPos = args[4]; - if (!isImage(input)) { + if (!isImage(new Uint8Array(input))) { throw new OperationError("Invalid file type."); } let image; try { - image = await jimp.read(Buffer.from(input)); + image = await jimp.read(input); } catch (err) { throw new OperationError(`Error loading image. (${err})`); } @@ -147,7 +147,7 @@ class AddTextToImage extends Operation { fontsMap.Roboto = fonts[0]; fontsMap["Roboto Black"] = fonts[1]; fontsMap["Roboto Mono"] = fonts[2]; - fontsMap["Roboto Slab"] = fonts[3] + fontsMap["Roboto Slab"] = fonts[3]; }); @@ -248,7 +248,7 @@ class AddTextToImage extends Operation { } else { imageBuffer = await image.getBufferAsync(jimp.AUTO); } - return [...imageBuffer]; + return imageBuffer.buffer; } catch (err) { throw new OperationError(`Error adding text to image. (${err})`); } @@ -257,18 +257,19 @@ class AddTextToImage extends Operation { /** * Displays the blurred image using HTML for web apps * - * @param {byteArray} data + * @param {ArrayBuffer} data * @returns {html} */ present(data) { - if (!data.length) return ""; + if (!data.byteLength) return ""; + const dataArray = new Uint8Array(data); - const type = isImage(data); + const type = isImage(dataArray); if (!type) { throw new OperationError("Invalid file type."); } - return ``; + return ``; } } diff --git a/src/core/operations/BlurImage.mjs b/src/core/operations/BlurImage.mjs index 68c8dbd6..d112d7c8 100644 --- a/src/core/operations/BlurImage.mjs +++ b/src/core/operations/BlurImage.mjs @@ -26,8 +26,8 @@ class BlurImage extends Operation { this.module = "Image"; this.description = "Applies a blur effect to the image.

Gaussian blur is much slower than fast blur, but produces better results."; this.infoURL = "https://wikipedia.org/wiki/Gaussian_blur"; - this.inputType = "byteArray"; - this.outputType = "byteArray"; + this.inputType = "ArrayBuffer"; + this.outputType = "ArrayBuffer"; this.presentType = "html"; this.args = [ { @@ -45,20 +45,20 @@ class BlurImage extends Operation { } /** - * @param {byteArray} input + * @param {ArrayBuffer} input * @param {Object[]} args * @returns {byteArray} */ async run(input, args) { const [blurAmount, blurType] = args; - if (!isImage(input)) { + if (!isImage(new Uint8Array(input))) { throw new OperationError("Invalid file type."); } let image; try { - image = await jimp.read(Buffer.from(input)); + image = await jimp.read(input); } catch (err) { throw new OperationError(`Error loading image. (${err})`); } @@ -82,7 +82,7 @@ class BlurImage extends Operation { } else { imageBuffer = await image.getBufferAsync(jimp.AUTO); } - return [...imageBuffer]; + return imageBuffer.buffer; } catch (err) { throw new OperationError(`Error blurring image. (${err})`); } @@ -91,18 +91,19 @@ class BlurImage extends Operation { /** * Displays the blurred image using HTML for web apps * - * @param {byteArray} data + * @param {ArrayBuffer} data * @returns {html} */ present(data) { - if (!data.length) return ""; + if (!data.byteLength) return ""; + const dataArray = new Uint8Array(data); - const type = isImage(data); + const type = isImage(dataArray); if (!type) { throw new OperationError("Invalid file type."); } - return ``; + return ``; } } diff --git a/src/core/operations/ContainImage.mjs b/src/core/operations/ContainImage.mjs index e16d3d58..e6edd9e1 100644 --- a/src/core/operations/ContainImage.mjs +++ b/src/core/operations/ContainImage.mjs @@ -25,8 +25,8 @@ class ContainImage extends Operation { this.module = "Image"; this.description = "Scales an image to the specified width and height, maintaining the aspect ratio. The image may be letterboxed."; this.infoURL = ""; - this.inputType = "byteArray"; - this.outputType = "byteArray"; + this.inputType = "ArrayBuffer"; + this.outputType = "ArrayBuffer"; this.presentType = "html"; this.args = [ { @@ -82,7 +82,7 @@ class ContainImage extends Operation { } /** - * @param {byteArray} input + * @param {ArrayBuffer} input * @param {Object[]} args * @returns {byteArray} */ @@ -106,13 +106,13 @@ class ContainImage extends Operation { "Bottom": jimp.VERTICAL_ALIGN_BOTTOM }; - if (!isImage(input)) { + if (!isImage(new Uint8Array(input))) { throw new OperationError("Invalid file type."); } let image; try { - image = await jimp.read(Buffer.from(input)); + image = await jimp.read(input); } catch (err) { throw new OperationError(`Error loading image. (${err})`); } @@ -133,7 +133,7 @@ class ContainImage extends Operation { } else { imageBuffer = await image.getBufferAsync(jimp.AUTO); } - return [...imageBuffer]; + return imageBuffer.buffer; } catch (err) { throw new OperationError(`Error containing image. (${err})`); } @@ -141,18 +141,19 @@ class ContainImage extends Operation { /** * Displays the contained image using HTML for web apps - * @param {byteArray} data + * @param {ArrayBuffer} data * @returns {html} */ present(data) { - if (!data.length) return ""; + if (!data.byteLength) return ""; + const dataArray = new Uint8Array(data); - const type = isImage(data); + const type = isImage(dataArray); if (!type) { throw new OperationError("Invalid file type."); } - return ``; + return ``; } } diff --git a/src/core/operations/ConvertImageFormat.mjs b/src/core/operations/ConvertImageFormat.mjs index 5900fbbc..cdcfc249 100644 --- a/src/core/operations/ConvertImageFormat.mjs +++ b/src/core/operations/ConvertImageFormat.mjs @@ -25,8 +25,8 @@ class ConvertImageFormat extends Operation { this.module = "Image"; this.description = "Converts an image between different formats. Supported formats:
  • Joint Photographic Experts Group (JPEG)
  • Portable Network Graphics (PNG)
  • Bitmap (BMP)
  • Tagged Image File Format (TIFF)

Note: GIF files are supported for input, but cannot be outputted."; this.infoURL = "https://wikipedia.org/wiki/Image_file_formats"; - this.inputType = "byteArray"; - this.outputType = "byteArray"; + this.inputType = "ArrayBuffer"; + this.outputType = "ArrayBuffer"; this.presentType = "html"; this.args = [ { @@ -69,7 +69,7 @@ class ConvertImageFormat extends Operation { } /** - * @param {byteArray} input + * @param {ArrayBuffer} input * @param {Object[]} args * @returns {byteArray} */ @@ -93,12 +93,12 @@ class ConvertImageFormat extends Operation { const mime = formatMap[format]; - if (!isImage(input)) { + if (!isImage(new Uint8Array(input))) { throw new OperationError("Invalid file format."); } let image; try { - image = await jimp.read(Buffer.from(input)); + image = await jimp.read(input); } catch (err) { throw new OperationError(`Error opening image file. (${err})`); } @@ -114,7 +114,7 @@ class ConvertImageFormat extends Operation { } const imageBuffer = await image.getBufferAsync(mime); - return [...imageBuffer]; + return imageBuffer.buffer; } catch (err) { throw new OperationError(`Error converting image format. (${err})`); } @@ -123,18 +123,19 @@ class ConvertImageFormat extends Operation { /** * Displays the converted image using HTML for web apps * - * @param {byteArray} data + * @param {ArrayBuffer} data * @returns {html} */ present(data) { - if (!data.length) return ""; + if (!data.byteLength) return ""; + const dataArray = new Uint8Array(data); - const type = isImage(data); + const type = isImage(dataArray); if (!type) { - throw new OperationError("Invalid image type."); + throw new OperationError("Invalid file type."); } - return ``; + return ``; } } diff --git a/src/core/operations/CoverImage.mjs b/src/core/operations/CoverImage.mjs index 492938ff..e55b4da1 100644 --- a/src/core/operations/CoverImage.mjs +++ b/src/core/operations/CoverImage.mjs @@ -25,8 +25,8 @@ class CoverImage extends Operation { this.module = "Image"; this.description = "Scales the image to the given width and height, keeping the aspect ratio. The image may be clipped."; this.infoURL = ""; - this.inputType = "byteArray"; - this.outputType = "byteArray"; + this.inputType = "ArrayBuffer"; + this.outputType = "ArrayBuffer"; this.presentType = "html"; this.args = [ { @@ -77,7 +77,7 @@ class CoverImage extends Operation { } /** - * @param {byteArray} input + * @param {ArrayBuffer} input * @param {Object[]} args * @returns {byteArray} */ @@ -101,13 +101,13 @@ class CoverImage extends Operation { "Bottom": jimp.VERTICAL_ALIGN_BOTTOM }; - if (!isImage(input)) { + if (!isImage(new Uint8Array(input))) { throw new OperationError("Invalid file type."); } let image; try { - image = await jimp.read(Buffer.from(input)); + image = await jimp.read(input); } catch (err) { throw new OperationError(`Error loading image. (${err})`); } @@ -121,7 +121,7 @@ class CoverImage extends Operation { } else { imageBuffer = await image.getBufferAsync(jimp.AUTO); } - return [...imageBuffer]; + return imageBuffer.buffer; } catch (err) { throw new OperationError(`Error covering image. (${err})`); } @@ -129,18 +129,19 @@ class CoverImage extends Operation { /** * Displays the covered image using HTML for web apps - * @param {byteArray} data + * @param {ArrayBuffer} data * @returns {html} */ present(data) { - if (!data.length) return ""; + if (!data.byteLength) return ""; + const dataArray = new Uint8Array(data); - const type = isImage(data); + const type = isImage(dataArray); if (!type) { throw new OperationError("Invalid file type."); } - return ``; + return ``; } } diff --git a/src/core/operations/CropImage.mjs b/src/core/operations/CropImage.mjs index fd04a907..a1114bea 100644 --- a/src/core/operations/CropImage.mjs +++ b/src/core/operations/CropImage.mjs @@ -25,8 +25,8 @@ class CropImage extends Operation { 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 = "byteArray"; - this.outputType = "byteArray"; + this.inputType = "ArrayBuffer"; + this.outputType = "ArrayBuffer"; this.presentType = "html"; this.args = [ { @@ -86,19 +86,19 @@ class CropImage extends Operation { } /** - * @param {byteArray} input + * @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)) { + if (!isImage(new Uint8Array(input))) { throw new OperationError("Invalid file type."); } let image; try { - image = await jimp.read(Buffer.from(input)); + image = await jimp.read(input); } catch (err) { throw new OperationError(`Error loading image. (${err})`); } @@ -122,7 +122,7 @@ class CropImage extends Operation { } else { imageBuffer = await image.getBufferAsync(jimp.AUTO); } - return [...imageBuffer]; + return imageBuffer.buffer; } catch (err) { throw new OperationError(`Error cropping image. (${err})`); } @@ -130,18 +130,19 @@ class CropImage extends Operation { /** * Displays the cropped image using HTML for web apps - * @param {byteArray} data + * @param {ArrayBuffer} data * @returns {html} */ present(data) { - if (!data.length) return ""; + if (!data.byteLength) return ""; + const dataArray = new Uint8Array(data); - const type = isImage(data); + const type = isImage(dataArray); if (!type) { throw new OperationError("Invalid file type."); } - return ``; + return ``; } } diff --git a/src/core/operations/DitherImage.mjs b/src/core/operations/DitherImage.mjs index 3e603016..aee70389 100644 --- a/src/core/operations/DitherImage.mjs +++ b/src/core/operations/DitherImage.mjs @@ -25,25 +25,25 @@ class DitherImage extends Operation { this.module = "Image"; this.description = "Apply a dither effect to an image."; this.infoURL = "https://wikipedia.org/wiki/Dither"; - this.inputType = "byteArray"; - this.outputType = "byteArray"; + this.inputType = "ArrayBuffer"; + this.outputType = "ArrayBuffer"; this.presentType = "html"; this.args = []; } /** - * @param {byteArray} input + * @param {ArrayBuffer} input * @param {Object[]} args * @returns {byteArray} */ async run(input, args) { - if (!isImage(input)) { + if (!isImage(new Uint8Array(input))) { throw new OperationError("Invalid file type."); } let image; try { - image = await jimp.read(Buffer.from(input)); + image = await jimp.read(input); } catch (err) { throw new OperationError(`Error loading image. (${err})`); } @@ -58,7 +58,7 @@ class DitherImage extends Operation { } else { imageBuffer = await image.getBufferAsync(jimp.AUTO); } - return [...imageBuffer]; + return imageBuffer.buffer; } catch (err) { throw new OperationError(`Error applying dither to image. (${err})`); } @@ -66,18 +66,19 @@ class DitherImage extends Operation { /** * Displays the dithered image using HTML for web apps - * @param {byteArray} data + * @param {ArrayBuffer} data * @returns {html} */ present(data) { - if (!data.length) return ""; + if (!data.byteLength) return ""; + const dataArray = new Uint8Array(data); - const type = isImage(data); + const type = isImage(dataArray); if (!type) { throw new OperationError("Invalid file type."); } - return ``; + return ``; } } diff --git a/src/core/operations/FlipImage.mjs b/src/core/operations/FlipImage.mjs index cebba0e0..16793441 100644 --- a/src/core/operations/FlipImage.mjs +++ b/src/core/operations/FlipImage.mjs @@ -25,8 +25,8 @@ class FlipImage extends Operation { this.module = "Image"; this.description = "Flips an image along its X or Y axis."; this.infoURL = ""; - this.inputType = "byteArray"; - this.outputType = "byteArray"; + this.inputType = "ArrayBuffer"; + this.outputType = "ArrayBuffer"; this.presentType = "html"; this.args = [ { @@ -38,19 +38,19 @@ class FlipImage extends Operation { } /** - * @param {byteArray} input + * @param {ArrayBuffer} input * @param {Object[]} args * @returns {byteArray} */ async run(input, args) { const [flipAxis] = args; - if (!isImage(input)) { + if (!isImage(new Uint8Array(input))) { throw new OperationError("Invalid input file type."); } let image; try { - image = await jimp.read(Buffer.from(input)); + image = await jimp.read(input); } catch (err) { throw new OperationError(`Error loading image. (${err})`); } @@ -72,7 +72,7 @@ class FlipImage extends Operation { } else { imageBuffer = await image.getBufferAsync(jimp.AUTO); } - return [...imageBuffer]; + return imageBuffer.buffer; } catch (err) { throw new OperationError(`Error flipping image. (${err})`); } @@ -80,18 +80,19 @@ class FlipImage extends Operation { /** * Displays the flipped image using HTML for web apps - * @param {byteArray} data + * @param {ArrayBuffer} data * @returns {html} */ present(data) { - if (!data.length) return ""; + if (!data.byteLength) return ""; + const dataArray = new Uint8Array(data); - const type = isImage(data); + const type = isImage(dataArray); if (!type) { throw new OperationError("Invalid file type."); } - return ``; + return ``; } } diff --git a/src/core/operations/ImageBrightnessContrast.mjs b/src/core/operations/ImageBrightnessContrast.mjs index f47134a2..f1c8f4e0 100644 --- a/src/core/operations/ImageBrightnessContrast.mjs +++ b/src/core/operations/ImageBrightnessContrast.mjs @@ -25,8 +25,8 @@ class ImageBrightnessContrast extends Operation { this.module = "Image"; this.description = "Adjust the brightness or contrast of an image."; this.infoURL = ""; - this.inputType = "byteArray"; - this.outputType = "byteArray"; + this.inputType = "ArrayBuffer"; + this.outputType = "ArrayBuffer"; this.presentType = "html"; this.args = [ { @@ -47,19 +47,19 @@ class ImageBrightnessContrast extends Operation { } /** - * @param {byteArray} input + * @param {ArrayBuffer} input * @param {Object[]} args * @returns {byteArray} */ async run(input, args) { const [brightness, contrast] = args; - if (!isImage(input)) { + if (!isImage(new Uint8Array(input))) { throw new OperationError("Invalid file type."); } let image; try { - image = await jimp.read(Buffer.from(input)); + image = await jimp.read(input); } catch (err) { throw new OperationError(`Error loading image. (${err})`); } @@ -81,7 +81,7 @@ class ImageBrightnessContrast extends Operation { } else { imageBuffer = await image.getBufferAsync(jimp.AUTO); } - return [...imageBuffer]; + return imageBuffer.buffer; } catch (err) { throw new OperationError(`Error adjusting image brightness or contrast. (${err})`); } @@ -89,18 +89,19 @@ class ImageBrightnessContrast extends Operation { /** * Displays the image using HTML for web apps - * @param {byteArray} data + * @param {ArrayBuffer} data * @returns {html} */ present(data) { - if (!data.length) return ""; + if (!data.byteLength) return ""; + const dataArray = new Uint8Array(data); - const type = isImage(data); + const type = isImage(dataArray); if (!type) { throw new OperationError("Invalid file type."); } - return ``; + return ``; } } diff --git a/src/core/operations/ImageFilter.mjs b/src/core/operations/ImageFilter.mjs index 6c1a5a65..be96c046 100644 --- a/src/core/operations/ImageFilter.mjs +++ b/src/core/operations/ImageFilter.mjs @@ -25,8 +25,8 @@ class ImageFilter extends Operation { this.module = "Image"; this.description = "Applies a greyscale or sepia filter to an image."; this.infoURL = ""; - this.inputType = "byteArray"; - this.outputType = "byteArray"; + this.inputType = "ArrayBuffer"; + this.outputType = "ArrayBuffer"; this.presentType = "html"; this.args = [ { @@ -41,19 +41,19 @@ class ImageFilter extends Operation { } /** - * @param {byteArray} input + * @param {ArrayBuffer} input * @param {Object[]} args * @returns {byteArray} */ async run(input, args) { const [filterType] = args; - if (!isImage(input)){ + if (!isImage(new Uint8Array(input))){ throw new OperationError("Invalid file type."); } let image; try { - image = await jimp.read(Buffer.from(input)); + image = await jimp.read(input); } catch (err) { throw new OperationError(`Error loading image. (${err})`); } @@ -72,7 +72,7 @@ class ImageFilter extends Operation { } else { imageBuffer = await image.getBufferAsync(jimp.AUTO); } - return [...imageBuffer]; + return imageBuffer.buffer; } catch (err) { throw new OperationError(`Error applying filter to image. (${err})`); } @@ -80,18 +80,19 @@ class ImageFilter extends Operation { /** * Displays the blurred image using HTML for web apps - * @param {byteArray} data + * @param {ArrayBuffer} data * @returns {html} */ present(data) { - if (!data.length) return ""; + if (!data.byteLength) return ""; + const dataArray = new Uint8Array(data); - const type = isImage(data); + const type = isImage(dataArray); if (!type) { throw new OperationError("Invalid file type."); } - return ``; + return ``; } } diff --git a/src/core/operations/ImageHueSaturationLightness.mjs b/src/core/operations/ImageHueSaturationLightness.mjs index 4bdd9fa7..d5b3718b 100644 --- a/src/core/operations/ImageHueSaturationLightness.mjs +++ b/src/core/operations/ImageHueSaturationLightness.mjs @@ -25,8 +25,8 @@ class ImageHueSaturationLightness extends Operation { this.module = "Image"; this.description = "Adjusts the hue / saturation / lightness (HSL) values of an image."; this.infoURL = ""; - this.inputType = "byteArray"; - this.outputType = "byteArray"; + this.inputType = "ArrayBuffer"; + this.outputType = "ArrayBuffer"; this.presentType = "html"; this.args = [ { @@ -54,20 +54,20 @@ class ImageHueSaturationLightness extends Operation { } /** - * @param {byteArray} input + * @param {ArrayBuffer} input * @param {Object[]} args * @returns {byteArray} */ async run(input, args) { const [hue, saturation, lightness] = args; - if (!isImage(input)) { + if (!isImage(new Uint8Array(input))) { throw new OperationError("Invalid file type."); } let image; try { - image = await jimp.read(Buffer.from(input)); + image = await jimp.read(input); } catch (err) { throw new OperationError(`Error loading image. (${err})`); } @@ -109,7 +109,7 @@ class ImageHueSaturationLightness extends Operation { } else { imageBuffer = await image.getBufferAsync(jimp.AUTO); } - return [...imageBuffer]; + return imageBuffer.buffer; } catch (err) { throw new OperationError(`Error adjusting image hue / saturation / lightness. (${err})`); } @@ -117,18 +117,19 @@ class ImageHueSaturationLightness extends Operation { /** * Displays the image using HTML for web apps - * @param {byteArray} data + * @param {ArrayBuffer} data * @returns {html} */ present(data) { - if (!data.length) return ""; + if (!data.byteLength) return ""; + const dataArray = new Uint8Array(data); - const type = isImage(data); + const type = isImage(dataArray); if (!type) { throw new OperationError("Invalid file type."); } - return ``; + return ``; } } diff --git a/src/core/operations/ImageOpacity.mjs b/src/core/operations/ImageOpacity.mjs index afa370ff..4303fcbf 100644 --- a/src/core/operations/ImageOpacity.mjs +++ b/src/core/operations/ImageOpacity.mjs @@ -25,8 +25,8 @@ class ImageOpacity extends Operation { this.module = "Image"; this.description = "Adjust the opacity of an image."; this.infoURL = ""; - this.inputType = "byteArray"; - this.outputType = "byteArray"; + this.inputType = "ArrayBuffer"; + this.outputType = "ArrayBuffer"; this.presentType = "html"; this.args = [ { @@ -40,19 +40,19 @@ class ImageOpacity extends Operation { } /** - * @param {byteArray} input + * @param {ArrayBuffer} input * @param {Object[]} args * @returns {byteArray} */ async run(input, args) { const [opacity] = args; - if (!isImage(input)) { + if (!isImage(new Uint8Array(input))) { throw new OperationError("Invalid file type."); } let image; try { - image = await jimp.read(Buffer.from(input)); + image = await jimp.read(input); } catch (err) { throw new OperationError(`Error loading image. (${err})`); } @@ -67,7 +67,7 @@ class ImageOpacity extends Operation { } else { imageBuffer = await image.getBufferAsync(jimp.AUTO); } - return [...imageBuffer]; + return imageBuffer.buffer; } catch (err) { throw new OperationError(`Error changing image opacity. (${err})`); } @@ -75,18 +75,19 @@ class ImageOpacity extends Operation { /** * Displays the image using HTML for web apps - * @param {byteArray} data + * @param {ArrayBuffer} data * @returns {html} */ present(data) { - if (!data.length) return ""; + if (!data.byteLength) return ""; + const dataArray = new Uint8Array(data); - const type = isImage(data); + const type = isImage(dataArray); if (!type) { throw new OperationError("Invalid file type."); } - return ``; + return ``; } } diff --git a/src/core/operations/InvertImage.mjs b/src/core/operations/InvertImage.mjs index 7c7a4d09..9c29f38a 100644 --- a/src/core/operations/InvertImage.mjs +++ b/src/core/operations/InvertImage.mjs @@ -25,25 +25,25 @@ class InvertImage extends Operation { this.module = "Image"; this.description = "Invert the colours of an image."; this.infoURL = ""; - this.inputType = "byteArray"; - this.outputType = "byteArray"; + this.inputType = "ArrayBuffer"; + this.outputType = "ArrayBuffer"; this.presentType = "html"; this.args = []; } /** - * @param {byteArray} input + * @param {ArrayBuffer} input * @param {Object[]} args * @returns {byteArray} */ async run(input, args) { - if (!isImage(input)) { + if (!isImage(new Uint8Array(input))) { throw new OperationError("Invalid input file format."); } let image; try { - image = await jimp.read(Buffer.from(input)); + image = await jimp.read(input); } catch (err) { throw new OperationError(`Error loading image. (${err})`); } @@ -58,7 +58,7 @@ class InvertImage extends Operation { } else { imageBuffer = await image.getBufferAsync(jimp.AUTO); } - return [...imageBuffer]; + return imageBuffer.buffer; } catch (err) { throw new OperationError(`Error inverting image. (${err})`); } @@ -66,18 +66,19 @@ class InvertImage extends Operation { /** * Displays the inverted image using HTML for web apps - * @param {byteArray} data + * @param {ArrayBuffer} data * @returns {html} */ present(data) { - if (!data.length) return ""; + if (!data.byteLength) return ""; + const dataArray = new Uint8Array(data); - const type = isImage(data); + const type = isImage(dataArray); if (!type) { throw new OperationError("Invalid file type."); } - return ``; + return ``; } } diff --git a/src/core/operations/NormaliseImage.mjs b/src/core/operations/NormaliseImage.mjs index c49cc977..befc8a92 100644 --- a/src/core/operations/NormaliseImage.mjs +++ b/src/core/operations/NormaliseImage.mjs @@ -25,25 +25,25 @@ class NormaliseImage extends Operation { this.module = "Image"; this.description = "Normalise the image colours."; this.infoURL = ""; - this.inputType = "byteArray"; - this.outputType = "byteArray"; + this.inputType = "ArrayBuffer"; + this.outputType = "ArrayBuffer"; this.presentType= "html"; this.args = []; } /** - * @param {byteArray} input + * @param {ArrayBuffer} input * @param {Object[]} args * @returns {byteArray} */ async run(input, args) { - if (!isImage(input)) { + if (!isImage(new Uint8Array(input))) { throw new OperationError("Invalid file type."); } let image; try { - image = await jimp.read(Buffer.from(input)); + image = await jimp.read(input); } catch (err) { throw new OperationError(`Error opening image file. (${err})`); } @@ -57,7 +57,7 @@ class NormaliseImage extends Operation { } else { imageBuffer = await image.getBufferAsync(jimp.AUTO); } - return [...imageBuffer]; + return imageBuffer.buffer; } catch (err) { throw new OperationError(`Error normalising image. (${err})`); } @@ -65,18 +65,19 @@ class NormaliseImage extends Operation { /** * Displays the normalised image using HTML for web apps - * @param {byteArray} data + * @param {ArrayBuffer} data * @returns {html} */ present(data) { - if (!data.length) return ""; + if (!data.byteLength) return ""; + const dataArray = new Uint8Array(data); - const type = isImage(data); + const type = isImage(dataArray); if (!type) { throw new OperationError("Invalid file type."); } - return ``; + return ``; } } diff --git a/src/core/operations/ParseQRCode.mjs b/src/core/operations/ParseQRCode.mjs index ef7af6d7..4c1e0fee 100644 --- a/src/core/operations/ParseQRCode.mjs +++ b/src/core/operations/ParseQRCode.mjs @@ -25,7 +25,7 @@ class ParseQRCode extends Operation { this.module = "Image"; this.description = "Reads an image file and attempts to detect and read a Quick Response (QR) code from the image.

Normalise Image
Attempts to normalise the image before parsing it to improve detection of a QR code."; this.infoURL = "https://wikipedia.org/wiki/QR_code"; - this.inputType = "byteArray"; + this.inputType = "ArrayBuffer"; this.outputType = "string"; this.args = [ { @@ -37,7 +37,7 @@ class ParseQRCode extends Operation { } /** - * @param {byteArray} input + * @param {ArrayBuffer} input * @param {Object[]} args * @returns {string} */ @@ -45,7 +45,7 @@ class ParseQRCode extends Operation { const [normalise] = args; // Make sure that the input is an image - if (!isImage(input)) throw new OperationError("Invalid file type."); + if (!isImage(new Uint8Array(input))) throw new OperationError("Invalid file type."); let image = input; @@ -57,7 +57,7 @@ class ParseQRCode extends Operation { // Makes the image greyscale // Converts image to a JPEG image = await new Promise((resolve, reject) => { - jimp.read(Buffer.from(input)) + jimp.read(input) .then(image => { image .rgba(false) diff --git a/src/core/operations/ResizeImage.mjs b/src/core/operations/ResizeImage.mjs index 11266ba8..1a1521e6 100644 --- a/src/core/operations/ResizeImage.mjs +++ b/src/core/operations/ResizeImage.mjs @@ -25,8 +25,8 @@ class ResizeImage extends Operation { this.module = "Image"; this.description = "Resizes an image to the specified width and height values."; this.infoURL = "https://wikipedia.org/wiki/Image_scaling"; - this.inputType = "byteArray"; - this.outputType = "byteArray"; + this.inputType = "ArrayBuffer"; + this.outputType = "ArrayBuffer"; this.presentType = "html"; this.args = [ { @@ -67,7 +67,7 @@ class ResizeImage extends Operation { } /** - * @param {byteArray} input + * @param {ArrayBuffer} input * @param {Object[]} args * @returns {byteArray} */ @@ -86,13 +86,13 @@ class ResizeImage extends Operation { "Bezier": jimp.RESIZE_BEZIER }; - if (!isImage(input)) { + if (!isImage(new Uint8Array(input))) { throw new OperationError("Invalid file type."); } let image; try { - image = await jimp.read(Buffer.from(input)); + image = await jimp.read(input); } catch (err) { throw new OperationError(`Error loading image. (${err})`); } @@ -116,7 +116,7 @@ class ResizeImage extends Operation { } else { imageBuffer = await image.getBufferAsync(jimp.AUTO); } - return [...imageBuffer]; + return imageBuffer.buffer; } catch (err) { throw new OperationError(`Error resizing image. (${err})`); } @@ -124,18 +124,19 @@ class ResizeImage extends Operation { /** * Displays the resized image using HTML for web apps - * @param {byteArray} data + * @param {ArrayBuffer} data * @returns {html} */ present(data) { - if (!data.length) return ""; + if (!data.byteLength) return ""; + const dataArray = new Uint8Array(data); - const type = isImage(data); + const type = isImage(dataArray); if (!type) { throw new OperationError("Invalid file type."); } - return ``; + return ``; } } diff --git a/src/core/operations/RotateImage.mjs b/src/core/operations/RotateImage.mjs index 16330c44..08e345f0 100644 --- a/src/core/operations/RotateImage.mjs +++ b/src/core/operations/RotateImage.mjs @@ -25,8 +25,8 @@ class RotateImage extends Operation { this.module = "Image"; this.description = "Rotates an image by the specified number of degrees."; this.infoURL = ""; - this.inputType = "byteArray"; - this.outputType = "byteArray"; + this.inputType = "ArrayBuffer"; + this.outputType = "ArrayBuffer"; this.presentType = "html"; this.args = [ { @@ -38,20 +38,20 @@ class RotateImage extends Operation { } /** - * @param {byteArray} input + * @param {ArrayBuffer} input * @param {Object[]} args * @returns {byteArray} */ async run(input, args) { const [degrees] = args; - if (!isImage(input)) { + if (!isImage(new Uint8Array(input))) { throw new OperationError("Invalid file type."); } let image; try { - image = await jimp.read(Buffer.from(input)); + image = await jimp.read(input); } catch (err) { throw new OperationError(`Error loading image. (${err})`); } @@ -66,7 +66,7 @@ class RotateImage extends Operation { } else { imageBuffer = await image.getBufferAsync(jimp.AUTO); } - return [...imageBuffer]; + return imageBuffer.buffer; } catch (err) { throw new OperationError(`Error rotating image. (${err})`); } @@ -74,18 +74,19 @@ class RotateImage extends Operation { /** * Displays the rotated image using HTML for web apps - * @param {byteArray} data + * @param {ArrayBuffer} data * @returns {html} */ present(data) { - if (!data.length) return ""; + if (!data.byteLength) return ""; + const dataArray = new Uint8Array(data); - const type = isImage(data); + const type = isImage(dataArray); if (!type) { throw new OperationError("Invalid file type."); } - return ``; + return ``; } } diff --git a/src/core/operations/SharpenImage.mjs b/src/core/operations/SharpenImage.mjs index de2f3603..d7a17357 100644 --- a/src/core/operations/SharpenImage.mjs +++ b/src/core/operations/SharpenImage.mjs @@ -26,8 +26,8 @@ class SharpenImage extends Operation { this.module = "Image"; this.description = "Sharpens an image (Unsharp mask)"; this.infoURL = "https://wikipedia.org/wiki/Unsharp_masking"; - this.inputType = "byteArray"; - this.outputType = "byteArray"; + this.inputType = "ArrayBuffer"; + this.outputType = "ArrayBuffer"; this.presentType = "html"; this.args = [ { @@ -54,20 +54,20 @@ class SharpenImage extends Operation { } /** - * @param {byteArray} input + * @param {ArrayBuffer} input * @param {Object[]} args * @returns {byteArray} */ async run(input, args) { const [radius, amount, threshold] = args; - if (!isImage(input)){ + if (!isImage(new Uint8Array(input))){ throw new OperationError("Invalid file type."); } let image; try { - image = await jimp.read(Buffer.from(input)); + image = await jimp.read(input); } catch (err) { throw new OperationError(`Error loading image. (${err})`); } @@ -140,7 +140,7 @@ class SharpenImage extends Operation { } else { imageBuffer = await image.getBufferAsync(jimp.AUTO); } - return [...imageBuffer]; + return imageBuffer.buffer; } catch (err) { throw new OperationError(`Error sharpening image. (${err})`); } @@ -148,18 +148,19 @@ class SharpenImage extends Operation { /** * Displays the sharpened image using HTML for web apps - * @param {byteArray} data + * @param {ArrayBuffer} data * @returns {html} */ present(data) { - if (!data.length) return ""; + if (!data.byteLength) return ""; + const dataArray = new Uint8Array(data); - const type = isImage(data); + const type = isImage(dataArray); if (!type) { - throw new OperationError("Invalid image type."); + throw new OperationError("Invalid file type."); } - return ``; + return ``; } } From 99bef09e0e4481ac5f5b2a737c02f31225271c46 Mon Sep 17 00:00:00 2001 From: j433866 Date: Mon, 1 Apr 2019 14:13:30 +0100 Subject: [PATCH 15/27] Fix invalid file type error --- src/core/operations/ParseQRCode.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/operations/ParseQRCode.mjs b/src/core/operations/ParseQRCode.mjs index 73ffec93..16b0be4d 100644 --- a/src/core/operations/ParseQRCode.mjs +++ b/src/core/operations/ParseQRCode.mjs @@ -51,7 +51,7 @@ class ParseQRCode extends Operation { async run(input, args) { const [normalise] = args; - if (!isImage(input)) { + if (!isImage(new Uint8Array(input))) { throw new OperationError("Invalid file type."); } return await parseQrCode(input, normalise); From 0bcf57e89c58bb0912819c562171bee0c2160be7 Mon Sep 17 00:00:00 2001 From: j433866 Date: Thu, 20 Jun 2019 12:58:02 +0100 Subject: [PATCH 16/27] Improve printing text to improve output quality. Now resizes the text instead of the image --- src/core/operations/AddTextToImage.mjs | 49 ++++++++++---------------- 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/src/core/operations/AddTextToImage.mjs b/src/core/operations/AddTextToImage.mjs index 99ea7bd0..97b2f799 100644 --- a/src/core/operations/AddTextToImage.mjs +++ b/src/core/operations/AddTextToImage.mjs @@ -23,7 +23,7 @@ class AddTextToImage extends Operation { this.name = "Add Text To Image"; this.module = "Image"; - this.description = "Adds text onto an image.

Text can be horizontally or vertically aligned, or the position can be manually specified.
Variants of the Roboto font face are available in any size or colour.

Note: This may cause a degradation in image quality, especially when using font sizes larger than 72."; + this.description = "Adds text onto an image.

Text can be horizontally or vertically aligned, or the position can be manually specified.
Variants of the Roboto font face are available in any size or colour."; this.infoURL = ""; this.inputType = "ArrayBuffer"; this.outputType = "ArrayBuffer"; @@ -152,14 +152,12 @@ class AddTextToImage extends Operation { // Make Webpack load the png font images - const fontImages = [ + await Promise.all([ import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/Roboto72White.png"), import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoSlab72White.png"), import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoMono72White.png"), import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoBlack72White.png") - ]; - - await Promise.all(fontImages); + ]); const font = fontsMap[fontFace]; @@ -190,14 +188,18 @@ class AddTextToImage extends Operation { } }); - // Scale the image to a factor of 72, so we can print the text at any size - const scaleFactor = 72 / size; - if (size !== 72) { + // Create a temporary image to hold the rendered text + const textImage = new jimp(jimp.measureText(jimpFont, text), jimp.measureTextHeight(jimpFont, text)); + textImage.print(jimpFont, 0, 0, text); + + // Scale the rendered text image to the correct size + const scaleFactor = size / 72; + if (size !== 1) { // Use bicubic for decreasing size - if (size > 72) { - image.scale(scaleFactor, jimp.RESIZE_BICUBIC); + if (size > 1) { + textImage.scale(scaleFactor, jimp.RESIZE_BICUBIC); } else { - image.scale(scaleFactor, jimp.RESIZE_BILINEAR); + textImage.scale(scaleFactor, jimp.RESIZE_BILINEAR); } } @@ -207,14 +209,11 @@ class AddTextToImage extends Operation { xPos = 0; break; case "Center": - xPos = (image.getWidth() / 2) - (jimp.measureText(jimpFont, text) / 2); + xPos = (image.getWidth() / 2) - (textImage.getWidth() / 2); break; case "Right": - xPos = image.getWidth() - jimp.measureText(jimpFont, text); + xPos = image.getWidth() - textImage.getWidth(); break; - default: - // Adjust x position for the scaled image - xPos = xPos * scaleFactor; } switch (vAlign) { @@ -222,25 +221,15 @@ class AddTextToImage extends Operation { yPos = 0; break; case "Middle": - yPos = (image.getHeight() / 2) - (jimp.measureTextHeight(jimpFont, text) / 2); + yPos = (image.getHeight() / 2) - (textImage.getHeight() / 2); break; case "Bottom": - yPos = image.getHeight() - jimp.measureTextHeight(jimpFont, text); + yPos = image.getHeight() - textImage.getHeight(); break; - default: - // Adjust y position for the scaled image - yPos = yPos * scaleFactor; } - image.print(jimpFont, xPos, yPos, text); - - if (size !== 72) { - if (size > 72) { - image.scale(1 / scaleFactor, jimp.RESIZE_BILINEAR); - } else { - image.scale(1 / scaleFactor, jimp.RESIZE_BICUBIC); - } - } + // Blit the rendered text image onto the original source image + image.blit(textImage, xPos, yPos); let imageBuffer; if (image.getMIME() === "image/gif") { From 4c27a46d35cad12a1827ee7031efa045a9039403 Mon Sep 17 00:00:00 2001 From: Matt Date: Thu, 27 Jun 2019 16:48:03 +0100 Subject: [PATCH 17/27] Added PGP verify operation Added some more metadata to decrypt & verify Fixes gchq/CyberChef#581 --- src/core/operations/PGPDecryptAndVerify.mjs | 5 +- src/core/operations/PGPVerify.mjs | 111 ++++++++++++++++++++ 2 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 src/core/operations/PGPVerify.mjs diff --git a/src/core/operations/PGPDecryptAndVerify.mjs b/src/core/operations/PGPDecryptAndVerify.mjs index 58c61c25..fabda3ee 100644 --- a/src/core/operations/PGPDecryptAndVerify.mjs +++ b/src/core/operations/PGPDecryptAndVerify.mjs @@ -93,7 +93,7 @@ class PGPDecryptAndVerify extends Operation { text += `${signer.username} `; } if (signer.comment) { - text += `${signer.comment} `; + text += `(${signer.comment}) `; } if (signer.email) { text += `<${signer.email}>`; @@ -102,7 +102,8 @@ class PGPDecryptAndVerify extends Operation { } text += [ `PGP fingerprint: ${km.get_pgp_fingerprint().toString("hex")}`, - `Signed on ${new Date(ds.sig.hashed_subpackets[0].time * 1000).toUTCString()}`, + `PGP key ID: ${km.get_pgp_short_key_id()}`, + `Signed on ${new Date(ds.sig.when_generated() * 1000).toUTCString()}`, "----------------------------------\n" ].join("\n"); text += unboxedLiterals.toString(); diff --git a/src/core/operations/PGPVerify.mjs b/src/core/operations/PGPVerify.mjs new file mode 100644 index 00000000..6f42ced8 --- /dev/null +++ b/src/core/operations/PGPVerify.mjs @@ -0,0 +1,111 @@ +/** + * @author Matt C [me@mitt.dev] + * @copyright Crown Copyright 2019 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; +import OperationError from "../errors/OperationError"; + +import kbpgp from "kbpgp"; +import { ASP, importPublicKey } from "../lib/PGP"; +import * as es6promisify from "es6-promisify"; +const promisify = es6promisify.default ? es6promisify.default.promisify : es6promisify.promisify; + +/** + * PGP Verify operation + */ +class PGPVerify extends Operation { + + /** + * PGPVerify constructor + */ + constructor() { + super(); + + this.name = "PGP Verify"; + this.module = "PGP"; + this.description = [ + "Input: the ASCII-armoured encrypted PGP message you want to verify.", + "

", + "Argument: the ASCII-armoured PGP public key of the signer", + "

", + "This operation uses PGP to decrypt a clearsigned message.", + "

", + "Pretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.", + "

", + "This function uses the Keybase implementation of PGP.", + ].join("\n"); + this.infoURL = "https://wikipedia.org/wiki/Pretty_Good_Privacy"; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Public key of signer", + "type": "text", + "value": "" + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + async run(input, args) { + const signedMessage = input, + [publicKey] = args, + keyring = new kbpgp.keyring.KeyRing(); + let unboxedLiterals; + + if (!publicKey) throw new OperationError("Enter the public key of the signer."); + const pubKey = await importPublicKey(publicKey); + keyring.add_key_manager(pubKey); + + try { + unboxedLiterals = await promisify(kbpgp.unbox)({ + armored: signedMessage, + keyfetch: keyring, + asp: ASP + }); + const ds = unboxedLiterals[0].get_data_signer(); + if (ds) { + const km = ds.get_key_manager(); + if (km) { + const signer = km.get_userids_mark_primary()[0].components; + let text = "Signed by "; + if (signer.email || signer.username || signer.comment) { + if (signer.username) { + text += `${signer.username} `; + } + if (signer.comment) { + text += `(${signer.comment}) `; + } + if (signer.email) { + text += `<${signer.email}>`; + } + text += "\n"; + } + text += [ + `PGP fingerprint: ${km.get_pgp_fingerprint().toString("hex")}`, + `PGP key ID: ${km.get_pgp_short_key_id()}`, + `Signed on ${new Date(ds.sig.when_generated() * 1000).toUTCString()}`, + "----------------------------------\n" + ].join("\n"); + text += unboxedLiterals.toString(); + return text.trim(); + } else { + throw new OperationError("Could not identify a key manager."); + } + } else { + throw new OperationError("The data does not appear to be signed."); + } + } catch (err) { + throw new OperationError(`Couldn't verify message: ${err}`); + } + } + +} + +export default PGPVerify; From c46928aefe7b4070d0bc673308176c305c28533c Mon Sep 17 00:00:00 2001 From: Matt Date: Thu, 27 Jun 2019 17:30:44 +0100 Subject: [PATCH 18/27] Added tests --- src/core/operations/PGPDecryptAndVerify.mjs | 2 +- src/core/operations/PGPVerify.mjs | 2 +- tests/operations/tests/PGP.mjs | 29 ++++++++++++++++++++- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/core/operations/PGPDecryptAndVerify.mjs b/src/core/operations/PGPDecryptAndVerify.mjs index fabda3ee..21612a0f 100644 --- a/src/core/operations/PGPDecryptAndVerify.mjs +++ b/src/core/operations/PGPDecryptAndVerify.mjs @@ -101,8 +101,8 @@ class PGPDecryptAndVerify extends Operation { text += "\n"; } text += [ - `PGP fingerprint: ${km.get_pgp_fingerprint().toString("hex")}`, `PGP key ID: ${km.get_pgp_short_key_id()}`, + `PGP fingerprint: ${km.get_pgp_fingerprint().toString("hex")}`, `Signed on ${new Date(ds.sig.when_generated() * 1000).toUTCString()}`, "----------------------------------\n" ].join("\n"); diff --git a/src/core/operations/PGPVerify.mjs b/src/core/operations/PGPVerify.mjs index 6f42ced8..ad1173b1 100644 --- a/src/core/operations/PGPVerify.mjs +++ b/src/core/operations/PGPVerify.mjs @@ -88,8 +88,8 @@ class PGPVerify extends Operation { text += "\n"; } text += [ - `PGP fingerprint: ${km.get_pgp_fingerprint().toString("hex")}`, `PGP key ID: ${km.get_pgp_short_key_id()}`, + `PGP fingerprint: ${km.get_pgp_fingerprint().toString("hex")}`, `Signed on ${new Date(ds.sig.when_generated() * 1000).toUTCString()}`, "----------------------------------\n" ].join("\n"); diff --git a/tests/operations/tests/PGP.mjs b/tests/operations/tests/PGP.mjs index baf76fb8..8449add4 100644 --- a/tests/operations/tests/PGP.mjs +++ b/tests/operations/tests/PGP.mjs @@ -248,7 +248,8 @@ IOE1W/Zqmqzq+4frwnzWwYv9/U1RwIs/qlFVnzliREOzW+om8EncSSd7fQ== =fEAT -----END PGP MESSAGE----- `, - expectedOutput: `Signed by PGP fingerprint: e94e06dd0b3744a0e970de9d84246548df98e485 + expectedOutput: `Signed by PGP key ID: DF98E485 +PGP fingerprint: e94e06dd0b3744a0e970de9d84246548df98e485 Signed on Tue, 29 May 2018 15:44:52 GMT ---------------------------------- ${UTF8_TEXT}`, @@ -282,4 +283,30 @@ H2qMY1O7hezH3fp+EZzCAccJMtK7VPk13WAgMRH22HirG4aK1i75IVOtjBgObzDh } ] }, + { + name: "PGP Verify: ASCII, Alice", + input: `-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA256 + +A common mistake that people make when trying to design something completely foolproof is to underestimate the ingenuity of complete fools. +-----BEGIN PGP SIGNATURE----- + +iLMEAQEIAB0WIQRLbJy6MLpYOr9qojE+2VNAUiMLOgUCXRTsvwAKCRA+2VNAUiML +OuaHBADMMNtsuN92Fb+UrDimsv6TDQpbJhDkwp9kZdKYP5HAmSYAhXBG7N+YCMw+ +v2FSpUu9jJiPBm1K1SEwLufQVexoRv6RsBNolRFB07sArau0s0DnIXUchCZWvyTP +1KsjBnDr84U2b11H58g4DlTT4gQrz30rFuHz9AGmPAtDHbSXIA== +=vnk/ +-----END PGP SIGNATURE-----`, + expectedOutput: `Signed by PGP key ID: DF98E485 +PGP fingerprint: e94e06dd0b3744a0e970de9d84246548df98e485 +Signed on Thu, 27 Jun 2019 16:20:15 GMT +---------------------------------- +A common mistake that people make when trying to design something completely foolproof is to underestimate the ingenuity of complete fools.`, + recipeConfig: [ + { + "op": "PGP Verify", + "args": [ALICE_PUBLIC] + } + ] + } ]); From be08a62f5246c80ec4b554dac13c8baddb233e53 Mon Sep 17 00:00:00 2001 From: j433866 Date: Tue, 2 Jul 2019 15:31:29 +0100 Subject: [PATCH 19/27] Add webpack config for font files --- src/web/static/fonts/bmfonts/Roboto72White.fnt | 2 +- src/web/static/fonts/bmfonts/RobotoBlack72White.fnt | 2 +- src/web/static/fonts/bmfonts/RobotoMono72White.fnt | 2 +- src/web/static/fonts/bmfonts/RobotoSlab72White.fnt | 2 +- webpack.config.js | 12 ++++++++++-- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/web/static/fonts/bmfonts/Roboto72White.fnt b/src/web/static/fonts/bmfonts/Roboto72White.fnt index fd186892..57238158 100644 --- a/src/web/static/fonts/bmfonts/Roboto72White.fnt +++ b/src/web/static/fonts/bmfonts/Roboto72White.fnt @@ -1,6 +1,6 @@ info face="Roboto" size=72 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=1,1,1,1 spacing=-2,-2 common lineHeight=85 base=67 scaleW=512 scaleH=512 pages=1 packed=0 -page id=0 file="images/Roboto72White.png" +page id=0 file="Roboto72White.png" chars count=98 char id=0 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=66 xadvance=0 page=0 chnl=0 char id=10 x=0 y=0 width=70 height=99 xoffset=2 yoffset=-11 xadvance=74 page=0 chnl=0 diff --git a/src/web/static/fonts/bmfonts/RobotoBlack72White.fnt b/src/web/static/fonts/bmfonts/RobotoBlack72White.fnt index 3d08fe95..d82c9c7b 100644 --- a/src/web/static/fonts/bmfonts/RobotoBlack72White.fnt +++ b/src/web/static/fonts/bmfonts/RobotoBlack72White.fnt @@ -1,6 +1,6 @@ info face="Roboto Black" size=72 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=1,1,1,1 spacing=-2,-2 common lineHeight=85 base=67 scaleW=512 scaleH=512 pages=1 packed=0 -page id=0 file="images/RobotoBlack72White.png" +page id=0 file="RobotoBlack72White.png" chars count=98 char id=0 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=66 xadvance=0 page=0 chnl=0 char id=10 x=0 y=0 width=70 height=99 xoffset=2 yoffset=-11 xadvance=74 page=0 chnl=0 diff --git a/src/web/static/fonts/bmfonts/RobotoMono72White.fnt b/src/web/static/fonts/bmfonts/RobotoMono72White.fnt index f280314d..b9be89b4 100644 --- a/src/web/static/fonts/bmfonts/RobotoMono72White.fnt +++ b/src/web/static/fonts/bmfonts/RobotoMono72White.fnt @@ -1,6 +1,6 @@ info face="Roboto Mono" size=72 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=1,1,1,1 spacing=-2,-2 common lineHeight=96 base=76 scaleW=512 scaleH=512 pages=1 packed=0 -page id=0 file="images/RobotoMono72White.png" +page id=0 file="RobotoMono72White.png" chars count=98 char id=0 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=75 xadvance=0 page=0 chnl=0 char id=10 x=0 y=0 width=45 height=99 xoffset=-1 yoffset=-2 xadvance=43 page=0 chnl=0 diff --git a/src/web/static/fonts/bmfonts/RobotoSlab72White.fnt b/src/web/static/fonts/bmfonts/RobotoSlab72White.fnt index 71e1b131..f1926d5c 100644 --- a/src/web/static/fonts/bmfonts/RobotoSlab72White.fnt +++ b/src/web/static/fonts/bmfonts/RobotoSlab72White.fnt @@ -1,6 +1,6 @@ info face="Roboto Slab Regular" size=72 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=1,1,1,1 spacing=-2,-2 common lineHeight=96 base=76 scaleW=512 scaleH=512 pages=1 packed=0 -page id=0 file="images/RobotoSlab72White.png" +page id=0 file="RobotoSlab72White.png" chars count=98 char id=0 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=75 xadvance=0 page=0 chnl=0 char id=10 x=0 y=0 width=70 height=98 xoffset=0 yoffset=-1 xadvance=70 page=0 chnl=0 diff --git a/webpack.config.js b/webpack.config.js index b811f2d1..c80a2b65 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -104,7 +104,7 @@ module.exports = { ] }, { - test: /\.(ico|eot|ttf|woff|woff2|fnt)$/, + test: /\.(ico|eot|ttf|woff|woff2)$/, loader: "url-loader", options: { limit: 10000, @@ -119,9 +119,17 @@ module.exports = { encoding: "base64" } }, + { // Store font .fnt and .png files in a separate fonts folder + test: /(\.fnt$|bmfonts\/.+\.png$)/, + loader: "file-loader", + options: { + name: "[name].[ext]", + outputPath: "assets/fonts" + } + }, { // First party images are saved as files to be cached test: /\.(png|jpg|gif)$/, - exclude: /node_modules/, + exclude: /(node_modules|bmfonts)/, loader: "file-loader", options: { name: "images/[name].[ext]" From 1135ca5fb4de6833befce1d52d9483d2b4fa91f2 Mon Sep 17 00:00:00 2001 From: j433866 Date: Tue, 2 Jul 2019 16:31:26 +0100 Subject: [PATCH 20/27] Remove duplicate function. Fix reading QR codes with transparent backgrounds --- src/core/Utils.mjs | 16 ---------------- src/core/lib/QRCode.mjs | 2 ++ 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/src/core/Utils.mjs b/src/core/Utils.mjs index 6499e936..fed67553 100755 --- a/src/core/Utils.mjs +++ b/src/core/Utils.mjs @@ -594,22 +594,6 @@ class Utils { } - /** - * Converts a string to an ArrayBuffer. - * - * @param {string} string - */ - static strToArrayBuffer(string) { - const arrayBuffer = new ArrayBuffer(string.length * 2); - const arrayBufferView = new Uint8Array(arrayBuffer); - for (let i = 0; i < string.length; i++) { - arrayBufferView[i] = string.charCodeAt(i); - } - - return arrayBuffer; - } - - /** * Parses CSV data and returns it as a two dimensional array or strings. * diff --git a/src/core/lib/QRCode.mjs b/src/core/lib/QRCode.mjs index 709aafa2..93b60024 100644 --- a/src/core/lib/QRCode.mjs +++ b/src/core/lib/QRCode.mjs @@ -33,6 +33,8 @@ export async function parseQrCode(input, normalise) { image.background(0xFFFFFFFF); image.normalize(); image.greyscale(); + image = await image.getBufferAsync(jimp.MIME_JPEG); + image = await jimp.read(image); } } catch (err) { throw new OperationError(`Error normalising iamge. (${err})`); From 5abc5279f515d51ba012ae8594869cde1b53c003 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Tue, 2 Jul 2019 18:39:21 +0100 Subject: [PATCH 21/27] Fixed spread operator support in older browsers --- babel.config.js | 6 ------ src/web/index.js | 2 +- webpack.config.js | 2 +- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/babel.config.js b/babel.config.js index f2f9c502..cb37b2c7 100644 --- a/babel.config.js +++ b/babel.config.js @@ -4,12 +4,6 @@ module.exports = function(api) { return { "presets": [ ["@babel/preset-env", { - "targets": { - "chrome": 40, - "firefox": 35, - "edge": 14, - "node": "6.5" - }, "modules": false, "useBuiltIns": "entry", "corejs": 3 diff --git a/src/web/index.js b/src/web/index.js index cbf7bccc..4f34e2c2 100755 --- a/src/web/index.js +++ b/src/web/index.js @@ -10,7 +10,7 @@ import "./stylesheets/index.js"; // Libs import "arrive"; import "snackbarjs"; -import "bootstrap-material-design"; +import "bootstrap-material-design/js/index"; import "bootstrap-colorpicker"; import moment from "moment-timezone"; import * as CanvasComponents from "../core/lib/CanvasComponents"; diff --git a/webpack.config.js b/webpack.config.js index effc70ba..ae385b97 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -60,7 +60,7 @@ module.exports = { rules: [ { test: /\.m?js$/, - exclude: /node_modules\/(?!jsesc|crypto-api)/, + exclude: /node_modules\/(?!jsesc|crypto-api|bootstrap)/, options: { configFile: path.resolve(__dirname, "babel.config.js"), cacheDirectory: true, From 6726994ad50a80feeba81eddd3c51a1c2c78fa01 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Tue, 2 Jul 2019 18:40:03 +0100 Subject: [PATCH 22/27] 8.34.3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index a5fb311e..7db91304 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "cyberchef", - "version": "8.34.2", + "version": "8.34.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 765b0cfb..81b9aadb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cyberchef", - "version": "8.34.2", + "version": "8.34.3", "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.", "author": "n1474335 ", "homepage": "https://gchq.github.io/CyberChef", From bed66298d13ed90dcbb9fcf4d85a3a8db7e9814a Mon Sep 17 00:00:00 2001 From: j433866 Date: Wed, 3 Jul 2019 08:53:44 +0100 Subject: [PATCH 23/27] Change jpeg test data to be a full image --- tests/operations/tests/Magic.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/operations/tests/Magic.mjs b/tests/operations/tests/Magic.mjs index b7fd5ca3..8247c376 100644 --- a/tests/operations/tests/Magic.mjs +++ b/tests/operations/tests/Magic.mjs @@ -34,7 +34,7 @@ TestRegister.addTests([ }, { name: "Magic: jpeg", - input: "\xFF\xD8\xFF", + input: "\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49\x46\x00\x01\x01\x01\x00\x48\x00\x48\x00\x00\xff\xdb\x00\x43\x00\x03\x02\x02\x03\x02\x02\x03\x03\x03\x03\x04\x03\x03\x04\x05\x08\x05\x05\x04\x04\x05\x0a\x07\x07\x06\x08\x0c\x0a\x0c\x0c\x0b\x0a\x0b\x0b\x0d\x0e\x12\x10\x0d\x0e\x11\x0e\x0b\x0b\x10\x16\x10\x11\x13\x14\x15\x15\x15\x0c\x0f\x17\x18\x16\x14\x18\x12\x14\x15\x14\xff\xdb\x00\x43\x01\x03\x04\x04\x05\x04\x05\x09\x05\x05\x09\x14\x0d\x0b\x0d\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\xff\xc2\x00\x11\x08\x00\x32\x00\x32\x03\x01\x11\x00\x02\x11\x01\x03\x11\x01\xff\xc4\x00\x1c\x00\x00\x02\x02\x03\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x07\x04\x05\x00\x02\x03\x01\x08\xff\xc4\x00\x1a\x01\x00\x03\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x05\x06\x03\x02\x01\x07\xff\xda\x00\x0c\x03\x01\x00\x02\x10\x03\x10\x00\x00\x01\xe7\x14\xd4\x6e\x92\x6e\xe0\x67\xd3\x01\x2e\xe2\x61\x94\xcc\xb8\xa2\x6a\x9e\xa0\x8a\x71\xfa\xde\xdc\x52\xd3\xd5\x89\x16\xe1\xbd\x57\x6b\x4c\xc9\xc9\x02\xad\xcd\x3f\x3d\xe3\x0e\xfc\xcd\x61\x95\xe9\x08\xa8\x74\x05\x4e\xc3\x14\x07\x5d\x62\xc5\x22\x57\xb8\x0f\xbd\x49\xd9\x50\xd2\x6b\x46\x3c\xe3\x8f\xa1\xd5\x83\x2d\x27\xa5\xbd\xf3\x24\x99\x82\x11\xf5\xd5\xf3\xf0\x05\x8f\x34\xbc\x16\xa5\x83\x00\x74\xaa\x86\x66\xb4\x8e\xf2\x89\x13\x88\xd9\xe2\x16\x56\xe5\xb3\x4a\x8c\xc9\xc9\x61\xa1\x95\xa5\x1d\x7e\xb8\xa8\x67\x65\xf3\xbd\xa4\xa7\xff\xc4\x00\x21\x10\x00\x02\x03\x00\x02\x02\x02\x03\x00\x00\x00\x00\x00\x00\x00\x00\x03\x04\x01\x02\x05\x00\x06\x11\x12\x13\x14\x16\x21\x24\xff\xda\x00\x08\x01\x01\x00\x01\x05\x02\xd9\xa5\x49\x5a\x1d\x6a\x39\xf8\xfa\xd5\x03\x98\xe6\x61\x44\x16\xa2\xc9\x82\xb4\xbc\x97\xae\x9e\xe4\x63\xec\x33\xd6\x24\x4b\x29\xa4\x98\xad\x5c\x4a\x68\xae\x4e\x5e\x41\x3c\x3f\xc8\x20\x0c\x4b\xc8\xd4\x42\x34\xb8\x7c\x2f\x3a\xd1\xea\x3a\x36\x19\xf4\x4d\x42\xd9\x41\xe9\x02\xc5\x8d\xbc\xd1\x45\xeb\xf5\x12\xcc\xb3\x9b\xc0\x8b\x17\x23\x99\x8e\xad\x9a\x67\xb7\x46\x65\x35\xd6\xa5\x9c\x81\xf8\x8b\x5e\x9f\x2e\x83\x4c\x35\xcd\xb3\x83\x45\x1c\xe1\xd9\x85\x35\xf3\x1c\xd2\x73\xad\x3a\x1a\xbd\x67\x87\xed\x89\x96\x96\x79\xb6\x11\x45\x9c\x9e\xb3\x03\x9d\x0c\x77\x06\xf2\xb8\x9b\x9f\x0b\x5a\x42\xaa\x4b\x58\xa4\xf6\x14\x45\xf4\x3b\x1d\x2a\x4c\x6c\xe5\x82\xba\x7d\x8f\xf9\x91\xcf\xa5\x46\xa6\xbf\xeb\x12\x0d\x7f\x1f\xff\xc4\x00\x2f\x11\x00\x01\x04\x01\x02\x03\x06\x04\x07\x00\x00\x00\x00\x00\x00\x00\x01\x00\x02\x03\x04\x11\x12\x31\x05\x13\x21\x14\x22\x41\x51\xa1\xf0\x32\x42\x71\x81\x23\x24\x52\x53\x61\x91\xf1\xff\xda\x00\x08\x01\x03\x01\x01\x3f\x01\xbf\x0e\x98\xc3\xc0\xfb\xa1\x19\x71\xca\xa8\x5b\x5d\xed\x73\xd3\x38\xe3\x98\xf7\x35\xad\x1a\x73\xfc\xa7\xcf\xda\x7b\xce\xf1\x4d\xb0\x21\x69\x0d\x0b\x4b\xcf\xce\x54\x5f\x98\xac\x1b\x28\xdf\x1f\xd6\x56\x98\x23\x9a\x37\x39\xbd\x4e\xde\xfd\x17\x16\xae\xd7\x5a\xdf\xa1\xea\x9d\x0c\x6d\x6e\x85\x2b\x66\x2d\x0d\x8c\x74\x5c\x2a\x06\x13\x87\x0c\xe1\x3d\xa0\x38\x85\x74\x4d\x5a\x00\xe8\xc6\xdf\x4f\xa2\xb1\x62\x6b\x04\x03\xd7\xc9\x43\x34\x92\x3f\x4b\xdd\x9c\xa6\x70\xfa\xad\xf9\x7b\xde\x6a\xd5\xc8\xe0\x7e\x83\xb8\x50\xdb\x9f\x99\xad\x87\x01\x3a\xce\xb7\x17\x13\xba\x3a\x2d\xf0\xf1\x8d\xb4\xfa\xff\x00\xaa\x0a\xd6\x2a\x1e\x7e\x94\x6a\x56\xbc\xe6\xcf\x19\xeb\xef\xd5\x5d\x12\x4b\x16\x23\x2a\xd5\x52\x23\x2e\x27\x38\x5c\x3e\x28\xa5\x92\x31\x27\xc3\xe2\xb1\x18\xe8\x1a\x14\x1c\x4a\x0a\xf0\xb7\x4e\xe0\x6c\xac\xf1\x37\xd8\xee\xe3\xba\x9c\x49\x87\x9b\x0e\xe3\x65\xda\x6c\xb2\x42\xf2\xed\xf7\x54\xa4\x80\xc4\xd9\x2c\x63\x27\xcf\x65\xc4\xed\x40\xf7\x35\x91\xbb\xa8\x59\x72\xbf\x15\x53\x8e\x46\xfe\xfe\xcb\x46\x32\x15\x2c\xb4\x38\x65\x5c\x8f\x97\x28\x78\xf1\xea\xa4\xa3\xda\x86\xac\xe1\x4b\xc3\xa1\x90\x08\x88\xc1\xf3\x43\x81\xd2\xfd\xc3\xe8\x9d\xf1\x39\x40\x01\x99\x80\xf9\x85\x60\x72\xec\x38\x33\xa7\x54\xd3\xf8\x79\x55\x09\x70\x76\xa5\x6f\x67\x95\xce\x93\xf5\x15\xff\xc4\x00\x2f\x11\x00\x01\x03\x02\x03\x06\x05\x03\x05\x00\x00\x00\x00\x00\x00\x00\x01\x00\x02\x03\x04\x21\x11\x13\x31\x05\x12\x22\x41\x51\x61\x71\xa1\xb1\xc1\xf0\x23\x32\xd1\x33\x81\x91\xe1\xf1\xff\xda\x00\x08\x01\x02\x01\x01\x3f\x01\xd9\x04\xef\x90\x2c\x3d\x4e\x1e\xca\xb2\x67\xc2\xc0\x19\x70\xa4\x95\xc6\x1e\x23\x74\xd9\xef\x8b\xee\x70\xbe\x9a\x76\xfc\x2a\x9a\x82\xe9\x4e\x04\x80\xb3\x09\xb3\x8e\x3e\x3e\x48\x6d\x9d\xdb\x64\xb7\xf8\x51\xc2\xd8\x2b\xfe\x96\x83\x1f\x45\x0b\xf8\xae\xab\x33\x62\x95\xed\x6d\xef\xeb\xa7\x9d\x94\x59\xd2\xcb\x8b\xec\x42\x73\x23\x67\x2f\x9c\x96\xc9\xa5\x8a\x79\x1c\x65\x18\xf0\xd9\x09\x48\x18\x0f\x45\x43\x4d\x9b\x2b\xa4\x71\xd7\x45\x2e\xfc\x2e\x31\xcc\x6c\x54\xad\x8a\x30\x66\x2d\xd1\x06\xc4\x00\x99\xfa\x15\x56\x59\x39\x73\xe0\x1c\x3e\xea\x16\xcf\x01\xce\x88\x1b\xe9\xd1\x3f\x67\x4a\xf7\x17\x11\xaa\x86\x4d\xe3\xbc\x3a\xa9\xaa\x29\x6a\x1c\x23\x79\xfd\xd5\x7d\x29\x7c\x6e\x11\x1c\x07\x44\xfa\x82\xfd\xd1\x26\x16\xeb\xa2\x64\x9c\x43\x28\x6e\xe2\xa1\x9c\xc4\xe9\x1b\x25\xc0\xbf\x6d\x7c\xb5\x42\x68\xb0\xfb\xbd\x11\x95\xad\xa7\xc8\xe6\xa9\xa9\x44\xd8\x1c\x78\x8f\x92\xa7\x7e\x55\x66\x4c\xda\x1d\x7a\x76\xf9\xe2\xa4\xa3\x8a\x46\x6e\x39\xbf\x31\x54\xf1\x06\xcd\x23\x59\x89\x23\x9f\x8f\xf7\x8e\x2a\xbd\x8d\x8f\x8d\xd6\xd2\xc8\xe4\x63\xa9\x55\x55\x70\xc8\x04\xad\x07\xba\xa6\xaa\x19\x8d\x7b\x6c\xb6\xa3\x9b\x23\x98\xe0\xdf\x9e\xfa\xaa\x08\xc1\xa7\x11\xbd\x45\x3c\x9b\x29\xfb\xae\x18\xa3\x2b\xaa\x5f\xbe\xe3\xa9\xd3\xb7\xfa\x8e\xcd\x18\xd9\x3b\x90\xef\xf9\x54\xc4\x87\x38\x8e\x40\xa9\x1e\xf7\x81\xbc\x71\xb7\xb2\xd9\xd2\xbc\xd8\xb9\x48\xf7\x1a\x9b\x9e\xbe\xaa\x8f\xf5\x23\xf1\xf7\x47\x55\xff\xc4\x00\x2f\x10\x00\x02\x01\x03\x02\x03\x07\x02\x07\x01\x00\x00\x00\x00\x00\x00\x01\x02\x03\x00\x04\x11\x12\x21\x13\x22\x31\x23\x32\x41\x51\x61\x71\x91\x33\xf0\x05\x15\x42\x52\x72\x81\xb1\xa1\xff\xda\x00\x08\x01\x01\x00\x06\x3f\x02\x4d\x71\xf2\xc8\x74\x97\x23\x97\xd0\x1f\x9a\x4b\x62\x0e\x95\x50\x4c\x63\x65\xd2\x69\xa5\xe0\x17\x94\x12\xe3\x9b\x53\x1f\x21\x4b\x24\x7a\x56\xed\x54\x1d\x12\xf4\xff\x00\x95\x1c\x57\x3c\x27\x98\x13\x92\x17\x6c\xe6\x99\x63\x0a\x90\xb0\xea\xa3\x07\x39\xde\x9d\xbf\x36\xbb\x19\x39\xc6\x05\x42\x67\x71\x3c\x93\x91\xac\x28\xdb\x3a\xaa\x07\xe1\x2c\x4c\xd9\x8f\x5f\x4e\xa3\x1b\x8a\x33\x63\xe8\xe7\x58\xf4\xf3\xf8\xa8\x73\x20\x3a\xfa\x11\xb8\xac\xb3\xa9\x45\xc9\x5e\x7d\xab\x07\x94\xe0\xb0\x22\x97\x55\xc2\x83\x8d\xc6\xa1\x56\xb6\x82\xec\xdb\x88\x70\x57\x4c\x7f\x53\x02\xb8\xd7\x40\xf6\x03\x66\x3d\xd6\xf5\xac\x22\x95\x4e\xb8\x5e\x95\xa9\x53\x97\x57\xd3\x45\xf5\xa6\x78\xad\x9c\xc5\xfb\x54\xe9\xfe\xfd\x29\xa0\x96\xe9\x4d\xc4\x6b\xd3\xc4\x7b\xd0\x4f\xdb\xb6\xf4\x62\x90\x88\xe5\x83\x1d\x5b\x1c\xc3\xd6\x83\x7e\x22\xdc\x18\x50\x03\x11\x55\xc3\xb1\xf3\x7f\xb1\x53\x76\x41\xb3\xe6\xdd\x3c\x32\x2a\x49\xa6\xb7\x6b\xce\x1a\xe1\x44\x60\x64\x93\xef\x5d\x94\x26\xd2\x72\x46\x1c\x91\x81\xbf\xd8\xa5\x62\x07\x1e\xe0\xe0\xe8\x18\xd7\x81\x9a\xe8\xc3\xd3\x02\x96\x6e\x49\x84\x8e\x18\x37\x9f\xf7\x49\xca\xca\x9a\x87\x67\xe0\x7d\xea\xde\xe4\x8d\x06\x16\xd5\x86\x3d\xdf\x03\x51\x49\x12\x34\x90\xe7\x02\x42\xa7\x07\xcf\x7a\x71\x15\xbb\x5c\x5a\xa0\x05\x94\x0c\x8c\xef\xb9\xfb\xf0\xa2\xef\x6c\xd2\x28\xe5\x17\x19\xc2\xc4\xd8\xe9\x83\xd7\x3b\x6e\x28\xf6\xac\x3d\xa8\x8b\xbb\x6e\xcc\x6e\x22\xea\x99\xf3\xa7\x9a\x2b\x45\x8d\x8a\xe5\x4a\xae\x9c\x7c\x55\xd6\x26\x26\x44\x8b\x05\x41\xca\x82\x4f\xfb\xb0\xa9\x97\xaa\x89\x0c\x40\x8d\xb4\x8f\xbc\xd4\xb1\xc2\x99\xfd\x32\x06\x3f\x18\xab\xbb\x9b\x7d\x1c\x69\x4e\xa7\x8c\xf7\x4e\xfb\xd1\xc4\x7b\x7b\x1a\x80\x1d\xc7\x1b\xa1\xfe\x55\x74\xac\x03\x29\x2a\x30\x7f\x98\xa6\x68\xa2\x48\xd8\xb9\xc9\x45\xc7\xeb\xa9\x38\x5d\x96\x48\xee\x6d\xe1\x50\xba\xa8\x57\x6d\x1a\x98\x0d\xcf\x66\xb5\x70\x06\xc3\x82\xdf\xe5\x77\xdb\xe6\xbf\xff\xc4\x00\x22\x10\x01\x00\x02\x02\x02\x03\x00\x03\x01\x01\x00\x00\x00\x00\x00\x00\x01\x11\x21\x00\x31\x41\x51\x61\x71\x81\x91\xa1\xb1\xc1\xf0\xff\xda\x00\x08\x01\x01\x00\x01\x3f\x21\x10\x32\xcf\xff\x00\x55\x6d\x07\xd7\x39\x55\x4c\x4f\x10\x53\x39\x7d\x17\x25\x21\xb4\x98\xf1\x0e\xb7\xde\x3e\x30\xd6\x2b\xcd\xeb\x1f\x75\x91\x1d\x35\x56\x4e\xce\x9c\x8a\x38\xb5\xaa\x29\xa9\xa2\xf0\x19\x37\xe0\xef\x5a\xc4\x09\x6c\x1f\x40\xf9\x13\xf7\x26\x8e\x52\xf0\x50\x51\xb9\x8b\xc0\xb0\x23\xe9\x2f\xda\xdc\x6f\x1d\x93\x08\x40\xa5\xdc\xf5\x94\xb2\x20\x4b\x48\xee\x3b\xc1\x3a\x59\x1a\x13\x5c\xfa\xe3\x1c\xd5\x99\x0a\x1c\x9a\xc2\xb0\x09\x24\xdd\x77\xee\x30\x2c\xeb\x99\x13\x50\x0e\x89\xdc\x34\x67\x1f\x94\xb8\xf6\x4e\xb2\x5e\x0d\x8c\x21\xf0\x0f\xb5\x8e\x6c\xa2\x01\x86\x9e\xd8\x24\xc4\x93\x28\xd0\xa3\x9a\x7f\x78\x4d\x28\xc6\x04\xd6\x21\xd1\x28\x94\x1c\xcf\xd1\x33\xcd\x63\x8b\x38\x94\xea\xce\x0a\x88\x2c\xde\xae\x12\x19\x8c\x3c\x38\x17\x61\xeb\x23\x79\x0d\x51\x5c\x40\xfa\xb8\x72\x01\xe3\x03\x0b\xee\x78\x79\x3c\x60\x5b\xb8\xe4\x38\xb7\xbd\x18\x20\x57\x3c\x3c\x4c\xa8\x62\xd5\xeb\x97\x00\x63\xc0\x83\xd1\xdd\xa8\x5b\xd7\xdc\x74\x8c\xc8\x4f\x0a\x9b\x89\x3f\xe7\x2b\xbc\x16\x68\x95\x23\x86\xce\x67\x22\x49\x35\xad\xc1\xf7\x5f\xe3\x2a\x6b\xe4\x21\x26\x44\xc1\xa1\x5e\x9c\xa6\x12\x75\x08\x32\xad\xfb\xe2\x54\x02\xdd\x3a\xc8\x0c\x7c\x9e\x25\xe5\x1b\x3e\x62\xb8\x63\x6a\x26\x6d\x04\x7e\x26\x74\x61\xae\x21\x26\xfb\xa2\x3b\x76\x99\xeb\x0a\xb8\x2d\x22\xad\x2e\x77\xfd\xcd\x46\x8c\xa9\x59\x47\x71\x36\x73\x18\x9b\x39\xd7\x56\x08\x63\x91\xb0\x4a\xe3\x17\x08\x72\x26\x98\xc1\x6b\xe0\x89\x88\x12\x98\x99\x5d\x87\x2e\xdc\x64\xf7\xad\x05\x6f\x6f\x36\xbf\x9c\x4b\x0e\x0c\xf6\xc4\x8f\xe8\xcf\xff\xda\x00\x0c\x03\x01\x00\x02\x00\x03\x00\x00\x00\x10\x89\x4a\x5d\xe3\xb4\xf3\x74\xe6\x50\xee\x11\x27\xec\x65\x8f\xfc\x21\x26\x5f\xff\xc4\x00\x23\x11\x01\x00\x02\x02\x02\x02\x02\x03\x01\x01\x00\x00\x00\x00\x00\x00\x01\x11\x21\x00\x31\x41\x51\x61\x71\x81\x91\xa1\xb1\xc1\xd1\xf0\xff\xda\x00\x08\x01\x03\x01\x01\x3f\x10\x69\xa6\x38\x70\x4d\x4f\x85\x62\x78\xd6\x40\x85\xbf\x37\xff\x00\x7f\x98\x74\x08\x6d\x78\x9d\xa4\xd4\x9c\x71\x3f\x78\xb9\x0e\x8e\xdb\xda\xcd\xc9\xb8\x0f\x9c\x59\x47\x22\xce\x2b\x5b\x9e\xb9\xe6\xfc\x61\x66\x9d\x91\x11\x3a\x67\xc6\xb4\x78\xf3\x8b\x25\xfb\x1c\x04\xb8\xd8\x95\x60\xbf\x47\xcd\x6b\x13\xa0\x74\x44\x1a\x0a\xaa\x46\x4b\x32\x48\x69\xc7\x11\x1e\xa7\x7b\xf9\x91\xc1\x43\x4d\xf9\x9e\xfe\x71\xf1\x4b\x70\x7f\x7a\xc4\x00\xa0\xb2\x77\x32\xfe\x0f\x8f\x38\x0c\x26\x17\x9f\x39\x11\xc2\x33\x74\x22\x12\x6d\x99\xd1\xad\xae\x2d\x92\x28\x07\x6f\x07\x6b\xf2\xd7\x46\x18\x56\x89\x6d\x9e\xa5\xb8\xfd\x7a\xc1\x79\x02\x64\xb1\x31\xc8\xc1\x1d\x46\xfe\x63\x08\x5a\x57\x05\x5d\x84\xce\xef\x67\x67\xa3\xca\x0d\xd4\x24\xcc\x5d\xfa\xe9\x86\x9c\x2b\x91\x2e\xbb\xbc\x14\x35\x5d\x9a\x01\x2a\xbd\xc3\x9f\x9a\x9c\xa6\x10\x0c\x8b\x69\xb7\xd3\x06\xb7\xba\xee\x00\x9c\xd8\xd9\xd3\x14\x03\xef\xd3\x38\xdd\x42\xb2\x93\xc1\xc1\xd4\xee\x28\xfc\x61\xee\x70\x9e\xcf\x9c\xae\x44\xa4\x98\xb8\x5d\x9c\x4c\x4e\x98\xe7\x00\xd3\x9a\xde\xbe\xb0\xa2\x44\x04\x09\x69\x0b\x36\x6e\xe6\x65\x83\x58\x26\x9e\x64\xca\xdf\x2d\x57\x8f\xb9\x6f\x24\x6c\x04\xa2\x93\x84\xfd\xf8\xd4\x60\x9a\x8c\x38\x43\x14\x49\xe0\xc7\x60\x40\x02\x25\x0b\x71\xea\x12\x64\x24\xe6\xf0\xa4\x59\x61\x51\xc5\xf7\xf6\x79\x19\xc2\x03\x58\xc2\x81\x3b\x01\x38\xe4\x88\x3d\x44\x6f\x1b\x98\xc9\x92\x92\x7a\x3b\xf4\xd1\x8c\x8a\xc0\x2b\xf1\xee\xa7\x8f\xee\x18\xa2\x0d\x31\x76\x0c\x47\xf2\x69\x36\xe4\x0e\x88\x0d\x1d\x93\x5e\xa7\x7c\xc4\x39\x04\x91\x7f\xe7\x59\xb3\xe3\xf8\x61\x29\x23\x21\xdd\xf3\x84\x1a\x1c\x0a\x3f\x18\x88\x6d\x85\x3c\x9c\x56\x4a\xe9\xa3\x77\xd6\x10\x36\xe1\xfd\x64\xbf\xe8\xe7\xff\xc4\x00\x24\x11\x01\x01\x00\x02\x02\x02\x01\x04\x03\x01\x00\x00\x00\x00\x00\x00\x01\x11\x21\x31\x00\x41\x51\x61\x71\x81\x91\xb1\xc1\xa1\xd1\xf1\xe1\xff\xda\x00\x08\x01\x02\x01\x01\x3f\x10\xd7\xa7\x57\x3d\x84\x75\x41\x50\xae\x6b\xe7\x8e\x43\x43\xe5\x3b\xff\x00\x9f\x7e\x68\xbc\x16\x48\xbe\xe6\xaf\x67\x7d\x78\xe2\x89\x90\xa0\x53\x16\x3a\x80\x1b\x59\xc2\xdd\x06\x5b\x21\x0b\xa2\x02\xa1\x8c\xef\x1d\x6f\xcb\x98\x8a\x0b\x93\x8c\x3d\x9c\xb5\xdb\x0d\xda\xc2\x20\xe0\xc7\x03\x46\x8d\x02\xdc\x88\xef\x76\xbf\x4c\x57\x9e\xd8\x3c\xf5\x44\xbe\xa7\xfb\xc0\x0b\x48\x65\xf0\xfe\x19\x6c\x4c\x75\xc1\x70\xe0\x22\x42\x6e\x47\x53\xbf\x1d\xf8\x40\x99\xb1\x95\x73\x83\xcf\xdd\xc1\x98\x0e\x39\x17\xcc\x83\xa6\xbb\x9a\x67\xee\xf8\xe0\x44\x00\xeb\xfd\x73\x0a\x4d\xa9\x17\x2b\x69\xd7\xdf\x63\x21\x78\x88\xe4\x17\x1b\x2e\x3a\xa6\x97\xb3\x13\xbe\x04\x46\x2d\xe8\xf1\x83\x67\xae\xf1\xee\xa3\xb2\x0b\x64\xcf\xbf\xae\x2f\xc7\x1a\xb3\x19\x60\xe1\x73\x82\x4d\x1d\x84\xcf\x28\x89\x91\x03\x95\x14\xf8\x83\x77\xf7\xc8\x99\xea\x57\x33\x2e\x74\x10\xf8\x38\x62\x58\xe9\xeb\x52\x75\x8a\x43\xe3\x61\xc7\xce\xa2\x40\x58\xac\x2b\xe2\xc2\x98\xa9\x9a\x50\xbb\xca\xb0\x4c\x56\x9a\x8d\x77\x93\x4c\xa7\x10\x14\x6c\xec\xf6\x91\xd4\x4e\xf3\x31\xc6\x1d\xc2\xdd\xc2\x76\xa4\xea\x77\xae\xf8\xb7\xd2\x04\xc0\xa0\xa1\xe5\xb7\x5b\xc7\x7c\x70\x7f\x3e\x60\x54\xef\x48\xb9\xcd\x7d\xe6\x9e\xf5\xc3\x46\x51\x2b\xac\x1c\x86\x72\x4d\xfd\x08\x71\x1c\xed\x00\xe5\x62\xaa\xe7\xa3\xda\xa9\x3a\xe6\x63\xa2\xc9\x66\x6b\x0f\xe9\xf7\xcb\x80\x6b\x83\x80\x98\x3a\xb1\x82\x36\x9a\x67\x14\xa4\x25\x13\x2e\x58\xe0\xd0\xd6\x2f\x56\x50\xa2\xd3\xee\x1f\xd7\x03\x71\xcc\x66\x78\x1a\xec\xcc\x62\xf5\x71\xc9\x6f\x24\x75\x07\x66\x8c\x7e\x3e\xb7\x84\x88\xc3\x7c\xa9\x02\x47\x02\xb7\xe4\x9b\x78\x02\xe1\x11\x2f\x4a\xfe\x9d\x7d\x39\x8c\x7b\xef\x60\xb1\xbd\x4e\xf1\x1b\xa3\x7c\xa8\xa9\x24\x14\xab\x37\x8c\x46\x44\x42\xa6\x6b\xcb\xd4\xce\x3c\x75\x2b\xf9\x6b\xef\xc4\x0a\x28\x1e\xcc\x3a\xf1\xc5\x67\x46\x15\x59\x72\x97\x5c\x96\xe4\xb2\x56\x4f\x1c\x39\x56\x31\x97\x19\x9f\x8c\x71\xa9\xaf\xf9\xc3\x98\x20\xe7\xff\xc4\x00\x1f\x10\x01\x01\x01\x01\x01\x01\x00\x02\x03\x01\x00\x00\x00\x00\x00\x00\x01\x11\x21\x00\x31\x41\x51\x61\x71\x81\xd1\x91\xff\xda\x00\x08\x01\x01\x00\x01\x3f\x10\xca\x95\xf8\x23\xa1\xff\x00\xa4\x51\xaa\x3a\xfa\xba\x8a\x07\x12\x09\xa8\x42\x89\x66\x0b\x78\x98\x94\xbb\x7a\x81\x41\xf3\x68\x54\xa4\x3f\x3f\x99\xc1\xac\x14\x9f\xe5\xc9\xa2\x63\xd4\x20\x1b\x60\x03\x7e\x78\x61\xc5\x9d\xc9\x6c\xce\x48\x04\x84\xb7\x5f\x9a\x7d\x70\x8f\xbd\x3f\xd3\x67\x03\x79\x27\x33\x40\x32\x80\x81\x2e\x33\xcb\xb5\xa4\xcd\x43\x4a\x92\x3e\x10\x97\xe1\xaa\xf3\x20\x83\x66\x0b\x16\x9a\x80\x3d\xec\x0c\x91\xb3\x44\xe8\x5b\x0b\x8d\x1f\x15\xe0\x07\xc3\x51\x49\x28\x68\x37\x84\xfc\xfd\x79\x70\x08\x93\xb5\x3c\x31\x4b\xf5\x4c\xf5\xe7\x5a\x4a\x54\x8a\x27\xc4\x7e\x72\x15\xef\x43\x85\x70\x3f\x25\x2a\x81\x64\x77\x7f\xa5\x88\xd3\x25\xd2\x8a\x07\x81\xcf\xe8\x65\xa6\xd2\x16\x0a\x8e\x3f\x5f\x97\x84\xd5\x81\x42\x90\x9f\x1c\xac\x10\x3c\x87\x7a\x81\xe8\x2e\x58\x00\x97\xc1\xbb\x76\xf0\x0e\xf9\x41\x10\x80\x53\x24\x8d\xf8\x8f\x36\x34\x8d\x9c\x21\x6b\x6e\x7d\xde\x42\x2f\x58\x58\x0d\x08\x88\x44\x6b\xc5\x38\x44\x28\x0a\x56\xb5\x1d\xdb\x2a\xe0\x71\x40\xe6\xd7\x40\x8d\xc4\xa0\x02\xe2\x8a\xa0\xf9\x1b\x8f\x96\x33\x41\x0a\x26\xbc\x2a\xfb\x8e\x25\x08\xf0\xbf\xb3\xed\xca\x89\x8f\x41\xa8\x18\xda\x07\xd8\x1a\x88\xe6\x60\x11\x2f\xd3\x5b\x9f\xbd\xe6\x98\x60\x8c\xc5\x3e\x18\x03\x63\x3d\x87\x04\x50\x82\x8a\xc5\x70\x53\x01\x29\x9e\x1d\xec\xd3\x64\x68\xc0\x80\x91\x5f\xc0\xe0\x04\xab\x86\x18\x84\x04\x92\xfa\x1a\x8f\xa4\xe9\xbb\x42\xa6\xa8\xfe\xd0\x1a\x15\x21\x73\x6e\xd0\x53\x3c\x60\x00\x28\x86\x5a\xf3\x95\xfb\x8c\x82\xf8\x33\xce\x7e\xee\x61\xdf\x91\x84\x0f\x45\xf4\xbe\x5e\x97\xcc\x8b\x06\xca\xc1\x34\xa5\x65\xe9\x16\xd6\x05\xda\x00\xc4\x11\x49\x27\x0c\x3a\xaa\x84\x8a\x5a\x11\x70\x81\xf5\x84\xe5\x4c\x1d\x0d\x86\x1e\x12\x8b\x82\x3e\x1c\xe9\xe7\x22\x03\x5b\x0e\x59\x08\x31\x4e\x73\x89\x22\x5d\x2d\x66\xdf\xc7\x01\x35\x22\x85\x04\x7d\x13\x27\xe3\x88\x8b\x69\x72\x89\x62\x7e\xb8\xcf\x34\xdf\x40\x00\xa0\x28\x5f\x05\x38\x49\x00\x4b\xf4\xa5\xc5\xd5\x7f\x95\x7a\x26\x52\x46\x28\x4b\x69\x1b\xf5\x3f\x79\xdc\x04\x5a\x04\x8e\x7e\xb9\xad\x75\x05\x5f\xf6\xef\xff\xd9", expectedMatch: /Render_Image\('Raw'\)/, recipeConfig: [ { From 8ada3bae0cc8eeac370e37e71ce74de238fd4bb4 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Wed, 3 Jul 2019 12:34:13 +0100 Subject: [PATCH 24/27] Updated CHANGELOG --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b63ff85e..d1f5dc23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ All major and minor version changes will be documented in this file. Details of patch-level version changes can be found in [commit messages](https://github.com/gchq/CyberChef/commits/master). +### [8.35.0] - 2019-07-03 +- 'Sharpen Image', 'Convert Image Format' and 'Add Text To Image' operations added [@j433866] | [#515] + ### [8.34.0] - 2019-06-28 - Various new visualisations added to the 'Entropy' operation [@MShwed] | [#535] - Efficiency improvements made to the 'Entropy' operation for large file support [@n1474335] @@ -140,6 +143,7 @@ All major and minor version changes will be documented in this file. Details of +[8.35.0]: https://github.com/gchq/CyberChef/releases/tag/v8.35.0 [8.34.0]: https://github.com/gchq/CyberChef/releases/tag/v8.34.0 [8.33.0]: https://github.com/gchq/CyberChef/releases/tag/v8.33.0 [8.32.0]: https://github.com/gchq/CyberChef/releases/tag/v8.32.0 @@ -244,6 +248,7 @@ All major and minor version changes will be documented in this file. Details of [#489]: https://github.com/gchq/CyberChef/pull/489 [#496]: https://github.com/gchq/CyberChef/pull/496 [#506]: https://github.com/gchq/CyberChef/pull/506 +[#515]: https://github.com/gchq/CyberChef/pull/515 [#516]: https://github.com/gchq/CyberChef/pull/516 [#525]: https://github.com/gchq/CyberChef/pull/525 [#531]: https://github.com/gchq/CyberChef/pull/531 From bb0eaf45973b715ae2c82a14ba744e15d9f94340 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Wed, 3 Jul 2019 12:34:17 +0100 Subject: [PATCH 25/27] 8.35.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7db91304..8d77fb55 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "cyberchef", - "version": "8.34.3", + "version": "8.35.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 81b9aadb..699bc983 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cyberchef", - "version": "8.34.3", + "version": "8.35.0", "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.", "author": "n1474335 ", "homepage": "https://gchq.github.io/CyberChef", From 30be3cab533e11b4dba3978255e9ab3f35f47c4e Mon Sep 17 00:00:00 2001 From: n1474335 Date: Wed, 3 Jul 2019 12:41:52 +0100 Subject: [PATCH 26/27] Updated CHANGELOG --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1f5dc23..856f7ce2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ All major and minor version changes will be documented in this file. Details of patch-level version changes can be found in [commit messages](https://github.com/gchq/CyberChef/commits/master). +### [8.36.0] - 2019-07-03 +- 'PGP Verify' operation added [@artemisbot] | [#585] + ### [8.35.0] - 2019-07-03 - 'Sharpen Image', 'Convert Image Format' and 'Add Text To Image' operations added [@j433866] | [#515] @@ -143,6 +146,7 @@ All major and minor version changes will be documented in this file. Details of +[8.36.0]: https://github.com/gchq/CyberChef/releases/tag/v8.36.0 [8.35.0]: https://github.com/gchq/CyberChef/releases/tag/v8.35.0 [8.34.0]: https://github.com/gchq/CyberChef/releases/tag/v8.34.0 [8.33.0]: https://github.com/gchq/CyberChef/releases/tag/v8.33.0 @@ -255,3 +259,4 @@ All major and minor version changes will be documented in this file. Details of [#533]: https://github.com/gchq/CyberChef/pull/533 [#535]: https://github.com/gchq/CyberChef/pull/535 [#571]: https://github.com/gchq/CyberChef/pull/571 +[#585]: https://github.com/gchq/CyberChef/pull/585 From 57e71f0e1a4149a8b3acaf788298352cd78601d2 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Wed, 3 Jul 2019 12:41:59 +0100 Subject: [PATCH 27/27] 8.36.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8d77fb55..280e3c41 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "cyberchef", - "version": "8.35.0", + "version": "8.36.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 699bc983..6775a8b3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cyberchef", - "version": "8.35.0", + "version": "8.36.0", "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.", "author": "n1474335 ", "homepage": "https://gchq.github.io/CyberChef",