mirror of
https://github.com/gchq/CyberChef.git
synced 2025-04-24 08:46:19 -04:00
Merge branch 'v9' of github.com:gchq/CyberChef into node-lib
This commit is contained in:
commit
368f508b17
122 changed files with 24317 additions and 4174 deletions
|
@ -170,7 +170,7 @@ export const FILE_SIGNATURES = {
|
|||
mime: "image/vnd.adobe.photoshop",
|
||||
description: "",
|
||||
signature: {
|
||||
0: 0x38,
|
||||
0: 0x38, // 8BPS
|
||||
1: 0x42,
|
||||
2: 0x50,
|
||||
3: 0x53,
|
||||
|
@ -185,6 +185,28 @@ export const FILE_SIGNATURES = {
|
|||
},
|
||||
extractor: null
|
||||
},
|
||||
{
|
||||
name: "Photoshop Large Document",
|
||||
extension: "psb",
|
||||
mime: "application/x-photoshop",
|
||||
description: "",
|
||||
signature: {
|
||||
0: 0x38, // 8BPS
|
||||
1: 0x42,
|
||||
2: 0x50,
|
||||
3: 0x53,
|
||||
4: 0x0,
|
||||
5: 0x2,
|
||||
6: 0x0,
|
||||
7: 0x0,
|
||||
8: 0x0,
|
||||
9: 0x0,
|
||||
10: 0x0,
|
||||
11: 0x0,
|
||||
12: 0x0
|
||||
},
|
||||
extractor: null
|
||||
},
|
||||
{
|
||||
name: "Paint Shop Pro image",
|
||||
extension: "psp",
|
||||
|
@ -233,10 +255,114 @@ export const FILE_SIGNATURES = {
|
|||
5: 0x0,
|
||||
6: [0x10, 0x20, 0x30, 0x40, 0x80],
|
||||
7: [0x10, 0x20, 0x30, 0x40, 0x80],
|
||||
9: 0x00,
|
||||
9: 0x0,
|
||||
10: [0x0, 0x1]
|
||||
},
|
||||
extractor: null
|
||||
},
|
||||
{
|
||||
name: "Radiance High Dynamic Range image",
|
||||
extension: "hdr",
|
||||
mime: "image/vnd.radiance",
|
||||
description: "",
|
||||
signature: {
|
||||
0: 0x23, // #?RADIANCE
|
||||
1: 0x3f,
|
||||
2: 0x52,
|
||||
3: 0x41,
|
||||
4: 0x44,
|
||||
5: 0x49,
|
||||
6: 0x41,
|
||||
7: 0x4e,
|
||||
8: 0x43,
|
||||
9: 0x45,
|
||||
10: 0x0a
|
||||
},
|
||||
extractor: null
|
||||
},
|
||||
{
|
||||
name: "Sony ARW image",
|
||||
extension: "arw",
|
||||
mime: "image/x-raw",
|
||||
description: "",
|
||||
signature: {
|
||||
0: 0x05,
|
||||
1: 0x0,
|
||||
2: 0x0,
|
||||
3: 0x0,
|
||||
4: 0x41,
|
||||
5: 0x57,
|
||||
6: 0x31,
|
||||
7: 0x2e
|
||||
},
|
||||
extractor: null
|
||||
},
|
||||
{
|
||||
name: "Fujifilm Raw Image",
|
||||
extension: "raf",
|
||||
mime: "image/x-raw",
|
||||
description: "",
|
||||
signature: {
|
||||
0: 0x46, // FUJIFILMCCD-RAW
|
||||
1: 0x55,
|
||||
2: 0x4a,
|
||||
3: 0x49,
|
||||
4: 0x46,
|
||||
5: 0x49,
|
||||
6: 0x4c,
|
||||
7: 0x4d,
|
||||
8: 0x43,
|
||||
9: 0x43,
|
||||
10: 0x44,
|
||||
11: 0x2d,
|
||||
12: 0x52,
|
||||
13: 0x41,
|
||||
14: 0x57
|
||||
},
|
||||
extractor: null
|
||||
},
|
||||
{
|
||||
name: "Minolta RAW image",
|
||||
extension: "mrw",
|
||||
mime: "image/x-raw",
|
||||
description: "",
|
||||
signature: {
|
||||
0: 0x0,
|
||||
1: 0x4d, // MRM
|
||||
2: 0x52,
|
||||
3: 0x4d
|
||||
},
|
||||
extractor: null
|
||||
},
|
||||
{
|
||||
name: "Adobe Bridge Thumbnail Cache",
|
||||
extension: "bct",
|
||||
mime: "application/octet-stream",
|
||||
description: "",
|
||||
signature: {
|
||||
0: 0x6c,
|
||||
1: 0x6e,
|
||||
2: 0x62,
|
||||
3: 0x74,
|
||||
4: 0x02,
|
||||
5: 0x0,
|
||||
6: 0x0,
|
||||
7: 0x0
|
||||
},
|
||||
extractor: null
|
||||
},
|
||||
{
|
||||
name: "Microsoft Document Imaging",
|
||||
extension: "mdi",
|
||||
mime: "image/vnd.ms-modi",
|
||||
description: "",
|
||||
signature: {
|
||||
0: 0x45,
|
||||
1: 0x50,
|
||||
2: 0x2a,
|
||||
3: 0x00
|
||||
},
|
||||
extractor: null
|
||||
}
|
||||
],
|
||||
"Video": [
|
||||
|
@ -534,6 +660,97 @@ export const FILE_SIGNATURES = {
|
|||
},
|
||||
extractor: null
|
||||
},
|
||||
{
|
||||
name: "Audacity",
|
||||
extension: "au",
|
||||
mime: "audio/x-au",
|
||||
description: "",
|
||||
signature: {
|
||||
0: 0x64, // dns.
|
||||
1: 0x6e,
|
||||
2: 0x73,
|
||||
3: 0x2e,
|
||||
|
||||
24: 0x41, // AudacityBlockFile
|
||||
25: 0x75,
|
||||
26: 0x64,
|
||||
27: 0x61,
|
||||
28: 0x63,
|
||||
29: 0x69,
|
||||
30: 0x74,
|
||||
31: 0x79,
|
||||
32: 0x42,
|
||||
33: 0x6c,
|
||||
34: 0x6f,
|
||||
35: 0x63,
|
||||
36: 0x6b,
|
||||
37: 0x46,
|
||||
38: 0x69,
|
||||
39: 0x6c,
|
||||
40: 0x65
|
||||
},
|
||||
extractor: null
|
||||
},
|
||||
{
|
||||
name: "Audacity Block",
|
||||
extension: "auf",
|
||||
mime: "application/octet-stream",
|
||||
description: "",
|
||||
signature: {
|
||||
0: 0x41, // AudacityBlockFile
|
||||
1: 0x75,
|
||||
2: 0x64,
|
||||
3: 0x61,
|
||||
4: 0x63,
|
||||
5: 0x69,
|
||||
6: 0x74,
|
||||
7: 0x79,
|
||||
8: 0x42,
|
||||
9: 0x6c,
|
||||
10: 0x6f,
|
||||
11: 0x63,
|
||||
12: 0x6b,
|
||||
13: 0x46,
|
||||
14: 0x69,
|
||||
15: 0x6c,
|
||||
16: 0x65
|
||||
},
|
||||
extractor: null
|
||||
},
|
||||
{
|
||||
name: "Audio Interchange File",
|
||||
extension: "aif",
|
||||
mime: "audio/x-aiff",
|
||||
description: "",
|
||||
signature: {
|
||||
0: 0x46, // FORM
|
||||
1: 0x4f,
|
||||
2: 0x52,
|
||||
3: 0x4d,
|
||||
8: 0x41, // AIFF
|
||||
9: 0x49,
|
||||
10: 0x46,
|
||||
11: 0x46
|
||||
},
|
||||
extractor: null
|
||||
},
|
||||
{
|
||||
name: "Audio Interchange File (compressed)",
|
||||
extension: "aifc",
|
||||
mime: "audio/x-aifc",
|
||||
description: "",
|
||||
signature: {
|
||||
0: 0x46, // FORM
|
||||
1: 0x4f,
|
||||
2: 0x52,
|
||||
3: 0x4d,
|
||||
8: 0x41, // AIFC
|
||||
9: 0x49,
|
||||
10: 0x46,
|
||||
11: 0x43
|
||||
},
|
||||
extractor: null
|
||||
}
|
||||
],
|
||||
"Documents": [
|
||||
{
|
||||
|
@ -898,6 +1115,110 @@ export const FILE_SIGNATURES = {
|
|||
},
|
||||
extractor: null
|
||||
},
|
||||
{
|
||||
name: "ARJ Archive",
|
||||
extension: "arj",
|
||||
mime: "application/x-arj-compressed",
|
||||
description: "",
|
||||
signature: {
|
||||
0: 0x60,
|
||||
1: 0xea,
|
||||
8: [0x0, 0x10, 0x14],
|
||||
9: 0x0,
|
||||
10: 0x2
|
||||
},
|
||||
extractor: null
|
||||
},
|
||||
{
|
||||
name: "WinAce Archive",
|
||||
extension: "ace",
|
||||
mime: "application/x-ace-compressed",
|
||||
description: "",
|
||||
signature: {
|
||||
7: 0x2a, // **ACE**
|
||||
8: 0x2a,
|
||||
9: 0x41,
|
||||
10: 0x43,
|
||||
11: 0x45,
|
||||
12: 0x2a,
|
||||
13: 0x2a
|
||||
},
|
||||
extractor: null
|
||||
},
|
||||
{
|
||||
name: "Macintosh BinHex Encoded File",
|
||||
extension: "hqx",
|
||||
mime: "application/mac-binhex",
|
||||
description: "",
|
||||
signature: {
|
||||
11: 0x6d, // must be converted with BinHex
|
||||
12: 0x75,
|
||||
13: 0x73,
|
||||
14: 0x74,
|
||||
15: 0x20,
|
||||
16: 0x62,
|
||||
17: 0x65,
|
||||
18: 0x20,
|
||||
19: 0x63,
|
||||
20: 0x6f,
|
||||
21: 0x6e,
|
||||
22: 0x76,
|
||||
23: 0x65,
|
||||
24: 0x72,
|
||||
25: 0x74,
|
||||
26: 0x65,
|
||||
27: 0x64,
|
||||
28: 0x20,
|
||||
29: 0x77,
|
||||
30: 0x69,
|
||||
31: 0x74,
|
||||
32: 0x68,
|
||||
33: 0x20,
|
||||
34: 0x42,
|
||||
35: 0x69,
|
||||
36: 0x6e,
|
||||
37: 0x48,
|
||||
38: 0x65,
|
||||
39: 0x78
|
||||
},
|
||||
extractor: null
|
||||
},
|
||||
{
|
||||
name: "ALZip Archive",
|
||||
extension: "alz",
|
||||
mime: "application/octet-stream",
|
||||
description: "",
|
||||
signature: {
|
||||
0: 0x41, // ALZ
|
||||
1: 0x4c,
|
||||
2: 0x5a,
|
||||
3: 0x01,
|
||||
4: 0x0a,
|
||||
5: 0x0,
|
||||
6: 0x0,
|
||||
7: 0x0
|
||||
},
|
||||
extractor: null
|
||||
},
|
||||
{
|
||||
name: "KGB Compressed Archive",
|
||||
extension: "kgb",
|
||||
mime: "application/x-kgb-compressed",
|
||||
description: "",
|
||||
signature: {
|
||||
0: 0x4b, // KGB_arch -
|
||||
1: 0x47,
|
||||
2: 0x42,
|
||||
3: 0x5f,
|
||||
4: 0x61,
|
||||
5: 0x72,
|
||||
6: 0x63,
|
||||
7: 0x68,
|
||||
8: 0x20,
|
||||
9: 0x2d
|
||||
},
|
||||
extractor: null
|
||||
}
|
||||
],
|
||||
"Miscellaneous": [
|
||||
{
|
||||
|
@ -1041,6 +1362,43 @@ export const FILE_SIGNATURES = {
|
|||
},
|
||||
extractor: null
|
||||
},
|
||||
{
|
||||
name: "BitTorrent link",
|
||||
extension: "torrent",
|
||||
mime: "application/x-bittorrent",
|
||||
description: "",
|
||||
signature: [
|
||||
{
|
||||
0: 0x64, // d8:announce##:
|
||||
1: 0x38,
|
||||
2: 0x3a,
|
||||
3: 0x61,
|
||||
4: 0x6e,
|
||||
5: 0x6e,
|
||||
6: 0x6f,
|
||||
7: 0x75,
|
||||
8: 0x6e,
|
||||
9: 0x63,
|
||||
10: 0x65,
|
||||
11: 0x23,
|
||||
12: 0x23,
|
||||
13: 0x3a
|
||||
},
|
||||
{
|
||||
0: 0x64, // d4:infod
|
||||
1: 0x34,
|
||||
2: 0x3a,
|
||||
3: 0x69,
|
||||
4: 0x6e,
|
||||
5: 0x66,
|
||||
6: 0x6f,
|
||||
7: 0x64,
|
||||
8: [0x34, 0x35, 0x36],
|
||||
9: 0x3a
|
||||
}
|
||||
],
|
||||
extractor: null
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import Utils from "../Utils";
|
|||
/**
|
||||
* Convert a byte array into a hex string.
|
||||
*
|
||||
* @param {Uint8Array|byteArray} data
|
||||
* @param {byteArray|Uint8Array|ArrayBuffer} data
|
||||
* @param {string} [delim=" "]
|
||||
* @param {number} [padding=2]
|
||||
* @returns {string}
|
||||
|
@ -26,6 +26,7 @@ import Utils from "../Utils";
|
|||
*/
|
||||
export function toHex(data, delim=" ", padding=2) {
|
||||
if (!data) return "";
|
||||
if (data instanceof ArrayBuffer) data = new Uint8Array(data);
|
||||
|
||||
let output = "";
|
||||
|
||||
|
@ -47,7 +48,7 @@ export function toHex(data, delim=" ", padding=2) {
|
|||
/**
|
||||
* Convert a byte array into a hex string as efficiently as possible with no options.
|
||||
*
|
||||
* @param {byteArray} data
|
||||
* @param {byteArray|Uint8Array|ArrayBuffer} data
|
||||
* @returns {string}
|
||||
*
|
||||
* @example
|
||||
|
@ -56,6 +57,7 @@ export function toHex(data, delim=" ", padding=2) {
|
|||
*/
|
||||
export function toHexFast(data) {
|
||||
if (!data) return "";
|
||||
if (data instanceof ArrayBuffer) data = new Uint8Array(data);
|
||||
|
||||
const output = [];
|
||||
|
||||
|
|
251
src/core/lib/ImageManipulation.mjs
Normal file
251
src/core/lib/ImageManipulation.mjs
Normal file
|
@ -0,0 +1,251 @@
|
|||
/**
|
||||
* 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 {number} 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) {
|
||||
throw new OperationError(`Error blurring image. (${err})`);
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {number} radius
|
||||
* @param {number} 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 {number} width
|
||||
* @param {number} height
|
||||
* @param {number} 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;
|
||||
}
|
|
@ -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();
|
||||
|
|
93
src/core/lib/QRCode.mjs
Normal file
93
src/core/lib/QRCode.mjs
Normal file
|
@ -0,0 +1,93 @@
|
|||
/**
|
||||
* 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";
|
||||
import Utils from "../Utils";
|
||||
|
||||
/**
|
||||
* Parses a QR code image from an image
|
||||
*
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {boolean} normalise
|
||||
* @returns {string}
|
||||
*/
|
||||
export async function parseQrCode(input, normalise) {
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error opening image. (${err})`);
|
||||
}
|
||||
|
||||
try {
|
||||
if (normalise) {
|
||||
image.rgba(false);
|
||||
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})`);
|
||||
}
|
||||
|
||||
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 {ArrayBuffer}
|
||||
*/
|
||||
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 Utils.strToArrayBuffer(qrImage);
|
||||
case "PNG":
|
||||
return qrImage.buffer;
|
||||
default:
|
||||
throw new OperationError("Unsupported QR code format.");
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue