mirror of
https://github.com/gchq/CyberChef
synced 2025-12-05 23:53:27 +00:00
Compare commits
65 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a43dff558a | ||
|
|
f39006ea1d | ||
|
|
2355ef9d31 | ||
|
|
13b0ab73d0 | ||
|
|
3766982734 | ||
|
|
54a864e18c | ||
|
|
9a1f4e40dd | ||
|
|
5a83ef4f48 | ||
|
|
a7d4e37851 | ||
|
|
57e71f0e1a | ||
|
|
30be3cab53 | ||
|
|
0e6626bf39 | ||
|
|
bb0eaf4597 | ||
|
|
8ada3bae0c | ||
|
|
db72cad610 | ||
|
|
bed66298d1 | ||
|
|
44643c151a | ||
|
|
bc1bd2427d | ||
|
|
6726994ad5 | ||
|
|
5abc5279f5 | ||
|
|
1135ca5fb4 | ||
|
|
be08a62f52 | ||
|
|
f473807459 | ||
|
|
4c9a61f5a7 | ||
|
|
550ab403f6 | ||
|
|
d148cae814 | ||
|
|
f22211ce8c | ||
|
|
f9c24f2528 | ||
|
|
6f6786d79e | ||
|
|
a5ea7f7d58 | ||
|
|
d637ac7633 | ||
|
|
c1ad2386ef | ||
|
|
b0b6de116d | ||
|
|
1b161f997b | ||
|
|
b99af58636 | ||
|
|
c46928aefe | ||
|
|
4c27a46d35 | ||
|
|
daee7ac761 | ||
|
|
824d8e929a | ||
|
|
862d2adf1d | ||
|
|
0bcf57e89c | ||
|
|
5225874498 | ||
|
|
802493fec4 | ||
|
|
8fc0e012e3 | ||
|
|
b7fb9635e5 | ||
|
|
f988a958bb | ||
|
|
c80cb57b07 | ||
|
|
dec28e16d4 | ||
|
|
99bef09e0e | ||
|
|
c97e77c765 | ||
|
|
e44a22e143 | ||
|
|
c2496fe63e | ||
|
|
6a01e40394 | ||
|
|
b312e17904 | ||
|
|
2cd3e9cacd | ||
|
|
ce72acdd61 | ||
|
|
8e74acbf3e | ||
|
|
4fafa39e54 | ||
|
|
bb7487c476 | ||
|
|
308195279c | ||
|
|
e95b7075b9 | ||
|
|
dfbc1beccd | ||
|
|
3e428c044a | ||
|
|
11451ac6b9 | ||
|
|
21a8d03201 |
22
CHANGELOG.md
22
CHANGELOG.md
@@ -2,6 +2,19 @@
|
||||
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.37.0] - 2019-07-03
|
||||
- 'CRC-8 Checksum' operation added [@MShwed] | [#591]
|
||||
|
||||
### [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]
|
||||
|
||||
### [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]
|
||||
|
||||
### [8.33.0] - 2019-06-27
|
||||
- 'Bzip2 Compress' operation added and 'Bzip2 Decompress' operation greatly improved [@artemisbot] | [#531]
|
||||
|
||||
@@ -136,6 +149,10 @@ All major and minor version changes will be documented in this file. Details of
|
||||
|
||||
|
||||
|
||||
[8.37.0]: https://github.com/gchq/CyberChef/releases/tag/v8.37.0
|
||||
[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
|
||||
[8.32.0]: https://github.com/gchq/CyberChef/releases/tag/v8.32.0
|
||||
[8.31.0]: https://github.com/gchq/CyberChef/releases/tag/v8.31.0
|
||||
@@ -198,6 +215,7 @@ All major and minor version changes will be documented in this file. Details of
|
||||
[@anthony-arnold]: https://github.com/anthony-arnold
|
||||
[@masq]: https://github.com/masq
|
||||
[@Ge0rg3]: https://github.com/Ge0rg3
|
||||
[@MShwed]: https://github.com/MShwed
|
||||
|
||||
[#95]: https://github.com/gchq/CyberChef/pull/299
|
||||
[#173]: https://github.com/gchq/CyberChef/pull/173
|
||||
@@ -238,8 +256,12 @@ 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
|
||||
[#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
|
||||
[#591]: https://github.com/gchq/CyberChef/pull/591
|
||||
|
||||
@@ -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
|
||||
|
||||
200
package-lock.json
generated
200
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cyberchef",
|
||||
"version": "8.33.1",
|
||||
"version": "8.37.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -5346,25 +5346,29 @@
|
||||
"dependencies": {
|
||||
"abbrev": {
|
||||
"version": "1.1.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
|
||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
|
||||
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"are-we-there-yet": {
|
||||
"version": "1.1.5",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
|
||||
"integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5374,13 +5378,15 @@
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5390,37 +5396,43 @@
|
||||
},
|
||||
"chownr": {
|
||||
"version": "1.1.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
|
||||
"integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
|
||||
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
||||
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.1.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
|
||||
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5429,25 +5441,29 @@
|
||||
},
|
||||
"deep-extend": {
|
||||
"version": "0.6.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
|
||||
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"delegates": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
|
||||
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"detect-libc": {
|
||||
"version": "1.0.3",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
|
||||
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"fs-minipass": {
|
||||
"version": "1.2.5",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz",
|
||||
"integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5456,13 +5472,15 @@
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"gauge": {
|
||||
"version": "2.7.4",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
|
||||
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5478,7 +5496,8 @@
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.3",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
|
||||
"integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5492,13 +5511,15 @@
|
||||
},
|
||||
"has-unicode": {
|
||||
"version": "2.0.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
|
||||
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"iconv-lite": {
|
||||
"version": "0.4.24",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5507,7 +5528,8 @@
|
||||
},
|
||||
"ignore-walk": {
|
||||
"version": "3.0.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz",
|
||||
"integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5516,7 +5538,8 @@
|
||||
},
|
||||
"inflight": {
|
||||
"version": "1.0.6",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5526,19 +5549,22 @@
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
|
||||
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
|
||||
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5547,13 +5573,15 @@
|
||||
},
|
||||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5562,13 +5590,15 @@
|
||||
},
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.3.5",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
|
||||
"integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5578,7 +5608,8 @@
|
||||
},
|
||||
"minizlib": {
|
||||
"version": "1.2.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz",
|
||||
"integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5587,7 +5618,8 @@
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
||||
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5596,13 +5628,15 @@
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
|
||||
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"needle": {
|
||||
"version": "2.3.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/needle/-/needle-2.3.0.tgz",
|
||||
"integrity": "sha512-QBZu7aAFR0522EyaXZM0FZ9GLpq6lvQ3uq8gteiDUp7wKdy0lSd2hPlgFwVuW1CBkfEs9PfDQsQzZghLs/psdg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5613,7 +5647,8 @@
|
||||
},
|
||||
"node-pre-gyp": {
|
||||
"version": "0.12.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz",
|
||||
"integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5631,7 +5666,8 @@
|
||||
},
|
||||
"nopt": {
|
||||
"version": "4.0.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
|
||||
"integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5641,13 +5677,15 @@
|
||||
},
|
||||
"npm-bundled": {
|
||||
"version": "1.0.6",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz",
|
||||
"integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"npm-packlist": {
|
||||
"version": "1.4.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.1.tgz",
|
||||
"integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5657,7 +5695,8 @@
|
||||
},
|
||||
"npmlog": {
|
||||
"version": "4.1.2",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
|
||||
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5669,19 +5708,22 @@
|
||||
},
|
||||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
|
||||
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5690,19 +5732,22 @@
|
||||
},
|
||||
"os-homedir": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
|
||||
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"os-tmpdir": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"osenv": {
|
||||
"version": "0.1.5",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
|
||||
"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5712,19 +5757,22 @@
|
||||
},
|
||||
"path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"process-nextick-args": {
|
||||
"version": "2.0.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
|
||||
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"rc": {
|
||||
"version": "1.2.8",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
|
||||
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5736,7 +5784,8 @@
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "1.2.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
}
|
||||
@@ -5744,7 +5793,8 @@
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5759,7 +5809,8 @@
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "2.6.3",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
|
||||
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5768,43 +5819,50 @@
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"sax": {
|
||||
"version": "1.2.4",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
|
||||
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"set-blocking": {
|
||||
"version": "2.0.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
||||
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"signal-exit": {
|
||||
"version": "3.0.2",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
|
||||
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"string-width": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
|
||||
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5815,7 +5873,8 @@
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5824,7 +5883,8 @@
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "3.0.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5833,13 +5893,15 @@
|
||||
},
|
||||
"strip-json-comments": {
|
||||
"version": "2.0.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
|
||||
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"tar": {
|
||||
"version": "4.4.8",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz",
|
||||
"integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5854,13 +5916,15 @@
|
||||
},
|
||||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"wide-align": {
|
||||
"version": "1.1.3",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
|
||||
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5869,13 +5933,15 @@
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.0.3",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
|
||||
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cyberchef",
|
||||
"version": "8.33.1",
|
||||
"version": "8.37.0",
|
||||
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
||||
"author": "n1474335 <n1474335@gmail.com>",
|
||||
"homepage": "https://gchq.github.io/CyberChef",
|
||||
|
||||
@@ -201,9 +201,11 @@ class Utils {
|
||||
* Utils.parseEscapedChars("\\n");
|
||||
*/
|
||||
static parseEscapedChars(str) {
|
||||
return str.replace(/(\\)?\\([bfnrtv'"]|[0-3][0-7]{2}|[0-7]{1,2}|x[\da-fA-F]{2}|u[\da-fA-F]{4}|u\{[\da-fA-F]{1,6}\})/g, function(m, a, b) {
|
||||
return str.replace(/(\\)?\\([bfnrtv'"]|[0-3][0-7]{2}|[0-7]{1,2}|x[\da-fA-F]{2}|u[\da-fA-F]{4}|u\{[\da-fA-F]{1,6}\}|\\)/g, function(m, a, b) {
|
||||
if (a === "\\") return "\\"+b;
|
||||
switch (b[0]) {
|
||||
case "\\":
|
||||
return "\\";
|
||||
case "0":
|
||||
case "1":
|
||||
case "2":
|
||||
|
||||
@@ -316,6 +316,7 @@
|
||||
"Fletcher-32 Checksum",
|
||||
"Fletcher-64 Checksum",
|
||||
"Adler-32 Checksum",
|
||||
"CRC-8 Checksum",
|
||||
"CRC-16 Checksum",
|
||||
"CRC-32 Checksum",
|
||||
"TCP/IP Checksum"
|
||||
@@ -384,6 +385,9 @@
|
||||
"Contain Image",
|
||||
"Cover Image",
|
||||
"Image Hue/Saturation/Lightness",
|
||||
"Sharpen Image",
|
||||
"Convert Image Format",
|
||||
"Add Text To Image",
|
||||
"Hex Density chart",
|
||||
"Scatter chart",
|
||||
"Series chart",
|
||||
|
||||
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 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.");
|
||||
}
|
||||
}
|
||||
266
src/core/operations/AddTextToImage.mjs
Normal file
266
src/core/operations/AddTextToImage.mjs
Normal file
@@ -0,0 +1,266 @@
|
||||
/**
|
||||
* @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.<br><br>Text can be horizontally or vertically aligned, or the position can be manually specified.<br>Variants of the Roboto font face are available in any size or colour.";
|
||||
this.infoURL = "";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "ArrayBuffer";
|
||||
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 {ArrayBuffer} 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(new Uint8Array(input))) {
|
||||
throw new OperationError("Invalid file type.");
|
||||
}
|
||||
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error loading image. (${err})`);
|
||||
}
|
||||
try {
|
||||
if (ENVIRONMENT_IS_WORKER())
|
||||
self.sendStatusMessage("Adding text to image...");
|
||||
|
||||
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 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")
|
||||
]);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 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 > 1) {
|
||||
textImage.scale(scaleFactor, jimp.RESIZE_BICUBIC);
|
||||
} else {
|
||||
textImage.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) - (textImage.getWidth() / 2);
|
||||
break;
|
||||
case "Right":
|
||||
xPos = image.getWidth() - textImage.getWidth();
|
||||
break;
|
||||
}
|
||||
|
||||
switch (vAlign) {
|
||||
case "Top":
|
||||
yPos = 0;
|
||||
break;
|
||||
case "Middle":
|
||||
yPos = (image.getHeight() / 2) - (textImage.getHeight() / 2);
|
||||
break;
|
||||
case "Bottom":
|
||||
yPos = image.getHeight() - textImage.getHeight();
|
||||
break;
|
||||
}
|
||||
|
||||
// Blit the rendered text image onto the original source image
|
||||
image.blit(textImage, xPos, yPos);
|
||||
|
||||
let imageBuffer;
|
||||
if (image.getMIME() === "image/gif") {
|
||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
} else {
|
||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
}
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error adding text to image. (${err})`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the blurred image using HTML for web apps
|
||||
*
|
||||
* @param {ArrayBuffer} data
|
||||
* @returns {html}
|
||||
*/
|
||||
present(data) {
|
||||
if (!data.byteLength) return "";
|
||||
const dataArray = new Uint8Array(data);
|
||||
|
||||
const type = isImage(dataArray);
|
||||
if (!type) {
|
||||
throw new OperationError("Invalid file type.");
|
||||
}
|
||||
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default AddTextToImage;
|
||||
@@ -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
|
||||
@@ -25,8 +26,8 @@ class BlurImage extends Operation {
|
||||
this.module = "Image";
|
||||
this.description = "Applies a blur effect to the image.<br><br>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 = [
|
||||
{
|
||||
@@ -44,37 +45,44 @@ 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})`);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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.buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error blurring image. (${err})`);
|
||||
}
|
||||
@@ -83,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 `<img src="data:${type};base64,${toBase64(data)}">`;
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
157
src/core/operations/CRC8Checksum.mjs
Normal file
157
src/core/operations/CRC8Checksum.mjs
Normal file
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
* @author mshwed [m@ttshwed.com]
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
import { toHexFast } from "../lib/Hex";
|
||||
|
||||
/**
|
||||
* CRC-8 Checksum operation
|
||||
*/
|
||||
class CRC8Checksum extends Operation {
|
||||
|
||||
/**
|
||||
* CRC8Checksum constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "CRC-8 Checksum";
|
||||
this.module = "Crypto";
|
||||
this.description = "A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data.<br><br>The CRC was invented by W. Wesley Peterson in 1961.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Cyclic_redundancy_check";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Algorithm",
|
||||
"type": "option",
|
||||
"value": [
|
||||
"CRC-8",
|
||||
"CRC-8/CDMA2000",
|
||||
"CRC-8/DARC",
|
||||
"CRC-8/DVB-S2",
|
||||
"CRC-8/EBU",
|
||||
"CRC-8/I-CODE",
|
||||
"CRC-8/ITU",
|
||||
"CRC-8/MAXIM",
|
||||
"CRC-8/ROHC",
|
||||
"CRC-8/WCDMA"
|
||||
]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the pre-computed lookup table for byte division
|
||||
*
|
||||
* @param polynomial
|
||||
*/
|
||||
calculateCRC8LookupTable(polynomial) {
|
||||
const crc8Table = new Uint8Array(256);
|
||||
|
||||
let currentByte;
|
||||
for (let i = 0; i < 256; i++) {
|
||||
currentByte = i;
|
||||
for (let bit = 0; bit < 8; bit++) {
|
||||
if ((currentByte & 0x80) !== 0) {
|
||||
currentByte <<= 1;
|
||||
currentByte ^= polynomial;
|
||||
} else {
|
||||
currentByte <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
crc8Table[i] = currentByte;
|
||||
}
|
||||
|
||||
return crc8Table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the CRC-8 Checksum from an input
|
||||
*
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {number} polynomial
|
||||
* @param {number} initializationValue
|
||||
* @param {boolean} inputReflection
|
||||
* @param {boolean} outputReflection
|
||||
* @param {number} xorOut
|
||||
*/
|
||||
calculateCRC8(input, polynomial, initializationValue, inputReflection, outputReflection, xorOut) {
|
||||
const crcSize = 8;
|
||||
const crcTable = this.calculateCRC8LookupTable(polynomial);
|
||||
|
||||
let crc = initializationValue !== 0 ? initializationValue : 0;
|
||||
let currentByte, position;
|
||||
|
||||
input = new Uint8Array(input);
|
||||
for (const inputByte of input) {
|
||||
currentByte = inputReflection ? this.reverseBits(inputByte, crcSize) : inputByte;
|
||||
|
||||
position = (currentByte ^ crc) & 255;
|
||||
crc = crcTable[position];
|
||||
}
|
||||
|
||||
crc = outputReflection ? this.reverseBits(crc, crcSize) : crc;
|
||||
|
||||
if (xorOut !== 0) crc = crc ^ xorOut;
|
||||
|
||||
return toHexFast(new Uint8Array([crc]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the bits for a given input byte.
|
||||
*
|
||||
* @param {number} input
|
||||
*/
|
||||
reverseBits(input, hashSize) {
|
||||
let reversedByte = 0;
|
||||
for (let i = hashSize - 1; i >= 0; i--) {
|
||||
reversedByte |= ((input & 1) << i);
|
||||
input >>= 1;
|
||||
}
|
||||
|
||||
return reversedByte;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const algorithm = args[0];
|
||||
|
||||
switch (algorithm) {
|
||||
case "CRC-8":
|
||||
return this.calculateCRC8(input, 0x7, 0x0, false, false, 0x0);
|
||||
case "CRC-8/CDMA2000":
|
||||
return this.calculateCRC8(input, 0x9B, 0xFF, false, false, 0x0);
|
||||
case "CRC-8/DARC":
|
||||
return this.calculateCRC8(input, 0x39, 0x0, true, true, 0x0);
|
||||
case "CRC-8/DVB-S2":
|
||||
return this.calculateCRC8(input, 0xD5, 0x0, false, false, 0x0);
|
||||
case "CRC-8/EBU":
|
||||
return this.calculateCRC8(input, 0x1D, 0xFF, true, true, 0x0);
|
||||
case "CRC-8/I-CODE":
|
||||
return this.calculateCRC8(input, 0x1D, 0xFD, false, false, 0x0);
|
||||
case "CRC-8/ITU":
|
||||
return this.calculateCRC8(input, 0x7, 0x0, false, false, 0x55);
|
||||
case "CRC-8/MAXIM":
|
||||
return this.calculateCRC8(input, 0x31, 0x0, true, true, 0x0);
|
||||
case "CRC-8/ROHC":
|
||||
return this.calculateCRC8(input, 0x7, 0xFF, true, true, 0x0);
|
||||
case "CRC-8/WCDMA":
|
||||
return this.calculateCRC8(input, 0x9B, 0x0, true, true, 0x0);
|
||||
default:
|
||||
throw new OperationError("Unknown checksum algorithm");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default CRC8Checksum;
|
||||
@@ -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 = [
|
||||
{
|
||||
@@ -72,17 +72,22 @@ class ContainImage extends Operation {
|
||||
"Bezier"
|
||||
],
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "Opaque background",
|
||||
type: "boolean",
|
||||
value: true
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @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,
|
||||
@@ -101,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})`);
|
||||
}
|
||||
@@ -115,8 +120,20 @@ class ContainImage extends Operation {
|
||||
if (ENVIRONMENT_IS_WORKER())
|
||||
self.sendStatusMessage("Containing image...");
|
||||
image.contain(width, height, alignMap[hAlign] | alignMap[vAlign], resizeMap[alg]);
|
||||
const imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
return [...imageBuffer];
|
||||
|
||||
if (opaqueBg) {
|
||||
const newImage = await jimp.read(width, height, 0x000000FF);
|
||||
newImage.blit(image, 0, 0);
|
||||
image = newImage;
|
||||
}
|
||||
|
||||
let imageBuffer;
|
||||
if (image.getMIME() === "image/gif") {
|
||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
} else {
|
||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
}
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error containing image. (${err})`);
|
||||
}
|
||||
@@ -124,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 `<img src="data:${type};base64,${toBase64(data)}">`;
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
143
src/core/operations/ConvertImageFormat.mjs
Normal file
143
src/core/operations/ConvertImageFormat.mjs
Normal file
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* @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:<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.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Image_file_formats";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "ArrayBuffer";
|
||||
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 {ArrayBuffer} 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(new Uint8Array(input))) {
|
||||
throw new OperationError("Invalid file format.");
|
||||
}
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(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.buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error converting image format. (${err})`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the converted image using HTML for web apps
|
||||
*
|
||||
* @param {ArrayBuffer} data
|
||||
* @returns {html}
|
||||
*/
|
||||
present(data) {
|
||||
if (!data.byteLength) return "";
|
||||
const dataArray = new Uint8Array(data);
|
||||
|
||||
const type = isImage(dataArray);
|
||||
if (!type) {
|
||||
throw new OperationError("Invalid file type.");
|
||||
}
|
||||
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ConvertImageFormat;
|
||||
@@ -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})`);
|
||||
}
|
||||
@@ -115,8 +115,13 @@ 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);
|
||||
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.buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error covering image. (${err})`);
|
||||
}
|
||||
@@ -124,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 `<img src="data:${type};base64,${toBase64(data)}">`;
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@ class CropImage extends Operation {
|
||||
this.module = "Image";
|
||||
this.description = "Crops an image to the specified region, or automatically crops edges.<br><br><b><u>Autocrop</u></b><br>Automatically crops same-colour borders from the image.<br><br><u>Autocrop tolerance</u><br>A percentage value for the tolerance of colour difference between pixels.<br><br><u>Only autocrop frames</u><br>Only crop real frames (all sides must have the same border)<br><br><u>Symmetric autocrop</u><br>Force autocrop to be symmetric (top/bottom and left/right are cropped by the same amount)<br><br><u>Autocrop keep border</u><br>The number of pixels of border to leave around the image.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Cropping_(image)";
|
||||
this.inputType = "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})`);
|
||||
}
|
||||
@@ -116,8 +116,13 @@ class CropImage extends Operation {
|
||||
image.crop(xPos, yPos, width, height);
|
||||
}
|
||||
|
||||
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.buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error cropping image. (${err})`);
|
||||
}
|
||||
@@ -125,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 `<img src="data:${type};base64,${toBase64(data)}">`;
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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})`);
|
||||
}
|
||||
@@ -51,8 +51,14 @@ class DitherImage extends Operation {
|
||||
if (ENVIRONMENT_IS_WORKER())
|
||||
self.sendStatusMessage("Applying dither to image...");
|
||||
image.dither565();
|
||||
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.buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error applying dither to image. (${err})`);
|
||||
}
|
||||
@@ -60,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 `<img src="data:${type};base64,${toBase64(data)}">`;
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,8 +4,13 @@
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import * as d3temp from "d3";
|
||||
import * as nodomtemp from "nodom";
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
|
||||
const d3 = d3temp.default ? d3temp.default : d3temp;
|
||||
const nodom = nodomtemp.default ? nodomtemp.default: nodomtemp;
|
||||
|
||||
/**
|
||||
* Entropy operation
|
||||
@@ -19,30 +24,45 @@ class Entropy extends Operation {
|
||||
super();
|
||||
|
||||
this.name = "Entropy";
|
||||
this.module = "Default";
|
||||
this.module = "Charts";
|
||||
this.description = "Shannon Entropy, in the context of information theory, is a measure of the rate at which information is produced by a source of data. It can be used, in a broad sense, to detect whether data is likely to be structured or unstructured. 8 is the maximum, representing highly unstructured, 'random' data. English language text usually falls somewhere between 3.5 and 5. Properly encrypted or compressed data should have an entropy of over 7.5.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Entropy_(information_theory)";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "number";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "json";
|
||||
this.presentType = "html";
|
||||
this.args = [];
|
||||
this.args = [
|
||||
{
|
||||
"name": "Visualisation",
|
||||
"type": "option",
|
||||
"value": ["Shannon scale", "Histogram (Bar)", "Histogram (Line)", "Curve", "Image"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* Calculates the frequency of bytes in the input.
|
||||
*
|
||||
* @param {Uint8Array} input
|
||||
* @returns {number}
|
||||
*/
|
||||
run(input, args) {
|
||||
calculateShannonEntropy(input) {
|
||||
const prob = [],
|
||||
uniques = input.unique(),
|
||||
str = Utils.byteArrayToChars(input);
|
||||
let i;
|
||||
occurrences = new Array(256).fill(0);
|
||||
|
||||
for (i = 0; i < uniques.length; i++) {
|
||||
prob.push(str.count(Utils.chr(uniques[i])) / input.length);
|
||||
// Count occurrences of each byte in the input
|
||||
let i;
|
||||
for (i = 0; i < input.length; i++) {
|
||||
occurrences[input[i]]++;
|
||||
}
|
||||
|
||||
// Store probability list
|
||||
for (i = 0; i < occurrences.length; i++) {
|
||||
if (occurrences[i] > 0) {
|
||||
prob.push(occurrences[i] / input.length);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate Shannon entropy
|
||||
let entropy = 0,
|
||||
p;
|
||||
|
||||
@@ -54,22 +74,289 @@ class Entropy extends Operation {
|
||||
return -entropy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the scanning entropy of the input
|
||||
*
|
||||
* @param {Uint8Array} inputBytes
|
||||
* @returns {Object}
|
||||
*/
|
||||
calculateScanningEntropy(inputBytes) {
|
||||
const entropyData = [];
|
||||
const binWidth = inputBytes.length < 256 ? 8 : 256;
|
||||
|
||||
for (let bytePos = 0; bytePos < inputBytes.length; bytePos += binWidth) {
|
||||
const block = inputBytes.slice(bytePos, bytePos+binWidth);
|
||||
entropyData.push(this.calculateShannonEntropy(block));
|
||||
}
|
||||
|
||||
return { entropyData, binWidth };
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the frequency of bytes in the input.
|
||||
*
|
||||
* @param {object} svg
|
||||
* @param {function} xScale
|
||||
* @param {function} yScale
|
||||
* @param {integer} svgHeight
|
||||
* @param {integer} svgWidth
|
||||
* @param {object} margins
|
||||
* @param {string} xTitle
|
||||
* @param {string} yTitle
|
||||
*/
|
||||
createAxes(svg, xScale, yScale, svgHeight, svgWidth, margins, title, xTitle, yTitle) {
|
||||
// Axes
|
||||
const yAxis = d3.axisLeft()
|
||||
.scale(yScale);
|
||||
|
||||
const xAxis = d3.axisBottom()
|
||||
.scale(xScale);
|
||||
|
||||
svg.append("g")
|
||||
.attr("transform", `translate(0, ${svgHeight - margins.bottom})`)
|
||||
.call(xAxis);
|
||||
|
||||
svg.append("g")
|
||||
.attr("transform", `translate(${margins.left},0)`)
|
||||
.call(yAxis);
|
||||
|
||||
// Axes labels
|
||||
svg.append("text")
|
||||
.attr("transform", "rotate(-90)")
|
||||
.attr("y", 0 - margins.left)
|
||||
.attr("x", 0 - (svgHeight / 2))
|
||||
.attr("dy", "1em")
|
||||
.style("text-anchor", "middle")
|
||||
.text(yTitle);
|
||||
|
||||
svg.append("text")
|
||||
.attr("transform", `translate(${svgWidth / 2}, ${svgHeight - margins.bottom + 40})`)
|
||||
.style("text-anchor", "middle")
|
||||
.text(xTitle);
|
||||
|
||||
// Add title
|
||||
svg.append("text")
|
||||
.attr("transform", `translate(${svgWidth / 2}, ${margins.top - 10})`)
|
||||
.style("text-anchor", "middle")
|
||||
.text(title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the frequency of bytes in the input.
|
||||
*
|
||||
* @param {Uint8Array} inputBytes
|
||||
* @returns {number[]}
|
||||
*/
|
||||
calculateByteFrequency(inputBytes) {
|
||||
const freq = new Array(256).fill(0);
|
||||
if (inputBytes.length === 0) return freq;
|
||||
|
||||
// Count occurrences of each byte in the input
|
||||
let i;
|
||||
for (i = 0; i < inputBytes.length; i++) {
|
||||
freq[inputBytes[i]]++;
|
||||
}
|
||||
|
||||
for (i = 0; i < freq.length; i++) {
|
||||
freq[i] = freq[i] / inputBytes.length;
|
||||
}
|
||||
|
||||
return freq;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the frequency of bytes in the input.
|
||||
*
|
||||
* @param {number[]} byteFrequency
|
||||
* @returns {HTML}
|
||||
*/
|
||||
createByteFrequencyLineHistogram(byteFrequency) {
|
||||
const margins = { top: 30, right: 20, bottom: 50, left: 30 };
|
||||
|
||||
const svgWidth = 500,
|
||||
svgHeight = 500;
|
||||
|
||||
const document = new nodom.Document();
|
||||
let svg = document.createElement("svg");
|
||||
|
||||
svg = d3.select(svg)
|
||||
.attr("width", "100%")
|
||||
.attr("height", "100%")
|
||||
.attr("viewBox", `0 0 ${svgWidth} ${svgHeight}`);
|
||||
|
||||
const yScale = d3.scaleLinear()
|
||||
.domain([0, d3.max(byteFrequency, d => d)])
|
||||
.range([svgHeight - margins.bottom, margins.top]);
|
||||
|
||||
const xScale = d3.scaleLinear()
|
||||
.domain([0, byteFrequency.length - 1])
|
||||
.range([margins.left, svgWidth - margins.right]);
|
||||
|
||||
const line = d3.line()
|
||||
.x((_, i) => xScale(i))
|
||||
.y(d => yScale(d))
|
||||
.curve(d3.curveMonotoneX);
|
||||
|
||||
svg.append("path")
|
||||
.datum(byteFrequency)
|
||||
.attr("fill", "none")
|
||||
.attr("stroke", "steelblue")
|
||||
.attr("d", line);
|
||||
|
||||
this.createAxes(svg, xScale, yScale, svgHeight, svgWidth, margins, "", "Byte", "Byte Frequency");
|
||||
|
||||
return svg._groups[0][0].outerHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a byte frequency histogram
|
||||
*
|
||||
* @param {number[]} byteFrequency
|
||||
* @returns {HTML}
|
||||
*/
|
||||
createByteFrequencyBarHistogram(byteFrequency) {
|
||||
const margins = { top: 30, right: 20, bottom: 50, left: 30 };
|
||||
|
||||
const svgWidth = 500,
|
||||
svgHeight = 500,
|
||||
binWidth = 1;
|
||||
|
||||
const document = new nodom.Document();
|
||||
let svg = document.createElement("svg");
|
||||
svg = d3.select(svg)
|
||||
.attr("width", "100%")
|
||||
.attr("height", "100%")
|
||||
.attr("viewBox", `0 0 ${svgWidth} ${svgHeight}`);
|
||||
|
||||
const yExtent = d3.extent(byteFrequency, d => d);
|
||||
const yScale = d3.scaleLinear()
|
||||
.domain(yExtent)
|
||||
.range([svgHeight - margins.bottom, margins.top]);
|
||||
|
||||
const xScale = d3.scaleLinear()
|
||||
.domain([0, byteFrequency.length - 1])
|
||||
.range([margins.left - binWidth, svgWidth - margins.right]);
|
||||
|
||||
svg.selectAll("rect")
|
||||
.data(byteFrequency)
|
||||
.enter().append("rect")
|
||||
.attr("x", (_, i) => xScale(i) + binWidth)
|
||||
.attr("y", dataPoint => yScale(dataPoint))
|
||||
.attr("width", binWidth)
|
||||
.attr("height", dataPoint => yScale(yExtent[0]) - yScale(dataPoint))
|
||||
.attr("fill", "blue");
|
||||
|
||||
this.createAxes(svg, xScale, yScale, svgHeight, svgWidth, margins, "", "Byte", "Byte Frequency");
|
||||
|
||||
return svg._groups[0][0].outerHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a byte frequency histogram
|
||||
*
|
||||
* @param {number[]} entropyData
|
||||
* @returns {HTML}
|
||||
*/
|
||||
createEntropyCurve(entropyData) {
|
||||
const margins = { top: 30, right: 20, bottom: 50, left: 30 };
|
||||
|
||||
const svgWidth = 500,
|
||||
svgHeight = 500;
|
||||
|
||||
const document = new nodom.Document();
|
||||
let svg = document.createElement("svg");
|
||||
svg = d3.select(svg)
|
||||
.attr("width", "100%")
|
||||
.attr("height", "100%")
|
||||
.attr("viewBox", `0 0 ${svgWidth} ${svgHeight}`);
|
||||
|
||||
const yScale = d3.scaleLinear()
|
||||
.domain([0, d3.max(entropyData, d => d)])
|
||||
.range([svgHeight - margins.bottom, margins.top]);
|
||||
|
||||
const xScale = d3.scaleLinear()
|
||||
.domain([0, entropyData.length])
|
||||
.range([margins.left, svgWidth - margins.right]);
|
||||
|
||||
const line = d3.line()
|
||||
.x((_, i) => xScale(i))
|
||||
.y(d => yScale(d))
|
||||
.curve(d3.curveMonotoneX);
|
||||
|
||||
if (entropyData.length > 0) {
|
||||
svg.append("path")
|
||||
.datum(entropyData)
|
||||
.attr("d", line);
|
||||
|
||||
svg.selectAll("path").attr("fill", "none").attr("stroke", "steelblue");
|
||||
}
|
||||
|
||||
this.createAxes(svg, xScale, yScale, svgHeight, svgWidth, margins, "Scanning Entropy", "Block", "Entropy");
|
||||
|
||||
return svg._groups[0][0].outerHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an image representation of the entropy
|
||||
*
|
||||
* @param {number[]} entropyData
|
||||
* @returns {HTML}
|
||||
*/
|
||||
createEntropyImage(entropyData) {
|
||||
const svgHeight = 100,
|
||||
svgWidth = 100,
|
||||
cellSize = 1,
|
||||
nodes = [];
|
||||
|
||||
for (let i = 0; i < entropyData.length; i++) {
|
||||
nodes.push({
|
||||
x: i % svgWidth,
|
||||
y: Math.floor(i / svgWidth),
|
||||
entropy: entropyData[i]
|
||||
});
|
||||
}
|
||||
|
||||
const document = new nodom.Document();
|
||||
let svg = document.createElement("svg");
|
||||
svg = d3.select(svg)
|
||||
.attr("width", "100%")
|
||||
.attr("height", "100%")
|
||||
.attr("viewBox", `0 0 ${svgWidth} ${svgHeight}`);
|
||||
|
||||
const greyScale = d3.scaleLinear()
|
||||
.domain([0, d3.max(entropyData, d => d)])
|
||||
.range(["#000000", "#FFFFFF"])
|
||||
.interpolate(d3.interpolateRgb);
|
||||
|
||||
svg
|
||||
.selectAll("rect")
|
||||
.data(nodes)
|
||||
.enter().append("rect")
|
||||
.attr("x", d => d.x * cellSize)
|
||||
.attr("y", d => d.y * cellSize)
|
||||
.attr("width", cellSize)
|
||||
.attr("height", cellSize)
|
||||
.style("fill", d => greyScale(d.entropy));
|
||||
|
||||
return svg._groups[0][0].outerHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the entropy as a scale bar for web apps.
|
||||
*
|
||||
* @param {number} entropy
|
||||
* @returns {html}
|
||||
* @returns {HTML}
|
||||
*/
|
||||
present(entropy) {
|
||||
createShannonEntropyVisualization(entropy) {
|
||||
return `Shannon entropy: ${entropy}
|
||||
<br><canvas id='chart-area'></canvas><br>
|
||||
- 0 represents no randomness (i.e. all the bytes in the data have the same value) whereas 8, the maximum, represents a completely random string.
|
||||
- Standard English text usually falls somewhere between 3.5 and 5.
|
||||
- Properly encrypted or compressed data of a reasonable length should have an entropy of over 7.5.
|
||||
<br><canvas id='chart-area'></canvas><br>
|
||||
- 0 represents no randomness (i.e. all the bytes in the data have the same value) whereas 8, the maximum, represents a completely random string.
|
||||
- Standard English text usually falls somewhere between 3.5 and 5.
|
||||
- Properly encrypted or compressed data of a reasonable length should have an entropy of over 7.5.
|
||||
|
||||
The following results show the entropy of chunks of the input data. Chunks with particularly high entropy could suggest encrypted or compressed sections.
|
||||
The following results show the entropy of chunks of the input data. Chunks with particularly high entropy could suggest encrypted or compressed sections.
|
||||
|
||||
<br><script>
|
||||
<br><script>
|
||||
var canvas = document.getElementById("chart-area"),
|
||||
parentRect = canvas.parentNode.getBoundingClientRect(),
|
||||
entropy = ${entropy},
|
||||
@@ -89,9 +376,55 @@ The following results show the entropy of chunks of the input data. Chunks with
|
||||
max: 8
|
||||
}
|
||||
]);
|
||||
</script>`;
|
||||
</script>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {json}
|
||||
*/
|
||||
run(input, args) {
|
||||
const visualizationType = args[0];
|
||||
input = new Uint8Array(input);
|
||||
|
||||
switch (visualizationType) {
|
||||
case "Histogram (Bar)":
|
||||
case "Histogram (Line)":
|
||||
return this.calculateByteFrequency(input);
|
||||
case "Curve":
|
||||
case "Image":
|
||||
return this.calculateScanningEntropy(input).entropyData;
|
||||
case "Shannon scale":
|
||||
default:
|
||||
return this.calculateShannonEntropy(input);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the entropy in a visualisation for web apps.
|
||||
*
|
||||
* @param {json} entropyData
|
||||
* @param {Object[]} args
|
||||
* @returns {html}
|
||||
*/
|
||||
present(entropyData, args) {
|
||||
const visualizationType = args[0];
|
||||
|
||||
switch (visualizationType) {
|
||||
case "Histogram (Bar)":
|
||||
return this.createByteFrequencyBarHistogram(entropyData);
|
||||
case "Histogram (Line)":
|
||||
return this.createByteFrequencyLineHistogram(entropyData);
|
||||
case "Curve":
|
||||
return this.createEntropyCurve(entropyData);
|
||||
case "Image":
|
||||
return this.createEntropyImage(entropyData);
|
||||
case "Shannon scale":
|
||||
default:
|
||||
return this.createShannonEntropyVisualization(entropyData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Entropy;
|
||||
|
||||
@@ -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})`);
|
||||
}
|
||||
@@ -66,8 +66,13 @@ class FlipImage extends Operation {
|
||||
break;
|
||||
}
|
||||
|
||||
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.buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error flipping image. (${err})`);
|
||||
}
|
||||
@@ -75,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 `<img src="data:${type};base64,${toBase64(data)}">`;
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -26,6 +26,7 @@ import Fletcher16Checksum from "./Fletcher16Checksum";
|
||||
import Fletcher32Checksum from "./Fletcher32Checksum";
|
||||
import Fletcher64Checksum from "./Fletcher64Checksum";
|
||||
import Adler32Checksum from "./Adler32Checksum";
|
||||
import CRC8Checksum from "./CRC8Checksum";
|
||||
import CRC16Checksum from "./CRC16Checksum";
|
||||
import CRC32Checksum from "./CRC32Checksum";
|
||||
import BLAKE2b from "./BLAKE2b";
|
||||
@@ -104,8 +105,9 @@ class GenerateAllHashes extends Operation {
|
||||
"\nFletcher-32: " + (new Fletcher32Checksum).run(byteArray, []) +
|
||||
"\nFletcher-64: " + (new Fletcher64Checksum).run(byteArray, []) +
|
||||
"\nAdler-32: " + (new Adler32Checksum).run(byteArray, []) +
|
||||
"\nCRC-16: " + (new CRC16Checksum).run(str, []) +
|
||||
"\nCRC-32: " + (new CRC32Checksum).run(str, []);
|
||||
"\nCRC-8: " + (new CRC8Checksum).run(arrayBuffer, ["CRC-8"]) +
|
||||
"\nCRC-16: " + (new CRC16Checksum).run(arrayBuffer, []) +
|
||||
"\nCRC-32: " + (new CRC32Checksum).run(arrayBuffer, []);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -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 { isImage } from "../lib/FileType";
|
||||
import Utils from "../Utils";
|
||||
@@ -27,7 +27,7 @@ class GenerateQRCode extends Operation {
|
||||
this.description = "Generates a Quick Response (QR) code from the input text.<br><br>A QR code is a type of matrix barcode (or two-dimensional barcode) first designed in 1994 for the automotive industry in Japan. A barcode is a machine-readable optical label that contains information about the item to which it is attached.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/QR_code";
|
||||
this.inputType = "string";
|
||||
this.outputType = "byteArray";
|
||||
this.outputType = "ArrayBuffer";
|
||||
this.presentType = "html";
|
||||
this.args = [
|
||||
{
|
||||
@@ -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",
|
||||
@@ -57,61 +59,34 @@ class GenerateQRCode extends Operation {
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
* @returns {ArrayBuffer}
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the QR image using HTML for web apps
|
||||
*
|
||||
* @param {byteArray} data
|
||||
* @param {ArrayBuffer} data
|
||||
* @returns {html}
|
||||
*/
|
||||
present(data, args) {
|
||||
if (!data.length) return "";
|
||||
|
||||
const [format] = args;
|
||||
|
||||
if (!data.byteLength && !data.length) return "";
|
||||
const dataArray = new Uint8Array(data),
|
||||
[format] = args;
|
||||
if (format === "PNG") {
|
||||
let dataURI = "data:";
|
||||
const mime = isImage(data);
|
||||
if (mime){
|
||||
dataURI += mime + ";";
|
||||
} else {
|
||||
throw new OperationError("Invalid PNG file generated by QR image");
|
||||
}
|
||||
dataURI += "base64," + toBase64(data);
|
||||
|
||||
return `<img src="${dataURI}">`;
|
||||
const type = isImage(dataArray);
|
||||
if (!type) {
|
||||
throw new OperationError("Invalid file type.");
|
||||
}
|
||||
|
||||
return Utils.byteArrayToChars(data);
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
|
||||
return Utils.arrayBufferToStr(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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})`);
|
||||
}
|
||||
@@ -75,8 +75,13 @@ class ImageBrightnessContrast extends Operation {
|
||||
image.contrast(contrast / 100);
|
||||
}
|
||||
|
||||
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.buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error adjusting image brightness or contrast. (${err})`);
|
||||
}
|
||||
@@ -84,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 `<img src="data:${type};base64,${toBase64(data)}">`;
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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})`);
|
||||
}
|
||||
@@ -66,8 +66,13 @@ class ImageFilter extends Operation {
|
||||
image.sepia();
|
||||
}
|
||||
|
||||
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.buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error applying filter to image. (${err})`);
|
||||
}
|
||||
@@ -75,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 `<img src="data:${type};base64,${toBase64(data)}">`;
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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})`);
|
||||
}
|
||||
@@ -102,8 +102,14 @@ class ImageHueSaturationLightness extends Operation {
|
||||
}
|
||||
]);
|
||||
}
|
||||
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.buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error adjusting image hue / saturation / lightness. (${err})`);
|
||||
}
|
||||
@@ -111,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 `<img src="data:${type};base64,${toBase64(data)}">`;
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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})`);
|
||||
}
|
||||
@@ -61,8 +61,13 @@ class ImageOpacity extends Operation {
|
||||
self.sendStatusMessage("Changing image opacity...");
|
||||
image.opacity(opacity / 100);
|
||||
|
||||
const imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
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.buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error changing image opacity. (${err})`);
|
||||
}
|
||||
@@ -70,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 `<img src="data:${type};base64,${toBase64(data)}">`;
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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})`);
|
||||
}
|
||||
@@ -51,8 +51,14 @@ class InvertImage extends Operation {
|
||||
if (ENVIRONMENT_IS_WORKER())
|
||||
self.sendStatusMessage("Inverting image...");
|
||||
image.invert();
|
||||
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.buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error inverting image. (${err})`);
|
||||
}
|
||||
@@ -60,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 `<img src="data:${type};base64,${toBase64(data)}">`;
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,44 +25,59 @@ 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.");
|
||||
}
|
||||
|
||||
const image = await jimp.read(Buffer.from(input));
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error opening image file. (${err})`);
|
||||
}
|
||||
|
||||
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.buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error normalising image. (${err})`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 `<img src="data:${type};base64,${toBase64(data)}">`;
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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}>`;
|
||||
@@ -101,8 +101,9 @@ class PGPDecryptAndVerify extends Operation {
|
||||
text += "\n";
|
||||
}
|
||||
text += [
|
||||
`PGP key ID: ${km.get_pgp_short_key_id()}`,
|
||||
`PGP fingerprint: ${km.get_pgp_fingerprint().toString("hex")}`,
|
||||
`Signed on ${new Date(ds.sig.hashed_subpackets[0].time * 1000).toUTCString()}`,
|
||||
`Signed on ${new Date(ds.sig.when_generated() * 1000).toUTCString()}`,
|
||||
"----------------------------------\n"
|
||||
].join("\n");
|
||||
text += unboxedLiterals.toString();
|
||||
|
||||
111
src/core/operations/PGPVerify.mjs
Normal file
111
src/core/operations/PGPVerify.mjs
Normal file
@@ -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.",
|
||||
"<br><br>",
|
||||
"Argument: the ASCII-armoured PGP public key of the signer",
|
||||
"<br><br>",
|
||||
"This operation uses PGP to decrypt a clearsigned message.",
|
||||
"<br><br>",
|
||||
"Pretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.",
|
||||
"<br><br>",
|
||||
"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 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");
|
||||
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;
|
||||
@@ -6,9 +6,8 @@
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import { isImage } from "../lib/FileType";
|
||||
import jsqr from "jsqr";
|
||||
import jimp from "jimp";
|
||||
import { isImage } from "../lib/FileType.mjs";
|
||||
import { parseQrCode } from "../lib/QRCode";
|
||||
|
||||
/**
|
||||
* Parse QR Code operation
|
||||
@@ -25,7 +24,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.<br><br><u>Normalise Image</u><br>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 = [
|
||||
{
|
||||
@@ -34,69 +33,28 @@ 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
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
async run(input, args) {
|
||||
const [normalise] = args;
|
||||
|
||||
// Make sure that the input is an image
|
||||
if (!isImage(input)) throw new OperationError("Invalid file type.");
|
||||
|
||||
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 (!isImage(new Uint8Array(input))) {
|
||||
throw new OperationError("Invalid file type.");
|
||||
}
|
||||
|
||||
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."));
|
||||
});
|
||||
});
|
||||
|
||||
return await parseQrCode(input, normalise);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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})`);
|
||||
}
|
||||
@@ -110,8 +110,13 @@ class ResizeImage extends Operation {
|
||||
image.resize(width, height, resizeMap[resizeAlg]);
|
||||
}
|
||||
|
||||
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.buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error resizing image. (${err})`);
|
||||
}
|
||||
@@ -119,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 `<img src="data:${type};base64,${toBase64(data)}">`;
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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})`);
|
||||
}
|
||||
@@ -59,8 +59,14 @@ class RotateImage extends Operation {
|
||||
if (ENVIRONMENT_IS_WORKER())
|
||||
self.sendStatusMessage("Rotating image...");
|
||||
image.rotate(degrees);
|
||||
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.buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error rotating image. (${err})`);
|
||||
}
|
||||
@@ -68,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 `<img src="data:${type};base64,${toBase64(data)}">`;
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
168
src/core/operations/SharpenImage.mjs
Normal file
168
src/core/operations/SharpenImage.mjs
Normal file
@@ -0,0 +1,168 @@
|
||||
/**
|
||||
* @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 { gaussianBlur } from "../lib/ImageManipulation";
|
||||
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 = "ArrayBuffer";
|
||||
this.outputType = "ArrayBuffer";
|
||||
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 {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
async run(input, args) {
|
||||
const [radius, amount, threshold] = args;
|
||||
|
||||
if (!isImage(new Uint8Array(input))){
|
||||
throw new OperationError("Invalid file type.");
|
||||
}
|
||||
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error loading image. (${err})`);
|
||||
}
|
||||
|
||||
try {
|
||||
if (ENVIRONMENT_IS_WORKER())
|
||||
self.sendStatusMessage("Sharpening image... (Cloning image)");
|
||||
const blurMask = image.clone();
|
||||
|
||||
if (ENVIRONMENT_IS_WORKER())
|
||||
self.sendStatusMessage("Sharpening image... (Blurring cloned image)");
|
||||
const blurImage = gaussianBlur(image.clone(), radius, 3);
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
});
|
||||
|
||||
let imageBuffer;
|
||||
if (image.getMIME() === "image/gif") {
|
||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
} else {
|
||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
}
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error sharpening image. (${err})`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the sharpened image using HTML for web apps
|
||||
* @param {ArrayBuffer} data
|
||||
* @returns {html}
|
||||
*/
|
||||
present(data) {
|
||||
if (!data.byteLength) return "";
|
||||
const dataArray = new Uint8Array(data);
|
||||
|
||||
const type = isImage(dataArray);
|
||||
if (!type) {
|
||||
throw new OperationError("Invalid file type.");
|
||||
}
|
||||
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default SharpenImage;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -244,7 +244,7 @@ class App {
|
||||
/**
|
||||
* Sets up the adjustable splitter to allow the user to resize areas of the page.
|
||||
*
|
||||
* @param {boolean} [minimise=false] - Set this flag if attempting to minimuse frames to 0 width
|
||||
* @param {boolean} [minimise=false] - Set this flag if attempting to minimise frames to 0 width
|
||||
*/
|
||||
initialiseSplitter(minimise=false) {
|
||||
if (this.columnSplitter) this.columnSplitter.destroy();
|
||||
@@ -252,9 +252,9 @@ class App {
|
||||
|
||||
this.columnSplitter = Split(["#operations", "#recipe", "#IO"], {
|
||||
sizes: [20, 30, 50],
|
||||
minSize: minimise ? [0, 0, 0] : [240, 370, 450],
|
||||
minSize: minimise ? [0, 0, 0] : [240, 310, 450],
|
||||
gutterSize: 4,
|
||||
expandToMin: false,
|
||||
expandToMin: true,
|
||||
onDrag: function() {
|
||||
this.manager.recipe.adjustWidth();
|
||||
}.bind(this)
|
||||
|
||||
@@ -617,6 +617,23 @@ class RecipeWaiter {
|
||||
ingredientRule.style.gridTemplateColumns = "auto auto auto auto";
|
||||
ingredientChildRule.style.gridColumn = "1 / span 4";
|
||||
}
|
||||
|
||||
// Hide Chef icon on Bake button if the page is compressed
|
||||
const bakeIcon = document.querySelector("#bake img");
|
||||
|
||||
if (recList.clientWidth < 370) {
|
||||
// Hide Chef icon on Bake button
|
||||
bakeIcon.style.display = "none";
|
||||
} else {
|
||||
bakeIcon.style.display = "inline-block";
|
||||
}
|
||||
|
||||
// Scale controls to fit pane width
|
||||
const controls = document.getElementById("controls");
|
||||
const controlsContent = document.getElementById("controls-content");
|
||||
const scale = (controls.clientWidth - 1) / controlsContent.scrollWidth;
|
||||
|
||||
controlsContent.style.transform = `translate(-50%, -50%) scale(${scale})`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@
|
||||
<ul id="rec-list" class="list-area no-select"></ul>
|
||||
|
||||
<div id="controls" class="no-select">
|
||||
<div class="d-flex align-items-center">
|
||||
<div id="controls-content" class="d-flex align-items-center">
|
||||
<button type="button" class="mx-2 btn btn-lg btn-secondary" id="step" data-toggle="tooltip" title="Step through the recipe">
|
||||
Step
|
||||
</button>
|
||||
|
||||
@@ -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";
|
||||
|
||||
485
src/web/static/fonts/bmfonts/Roboto72White.fnt
Normal file
485
src/web/static/fonts/bmfonts/Roboto72White.fnt
Normal file
@@ -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="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
|
||||
BIN
src/web/static/fonts/bmfonts/Roboto72White.png
Normal file
BIN
src/web/static/fonts/bmfonts/Roboto72White.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
488
src/web/static/fonts/bmfonts/RobotoBlack72White.fnt
Normal file
488
src/web/static/fonts/bmfonts/RobotoBlack72White.fnt
Normal file
@@ -0,0 +1,488 @@
|
||||
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="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
|
||||
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=460 y=156 width=15 height=55 xoffset=3 yoffset=14 xadvance=20 page=0 chnl=0
|
||||
char id=34 x=207 y=362 width=22 height=22 xoffset=0 yoffset=12 xadvance=23 page=0 chnl=0
|
||||
char id=35 x=404 y=266 width=41 height=54 xoffset=0 yoffset=14 xadvance=42 page=0 chnl=0
|
||||
char id=36 x=220 y=0 width=38 height=69 xoffset=2 yoffset=7 xadvance=42 page=0 chnl=0
|
||||
char id=37 x=167 y=156 width=49 height=56 xoffset=2 yoffset=13 xadvance=53 page=0 chnl=0
|
||||
char id=38 x=216 y=156 width=48 height=56 xoffset=1 yoffset=13 xadvance=48 page=0 chnl=0
|
||||
char id=39 x=499 y=320 width=10 height=22 xoffset=1 yoffset=12 xadvance=11 page=0 chnl=0
|
||||
char id=40 x=70 y=0 width=22 height=75 xoffset=3 yoffset=9 xadvance=25 page=0 chnl=0
|
||||
char id=41 x=92 y=0 width=23 height=75 xoffset=0 yoffset=9 xadvance=25 page=0 chnl=0
|
||||
char id=42 x=103 y=362 width=36 height=34 xoffset=-1 yoffset=14 xadvance=33 page=0 chnl=0
|
||||
char id=43 x=0 y=362 width=37 height=40 xoffset=1 yoffset=23 xadvance=39 page=0 chnl=0
|
||||
char id=44 x=483 y=320 width=16 height=25 xoffset=0 yoffset=57 xadvance=20 page=0 chnl=0
|
||||
char id=45 x=308 y=362 width=23 height=12 xoffset=4 yoffset=38 xadvance=32 page=0 chnl=0
|
||||
char id=46 x=270 y=362 width=15 height=15 xoffset=3 yoffset=54 xadvance=22 page=0 chnl=0
|
||||
char id=47 x=374 y=0 width=29 height=58 xoffset=-3 yoffset=14 xadvance=25 page=0 chnl=0
|
||||
char id=48 x=77 y=156 width=38 height=56 xoffset=2 yoffset=13 xadvance=42 page=0 chnl=0
|
||||
char id=49 x=299 y=266 width=26 height=54 xoffset=4 yoffset=14 xadvance=41 page=0 chnl=0
|
||||
char id=50 x=383 y=156 width=39 height=55 xoffset=1 yoffset=13 xadvance=42 page=0 chnl=0
|
||||
char id=51 x=434 y=99 width=39 height=56 xoffset=1 yoffset=13 xadvance=42 page=0 chnl=0
|
||||
char id=52 x=325 y=266 width=40 height=54 xoffset=1 yoffset=14 xadvance=42 page=0 chnl=0
|
||||
char id=53 x=422 y=156 width=38 height=55 xoffset=2 yoffset=14 xadvance=42 page=0 chnl=0
|
||||
char id=54 x=0 y=156 width=39 height=56 xoffset=2 yoffset=13 xadvance=42 page=0 chnl=0
|
||||
char id=55 x=365 y=266 width=39 height=54 xoffset=1 yoffset=14 xadvance=42 page=0 chnl=0
|
||||
char id=56 x=473 y=99 width=38 height=56 xoffset=2 yoffset=13 xadvance=42 page=0 chnl=0
|
||||
char id=57 x=39 y=156 width=38 height=56 xoffset=2 yoffset=13 xadvance=42 page=0 chnl=0
|
||||
char id=58 x=471 y=266 width=15 height=43 xoffset=3 yoffset=26 xadvance=21 page=0 chnl=0
|
||||
char id=59 x=150 y=156 width=17 height=56 xoffset=1 yoffset=26 xadvance=21 page=0 chnl=0
|
||||
char id=60 x=37 y=362 width=33 height=38 xoffset=1 yoffset=26 xadvance=37 page=0 chnl=0
|
||||
char id=61 x=172 y=362 width=35 height=27 xoffset=3 yoffset=31 xadvance=42 page=0 chnl=0
|
||||
char id=62 x=70 y=362 width=33 height=38 xoffset=3 yoffset=26 xadvance=37 page=0 chnl=0
|
||||
char id=63 x=115 y=156 width=35 height=56 xoffset=0 yoffset=13 xadvance=36 page=0 chnl=0
|
||||
char id=64 x=258 y=0 width=61 height=68 xoffset=1 yoffset=16 xadvance=64 page=0 chnl=0
|
||||
char id=65 x=0 y=212 width=53 height=54 xoffset=-2 yoffset=14 xadvance=49 page=0 chnl=0
|
||||
char id=66 x=53 y=212 width=42 height=54 xoffset=3 yoffset=14 xadvance=47 page=0 chnl=0
|
||||
char id=67 x=37 y=99 width=46 height=56 xoffset=1 yoffset=13 xadvance=47 page=0 chnl=0
|
||||
char id=68 x=95 y=212 width=42 height=54 xoffset=3 yoffset=14 xadvance=47 page=0 chnl=0
|
||||
char id=69 x=137 y=212 width=38 height=54 xoffset=3 yoffset=14 xadvance=41 page=0 chnl=0
|
||||
char id=70 x=475 y=156 width=36 height=54 xoffset=3 yoffset=14 xadvance=39 page=0 chnl=0
|
||||
char id=71 x=83 y=99 width=45 height=56 xoffset=2 yoffset=13 xadvance=49 page=0 chnl=0
|
||||
char id=72 x=175 y=212 width=45 height=54 xoffset=3 yoffset=14 xadvance=51 page=0 chnl=0
|
||||
char id=73 x=220 y=212 width=14 height=54 xoffset=4 yoffset=14 xadvance=22 page=0 chnl=0
|
||||
char id=74 x=264 y=156 width=37 height=55 xoffset=0 yoffset=14 xadvance=40 page=0 chnl=0
|
||||
char id=75 x=234 y=212 width=45 height=54 xoffset=3 yoffset=14 xadvance=46 page=0 chnl=0
|
||||
char id=76 x=279 y=212 width=36 height=54 xoffset=3 yoffset=14 xadvance=39 page=0 chnl=0
|
||||
char id=77 x=315 y=212 width=58 height=54 xoffset=3 yoffset=14 xadvance=63 page=0 chnl=0
|
||||
char id=78 x=373 y=212 width=45 height=54 xoffset=3 yoffset=14 xadvance=51 page=0 chnl=0
|
||||
char id=79 x=128 y=99 width=47 height=56 xoffset=1 yoffset=13 xadvance=50 page=0 chnl=0
|
||||
char id=80 x=418 y=212 width=43 height=54 xoffset=3 yoffset=14 xadvance=48 page=0 chnl=0
|
||||
char id=81 x=319 y=0 width=47 height=65 xoffset=2 yoffset=13 xadvance=50 page=0 chnl=0
|
||||
char id=82 x=461 y=212 width=43 height=54 xoffset=3 yoffset=14 xadvance=46 page=0 chnl=0
|
||||
char id=83 x=175 y=99 width=42 height=56 xoffset=1 yoffset=13 xadvance=44 page=0 chnl=0
|
||||
char id=84 x=0 y=266 width=45 height=54 xoffset=0 yoffset=14 xadvance=45 page=0 chnl=0
|
||||
char id=85 x=301 y=156 width=42 height=55 xoffset=3 yoffset=14 xadvance=48 page=0 chnl=0
|
||||
char id=86 x=45 y=266 width=51 height=54 xoffset=-2 yoffset=14 xadvance=48 page=0 chnl=0
|
||||
char id=87 x=96 y=266 width=64 height=54 xoffset=-1 yoffset=14 xadvance=63 page=0 chnl=0
|
||||
char id=88 x=160 y=266 width=48 height=54 xoffset=-1 yoffset=14 xadvance=46 page=0 chnl=0
|
||||
char id=89 x=208 y=266 width=49 height=54 xoffset=-2 yoffset=14 xadvance=45 page=0 chnl=0
|
||||
char id=90 x=257 y=266 width=42 height=54 xoffset=1 yoffset=14 xadvance=44 page=0 chnl=0
|
||||
char id=91 x=115 y=0 width=18 height=75 xoffset=3 yoffset=5 xadvance=21 page=0 chnl=0
|
||||
char id=92 x=403 y=0 width=37 height=58 xoffset=-2 yoffset=14 xadvance=31 page=0 chnl=0
|
||||
char id=93 x=133 y=0 width=18 height=75 xoffset=0 yoffset=5 xadvance=21 page=0 chnl=0
|
||||
char id=94 x=139 y=362 width=33 height=28 xoffset=0 yoffset=14 xadvance=32 page=0 chnl=0
|
||||
char id=95 x=331 y=362 width=34 height=12 xoffset=-1 yoffset=65 xadvance=33 page=0 chnl=0
|
||||
char id=96 x=285 y=362 width=23 height=13 xoffset=0 yoffset=12 xadvance=24 page=0 chnl=0
|
||||
char id=97 x=0 y=320 width=37 height=42 xoffset=1 yoffset=27 xadvance=38 page=0 chnl=0
|
||||
char id=98 x=440 y=0 width=37 height=57 xoffset=2 yoffset=12 xadvance=40 page=0 chnl=0
|
||||
char id=99 x=37 y=320 width=36 height=42 xoffset=1 yoffset=27 xadvance=38 page=0 chnl=0
|
||||
char id=100 x=0 y=99 width=37 height=57 xoffset=1 yoffset=12 xadvance=40 page=0 chnl=0
|
||||
char id=101 x=73 y=320 width=38 height=42 xoffset=1 yoffset=27 xadvance=39 page=0 chnl=0
|
||||
char id=102 x=477 y=0 width=28 height=57 xoffset=0 yoffset=11 xadvance=27 page=0 chnl=0
|
||||
char id=103 x=217 y=99 width=38 height=56 xoffset=1 yoffset=27 xadvance=41 page=0 chnl=0
|
||||
char id=104 x=255 y=99 width=36 height=56 xoffset=2 yoffset=12 xadvance=40 page=0 chnl=0
|
||||
char id=105 x=291 y=99 width=15 height=56 xoffset=2 yoffset=12 xadvance=19 page=0 chnl=0
|
||||
char id=106 x=197 y=0 width=23 height=71 xoffset=-5 yoffset=12 xadvance=20 page=0 chnl=0
|
||||
char id=107 x=306 y=99 width=40 height=56 xoffset=2 yoffset=12 xadvance=39 page=0 chnl=0
|
||||
char id=108 x=346 y=99 width=14 height=56 xoffset=3 yoffset=12 xadvance=20 page=0 chnl=0
|
||||
char id=109 x=186 y=320 width=58 height=41 xoffset=2 yoffset=27 xadvance=63 page=0 chnl=0
|
||||
char id=110 x=244 y=320 width=36 height=41 xoffset=2 yoffset=27 xadvance=40 page=0 chnl=0
|
||||
char id=111 x=111 y=320 width=39 height=42 xoffset=1 yoffset=27 xadvance=41 page=0 chnl=0
|
||||
char id=112 x=360 y=99 width=37 height=56 xoffset=2 yoffset=27 xadvance=40 page=0 chnl=0
|
||||
char id=113 x=397 y=99 width=37 height=56 xoffset=1 yoffset=27 xadvance=40 page=0 chnl=0
|
||||
char id=114 x=486 y=266 width=25 height=41 xoffset=2 yoffset=27 xadvance=27 page=0 chnl=0
|
||||
char id=115 x=150 y=320 width=36 height=42 xoffset=0 yoffset=27 xadvance=37 page=0 chnl=0
|
||||
char id=116 x=445 y=266 width=26 height=51 xoffset=0 yoffset=18 xadvance=25 page=0 chnl=0
|
||||
char id=117 x=280 y=320 width=36 height=41 xoffset=2 yoffset=28 xadvance=40 page=0 chnl=0
|
||||
char id=118 x=316 y=320 width=39 height=40 xoffset=-1 yoffset=28 xadvance=37 page=0 chnl=0
|
||||
char id=119 x=355 y=320 width=54 height=40 xoffset=-1 yoffset=28 xadvance=52 page=0 chnl=0
|
||||
char id=120 x=409 y=320 width=40 height=40 xoffset=-1 yoffset=28 xadvance=37 page=0 chnl=0
|
||||
char id=121 x=343 y=156 width=40 height=55 xoffset=-1 yoffset=28 xadvance=37 page=0 chnl=0
|
||||
char id=122 x=449 y=320 width=34 height=40 xoffset=1 yoffset=28 xadvance=36 page=0 chnl=0
|
||||
char id=123 x=151 y=0 width=23 height=72 xoffset=0 yoffset=9 xadvance=23 page=0 chnl=0
|
||||
char id=124 x=366 y=0 width=8 height=63 xoffset=5 yoffset=14 xadvance=18 page=0 chnl=0
|
||||
char id=125 x=174 y=0 width=23 height=72 xoffset=0 yoffset=9 xadvance=23 page=0 chnl=0
|
||||
char id=126 x=229 y=362 width=41 height=19 xoffset=2 yoffset=36 xadvance=45 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=385
|
||||
kerning first=84 second=74 amount=-8
|
||||
kerning first=86 second=100 amount=-2
|
||||
kerning first=114 second=113 amount=-1
|
||||
kerning first=70 second=121 amount=-1
|
||||
kerning first=34 second=99 amount=-2
|
||||
kerning first=70 second=99 amount=-1
|
||||
kerning first=69 second=99 amount=-1
|
||||
kerning first=88 second=113 amount=-1
|
||||
kerning first=84 second=46 amount=-9
|
||||
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=121 second=34 amount=1
|
||||
kerning first=40 second=86 amount=1
|
||||
kerning first=85 second=65 amount=-1
|
||||
kerning first=72 second=65 amount=1
|
||||
kerning first=114 second=102 amount=1
|
||||
kerning first=89 second=42 amount=-2
|
||||
kerning first=114 second=34 amount=1
|
||||
kerning first=75 second=67 amount=-1
|
||||
kerning first=89 second=85 amount=-3
|
||||
kerning first=77 second=88 amount=1
|
||||
kerning first=84 second=115 amount=-3
|
||||
kerning first=84 second=71 amount=-1
|
||||
kerning first=89 second=101 amount=-2
|
||||
kerning first=89 second=45 amount=-5
|
||||
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=79 amount=-1
|
||||
kerning first=75 second=111 amount=-1
|
||||
kerning first=111 second=120 amount=-1
|
||||
kerning first=87 second=44 amount=-5
|
||||
kerning first=67 second=84 amount=-1
|
||||
kerning first=84 second=111 amount=-7
|
||||
kerning first=84 second=83 amount=-1
|
||||
kerning first=102 second=113 amount=-1
|
||||
kerning first=39 second=101 amount=-2
|
||||
kerning first=80 second=88 amount=-2
|
||||
kerning first=66 second=84 amount=-1
|
||||
kerning first=65 second=87 amount=-1
|
||||
kerning first=122 second=100 amount=-1
|
||||
kerning first=75 second=118 amount=-1
|
||||
kerning first=73 second=65 amount=1
|
||||
kerning first=70 second=118 amount=-1
|
||||
kerning first=73 second=88 amount=1
|
||||
kerning first=82 second=89 amount=-2
|
||||
kerning first=65 second=34 amount=-4
|
||||
kerning first=120 second=99 amount=-1
|
||||
kerning first=84 second=99 amount=-3
|
||||
kerning first=84 second=65 amount=-4
|
||||
kerning first=112 second=39 amount=-1
|
||||
kerning first=76 second=39 amount=-10
|
||||
kerning first=78 second=65 amount=1
|
||||
kerning first=88 second=45 amount=-5
|
||||
kerning first=34 second=111 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=89 second=89 amount=1
|
||||
kerning first=89 second=117 amount=-1
|
||||
kerning first=75 second=117 amount=-1
|
||||
kerning first=76 second=65 amount=1
|
||||
kerning first=34 second=34 amount=-1
|
||||
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=80 second=44 amount=-14
|
||||
kerning first=98 second=39 amount=-1
|
||||
kerning first=70 second=65 amount=-7
|
||||
kerning first=89 second=116 amount=-1
|
||||
kerning first=70 second=46 amount=-10
|
||||
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=65 second=118 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=65 second=110 amount=-2
|
||||
kerning first=114 second=121 amount=1
|
||||
kerning first=89 second=100 amount=-2
|
||||
kerning first=80 second=65 amount=-6
|
||||
kerning first=121 second=111 amount=-1
|
||||
kerning first=34 second=101 amount=-2
|
||||
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=68 second=88 amount=-1
|
||||
kerning first=81 second=89 amount=-1
|
||||
kerning first=114 second=111 amount=-1
|
||||
kerning first=46 second=34 amount=-10
|
||||
kerning first=84 second=112 amount=-3
|
||||
kerning first=76 second=34 amount=-10
|
||||
kerning first=39 second=115 amount=-3
|
||||
kerning first=76 second=118 amount=-4
|
||||
kerning first=86 second=99 amount=-2
|
||||
kerning first=84 second=84 amount=1
|
||||
kerning first=120 second=111 amount=-1
|
||||
kerning first=65 second=79 amount=-1
|
||||
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=-6
|
||||
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=-6
|
||||
kerning first=34 second=39 amount=-1
|
||||
kerning first=65 second=121 amount=-2
|
||||
kerning first=114 second=44 amount=-6
|
||||
kerning first=69 second=84 amount=1
|
||||
kerning first=89 second=46 amount=-8
|
||||
kerning first=97 second=39 amount=-1
|
||||
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=89 second=86 amount=1
|
||||
kerning first=86 second=113 amount=-2
|
||||
kerning first=88 second=71 amount=-1
|
||||
kerning first=122 second=99 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=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=89 second=67 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=120 second=100 amount=-1
|
||||
kerning first=104 second=34 amount=-3
|
||||
kerning first=86 second=41 amount=1
|
||||
kerning first=111 second=34 amount=-3
|
||||
kerning first=40 second=89 amount=1
|
||||
kerning first=121 second=39 amount=1
|
||||
kerning first=70 second=74 amount=-7
|
||||
kerning first=68 second=90 amount=-1
|
||||
kerning first=98 second=120 amount=-1
|
||||
kerning first=110 second=34 amount=-3
|
||||
kerning first=119 second=46 amount=-4
|
||||
kerning first=69 second=102 amount=-1
|
||||
kerning first=118 second=44 amount=-6
|
||||
kerning first=84 second=114 amount=-2
|
||||
kerning first=86 second=97 amount=-2
|
||||
kerning first=40 second=87 amount=1
|
||||
kerning first=65 second=109 amount=-2
|
||||
kerning first=68 second=86 amount=-1
|
||||
kerning first=86 second=93 amount=1
|
||||
kerning first=65 second=67 amount=-1
|
||||
kerning first=97 second=34 amount=-1
|
||||
kerning first=34 second=65 amount=-4
|
||||
kerning first=84 second=118 amount=-3
|
||||
kerning first=112 second=34 amount=-1
|
||||
kerning first=76 second=84 amount=-7
|
||||
kerning first=107 second=99 amount=-1
|
||||
kerning first=123 second=85 amount=-1
|
||||
kerning first=102 second=125 amount=1
|
||||
kerning first=65 second=63 amount=-3
|
||||
kerning first=89 second=44 amount=-8
|
||||
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=86 second=65 amount=-3
|
||||
kerning first=65 second=81 amount=-1
|
||||
kerning first=68 second=44 amount=-4
|
||||
kerning first=86 second=45 amount=-6
|
||||
kerning first=39 second=34 amount=-1
|
||||
kerning first=72 second=88 amount=1
|
||||
kerning first=68 second=46 amount=-4
|
||||
kerning first=65 second=89 amount=-5
|
||||
kerning first=69 second=118 amount=-1
|
||||
kerning first=89 second=38 amount=-1
|
||||
kerning first=88 second=99 amount=-1
|
||||
kerning first=65 second=71 amount=-1
|
||||
kerning first=91 second=74 amount=-1
|
||||
kerning first=75 second=101 amount=-1
|
||||
kerning first=39 second=112 amount=-1
|
||||
kerning first=70 second=113 amount=-1
|
||||
kerning first=119 second=44 amount=-4
|
||||
kerning first=72 second=89 amount=-1
|
||||
kerning first=90 second=103 amount=-1
|
||||
kerning first=65 second=86 amount=-3
|
||||
kerning first=84 second=119 amount=-2
|
||||
kerning first=34 second=110 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=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=79 second=89 amount=-2
|
||||
kerning first=84 second=122 amount=-2
|
||||
kerning first=68 second=84 amount=-3
|
||||
kerning first=76 second=86 amount=-7
|
||||
kerning first=74 second=65 amount=-1
|
||||
kerning first=107 second=101 amount=-1
|
||||
kerning first=80 second=46 amount=-14
|
||||
kerning first=89 second=93 amount=1
|
||||
kerning first=89 second=65 amount=-5
|
||||
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=87 second=46 amount=-5
|
||||
kerning first=47 second=47 amount=-9
|
||||
kerning first=75 second=103 amount=-1
|
||||
kerning first=89 second=84 amount=1
|
||||
kerning first=84 second=110 amount=-3
|
||||
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=-3
|
||||
kerning first=88 second=118 amount=-1
|
||||
kerning first=86 second=114 amount=-1
|
||||
kerning first=80 second=74 amount=-6
|
||||
kerning first=84 second=97 amount=-6
|
||||
kerning first=82 second=84 amount=-2
|
||||
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=44 second=39 amount=-10
|
||||
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=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=70 second=101 amount=-1
|
||||
kerning first=114 second=97 amount=-1
|
||||
kerning first=70 second=97 amount=-1
|
||||
kerning first=34 second=97 amount=-2
|
||||
kerning first=89 second=102 amount=-1
|
||||
kerning first=78 second=89 amount=-1
|
||||
kerning first=70 second=44 amount=-10
|
||||
kerning first=104 second=39 amount=-3
|
||||
kerning first=84 second=45 amount=-10
|
||||
kerning first=89 second=121 amount=-1
|
||||
kerning first=109 second=34 amount=-3
|
||||
kerning first=84 second=86 amount=1
|
||||
kerning first=87 second=99 amount=-1
|
||||
kerning first=32 second=84 amount=-2
|
||||
kerning first=98 second=122 amount=-1
|
||||
kerning first=89 second=112 amount=-1
|
||||
kerning first=89 second=103 amount=-2
|
||||
kerning first=65 second=116 amount=-1
|
||||
kerning first=88 second=81 amount=-1
|
||||
kerning first=102 second=34 amount=1
|
||||
kerning first=109 second=39 amount=-3
|
||||
kerning first=81 second=84 amount=-1
|
||||
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=-9
|
||||
kerning first=102 second=39 amount=1
|
||||
kerning first=44 second=34 amount=-10
|
||||
kerning first=34 second=109 amount=-1
|
||||
kerning first=84 second=101 amount=-3
|
||||
kerning first=75 second=119 amount=-2
|
||||
kerning first=84 second=81 amount=-1
|
||||
kerning first=76 second=121 amount=-4
|
||||
kerning first=69 second=101 amount=-1
|
||||
kerning first=80 second=90 amount=-1
|
||||
kerning first=89 second=97 amount=-2
|
||||
kerning first=89 second=109 amount=-1
|
||||
kerning first=90 second=99 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=34 second=113 amount=-2
|
||||
kerning first=89 second=41 amount=1
|
||||
kerning first=75 second=71 amount=-1
|
||||
kerning first=76 second=87 amount=-3
|
||||
kerning first=77 second=89 amount=-1
|
||||
kerning first=90 second=113 amount=-1
|
||||
kerning first=118 second=111 amount=-1
|
||||
kerning first=118 second=97 amount=-1
|
||||
kerning first=88 second=100 amount=-1
|
||||
kerning first=89 second=111 amount=-2
|
||||
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=-3
|
||||
kerning first=39 second=100 amount=-2
|
||||
kerning first=75 second=113 amount=-1
|
||||
kerning first=88 second=111 amount=-1
|
||||
kerning first=87 second=111 amount=-1
|
||||
kerning first=89 second=83 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=-6
|
||||
kerning first=97 second=121 amount=-1
|
||||
kerning first=87 second=113 amount=-1
|
||||
kerning first=73 second=84 amount=-1
|
||||
kerning first=121 second=46 amount=-6
|
||||
kerning first=75 second=99 amount=-1
|
||||
kerning first=65 second=112 amount=-2
|
||||
kerning first=65 second=85 amount=-1
|
||||
kerning first=76 second=67 amount=-2
|
||||
kerning first=76 second=81 amount=-2
|
||||
kerning first=102 second=100 amount=-1
|
||||
kerning first=75 second=79 amount=-1
|
||||
kerning first=39 second=65 amount=-4
|
||||
kerning first=65 second=84 amount=-4
|
||||
kerning first=90 second=101 amount=-1
|
||||
kerning first=84 second=121 amount=-3
|
||||
kerning first=114 second=39 amount=1
|
||||
kerning first=84 second=109 amount=-3
|
||||
kerning first=123 second=74 amount=-1
|
||||
kerning first=76 second=119 amount=-2
|
||||
kerning first=84 second=117 amount=-2
|
||||
kerning first=76 second=85 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=-6
|
||||
kerning first=79 second=86 amount=-1
|
||||
kerning first=79 second=46 amount=-4
|
||||
kerning first=76 second=89 amount=-10
|
||||
kerning first=68 second=65 amount=-1
|
||||
kerning first=79 second=84 amount=-3
|
||||
kerning first=87 second=100 amount=-1
|
||||
kerning first=84 second=32 amount=-2
|
||||
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=-10
|
||||
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=73 second=89 amount=-1
|
||||
kerning first=39 second=39 amount=-1
|
||||
kerning first=69 second=117 amount=-1
|
||||
kerning first=111 second=39 amount=-3
|
||||
kerning first=90 second=81 amount=-1
|
||||
BIN
src/web/static/fonts/bmfonts/RobotoBlack72White.png
Normal file
BIN
src/web/static/fonts/bmfonts/RobotoBlack72White.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 49 KiB |
103
src/web/static/fonts/bmfonts/RobotoMono72White.fnt
Normal file
103
src/web/static/fonts/bmfonts/RobotoMono72White.fnt
Normal file
@@ -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="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
|
||||
BIN
src/web/static/fonts/bmfonts/RobotoMono72White.png
Normal file
BIN
src/web/static/fonts/bmfonts/RobotoMono72White.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 51 KiB |
492
src/web/static/fonts/bmfonts/RobotoSlab72White.fnt
Normal file
492
src/web/static/fonts/bmfonts/RobotoSlab72White.fnt
Normal file
@@ -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="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
|
||||
BIN
src/web/static/fonts/bmfonts/RobotoSlab72White.png
Normal file
BIN
src/web/static/fonts/bmfonts/RobotoSlab72White.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 53 KiB |
@@ -21,6 +21,14 @@
|
||||
background-color: var(--secondary-background-colour);
|
||||
}
|
||||
|
||||
#controls-content {
|
||||
position: relative;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
transform-origin: center left;
|
||||
}
|
||||
|
||||
#auto-bake-label {
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
|
||||
@@ -29,6 +29,127 @@ const ALL_BYTES = [
|
||||
].join("");
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "CRC-8: nothing",
|
||||
input: "",
|
||||
expectedOutput: "00",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "CRC-8 Checksum",
|
||||
"args": ["CRC-8"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "CRC-8: default check",
|
||||
input: "123456789",
|
||||
expectedOutput: "f4",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "CRC-8 Checksum",
|
||||
"args": ["CRC-8"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "CRC-8: CDMA2000",
|
||||
input: "123456789",
|
||||
expectedOutput: "da",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "CRC-8 Checksum",
|
||||
"args": ["CRC-8/CDMA2000"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "CRC-8: DARC",
|
||||
input: "123456789",
|
||||
expectedOutput: "15",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "CRC-8 Checksum",
|
||||
"args": ["CRC-8/DARC"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "CRC-8: DVB-S2",
|
||||
input: "123456789",
|
||||
expectedOutput: "bc",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "CRC-8 Checksum",
|
||||
"args": ["CRC-8/DVB-S2"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "CRC-8: EBU",
|
||||
input: "123456789",
|
||||
expectedOutput: "97",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "CRC-8 Checksum",
|
||||
"args": ["CRC-8/EBU"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "CRC-8: I-CODE",
|
||||
input: "123456789",
|
||||
expectedOutput: "7e",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "CRC-8 Checksum",
|
||||
"args": ["CRC-8/I-CODE"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "CRC-8: ITU",
|
||||
input: "123456789",
|
||||
expectedOutput: "a1",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "CRC-8 Checksum",
|
||||
"args": ["CRC-8/ITU"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "CRC-8: MAXIM",
|
||||
input: "123456789",
|
||||
expectedOutput: "a1",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "CRC-8 Checksum",
|
||||
"args": ["CRC-8/MAXIM"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "CRC-8: ROHC",
|
||||
input: "123456789",
|
||||
expectedOutput: "d0",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "CRC-8 Checksum",
|
||||
"args": ["CRC-8/ROHC"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "CRC-8: WCDMA",
|
||||
input: "123456789",
|
||||
expectedOutput: "25",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "CRC-8 Checksum",
|
||||
"args": ["CRC-8/WCDMA"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "CRC-16: nothing",
|
||||
input: "",
|
||||
@@ -116,5 +237,5 @@ TestRegister.addTests([
|
||||
"args": []
|
||||
}
|
||||
]
|
||||
},
|
||||
}
|
||||
]);
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -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]
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
||||
|
||||
@@ -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,
|
||||
@@ -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]"
|
||||
|
||||
Reference in New Issue
Block a user