Replace png encode dependency with optimized CRC32 calculation
| @@ -48,6 +48,7 @@ | ||
| 48 | 48 | "cookie-parser": "^1.4.6", |
| 49 | 49 | "cookie-session": "^2.1.0", |
| 50 | 50 | "cors": "^2.8.5", |
| 51 | + "crc": "^4.3.2", | |
| 51 | 52 | "csrf-sync": "^4.0.3", |
| 52 | 53 | "diff-match-patch": "^1.0.5", |
| 53 | 54 | "dompurify": "^3.2.4", |
| @@ -76,7 +77,6 @@ | ||
| 76 | 77 | "node-persist": "^4.0.4", |
| 77 | 78 | "open": "^8.4.2", |
| 78 | 79 | "png-chunk-text": "^1.0.0", |
| 79 | - "png-chunks-encode": "^1.0.0", | |
| 80 | 80 | "png-chunks-extract": "^1.0.0", |
| 81 | 81 | "proxy-agent": "^6.5.0", |
| 82 | 82 | "rate-limiter-flexible": "^5.0.5", |
| @@ -121,7 +121,6 @@ | ||
| 121 | 121 | "@types/node": "^18.19.80", |
| 122 | 122 | "@types/node-persist": "^3.1.8", |
| 123 | 123 | "@types/png-chunk-text": "^1.0.3", |
| 124 | - "@types/png-chunks-encode": "^1.0.2", | |
| 125 | 124 | "@types/png-chunks-extract": "^1.0.2", |
| 126 | 125 | "@types/response-time": "^2.3.8", |
| 127 | 126 | "@types/select2": "^4.0.63", |
| @@ -2033,13 +2032,6 @@ | ||
| 2033 | 2032 | "dev": true, |
| 2034 | 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 | 2035 | "node_modules/@types/png-chunks-extract": { |
| 2044 | 2036 | "version": "1.0.2", |
| 2045 | 2037 | "resolved": "https://registry.npmjs.org/@types/png-chunks-extract/-/png-chunks-extract-1.0.2.tgz", |
| @@ -3542,6 +3534,23 @@ | ||
| 3542 | 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 | 3554 | "node_modules/crc-32": { |
| 3546 | 3555 | "version": "0.3.0", |
| 3547 | 3556 | "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-0.3.0.tgz", |
| @@ -6686,16 +6695,6 @@ | ||
| 6686 | 6695 | "integrity": "sha512-DEROKU3SkkLGWNMzru3xPVgxyd48UGuMSZvioErCure6yhOc/pRH2ZV+SEn7nmaf7WNf3NdIpH+UTrRdKyq9Lw==", |
| 6687 | 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 | 6698 | "node_modules/png-chunks-extract": { |
| 6700 | 6699 | "version": "1.0.0", |
| 6701 | 6700 | "resolved": "https://registry.npmjs.org/png-chunks-extract/-/png-chunks-extract-1.0.0.tgz", |
| @@ -7532,12 +7531,6 @@ | ||
| 7532 | 7531 | "dev": true, |
| 7533 | 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 | 7534 | "node_modules/slidetoggle": { |
| 7542 | 7535 | "version": "4.0.0", |
| 7543 | 7536 | "resolved": "https://registry.npmjs.org/slidetoggle/-/slidetoggle-4.0.0.tgz", |
| @@ -38,6 +38,7 @@ | ||
| 38 | 38 | "cookie-parser": "^1.4.6", |
| 39 | 39 | "cookie-session": "^2.1.0", |
| 40 | 40 | "cors": "^2.8.5", |
| 41 | + "crc": "^4.3.2", | |
| 41 | 42 | "csrf-sync": "^4.0.3", |
| 42 | 43 | "diff-match-patch": "^1.0.5", |
| 43 | 44 | "dompurify": "^3.2.4", |
| @@ -66,7 +67,6 @@ | ||
| 66 | 67 | "node-persist": "^4.0.4", |
| 67 | 68 | "open": "^8.4.2", |
| 68 | 69 | "png-chunk-text": "^1.0.0", |
| 69 | - "png-chunks-encode": "^1.0.0", | |
| 70 | 70 | "png-chunks-extract": "^1.0.0", |
| 71 | 71 | "proxy-agent": "^6.5.0", |
| 72 | 72 | "rate-limiter-flexible": "^5.0.5", |
| @@ -151,7 +151,6 @@ | ||
| 151 | 151 | "@types/node": "^18.19.80", |
| 152 | 152 | "@types/node-persist": "^3.1.8", |
| 153 | 153 | "@types/png-chunk-text": "^1.0.3", |
| 154 | - "@types/png-chunks-encode": "^1.0.2", | |
| 155 | 154 | "@types/png-chunks-extract": "^1.0.2", |
| 156 | 155 | "@types/response-time": "^2.3.8", |
| 157 | 156 | "@types/select2": "^4.0.63", |
| @@ -1,7 +1,7 @@ | ||
| 1 | 1 | import fs from 'node:fs'; |
| 2 | 2 | import { Buffer } from 'node:buffer'; |
| 3 | 3 | |
| 4 | 4 | import encode from './png-chunks-/encode.js'; |
| 5 | 5 | import extract from 'png-chunks-extract'; |
| 6 | 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 | +} | |