cyberchef 10.22.1 → 10.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +182 -0
- package/CONTRIBUTING.md +40 -0
- package/Dockerfile +2 -0
- package/Gruntfile.js +2 -28
- package/README.md +1 -1
- package/babel.config.js +0 -6
- package/package.json +64 -63
- package/src/core/Chef.mjs +8 -1
- package/src/core/Ingredient.mjs +5 -2
- package/src/core/Operation.mjs +6 -1
- package/src/core/Recipe.mjs +10 -5
- package/src/core/config/Categories.json +20 -4
- package/src/core/config/OperationConfig.json +550 -26
- package/src/core/config/modules/Ciphers.mjs +6 -0
- package/src/core/config/modules/Crypto.mjs +6 -0
- package/src/core/config/modules/Default.mjs +8 -0
- package/src/core/config/modules/Shellcode.mjs +2 -0
- package/src/core/config/scripts/fixCryptoApiImports.mjs +54 -0
- package/src/core/config/scripts/fixSnackBarMarkup.mjs +28 -0
- package/src/core/lib/AudioBytes.mjs +103 -0
- package/src/core/lib/AudioMetaSchema.mjs +82 -0
- package/src/core/lib/AudioParsers.mjs +630 -0
- package/src/core/lib/BigIntUtils.mjs +73 -0
- package/src/core/lib/Extract.mjs +5 -0
- package/src/core/lib/Modhex.mjs +2 -0
- package/src/core/lib/ParityBit.mjs +50 -0
- package/src/core/lib/QRCode.mjs +30 -10
- package/src/core/lib/RC6.mjs +625 -0
- package/src/core/operations/A1Z26CipherDecode.mjs +1 -1
- package/src/core/operations/AddTextToImage.mjs +116 -64
- package/src/core/operations/AnalyseUUID.mjs +109 -6
- package/src/core/operations/BlurImage.mjs +10 -12
- package/src/core/operations/ContainImage.mjs +50 -40
- package/src/core/operations/ConvertImageFormat.mjs +33 -39
- package/src/core/operations/CoverImage.mjs +39 -37
- package/src/core/operations/CropImage.mjs +35 -21
- package/src/core/operations/DisassembleARM.mjs +193 -0
- package/src/core/operations/DitherImage.mjs +8 -8
- package/src/core/operations/EscapeUnicodeCharacters.mjs +0 -17
- package/src/core/operations/ExtractAudioMetadata.mjs +175 -0
- package/src/core/operations/ExtractEmailAddresses.mjs +2 -3
- package/src/core/operations/ExtractLSB.mjs +17 -11
- package/src/core/operations/ExtractRGBA.mjs +12 -10
- package/src/core/operations/FlaskSessionDecode.mjs +80 -0
- package/src/core/operations/FlaskSessionSign.mjs +89 -0
- package/src/core/operations/FlaskSessionVerify.mjs +136 -0
- package/src/core/operations/FlipImage.mjs +14 -10
- package/src/core/operations/GenerateImage.mjs +39 -32
- package/src/core/operations/ImageBrightnessContrast.mjs +10 -10
- package/src/core/operations/ImageFilter.mjs +14 -13
- package/src/core/operations/ImageHueSaturationLightness.mjs +22 -20
- package/src/core/operations/ImageOpacity.mjs +6 -8
- package/src/core/operations/InvertImage.mjs +4 -6
- package/src/core/operations/Jq.mjs +12 -4
- package/src/core/operations/NormaliseImage.mjs +5 -7
- package/src/core/operations/OffsetChecker.mjs +1 -1
- package/src/core/operations/ParityBit.mjs +128 -0
- package/src/core/operations/ParseEthernetFrame.mjs +112 -0
- package/src/core/operations/ParseIPv4Header.mjs +23 -6
- package/src/core/operations/ParseQRCode.mjs +13 -13
- package/src/core/operations/PseudoRandomIntegerGenerator.mjs +164 -0
- package/src/core/operations/RC6Decrypt.mjs +119 -0
- package/src/core/operations/RC6Encrypt.mjs +119 -0
- package/src/core/operations/RandomizeColourPalette.mjs +11 -11
- package/src/core/operations/RegularExpression.mjs +2 -1
- package/src/core/operations/RenderMarkdown.mjs +35 -4
- package/src/core/operations/ResizeImage.mjs +30 -23
- package/src/core/operations/RotateImage.mjs +8 -9
- package/src/core/operations/SQLBeautify.mjs +21 -3
- package/src/core/operations/SharpenImage.mjs +94 -62
- package/src/core/operations/SplitColourChannels.mjs +47 -21
- package/src/core/operations/TextIntegerConverter.mjs +123 -0
- package/src/core/operations/UnescapeUnicodeCharacters.mjs +17 -0
- package/src/core/operations/ViewBitPlane.mjs +16 -20
- package/src/core/operations/index.mjs +22 -0
- package/src/node/index.mjs +55 -0
- package/src/web/HTMLIngredient.mjs +24 -43
- package/src/web/HTMLOperation.mjs +8 -2
- package/src/web/Manager.mjs +1 -0
- package/src/web/html/index.html +6 -6
- package/src/web/static/fonts/bmfonts/Roboto72White.fnt +491 -485
- package/src/web/static/fonts/bmfonts/RobotoBlack72White.fnt +494 -488
- package/src/web/static/fonts/bmfonts/RobotoMono72White.fnt +110 -103
- package/src/web/static/fonts/bmfonts/RobotoSlab72White.fnt +498 -492
- package/src/web/stylesheets/layout/_banner.css +30 -0
- package/src/web/stylesheets/layout/_modals.css +5 -0
- package/src/web/stylesheets/utils/_overrides.css +7 -0
- package/src/web/waiters/ControlsWaiter.mjs +82 -0
- package/src/web/waiters/InputWaiter.mjs +12 -6
- package/src/web/waiters/OperationsWaiter.mjs +30 -13
- package/src/web/waiters/RecipeWaiter.mjs +2 -2
- package/tests/browser/02_ops.js +23 -3
- package/tests/node/index.mjs +1 -0
- package/tests/node/tests/lib/BigIntUtils.mjs +150 -0
- package/tests/node/tests/operations.mjs +11 -10
- package/tests/operations/index.mjs +13 -0
- package/tests/operations/tests/A1Z26CipherDecode.mjs +33 -0
- package/tests/operations/tests/AnalyseUUID.mjs +66 -0
- package/tests/operations/tests/DisassembleARM.mjs +377 -0
- package/tests/operations/tests/ExtractAudioMetadata.mjs +287 -0
- package/tests/operations/tests/ExtractEmailAddresses.mjs +38 -12
- package/tests/operations/tests/Fernet.mjs +18 -3
- package/tests/operations/tests/FlaskSession.mjs +246 -0
- package/tests/operations/tests/GenerateQRCode.mjs +67 -0
- package/tests/operations/tests/JWTSign.mjs +83 -8
- package/tests/operations/tests/Jq.mjs +32 -0
- package/tests/operations/tests/Modhex.mjs +20 -0
- package/tests/operations/tests/ParityBit.mjs +147 -0
- package/tests/operations/tests/ParseEthernetFrame.mjs +45 -0
- package/tests/operations/tests/RC6.mjs +487 -0
- package/tests/operations/tests/RegularExpression.mjs +75 -0
- package/tests/operations/tests/RenderMarkdown.mjs +110 -0
- package/tests/operations/tests/SQLBeautify.mjs +54 -0
- package/tests/operations/tests/TextIntegerConverter.mjs +199 -0
- package/tests/samples/Audio.mjs +73 -0
- package/tests/samples/Images.mjs +0 -12
- package/webpack.config.js +10 -7
- package/src/core/lib/ImageManipulation.mjs +0 -251
|
@@ -9,13 +9,18 @@ import OperationError from "../errors/OperationError.mjs";
|
|
|
9
9
|
import { isImage } from "../lib/FileType.mjs";
|
|
10
10
|
import { toBase64 } from "../lib/Base64.mjs";
|
|
11
11
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
|
12
|
-
import
|
|
12
|
+
import {
|
|
13
|
+
Jimp,
|
|
14
|
+
JimpMime,
|
|
15
|
+
ResizeStrategy,
|
|
16
|
+
HorizontalAlign,
|
|
17
|
+
VerticalAlign,
|
|
18
|
+
} from "jimp";
|
|
13
19
|
|
|
14
20
|
/**
|
|
15
21
|
* Contain Image operation
|
|
16
22
|
*/
|
|
17
23
|
class ContainImage extends Operation {
|
|
18
|
-
|
|
19
24
|
/**
|
|
20
25
|
* ContainImage constructor
|
|
21
26
|
*/
|
|
@@ -24,7 +29,8 @@ class ContainImage extends Operation {
|
|
|
24
29
|
|
|
25
30
|
this.name = "Contain Image";
|
|
26
31
|
this.module = "Image";
|
|
27
|
-
this.description =
|
|
32
|
+
this.description =
|
|
33
|
+
"Scales an image to the specified width and height, maintaining the aspect ratio. The image may be letterboxed.";
|
|
28
34
|
this.infoURL = "";
|
|
29
35
|
this.inputType = "ArrayBuffer";
|
|
30
36
|
this.outputType = "ArrayBuffer";
|
|
@@ -34,33 +40,25 @@ class ContainImage extends Operation {
|
|
|
34
40
|
name: "Width",
|
|
35
41
|
type: "number",
|
|
36
42
|
value: 100,
|
|
37
|
-
min: 1
|
|
43
|
+
min: 1,
|
|
38
44
|
},
|
|
39
45
|
{
|
|
40
46
|
name: "Height",
|
|
41
47
|
type: "number",
|
|
42
48
|
value: 100,
|
|
43
|
-
min: 1
|
|
49
|
+
min: 1,
|
|
44
50
|
},
|
|
45
51
|
{
|
|
46
52
|
name: "Horizontal align",
|
|
47
53
|
type: "option",
|
|
48
|
-
value: [
|
|
49
|
-
|
|
50
|
-
"Center",
|
|
51
|
-
"Right"
|
|
52
|
-
],
|
|
53
|
-
defaultIndex: 1
|
|
54
|
+
value: ["Left", "Center", "Right"],
|
|
55
|
+
defaultIndex: 1,
|
|
54
56
|
},
|
|
55
57
|
{
|
|
56
58
|
name: "Vertical align",
|
|
57
59
|
type: "option",
|
|
58
|
-
value: [
|
|
59
|
-
|
|
60
|
-
"Middle",
|
|
61
|
-
"Bottom"
|
|
62
|
-
],
|
|
63
|
-
defaultIndex: 1
|
|
60
|
+
value: ["Top", "Middle", "Bottom"],
|
|
61
|
+
defaultIndex: 1,
|
|
64
62
|
},
|
|
65
63
|
{
|
|
66
64
|
name: "Resizing algorithm",
|
|
@@ -70,15 +68,15 @@ class ContainImage extends Operation {
|
|
|
70
68
|
"Bilinear",
|
|
71
69
|
"Bicubic",
|
|
72
70
|
"Hermite",
|
|
73
|
-
"Bezier"
|
|
71
|
+
"Bezier",
|
|
74
72
|
],
|
|
75
|
-
defaultIndex: 1
|
|
73
|
+
defaultIndex: 1,
|
|
76
74
|
},
|
|
77
75
|
{
|
|
78
76
|
name: "Opaque background",
|
|
79
77
|
type: "boolean",
|
|
80
|
-
value: true
|
|
81
|
-
}
|
|
78
|
+
value: true,
|
|
79
|
+
},
|
|
82
80
|
];
|
|
83
81
|
}
|
|
84
82
|
|
|
@@ -91,20 +89,20 @@ class ContainImage extends Operation {
|
|
|
91
89
|
const [width, height, hAlign, vAlign, alg, opaqueBg] = args;
|
|
92
90
|
|
|
93
91
|
const resizeMap = {
|
|
94
|
-
"Nearest Neighbour":
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
92
|
+
"Nearest Neighbour": ResizeStrategy.NEAREST_NEIGHBOR,
|
|
93
|
+
Bilinear: ResizeStrategy.BILINEAR,
|
|
94
|
+
Bicubic: ResizeStrategy.BICUBIC,
|
|
95
|
+
Hermite: ResizeStrategy.HERMITE,
|
|
96
|
+
Bezier: ResizeStrategy.BEZIER,
|
|
99
97
|
};
|
|
100
98
|
|
|
101
99
|
const alignMap = {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
100
|
+
Left: HorizontalAlign.LEFT,
|
|
101
|
+
Center: HorizontalAlign.CENTER,
|
|
102
|
+
Right: HorizontalAlign.RIGHT,
|
|
103
|
+
Top: VerticalAlign.TOP,
|
|
104
|
+
Middle: VerticalAlign.MIDDLE,
|
|
105
|
+
Bottom: VerticalAlign.BOTTOM,
|
|
108
106
|
};
|
|
109
107
|
|
|
110
108
|
if (!isImage(input)) {
|
|
@@ -117,22 +115,35 @@ class ContainImage extends Operation {
|
|
|
117
115
|
} catch (err) {
|
|
118
116
|
throw new OperationError(`Error loading image. (${err})`);
|
|
119
117
|
}
|
|
118
|
+
const originalMime = image.mime;
|
|
120
119
|
try {
|
|
121
120
|
if (isWorkerEnvironment())
|
|
122
121
|
self.sendStatusMessage("Containing image...");
|
|
123
|
-
image.contain(
|
|
122
|
+
image.contain({
|
|
123
|
+
w: width,
|
|
124
|
+
h: height,
|
|
125
|
+
align: alignMap[hAlign] | alignMap[vAlign],
|
|
126
|
+
mode: resizeMap[alg],
|
|
127
|
+
});
|
|
124
128
|
|
|
125
129
|
if (opaqueBg) {
|
|
126
|
-
const newImage =
|
|
127
|
-
|
|
128
|
-
|
|
130
|
+
const newImage = new Jimp({
|
|
131
|
+
width,
|
|
132
|
+
height,
|
|
133
|
+
color: 0x000000ff,
|
|
134
|
+
});
|
|
135
|
+
image = newImage.blit({
|
|
136
|
+
src: image,
|
|
137
|
+
x: 0,
|
|
138
|
+
y: 0,
|
|
139
|
+
});
|
|
129
140
|
}
|
|
130
141
|
|
|
131
142
|
let imageBuffer;
|
|
132
|
-
if (
|
|
133
|
-
imageBuffer = await image.
|
|
143
|
+
if (originalMime === "image/gif") {
|
|
144
|
+
imageBuffer = await image.getBuffer(JimpMime.png);
|
|
134
145
|
} else {
|
|
135
|
-
imageBuffer = await image.
|
|
146
|
+
imageBuffer = await image.getBuffer(originalMime);
|
|
136
147
|
}
|
|
137
148
|
return imageBuffer.buffer;
|
|
138
149
|
} catch (err) {
|
|
@@ -156,7 +167,6 @@ class ContainImage extends Operation {
|
|
|
156
167
|
|
|
157
168
|
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
|
158
169
|
}
|
|
159
|
-
|
|
160
170
|
}
|
|
161
171
|
|
|
162
172
|
export default ContainImage;
|
|
@@ -8,13 +8,12 @@ import Operation from "../Operation.mjs";
|
|
|
8
8
|
import OperationError from "../errors/OperationError.mjs";
|
|
9
9
|
import { isImage } from "../lib/FileType.mjs";
|
|
10
10
|
import { toBase64 } from "../lib/Base64.mjs";
|
|
11
|
-
import Jimp from "jimp
|
|
11
|
+
import { Jimp, JimpMime, PNGFilterType } from "jimp";
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Convert Image Format operation
|
|
15
15
|
*/
|
|
16
16
|
class ConvertImageFormat extends Operation {
|
|
17
|
-
|
|
18
17
|
/**
|
|
19
18
|
* ConvertImageFormat constructor
|
|
20
19
|
*/
|
|
@@ -23,7 +22,8 @@ class ConvertImageFormat extends Operation {
|
|
|
23
22
|
|
|
24
23
|
this.name = "Convert Image Format";
|
|
25
24
|
this.module = "Image";
|
|
26
|
-
this.description =
|
|
25
|
+
this.description =
|
|
26
|
+
"Converts an image between different formats. Supported formats:<br><ul><li>Joint Photographic Experts Group (JPEG)</li><li>Portable Network Graphics (PNG)</li><li>Bitmap (BMP)</li><li>Tagged Image File Format (TIFF)</li></ul><br>Note: GIF files are supported for input, but cannot be outputted.";
|
|
27
27
|
this.infoURL = "https://wikipedia.org/wiki/Image_file_formats";
|
|
28
28
|
this.inputType = "ArrayBuffer";
|
|
29
29
|
this.outputType = "ArrayBuffer";
|
|
@@ -32,39 +32,27 @@ class ConvertImageFormat extends Operation {
|
|
|
32
32
|
{
|
|
33
33
|
name: "Output Format",
|
|
34
34
|
type: "option",
|
|
35
|
-
value: [
|
|
36
|
-
"JPEG",
|
|
37
|
-
"PNG",
|
|
38
|
-
"BMP",
|
|
39
|
-
"TIFF"
|
|
40
|
-
]
|
|
35
|
+
value: ["JPEG", "PNG", "BMP", "TIFF"],
|
|
41
36
|
},
|
|
42
37
|
{
|
|
43
38
|
name: "JPEG Quality",
|
|
44
39
|
type: "number",
|
|
45
40
|
value: 80,
|
|
46
41
|
min: 1,
|
|
47
|
-
max: 100
|
|
42
|
+
max: 100,
|
|
48
43
|
},
|
|
49
44
|
{
|
|
50
45
|
name: "PNG Filter Type",
|
|
51
46
|
type: "option",
|
|
52
|
-
value: [
|
|
53
|
-
"Auto",
|
|
54
|
-
"None",
|
|
55
|
-
"Sub",
|
|
56
|
-
"Up",
|
|
57
|
-
"Average",
|
|
58
|
-
"Paeth"
|
|
59
|
-
]
|
|
47
|
+
value: ["Auto", "None", "Sub", "Up", "Average", "Paeth"],
|
|
60
48
|
},
|
|
61
49
|
{
|
|
62
50
|
name: "PNG Deflate Level",
|
|
63
51
|
type: "number",
|
|
64
52
|
value: 9,
|
|
65
53
|
min: 0,
|
|
66
|
-
max: 9
|
|
67
|
-
}
|
|
54
|
+
max: 9,
|
|
55
|
+
},
|
|
68
56
|
];
|
|
69
57
|
}
|
|
70
58
|
|
|
@@ -76,19 +64,19 @@ class ConvertImageFormat extends Operation {
|
|
|
76
64
|
async run(input, args) {
|
|
77
65
|
const [format, jpegQuality, pngFilterType, pngDeflateLevel] = args;
|
|
78
66
|
const formatMap = {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
67
|
+
JPEG: JimpMime.jpeg,
|
|
68
|
+
PNG: JimpMime.png,
|
|
69
|
+
BMP: JimpMime.bmp,
|
|
70
|
+
TIFF: JimpMime.tiff,
|
|
83
71
|
};
|
|
84
72
|
|
|
85
73
|
const pngFilterMap = {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
74
|
+
Auto: PNGFilterType.AUTO,
|
|
75
|
+
None: PNGFilterType.NONE,
|
|
76
|
+
Sub: PNGFilterType.SUB,
|
|
77
|
+
Up: PNGFilterType.UP,
|
|
78
|
+
Average: PNGFilterType.AVERAGE,
|
|
79
|
+
Paeth: PNGFilterType.PATH,
|
|
92
80
|
};
|
|
93
81
|
|
|
94
82
|
const mime = formatMap[format];
|
|
@@ -103,18 +91,25 @@ class ConvertImageFormat extends Operation {
|
|
|
103
91
|
throw new OperationError(`Error opening image file. (${err})`);
|
|
104
92
|
}
|
|
105
93
|
try {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
94
|
+
let buffer;
|
|
95
|
+
switch (mime) {
|
|
96
|
+
case JimpMime.jpeg:
|
|
97
|
+
buffer = await image.getBuffer(mime, {
|
|
98
|
+
quality: jpegQuality,
|
|
99
|
+
});
|
|
109
100
|
break;
|
|
110
|
-
case
|
|
111
|
-
image.
|
|
112
|
-
|
|
101
|
+
case JimpMime.png:
|
|
102
|
+
buffer = await image.getBuffer(mime, {
|
|
103
|
+
filterType: pngFilterMap[pngFilterType],
|
|
104
|
+
deflateLevel: pngDeflateLevel,
|
|
105
|
+
});
|
|
106
|
+
break;
|
|
107
|
+
default:
|
|
108
|
+
buffer = await image.getBuffer(mime);
|
|
113
109
|
break;
|
|
114
110
|
}
|
|
115
111
|
|
|
116
|
-
|
|
117
|
-
return imageBuffer.buffer;
|
|
112
|
+
return buffer.buffer;
|
|
118
113
|
} catch (err) {
|
|
119
114
|
throw new OperationError(`Error converting image format. (${err})`);
|
|
120
115
|
}
|
|
@@ -137,7 +132,6 @@ class ConvertImageFormat extends Operation {
|
|
|
137
132
|
|
|
138
133
|
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
|
139
134
|
}
|
|
140
|
-
|
|
141
135
|
}
|
|
142
136
|
|
|
143
137
|
export default ConvertImageFormat;
|
|
@@ -9,13 +9,18 @@ import OperationError from "../errors/OperationError.mjs";
|
|
|
9
9
|
import { isImage } from "../lib/FileType.mjs";
|
|
10
10
|
import { toBase64 } from "../lib/Base64.mjs";
|
|
11
11
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
|
12
|
-
import
|
|
12
|
+
import {
|
|
13
|
+
Jimp,
|
|
14
|
+
JimpMime,
|
|
15
|
+
ResizeStrategy,
|
|
16
|
+
HorizontalAlign,
|
|
17
|
+
VerticalAlign,
|
|
18
|
+
} from "jimp";
|
|
13
19
|
|
|
14
20
|
/**
|
|
15
21
|
* Cover Image operation
|
|
16
22
|
*/
|
|
17
23
|
class CoverImage extends Operation {
|
|
18
|
-
|
|
19
24
|
/**
|
|
20
25
|
* CoverImage constructor
|
|
21
26
|
*/
|
|
@@ -24,7 +29,8 @@ class CoverImage extends Operation {
|
|
|
24
29
|
|
|
25
30
|
this.name = "Cover Image";
|
|
26
31
|
this.module = "Image";
|
|
27
|
-
this.description =
|
|
32
|
+
this.description =
|
|
33
|
+
"Scales the image to the given width and height, keeping the aspect ratio. The image may be clipped.";
|
|
28
34
|
this.infoURL = "";
|
|
29
35
|
this.inputType = "ArrayBuffer";
|
|
30
36
|
this.outputType = "ArrayBuffer";
|
|
@@ -34,33 +40,25 @@ class CoverImage extends Operation {
|
|
|
34
40
|
name: "Width",
|
|
35
41
|
type: "number",
|
|
36
42
|
value: 100,
|
|
37
|
-
min: 1
|
|
43
|
+
min: 1,
|
|
38
44
|
},
|
|
39
45
|
{
|
|
40
46
|
name: "Height",
|
|
41
47
|
type: "number",
|
|
42
48
|
value: 100,
|
|
43
|
-
min: 1
|
|
49
|
+
min: 1,
|
|
44
50
|
},
|
|
45
51
|
{
|
|
46
52
|
name: "Horizontal align",
|
|
47
53
|
type: "option",
|
|
48
|
-
value: [
|
|
49
|
-
|
|
50
|
-
"Center",
|
|
51
|
-
"Right"
|
|
52
|
-
],
|
|
53
|
-
defaultIndex: 1
|
|
54
|
+
value: ["Left", "Center", "Right"],
|
|
55
|
+
defaultIndex: 1,
|
|
54
56
|
},
|
|
55
57
|
{
|
|
56
58
|
name: "Vertical align",
|
|
57
59
|
type: "option",
|
|
58
|
-
value: [
|
|
59
|
-
|
|
60
|
-
"Middle",
|
|
61
|
-
"Bottom"
|
|
62
|
-
],
|
|
63
|
-
defaultIndex: 1
|
|
60
|
+
value: ["Top", "Middle", "Bottom"],
|
|
61
|
+
defaultIndex: 1,
|
|
64
62
|
},
|
|
65
63
|
{
|
|
66
64
|
name: "Resizing algorithm",
|
|
@@ -70,10 +68,10 @@ class CoverImage extends Operation {
|
|
|
70
68
|
"Bilinear",
|
|
71
69
|
"Bicubic",
|
|
72
70
|
"Hermite",
|
|
73
|
-
"Bezier"
|
|
71
|
+
"Bezier",
|
|
74
72
|
],
|
|
75
|
-
defaultIndex: 1
|
|
76
|
-
}
|
|
73
|
+
defaultIndex: 1,
|
|
74
|
+
},
|
|
77
75
|
];
|
|
78
76
|
}
|
|
79
77
|
|
|
@@ -86,20 +84,20 @@ class CoverImage extends Operation {
|
|
|
86
84
|
const [width, height, hAlign, vAlign, alg] = args;
|
|
87
85
|
|
|
88
86
|
const resizeMap = {
|
|
89
|
-
"Nearest Neighbour":
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
87
|
+
"Nearest Neighbour": ResizeStrategy.NEAREST_NEIGHBOR,
|
|
88
|
+
Bilinear: ResizeStrategy.BILINEAR,
|
|
89
|
+
Bicubic: ResizeStrategy.BICUBIC,
|
|
90
|
+
Hermite: ResizeStrategy.HERMITE,
|
|
91
|
+
Bezier: ResizeStrategy.BEZIER,
|
|
94
92
|
};
|
|
95
93
|
|
|
96
94
|
const alignMap = {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
95
|
+
Left: HorizontalAlign.LEFT,
|
|
96
|
+
Center: HorizontalAlign.CENTER,
|
|
97
|
+
Right: HorizontalAlign.RIGHT,
|
|
98
|
+
Top: VerticalAlign.TOP,
|
|
99
|
+
Middle: VerticalAlign.MIDDLE,
|
|
100
|
+
Bottom: VerticalAlign.BOTTOM,
|
|
103
101
|
};
|
|
104
102
|
|
|
105
103
|
if (!isImage(input)) {
|
|
@@ -108,19 +106,24 @@ class CoverImage extends Operation {
|
|
|
108
106
|
|
|
109
107
|
let image;
|
|
110
108
|
try {
|
|
111
|
-
image = await
|
|
109
|
+
image = await Jimp.read(input);
|
|
112
110
|
} catch (err) {
|
|
113
111
|
throw new OperationError(`Error loading image. (${err})`);
|
|
114
112
|
}
|
|
115
113
|
try {
|
|
116
114
|
if (isWorkerEnvironment())
|
|
117
115
|
self.sendStatusMessage("Covering image...");
|
|
118
|
-
image.cover(
|
|
116
|
+
image.cover({
|
|
117
|
+
w: width,
|
|
118
|
+
h: height,
|
|
119
|
+
align: alignMap[hAlign] | alignMap[vAlign],
|
|
120
|
+
mode: resizeMap[alg],
|
|
121
|
+
});
|
|
119
122
|
let imageBuffer;
|
|
120
|
-
if (image.
|
|
121
|
-
imageBuffer = await image.
|
|
123
|
+
if (image.mime === "image/gif") {
|
|
124
|
+
imageBuffer = await image.getBuffer(JimpMime.png);
|
|
122
125
|
} else {
|
|
123
|
-
imageBuffer = await image.
|
|
126
|
+
imageBuffer = await image.getBuffer(image.mime);
|
|
124
127
|
}
|
|
125
128
|
return imageBuffer.buffer;
|
|
126
129
|
} catch (err) {
|
|
@@ -144,7 +147,6 @@ class CoverImage extends Operation {
|
|
|
144
147
|
|
|
145
148
|
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
|
146
149
|
}
|
|
147
|
-
|
|
148
150
|
}
|
|
149
151
|
|
|
150
152
|
export default CoverImage;
|
|
@@ -9,13 +9,12 @@ import OperationError from "../errors/OperationError.mjs";
|
|
|
9
9
|
import { isImage } from "../lib/FileType.mjs";
|
|
10
10
|
import { toBase64 } from "../lib/Base64.mjs";
|
|
11
11
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
|
12
|
-
import Jimp from "jimp
|
|
12
|
+
import { Jimp, JimpMime } from "jimp";
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Crop Image operation
|
|
16
16
|
*/
|
|
17
17
|
class CropImage extends Operation {
|
|
18
|
-
|
|
19
18
|
/**
|
|
20
19
|
* CropImage constructor
|
|
21
20
|
*/
|
|
@@ -24,7 +23,8 @@ class CropImage extends Operation {
|
|
|
24
23
|
|
|
25
24
|
this.name = "Crop Image";
|
|
26
25
|
this.module = "Image";
|
|
27
|
-
this.description =
|
|
26
|
+
this.description =
|
|
27
|
+
"Crops an image to the specified region, or automatically crops edges.<br><br><b><u>Autocrop</u></b><br>Automatically crops same-colour borders from the image.<br><br><u>Autocrop tolerance</u><br>A percentage value for the tolerance of colour difference between pixels.<br><br><u>Only autocrop frames</u><br>Only crop real frames (all sides must have the same border)<br><br><u>Symmetric autocrop</u><br>Force autocrop to be symmetric (top/bottom and left/right are cropped by the same amount)<br><br><u>Autocrop keep border</u><br>The number of pixels of border to leave around the image.";
|
|
28
28
|
this.infoURL = "https://wikipedia.org/wiki/Cropping_(image)";
|
|
29
29
|
this.inputType = "ArrayBuffer";
|
|
30
30
|
this.outputType = "ArrayBuffer";
|
|
@@ -34,30 +34,30 @@ class CropImage extends Operation {
|
|
|
34
34
|
name: "X Position",
|
|
35
35
|
type: "number",
|
|
36
36
|
value: 0,
|
|
37
|
-
min: 0
|
|
37
|
+
min: 0,
|
|
38
38
|
},
|
|
39
39
|
{
|
|
40
40
|
name: "Y Position",
|
|
41
41
|
type: "number",
|
|
42
42
|
value: 0,
|
|
43
|
-
min: 0
|
|
43
|
+
min: 0,
|
|
44
44
|
},
|
|
45
45
|
{
|
|
46
46
|
name: "Width",
|
|
47
47
|
type: "number",
|
|
48
48
|
value: 10,
|
|
49
|
-
min: 1
|
|
49
|
+
min: 1,
|
|
50
50
|
},
|
|
51
51
|
{
|
|
52
52
|
name: "Height",
|
|
53
53
|
type: "number",
|
|
54
54
|
value: 10,
|
|
55
|
-
min: 1
|
|
55
|
+
min: 1,
|
|
56
56
|
},
|
|
57
57
|
{
|
|
58
58
|
name: "Autocrop",
|
|
59
59
|
type: "boolean",
|
|
60
|
-
value: false
|
|
60
|
+
value: false,
|
|
61
61
|
},
|
|
62
62
|
{
|
|
63
63
|
name: "Autocrop tolerance (%)",
|
|
@@ -65,24 +65,24 @@ class CropImage extends Operation {
|
|
|
65
65
|
value: 0.02,
|
|
66
66
|
min: 0,
|
|
67
67
|
max: 100,
|
|
68
|
-
step: 0.01
|
|
68
|
+
step: 0.01,
|
|
69
69
|
},
|
|
70
70
|
{
|
|
71
71
|
name: "Only autocrop frames",
|
|
72
72
|
type: "boolean",
|
|
73
|
-
value: true
|
|
73
|
+
value: true,
|
|
74
74
|
},
|
|
75
75
|
{
|
|
76
76
|
name: "Symmetric autocrop",
|
|
77
77
|
type: "boolean",
|
|
78
|
-
value: false
|
|
78
|
+
value: false,
|
|
79
79
|
},
|
|
80
80
|
{
|
|
81
81
|
name: "Autocrop keep border (px)",
|
|
82
82
|
type: "number",
|
|
83
83
|
value: 0,
|
|
84
|
-
min: 0
|
|
85
|
-
}
|
|
84
|
+
min: 0,
|
|
85
|
+
},
|
|
86
86
|
];
|
|
87
87
|
}
|
|
88
88
|
|
|
@@ -92,7 +92,17 @@ class CropImage extends Operation {
|
|
|
92
92
|
* @returns {byteArray}
|
|
93
93
|
*/
|
|
94
94
|
async run(input, args) {
|
|
95
|
-
const [
|
|
95
|
+
const [
|
|
96
|
+
xPos,
|
|
97
|
+
yPos,
|
|
98
|
+
width,
|
|
99
|
+
height,
|
|
100
|
+
autocrop,
|
|
101
|
+
autoTolerance,
|
|
102
|
+
autoFrames,
|
|
103
|
+
autoSymmetric,
|
|
104
|
+
autoBorder,
|
|
105
|
+
] = args;
|
|
96
106
|
if (!isImage(input)) {
|
|
97
107
|
throw new OperationError("Invalid file type.");
|
|
98
108
|
}
|
|
@@ -108,20 +118,25 @@ class CropImage extends Operation {
|
|
|
108
118
|
self.sendStatusMessage("Cropping image...");
|
|
109
119
|
if (autocrop) {
|
|
110
120
|
image.autocrop({
|
|
111
|
-
tolerance:
|
|
121
|
+
tolerance: autoTolerance / 100,
|
|
112
122
|
cropOnlyFrames: autoFrames,
|
|
113
123
|
cropSymmetric: autoSymmetric,
|
|
114
|
-
leaveBorder: autoBorder
|
|
124
|
+
leaveBorder: autoBorder,
|
|
115
125
|
});
|
|
116
126
|
} else {
|
|
117
|
-
image.crop(
|
|
127
|
+
image.crop({
|
|
128
|
+
x: xPos,
|
|
129
|
+
y: yPos,
|
|
130
|
+
w: width,
|
|
131
|
+
h: height,
|
|
132
|
+
});
|
|
118
133
|
}
|
|
119
134
|
|
|
120
135
|
let imageBuffer;
|
|
121
|
-
if (image.
|
|
122
|
-
imageBuffer = await image.
|
|
136
|
+
if (image.mime === "image/gif") {
|
|
137
|
+
imageBuffer = await image.getBuffer(JimpMime.png);
|
|
123
138
|
} else {
|
|
124
|
-
imageBuffer = await image.
|
|
139
|
+
imageBuffer = await image.getBuffer(image.mime);
|
|
125
140
|
}
|
|
126
141
|
return imageBuffer.buffer;
|
|
127
142
|
} catch (err) {
|
|
@@ -145,7 +160,6 @@ class CropImage extends Operation {
|
|
|
145
160
|
|
|
146
161
|
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
|
147
162
|
}
|
|
148
|
-
|
|
149
163
|
}
|
|
150
164
|
|
|
151
165
|
export default CropImage;
|