Replace png encode dependency with optimized CRC32 calculation
| @@ -48,6 +48,7 @@ | |||
| 48 | "cookie-parser": "^1.4.6", | 48 | "cookie-parser": "^1.4.6", |
| 49 | "cookie-session": "^2.1.0", | 49 | "cookie-session": "^2.1.0", |
| 50 | "cors": "^2.8.5", | 50 | "cors": "^2.8.5", |
| 51 | "crc": "^4.3.2", | ||
| 51 | "csrf-sync": "^4.0.3", | 52 | "csrf-sync": "^4.0.3", |
| 52 | "diff-match-patch": "^1.0.5", | 53 | "diff-match-patch": "^1.0.5", |
| 53 | "dompurify": "^3.2.4", | 54 | "dompurify": "^3.2.4", |
| @@ -76,7 +77,6 @@ | |||
| 76 | "node-persist": "^4.0.4", | 77 | "node-persist": "^4.0.4", |
| 77 | "open": "^8.4.2", | 78 | "open": "^8.4.2", |
| 78 | "png-chunk-text": "^1.0.0", | 79 | "png-chunk-text": "^1.0.0", |
| 79 | "png-chunks-encode": "^1.0.0", | ||
| 80 | "png-chunks-extract": "^1.0.0", | 80 | "png-chunks-extract": "^1.0.0", |
| 81 | "proxy-agent": "^6.5.0", | 81 | "proxy-agent": "^6.5.0", |
| 82 | "rate-limiter-flexible": "^5.0.5", | 82 | "rate-limiter-flexible": "^5.0.5", |
| @@ -121,7 +121,6 @@ | |||
| 121 | "@types/node": "^18.19.80", | 121 | "@types/node": "^18.19.80", |
| 122 | "@types/node-persist": "^3.1.8", | 122 | "@types/node-persist": "^3.1.8", |
| 123 | "@types/png-chunk-text": "^1.0.3", | 123 | "@types/png-chunk-text": "^1.0.3", |
| 124 | "@types/png-chunks-encode": "^1.0.2", | ||
| 125 | "@types/png-chunks-extract": "^1.0.2", | 124 | "@types/png-chunks-extract": "^1.0.2", |
| 126 | "@types/response-time": "^2.3.8", | 125 | "@types/response-time": "^2.3.8", |
| 127 | "@types/select2": "^4.0.63", | 126 | "@types/select2": "^4.0.63", |
| @@ -2033,13 +2032,6 @@ | |||
| 2033 | "dev": true, | 2032 | "dev": true, |
| 2034 | "license": "MIT" | 2033 | "license": "MIT" |
| 2035 | }, | 2034 | }, |
| 2036 | "node_modules/@types/png-chunks-encode": { | ||
| 2037 | "version": "1.0.2", | ||
| 2038 | "resolved": "https://registry.npmjs.org/@types/png-chunks-encode/-/png-chunks-encode-1.0.2.tgz", | ||
| 2039 | "integrity": "sha512-Dxn0aXEcSg1wVeHjvNlygm/+fKBDzWMCdxJYhjGUTeefFW/jYxWcrg+W7ppLBfH44iJMqeVBHtHBwtYQUeYvgw==", | ||
| 2040 | "dev": true, | ||
| 2041 | "license": "MIT" | ||
| 2042 | }, | ||
| 2043 | "node_modules/@types/png-chunks-extract": { | 2035 | "node_modules/@types/png-chunks-extract": { |
| 2044 | "version": "1.0.2", | 2036 | "version": "1.0.2", |
| 2045 | "resolved": "https://registry.npmjs.org/@types/png-chunks-extract/-/png-chunks-extract-1.0.2.tgz", | 2037 | "resolved": "https://registry.npmjs.org/@types/png-chunks-extract/-/png-chunks-extract-1.0.2.tgz", |
| @@ -3542,6 +3534,23 @@ | |||
| 3542 | "node": ">= 0.10" | 3534 | "node": ">= 0.10" |
| 3543 | } | 3535 | } |
| 3544 | }, | 3536 | }, |
| 3537 | "node_modules/crc": { | ||
| 3538 | "version": "4.3.2", | ||
| 3539 | "resolved": "https://registry.npmjs.org/crc/-/crc-4.3.2.tgz", | ||
| 3540 | "integrity": "sha512-uGDHf4KLLh2zsHa8D8hIQ1H/HtFQhyHrc0uhHBcoKGol/Xnb+MPYfUMw7cvON6ze/GUESTudKayDcJC5HnJv1A==", | ||
| 3541 | "license": "MIT", | ||
| 3542 | "engines": { | ||
| 3543 | "node": ">=12" | ||
| 3544 | }, | ||
| 3545 | "peerDependencies": { | ||
| 3546 | "buffer": ">=6.0.3" | ||
| 3547 | }, | ||
| 3548 | "peerDependenciesMeta": { | ||
| 3549 | "buffer": { | ||
| 3550 | "optional": true | ||
| 3551 | } | ||
| 3552 | } | ||
| 3553 | }, | ||
| 3545 | "node_modules/crc-32": { | 3554 | "node_modules/crc-32": { |
| 3546 | "version": "0.3.0", | 3555 | "version": "0.3.0", |
| 3547 | "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-0.3.0.tgz", | 3556 | "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-0.3.0.tgz", |
| @@ -6686,16 +6695,6 @@ | |||
| 6686 | "integrity": "sha512-DEROKU3SkkLGWNMzru3xPVgxyd48UGuMSZvioErCure6yhOc/pRH2ZV+SEn7nmaf7WNf3NdIpH+UTrRdKyq9Lw==", | 6695 | "integrity": "sha512-DEROKU3SkkLGWNMzru3xPVgxyd48UGuMSZvioErCure6yhOc/pRH2ZV+SEn7nmaf7WNf3NdIpH+UTrRdKyq9Lw==", |
| 6687 | "license": "MIT" | 6696 | "license": "MIT" |
| 6688 | }, | 6697 | }, |
| 6689 | "node_modules/png-chunks-encode": { | ||
| 6690 | "version": "1.0.0", | ||
| 6691 | "resolved": "https://registry.npmjs.org/png-chunks-encode/-/png-chunks-encode-1.0.0.tgz", | ||
| 6692 | "integrity": "sha512-J1jcHgbQRsIIgx5wxW9UmCymV3wwn4qCCJl6KYgEU/yHCh/L2Mwq/nMOkRPtmV79TLxRZj5w3tH69pvygFkDqA==", | ||
| 6693 | "license": "MIT", | ||
| 6694 | "dependencies": { | ||
| 6695 | "crc-32": "^0.3.0", | ||
| 6696 | "sliced": "^1.0.1" | ||
| 6697 | } | ||
| 6698 | }, | ||
| 6699 | "node_modules/png-chunks-extract": { | 6698 | "node_modules/png-chunks-extract": { |
| 6700 | "version": "1.0.0", | 6699 | "version": "1.0.0", |
| 6701 | "resolved": "https://registry.npmjs.org/png-chunks-extract/-/png-chunks-extract-1.0.0.tgz", | 6700 | "resolved": "https://registry.npmjs.org/png-chunks-extract/-/png-chunks-extract-1.0.0.tgz", |
| @@ -7532,12 +7531,6 @@ | |||
| 7532 | "dev": true, | 7531 | "dev": true, |
| 7533 | "license": "ISC" | 7532 | "license": "ISC" |
| 7534 | }, | 7533 | }, |
| 7535 | "node_modules/sliced": { | ||
| 7536 | "version": "1.0.1", | ||
| 7537 | "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", | ||
| 7538 | "integrity": "sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2Xxzm/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yA==", | ||
| 7539 | "license": "MIT" | ||
| 7540 | }, | ||
| 7541 | "node_modules/slidetoggle": { | 7534 | "node_modules/slidetoggle": { |
| 7542 | "version": "4.0.0", | 7535 | "version": "4.0.0", |
| 7543 | "resolved": "https://registry.npmjs.org/slidetoggle/-/slidetoggle-4.0.0.tgz", | 7536 | "resolved": "https://registry.npmjs.org/slidetoggle/-/slidetoggle-4.0.0.tgz", |
| @@ -38,6 +38,7 @@ | |||
| 38 | "cookie-parser": "^1.4.6", | 38 | "cookie-parser": "^1.4.6", |
| 39 | "cookie-session": "^2.1.0", | 39 | "cookie-session": "^2.1.0", |
| 40 | "cors": "^2.8.5", | 40 | "cors": "^2.8.5", |
| 41 | "crc": "^4.3.2", | ||
| 41 | "csrf-sync": "^4.0.3", | 42 | "csrf-sync": "^4.0.3", |
| 42 | "diff-match-patch": "^1.0.5", | 43 | "diff-match-patch": "^1.0.5", |
| 43 | "dompurify": "^3.2.4", | 44 | "dompurify": "^3.2.4", |
| @@ -66,7 +67,6 @@ | |||
| 66 | "node-persist": "^4.0.4", | 67 | "node-persist": "^4.0.4", |
| 67 | "open": "^8.4.2", | 68 | "open": "^8.4.2", |
| 68 | "png-chunk-text": "^1.0.0", | 69 | "png-chunk-text": "^1.0.0", |
| 69 | "png-chunks-encode": "^1.0.0", | ||
| 70 | "png-chunks-extract": "^1.0.0", | 70 | "png-chunks-extract": "^1.0.0", |
| 71 | "proxy-agent": "^6.5.0", | 71 | "proxy-agent": "^6.5.0", |
| 72 | "rate-limiter-flexible": "^5.0.5", | 72 | "rate-limiter-flexible": "^5.0.5", |
| @@ -151,7 +151,6 @@ | |||
| 151 | "@types/node": "^18.19.80", | 151 | "@types/node": "^18.19.80", |
| 152 | "@types/node-persist": "^3.1.8", | 152 | "@types/node-persist": "^3.1.8", |
| 153 | "@types/png-chunk-text": "^1.0.3", | 153 | "@types/png-chunk-text": "^1.0.3", |
| 154 | "@types/png-chunks-encode": "^1.0.2", | ||
| 155 | "@types/png-chunks-extract": "^1.0.2", | 154 | "@types/png-chunks-extract": "^1.0.2", |
| 156 | "@types/response-time": "^2.3.8", | 155 | "@types/response-time": "^2.3.8", |
| 157 | "@types/select2": "^4.0.63", | 156 | "@types/select2": "^4.0.63", |
| @@ -1,7 +1,7 @@ | |||
| 1 | import fs from 'node:fs'; | 1 | import fs from 'node:fs'; |
| 2 | import { Buffer } from 'node:buffer'; | 2 | import { Buffer } from 'node:buffer'; |
| 3 | 3 | ||
| 4 | import encode from 'png-chunks-encode'; | 4 | import encode from './png/encode.js'; |
| 5 | import extract from 'png-chunks-extract'; | 5 | import extract from 'png-chunks-extract'; |
| 6 | import PNGtext from 'png-chunk-text'; | 6 | import PNGtext from 'png-chunk-text'; |
| 7 | 7 | ||
| @@ -0,0 +1,68 @@ | |||
| 1 | import { crc32 } from 'crc'; | ||
| 2 | |||
| 3 | /** | ||
| 4 | * Encodes PNG chunks into a PNG file format buffer. | ||
| 5 | * @param {Array<{ name: string; data: Uint8Array }>} chunks Array of PNG chunks | ||
| 6 | * @returns {Uint8Array} Encoded PNG data | ||
| 7 | * @copyright Based on https://github.com/hughsk/png-chunks-encode (MIT) | ||
| 8 | */ | ||
| 9 | export default function encode(chunks) { | ||
| 10 | const uint8 = new Uint8Array(4); | ||
| 11 | const int32 = new Int32Array(uint8.buffer); | ||
| 12 | const uint32 = new Uint32Array(uint8.buffer); | ||
| 13 | |||
| 14 | let totalSize = 8; | ||
| 15 | let idx = totalSize; | ||
| 16 | |||
| 17 | for (let i = 0; i < chunks.length; i++) { | ||
| 18 | totalSize += chunks[i].data.length; | ||
| 19 | totalSize += 12; | ||
| 20 | } | ||
| 21 | |||
| 22 | const output = new Uint8Array(totalSize); | ||
| 23 | |||
| 24 | output[0] = 0x89; | ||
| 25 | output[1] = 0x50; | ||
| 26 | output[2] = 0x4E; | ||
| 27 | output[3] = 0x47; | ||
| 28 | output[4] = 0x0D; | ||
| 29 | output[5] = 0x0A; | ||
| 30 | output[6] = 0x1A; | ||
| 31 | output[7] = 0x0A; | ||
| 32 | |||
| 33 | for (let i = 0; i < chunks.length; i++) { | ||
| 34 | const { name, data } = chunks[i]; | ||
| 35 | const size = data.length; | ||
| 36 | const nameChars = [ | ||
| 37 | name.charCodeAt(0), | ||
| 38 | name.charCodeAt(1), | ||
| 39 | name.charCodeAt(2), | ||
| 40 | name.charCodeAt(3), | ||
| 41 | ]; | ||
| 42 | |||
| 43 | uint32[0] = size; | ||
| 44 | output[idx++] = uint8[3]; | ||
| 45 | output[idx++] = uint8[2]; | ||
| 46 | output[idx++] = uint8[1]; | ||
| 47 | output[idx++] = uint8[0]; | ||
| 48 | |||
| 49 | output[idx++] = nameChars[0]; | ||
| 50 | output[idx++] = nameChars[1]; | ||
| 51 | output[idx++] = nameChars[2]; | ||
| 52 | output[idx++] = nameChars[3]; | ||
| 53 | |||
| 54 | for (let j = 0; j < size;) { | ||
| 55 | output[idx++] = data[j++]; | ||
| 56 | } | ||
| 57 | |||
| 58 | const crc = crc32(data, crc32(new Uint8Array(nameChars))); | ||
| 59 | |||
| 60 | int32[0] = crc; | ||
| 61 | output[idx++] = uint8[3]; | ||
| 62 | output[idx++] = uint8[2]; | ||
| 63 | output[idx++] = uint8[1]; | ||
| 64 | output[idx++] = uint8[0]; | ||
| 65 | } | ||
| 66 | |||
| 67 | return output; | ||
| 68 | } | ||