sharp by wasm
This commit is contained in:
@@ -563,7 +563,7 @@ Company-scoped POS terminals. Auth via selected company (`google_auth.selected_c
|
|||||||
|
|
||||||
`move` moves a category to a new parent. Both `id` (source) and `parentId` (target) are validated via `resolveCategoryAccess` — the target must be a real category of the same authorized company, else `Parent not found`. Moving into itself or into a descendant (cycle) → `Invalid parent`. The moved category gets the next sibling `sort` under the new parent. Returns `{ id, parentId, sort }`. For `POST /api/category/:id/move`.
|
`move` moves a category to a new parent. Both `id` (source) and `parentId` (target) are validated via `resolveCategoryAccess` — the target must be a real category of the same authorized company, else `Parent not found`. Moving into itself or into a descendant (cycle) → `Invalid parent`. The moved category gets the next sibling `sort` under the new parent. Returns `{ id, parentId, sort }`. For `POST /api/category/:id/move`.
|
||||||
|
|
||||||
`addImage` accepts a full-size AVIF `Buffer`. Full image: if already AVIF and ≤1000×1000, stored as-is; otherwise scaled to max 1000×1000 (`storageDir/fullbinary`). Thumb always scaled to max 200×200 (`storageDir/thumbbinary`) via `sharp`. Assigns random `fullHash` (`pic.hash`, unique), computes `thumbhash`, links `categorypic`. Auth via `resolveCategoryAccess`. Errors: `Category not found`, `Not authorized`.
|
`addImage` accepts a full-size AVIF `Buffer`. Full image: if already AVIF and ≤1000×1000, stored as-is; otherwise scaled to max 1000×1000 (`storageDir/fullbinary`). Thumb always scaled to max 200×200 (`storageDir/thumbbinary`) via `wasm-image-optimization`. Assigns random `fullHash` (`pic.hash`, unique), computes `thumbhash`, links `categorypic`. Auth via `resolveCategoryAccess`. Errors: `Category not found`, `Not authorized`.
|
||||||
|
|
||||||
`addImage` returns:
|
`addImage` returns:
|
||||||
|
|
||||||
@@ -601,7 +601,7 @@ Company-scoped POS terminals. Auth via selected company (`google_auth.selected_c
|
|||||||
| `orderImages` | `(googleAuthId: string, sku: string, { fullHashes: string[] })` | `{ fullHashes: string[] }` |
|
| `orderImages` | `(googleAuthId: string, sku: string, { fullHashes: string[] })` | `{ fullHashes: string[] }` |
|
||||||
| `delete` | `(googleAuthId: string, sku: string)` | `void` |
|
| `delete` | `(googleAuthId: string, sku: string)` | `void` |
|
||||||
|
|
||||||
`addImage` accepts a full-size AVIF `Buffer`. Full image: if already AVIF and ≤1000×1000, stored as-is; otherwise scaled to max 1000×1000 (`storageDir/fullbinary`). Thumb always scaled to max 200×200 (`storageDir/thumbbinary`) via `sharp`. Assigns random `fullHash` (`pic.hash`, unique), computes `thumbhash`, links `articlepic`. Auth like `getBySku`. Errors: `Article not found`, `Not authorized`.
|
`addImage` accepts a full-size AVIF `Buffer`. Full image: if already AVIF and ≤1000×1000, stored as-is; otherwise scaled to max 1000×1000 (`storageDir/fullbinary`). Thumb always scaled to max 200×200 (`storageDir/thumbbinary`) via `wasm-image-optimization`. Assigns random `fullHash` (`pic.hash`, unique), computes `thumbhash`, links `articlepic`. Auth like `getBySku`. Errors: `Article not found`, `Not authorized`.
|
||||||
|
|
||||||
`addImage` returns `ImageResult`:
|
`addImage` returns `ImageResult`:
|
||||||
|
|
||||||
|
|||||||
651
package-lock.json
generated
651
package-lock.json
generated
@@ -14,9 +14,9 @@
|
|||||||
"chalk": "^6.0.1",
|
"chalk": "^6.0.1",
|
||||||
"dotenv": "^18.0.8",
|
"dotenv": "^18.0.8",
|
||||||
"pdfconvert-wasm": "^0.3.0",
|
"pdfconvert-wasm": "^0.3.0",
|
||||||
"sharp": "^0.35.5",
|
|
||||||
"skelehash-wasm": "^0.1.1",
|
"skelehash-wasm": "^0.1.1",
|
||||||
"thumbhash": "^0.1.1"
|
"thumbhash": "^0.1.1",
|
||||||
|
"wasm-image-optimization": "^2.0.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"better-sqlite3": "^13.0.3",
|
"better-sqlite3": "^13.0.3",
|
||||||
@@ -339,570 +339,12 @@
|
|||||||
"node": ">= 20.12.0"
|
"node": ">= 20.12.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@emnapi/runtime": {
|
|
||||||
"version": "1.11.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz",
|
|
||||||
"integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
|
||||||
"tslib": "^2.4.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@hpcc-js/wasm-graphviz": {
|
"node_modules/@hpcc-js/wasm-graphviz": {
|
||||||
"version": "1.30.0",
|
"version": "1.30.0",
|
||||||
"resolved": "https://registry.npmjs.org/@hpcc-js/wasm-graphviz/-/wasm-graphviz-1.30.0.tgz",
|
"resolved": "https://registry.npmjs.org/@hpcc-js/wasm-graphviz/-/wasm-graphviz-1.30.0.tgz",
|
||||||
"integrity": "sha512-T20IKosOZuex2qV049fQokVJy2MWv8w9Md5V/4mRKCXDf49fBCR50VD1yBlPYHaQlHPsFGRdqXN//r59vZliWQ==",
|
"integrity": "sha512-T20IKosOZuex2qV049fQokVJy2MWv8w9Md5V/4mRKCXDf49fBCR50VD1yBlPYHaQlHPsFGRdqXN//r59vZliWQ==",
|
||||||
"license": "Apache-2.0"
|
"license": "Apache-2.0"
|
||||||
},
|
},
|
||||||
"node_modules/@img/colour": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz",
|
|
||||||
"integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-darwin-arm64": {
|
|
||||||
"version": "0.35.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.5.tgz",
|
|
||||||
"integrity": "sha512-QRUlFQ0WxvdWyqqG/WtI3iupfD5rBzmCHXSdPsY91sAtVtTo7Q4cb6zOccZ3gqEqkr0f1As1ehLqmEpDsRf+lg==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"darwin"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=20.9.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@img/sharp-libvips-darwin-arm64": "1.3.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-darwin-x64": {
|
|
||||||
"version": "0.35.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.5.tgz",
|
|
||||||
"integrity": "sha512-+BR255RhDlpygUpOc/Jdt1nT6DQ3XG/ERo5wbcdOf5Q320dKtPCKPLR1LJs9VGXRaMa8l1uUa0tkCNOXiAxZUw==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"darwin"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=20.9.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@img/sharp-libvips-darwin-x64": "1.3.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-freebsd-wasm32": {
|
|
||||||
"version": "0.35.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.5.tgz",
|
|
||||||
"integrity": "sha512-Y/z91nEZ4uIBX5X3nfTovjU9lHNKFYbL2lpHCLVNmXQK03VIZvXBBt0KxbPGp2SdGSF+2mQU4e+hQaWOt86iAw==",
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"freebsd"
|
|
||||||
],
|
|
||||||
"dependencies": {
|
|
||||||
"@img/sharp-wasm32": "0.35.5"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=20.9.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-libvips-darwin-arm64": {
|
|
||||||
"version": "1.3.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.4.tgz",
|
|
||||||
"integrity": "sha512-5R89nBYiRdUlSWJxPhO+GVtaXzXSxKnRu/xqMn3KTA3L9EB9Oy/P+Nn2f2vlhPuUdy/Zusb2DarbyTpGCfEDuw==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"license": "LGPL-3.0-or-later",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"darwin"
|
|
||||||
],
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-libvips-darwin-x64": {
|
|
||||||
"version": "1.3.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.4.tgz",
|
|
||||||
"integrity": "sha512-iR2OKH80yi0U+dUplyh3/xdpFvps6YkCwsXenIJxqxR1v9o+xtKTGbS9H7cps+2Vxjc8B1j96p75NmTGjIhtpQ==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"license": "LGPL-3.0-or-later",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"darwin"
|
|
||||||
],
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-libvips-linux-arm": {
|
|
||||||
"version": "1.3.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.4.tgz",
|
|
||||||
"integrity": "sha512-LmRtTsOHuvM2+wlO2Db37dx5MiZhB0FvSunciw48YjdOkZz9KAiRbm8ujeMOA1INqmei5NapFxYEK1D1ZSidmw==",
|
|
||||||
"cpu": [
|
|
||||||
"arm"
|
|
||||||
],
|
|
||||||
"libc": [
|
|
||||||
"glibc"
|
|
||||||
],
|
|
||||||
"license": "LGPL-3.0-or-later",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-libvips-linux-arm64": {
|
|
||||||
"version": "1.3.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.4.tgz",
|
|
||||||
"integrity": "sha512-Y3dgX/6lE2QhQb+Gxy0WZxfg9MEm/JBjamZpS2IklP7xIQoKN4hzAm7KcMVGtaVDt3neE9OKBC7vAfonA/Lr1A==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"libc": [
|
|
||||||
"glibc"
|
|
||||||
],
|
|
||||||
"license": "LGPL-3.0-or-later",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-libvips-linux-ppc64": {
|
|
||||||
"version": "1.3.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.4.tgz",
|
|
||||||
"integrity": "sha512-Le6boB8Tai0Nis+gIxIpKx68UDVVIqdR8Tin5Yf1z2LJJQLDJvCDRqRu+jC2qCoD+eIomonmOwB4smBRxfVpYQ==",
|
|
||||||
"cpu": [
|
|
||||||
"ppc64"
|
|
||||||
],
|
|
||||||
"libc": [
|
|
||||||
"glibc"
|
|
||||||
],
|
|
||||||
"license": "LGPL-3.0-or-later",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-libvips-linux-riscv64": {
|
|
||||||
"version": "1.3.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.4.tgz",
|
|
||||||
"integrity": "sha512-aHkkIEHPRdQEegJN20MLmGtxYD9R2wQr3Cwpddnu5+YKMt6Uzax7S9h5gpZTo8wyrGuZSlfQ63OevL5mTyOC7Q==",
|
|
||||||
"cpu": [
|
|
||||||
"riscv64"
|
|
||||||
],
|
|
||||||
"libc": [
|
|
||||||
"glibc"
|
|
||||||
],
|
|
||||||
"license": "LGPL-3.0-or-later",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-libvips-linux-s390x": {
|
|
||||||
"version": "1.3.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.4.tgz",
|
|
||||||
"integrity": "sha512-ra/mB6MikESDUO7Yg+Mi95bFBb9GsObURuhnOv3OqknjGe9sZrG8tCe9q0xSIGrtLgvgw0gKnFWcK4blSgQOuQ==",
|
|
||||||
"cpu": [
|
|
||||||
"s390x"
|
|
||||||
],
|
|
||||||
"libc": [
|
|
||||||
"glibc"
|
|
||||||
],
|
|
||||||
"license": "LGPL-3.0-or-later",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-libvips-linux-x64": {
|
|
||||||
"version": "1.3.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.4.tgz",
|
|
||||||
"integrity": "sha512-GJ//SSXbnwSDes02umB3nDJLFcQzw8a18V8fyhqr6tV515tOEMdImjjxj1AoafMRz56F3PHgftnj1QEKSU1zkw==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"libc": [
|
|
||||||
"glibc"
|
|
||||||
],
|
|
||||||
"license": "LGPL-3.0-or-later",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-libvips-linuxmusl-arm64": {
|
|
||||||
"version": "1.3.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.4.tgz",
|
|
||||||
"integrity": "sha512-hvulFwtjUcagsis6BBxHwGFwWoNZjgYmULGVrZcyfNbjA8hKILbRxGg15/7w5HDyXHXUos/j6baAWqnCyQ2DWA==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"libc": [
|
|
||||||
"musl"
|
|
||||||
],
|
|
||||||
"license": "LGPL-3.0-or-later",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-libvips-linuxmusl-x64": {
|
|
||||||
"version": "1.3.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.4.tgz",
|
|
||||||
"integrity": "sha512-6zXKeE/p39I1AmA3cJG35eyBGNqNddLnUXjhwBnsGjFPWqf5VKkDBEqaEkPDoTEtkxwi2vv8Tcr2mDyP4So7Fg==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"libc": [
|
|
||||||
"musl"
|
|
||||||
],
|
|
||||||
"license": "LGPL-3.0-or-later",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-linux-arm": {
|
|
||||||
"version": "0.35.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.5.tgz",
|
|
||||||
"integrity": "sha512-LEaXK2WdXVK5ykcw0buWyPMsmLLL2vpHLD6yrNSW+JGEL3BZPA4tpKN6iaMc4AxTTAoaX/sU1rOL51lcIz48ZQ==",
|
|
||||||
"cpu": [
|
|
||||||
"arm"
|
|
||||||
],
|
|
||||||
"libc": [
|
|
||||||
"glibc"
|
|
||||||
],
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=20.9.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@img/sharp-libvips-linux-arm": "1.3.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-linux-arm64": {
|
|
||||||
"version": "0.35.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.5.tgz",
|
|
||||||
"integrity": "sha512-LYVx5JTsOM2CBzmxreh+nl64/3H6Xb09iSLknqH47z2T2DFFxDeFLP5y4dJwe6H7uGQlHPyEEtIqyo3DYsRwdQ==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"libc": [
|
|
||||||
"glibc"
|
|
||||||
],
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=20.9.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@img/sharp-libvips-linux-arm64": "1.3.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-linux-ppc64": {
|
|
||||||
"version": "0.35.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.5.tgz",
|
|
||||||
"integrity": "sha512-QVxAAq8evVRI9ia2vqgwrmWucn5Dfv+JdWzj75pD8omHLPSP7f8p20O8jxzjCcuCEQEOtYOZUmX1hkiZ0kdevA==",
|
|
||||||
"cpu": [
|
|
||||||
"ppc64"
|
|
||||||
],
|
|
||||||
"libc": [
|
|
||||||
"glibc"
|
|
||||||
],
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=20.9.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@img/sharp-libvips-linux-ppc64": "1.3.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-linux-riscv64": {
|
|
||||||
"version": "0.35.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.5.tgz",
|
|
||||||
"integrity": "sha512-LtdreXguaavKODPIfzJ4kffx7UNt1omwtK0rch4EBbbSTXPnxWmYSayXdLJw0fJzQ97kHt1gL/yh4tvU+nCyRQ==",
|
|
||||||
"cpu": [
|
|
||||||
"riscv64"
|
|
||||||
],
|
|
||||||
"libc": [
|
|
||||||
"glibc"
|
|
||||||
],
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=20.9.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@img/sharp-libvips-linux-riscv64": "1.3.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-linux-s390x": {
|
|
||||||
"version": "0.35.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.5.tgz",
|
|
||||||
"integrity": "sha512-UZasTOFiYzotTsGOCu42BfUzP6Tu6Do/947iRm1RsLKvlllxwGcn4RN27LibGWceix4Y+Pmw3jsnTcCQIgWjqA==",
|
|
||||||
"cpu": [
|
|
||||||
"s390x"
|
|
||||||
],
|
|
||||||
"libc": [
|
|
||||||
"glibc"
|
|
||||||
],
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=20.9.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@img/sharp-libvips-linux-s390x": "1.3.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-linux-x64": {
|
|
||||||
"version": "0.35.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.5.tgz",
|
|
||||||
"integrity": "sha512-SxFtLTeJInhAA9Q836kux2vZNeOBQEx658qvbboZScr0wIARym3IcGmW7KpVD5sbVg0Ojy+udFQdayYIZyoNog==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"libc": [
|
|
||||||
"glibc"
|
|
||||||
],
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=20.9.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@img/sharp-libvips-linux-x64": "1.3.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-linuxmusl-arm64": {
|
|
||||||
"version": "0.35.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.5.tgz",
|
|
||||||
"integrity": "sha512-9HbMclmI1zlNkFRs3z9/eBtDjfD0sGlrX1z6b1qwmiFY5ElDLh4BC0LPBdVp7z1DXFiKlIcznf+ZlsuZzLxQqg==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"libc": [
|
|
||||||
"musl"
|
|
||||||
],
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=20.9.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@img/sharp-libvips-linuxmusl-arm64": "1.3.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-linuxmusl-x64": {
|
|
||||||
"version": "0.35.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.5.tgz",
|
|
||||||
"integrity": "sha512-4KOphqB035HrVdqLZfCgMzzERrQkkzOwRhl4OAkRO1YCldbaFjySXMaK534Mo0V+LndnlJk+sbUyLeU0ULyD1A==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"libc": [
|
|
||||||
"musl"
|
|
||||||
],
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=20.9.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@img/sharp-libvips-linuxmusl-x64": "1.3.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-wasm32": {
|
|
||||||
"version": "0.35.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.5.tgz",
|
|
||||||
"integrity": "sha512-Ptsga1su4tQx+LLF1ECS9U6nz5kmrXKo6XVbtR48Ke3ZRxxgaWBu7IDtEe1quo8hiupwm6WFqxVlXaSf7IINGQ==",
|
|
||||||
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
|
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@emnapi/runtime": "^1.11.3"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=20.9.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-webcontainers-wasm32": {
|
|
||||||
"version": "0.35.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.5.tgz",
|
|
||||||
"integrity": "sha512-hfhF/FmoQyTUkA0bIKFOtw536BQSeBMe6BF6QyWlrPxT754+TFLaZ7sKKTfvvM0yJgKgaYTwnFCIZ/GuDw5SUA==",
|
|
||||||
"cpu": [
|
|
||||||
"wasm32"
|
|
||||||
],
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@img/sharp-wasm32": "0.35.5"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=20.9.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-win32-arm64": {
|
|
||||||
"version": "0.35.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.5.tgz",
|
|
||||||
"integrity": "sha512-X4t7g+7ZA5DKblCBEXGjUqqemj4vczING/5viFwAL8h4N3qYeyjwdCvRLHi4EdOUI+2Z7UFlp1VM+p/AuEtm6Q==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"license": "Apache-2.0 AND LGPL-3.0-or-later",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"win32"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=20.9.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-win32-ia32": {
|
|
||||||
"version": "0.35.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.5.tgz",
|
|
||||||
"integrity": "sha512-5Zm82LoBc43nhwNybZlG7Y1KO//Zhsn306fQl29ZOuStHLGTo3BWL83q3cznX0poxSAMuYL1On/BHBxkBeKr6A==",
|
|
||||||
"cpu": [
|
|
||||||
"ia32"
|
|
||||||
],
|
|
||||||
"license": "Apache-2.0 AND LGPL-3.0-or-later",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"win32"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": "^20.9.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-win32-x64": {
|
|
||||||
"version": "0.35.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.5.tgz",
|
|
||||||
"integrity": "sha512-x76eH0vEiHlcMQu8Y8IenntaACtddpT6W0wmXtWrnKcnKI7ME5DdgqhAD6SEWOEl1v2zDvkZDhFA9KnURwpfqg==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"license": "Apache-2.0 AND LGPL-3.0-or-later",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"win32"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=20.9.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@js-joda/core": {
|
"node_modules/@js-joda/core": {
|
||||||
"version": "6.3.0",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@js-joda/core/-/core-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@js-joda/core/-/core-6.3.0.tgz",
|
||||||
@@ -1153,15 +595,6 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/detect-libc": {
|
|
||||||
"version": "2.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
|
||||||
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/dotenv": {
|
"node_modules/dotenv": {
|
||||||
"version": "18.0.9",
|
"version": "18.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-18.0.9.tgz",
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-18.0.9.tgz",
|
||||||
@@ -1626,6 +1059,7 @@
|
|||||||
"version": "7.8.5",
|
"version": "7.8.5",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
|
||||||
"integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
|
"integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
|
||||||
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"bin": {
|
"bin": {
|
||||||
"semver": "bin/semver.js"
|
"semver": "bin/semver.js"
|
||||||
@@ -1634,55 +1068,6 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/sharp": {
|
|
||||||
"version": "0.35.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.5.tgz",
|
|
||||||
"integrity": "sha512-Ywn4OnzGukp7CDMrp08RQ50YKmuwG47brZgIVPTvBaaAfQlRlygrRqSrxdCiL9M+LlzLBiJ68IR1QqvzHyjC7g==",
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"dependencies": {
|
|
||||||
"@img/colour": "^1.1.0",
|
|
||||||
"detect-libc": "^2.1.2",
|
|
||||||
"semver": "^7.8.5"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=20.9.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@img/sharp-darwin-arm64": "0.35.5",
|
|
||||||
"@img/sharp-darwin-x64": "0.35.5",
|
|
||||||
"@img/sharp-freebsd-wasm32": "0.35.5",
|
|
||||||
"@img/sharp-libvips-darwin-arm64": "1.3.4",
|
|
||||||
"@img/sharp-libvips-darwin-x64": "1.3.4",
|
|
||||||
"@img/sharp-libvips-linux-arm": "1.3.4",
|
|
||||||
"@img/sharp-libvips-linux-arm64": "1.3.4",
|
|
||||||
"@img/sharp-libvips-linux-ppc64": "1.3.4",
|
|
||||||
"@img/sharp-libvips-linux-riscv64": "1.3.4",
|
|
||||||
"@img/sharp-libvips-linux-s390x": "1.3.4",
|
|
||||||
"@img/sharp-libvips-linux-x64": "1.3.4",
|
|
||||||
"@img/sharp-libvips-linuxmusl-arm64": "1.3.4",
|
|
||||||
"@img/sharp-libvips-linuxmusl-x64": "1.3.4",
|
|
||||||
"@img/sharp-linux-arm": "0.35.5",
|
|
||||||
"@img/sharp-linux-arm64": "0.35.5",
|
|
||||||
"@img/sharp-linux-ppc64": "0.35.5",
|
|
||||||
"@img/sharp-linux-riscv64": "0.35.5",
|
|
||||||
"@img/sharp-linux-s390x": "0.35.5",
|
|
||||||
"@img/sharp-linux-x64": "0.35.5",
|
|
||||||
"@img/sharp-linuxmusl-arm64": "0.35.5",
|
|
||||||
"@img/sharp-linuxmusl-x64": "0.35.5",
|
|
||||||
"@img/sharp-webcontainers-wasm32": "0.35.5",
|
|
||||||
"@img/sharp-win32-arm64": "0.35.5",
|
|
||||||
"@img/sharp-win32-ia32": "0.35.5",
|
|
||||||
"@img/sharp-win32-x64": "0.35.5"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"@types/node": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/sisteransi": {
|
"node_modules/sisteransi": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
||||||
@@ -1746,7 +1131,7 @@
|
|||||||
"version": "2.8.1",
|
"version": "2.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "0BSD"
|
"license": "0BSD"
|
||||||
},
|
},
|
||||||
"node_modules/undici-types": {
|
"node_modules/undici-types": {
|
||||||
@@ -1756,6 +1141,34 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/wasm-image-optimization": {
|
||||||
|
"version": "2.0.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/wasm-image-optimization/-/wasm-image-optimization-2.0.13.tgz",
|
||||||
|
"integrity": "sha512-MGaFZtdxMHZyaL3VUUcNkN8qccJcy33lcXoUIaegav/y1TiK6c2aALbKAjoe4bXHFI7nDl+5+TG0e9Y8j1/h9Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"commander": "15.0.0",
|
||||||
|
"worker-lib": "2.2.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"wasm-image-optimization": "dist/cli.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/wasm-image-optimization/node_modules/commander": {
|
||||||
|
"version": "15.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz",
|
||||||
|
"integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=22.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/worker-lib": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/worker-lib/-/worker-lib-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-CauU4vz3vZUBG3A2CY93GY94KLhbH8JtPKtuvKu2w5G07cHkZ73QkTAJ/lEHDL6arT5WDu1qpU++T0+kGDgSCg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/wsl-utils": {
|
"node_modules/wsl-utils": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-1.0.1.tgz",
|
||||||
|
|||||||
@@ -30,9 +30,9 @@
|
|||||||
"chalk": "^6.0.1",
|
"chalk": "^6.0.1",
|
||||||
"dotenv": "^18.0.8",
|
"dotenv": "^18.0.8",
|
||||||
"pdfconvert-wasm": "^0.3.0",
|
"pdfconvert-wasm": "^0.3.0",
|
||||||
"sharp": "^0.35.5",
|
|
||||||
"skelehash-wasm": "^0.1.1",
|
"skelehash-wasm": "^0.1.1",
|
||||||
"thumbhash": "^0.1.1"
|
"thumbhash": "^0.1.1",
|
||||||
|
"wasm-image-optimization": "^2.0.13"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"better-sqlite3": "^12.0.0",
|
"better-sqlite3": "^12.0.0",
|
||||||
|
|||||||
@@ -1,35 +1,21 @@
|
|||||||
import sharp from 'sharp';
|
import { optimizeImage } from 'wasm-image-optimization';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates sample PNG image buffer.
|
* Creates sample PNG image buffer.
|
||||||
*/
|
*/
|
||||||
async function makeSampleImage(width = 200, height = 200, color = { r: 50, g: 120, b: 220 }) {
|
async function makeSampleImage(width = 200, height = 200, color = { r: 50, g: 120, b: 220 }) {
|
||||||
return sharp({
|
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}"><rect width="${width}" height="${height}" fill="rgb(${color.r},${color.g},${color.b})"/></svg>`;
|
||||||
create: {
|
const res = await optimizeImage({ image: svg, format: 'png' });
|
||||||
width,
|
return Buffer.from(res.data);
|
||||||
height,
|
|
||||||
channels: 4,
|
|
||||||
background: { ...color, alpha: 1 },
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.png()
|
|
||||||
.toBuffer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates sample AVIF thumbnail buffer.
|
* Creates sample AVIF thumbnail buffer.
|
||||||
*/
|
*/
|
||||||
async function makeSampleThumb(width = 64, height = 64) {
|
async function makeSampleThumb(width = 64, height = 64) {
|
||||||
return sharp({
|
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}"><rect width="${width}" height="${height}" fill="rgb(200,60,60)"/></svg>`;
|
||||||
create: {
|
const res = await optimizeImage({ image: svg, format: 'avif' });
|
||||||
width,
|
return Buffer.from(res.data);
|
||||||
height,
|
|
||||||
channels: 4,
|
|
||||||
background: { r: 200, g: 60, b: 60, alpha: 1 },
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.avif()
|
|
||||||
.toBuffer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import assert from 'node:assert/strict';
|
|||||||
import { mkdtempSync, rmSync } from 'node:fs';
|
import { mkdtempSync, rmSync } from 'node:fs';
|
||||||
import { tmpdir } from 'node:os';
|
import { tmpdir } from 'node:os';
|
||||||
import { join } from 'node:path';
|
import { join } from 'node:path';
|
||||||
import sharp from 'sharp';
|
import { optimizeImage } from 'wasm-image-optimization';
|
||||||
import LibDashStore from '../src/index.js';
|
import LibDashStore from '../src/index.js';
|
||||||
import { BetterSqlite3Provider } from '../src/providers/sqlite3/index.js';
|
import { BetterSqlite3Provider } from '../src/providers/sqlite3/index.js';
|
||||||
|
|
||||||
@@ -42,16 +42,9 @@ async function run() {
|
|||||||
assert.ok(val.id > 0);
|
assert.ok(val.id > 0);
|
||||||
|
|
||||||
// Create a 100x100 test image
|
// Create a 100x100 test image
|
||||||
const imageBuffer = await sharp({
|
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"><rect width="100" height="100" fill="rgb(25,25,112)"/></svg>`;
|
||||||
create: {
|
const encoded = await optimizeImage({ image: svg, format: 'avif' });
|
||||||
width: 100,
|
const imageBuffer = Buffer.from(encoded.data);
|
||||||
height: 100,
|
|
||||||
channels: 4,
|
|
||||||
background: { r: 25, g: 25, b: 112, alpha: 1 },
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.avif()
|
|
||||||
.toBuffer();
|
|
||||||
|
|
||||||
console.log('1. Adding image to attribute value...');
|
console.log('1. Adding image to attribute value...');
|
||||||
const addResult = await store.attributevalue.addImage(googleAuthId, val.id, imageBuffer);
|
const addResult = await store.attributevalue.addImage(googleAuthId, val.id, imageBuffer);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import assert from 'node:assert/strict';
|
|||||||
import { mkdtempSync, existsSync, readFileSync, rmSync } from 'node:fs';
|
import { mkdtempSync, existsSync, readFileSync, rmSync } from 'node:fs';
|
||||||
import { tmpdir } from 'node:os';
|
import { tmpdir } from 'node:os';
|
||||||
import { join } from 'node:path';
|
import { join } from 'node:path';
|
||||||
import sharp from 'sharp';
|
import { optimizeImage } from 'wasm-image-optimization';
|
||||||
import LibDashStore from '../src/index.js';
|
import LibDashStore from '../src/index.js';
|
||||||
import { BetterSqlite3Provider } from '../src/providers/sqlite3/index.js';
|
import { BetterSqlite3Provider } from '../src/providers/sqlite3/index.js';
|
||||||
|
|
||||||
@@ -72,16 +72,9 @@ async function runTests() {
|
|||||||
|
|
||||||
const manifestId = delivery.id;
|
const manifestId = delivery.id;
|
||||||
const testContent = Buffer.from('Hello SQLite Storage Engine! PDF or text content test.');
|
const testContent = Buffer.from('Hello SQLite Storage Engine! PDF or text content test.');
|
||||||
const testThumb = await sharp({
|
const thumbSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64"><rect width="64" height="64" fill="rgb(255,0,0)"/></svg>`;
|
||||||
create: {
|
const testThumbRes = await optimizeImage({ image: thumbSvg, format: 'avif' });
|
||||||
width: 64,
|
const testThumb = Buffer.from(testThumbRes.data);
|
||||||
height: 64,
|
|
||||||
channels: 4,
|
|
||||||
background: { r: 255, g: 0, b: 0, alpha: 1 },
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.avif()
|
|
||||||
.toBuffer();
|
|
||||||
|
|
||||||
const attachment = await store.manifestattachment.add(googleAuthId, manifestId, {
|
const attachment = await store.manifestattachment.add(googleAuthId, manifestId, {
|
||||||
name: 'test-doc.txt',
|
name: 'test-doc.txt',
|
||||||
@@ -202,16 +195,9 @@ async function runTests() {
|
|||||||
|
|
||||||
console.log('Article track_stock tests passed!');
|
console.log('Article track_stock tests passed!');
|
||||||
|
|
||||||
const sampleImage = await sharp({
|
const sampleSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="300" height="200"><rect width="300" height="200" fill="rgb(0,128,255)"/></svg>`;
|
||||||
create: {
|
const sampleImageRes = await optimizeImage({ image: sampleSvg, format: 'png' });
|
||||||
width: 300,
|
const sampleImage = Buffer.from(sampleImageRes.data);
|
||||||
height: 200,
|
|
||||||
channels: 4,
|
|
||||||
background: { r: 0, g: 128, b: 255, alpha: 1 },
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.png()
|
|
||||||
.toBuffer();
|
|
||||||
|
|
||||||
const picResult = await store.article.addImage(googleAuthId, article.sku, sampleImage);
|
const picResult = await store.article.addImage(googleAuthId, article.sku, sampleImage);
|
||||||
const fullHash = picResult.fullHash;
|
const fullHash = picResult.fullHash;
|
||||||
@@ -223,10 +209,10 @@ async function runTests() {
|
|||||||
assert.equal(smallThumbRow.smallthumbw, 32);
|
assert.equal(smallThumbRow.smallthumbw, 32);
|
||||||
assert.equal(smallThumbRow.smallthumbh, 21);
|
assert.equal(smallThumbRow.smallthumbh, 21);
|
||||||
assert(Buffer.isBuffer(smallThumbRow.smallthumbbinary), 'Small thumb AVIF must be stored in the pic row');
|
assert(Buffer.isBuffer(smallThumbRow.smallthumbbinary), 'Small thumb AVIF must be stored in the pic row');
|
||||||
const smallThumbMetadata = await sharp(smallThumbRow.smallthumbbinary).metadata();
|
const smallThumbMetadata = await optimizeImage({ image: smallThumbRow.smallthumbbinary, format: 'none' });
|
||||||
assert.equal(smallThumbMetadata.format, 'heif');
|
assert.equal(smallThumbMetadata.originalFormat, 'avif');
|
||||||
assert.equal(smallThumbMetadata.width, 32);
|
assert.equal(smallThumbMetadata.originalWidth, 32);
|
||||||
assert.equal(smallThumbMetadata.height, 21);
|
assert.equal(smallThumbMetadata.originalHeight, 21);
|
||||||
|
|
||||||
const brand = await store.brand.create(googleAuthId, { name: 'Small Thumb Test Brand' });
|
const brand = await store.brand.create(googleAuthId, { name: 'Small Thumb Test Brand' });
|
||||||
await store.brand.addImage(googleAuthId, brand.id, sampleImage);
|
await store.brand.addImage(googleAuthId, brand.id, sampleImage);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import sharp from 'sharp';
|
import { optimizeImage } from 'wasm-image-optimization';
|
||||||
import { encodeRGBA } from 'skelehash-wasm';
|
import { encodeRGBA } from 'skelehash-wasm';
|
||||||
import { DELETE_BY_ARTICLE_AND_HASH as MSSQL_QUERY } from '../../providers/mssql/queries/pic.js';
|
import { DELETE_BY_ARTICLE_AND_HASH as MSSQL_QUERY } from '../../providers/mssql/queries/pic.js';
|
||||||
import { DELETE_BY_ARTICLE_AND_HASH as SQLITE_QUERY } from '../../providers/sqlite3/queries/pic.js';
|
import { DELETE_BY_ARTICLE_AND_HASH as SQLITE_QUERY } from '../../providers/sqlite3/queries/pic.js';
|
||||||
@@ -49,8 +49,8 @@ export default function deleteImage(provider) {
|
|||||||
|
|
||||||
let skelehash = null;
|
let skelehash = null;
|
||||||
if (thumbBuffer) {
|
if (thumbBuffer) {
|
||||||
const { data, info } = await sharp(thumbBuffer).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
|
const raw = await optimizeImage({ image: thumbBuffer, format: 'raw' });
|
||||||
const res = await encodeRGBA(info.width, info.height, data);
|
const res = await encodeRGBA(raw.width, raw.height, raw.data);
|
||||||
skelehash = res?.base62;
|
skelehash = res?.base62;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
import resolveCategoryAccess from './resolveCategoryAccess.js';
|
import resolveCategoryAccess from './resolveCategoryAccess.js';
|
||||||
import addImage from './addImage.js';
|
import addImage from './addImage.js';
|
||||||
import makeRunner from '../runner.js';
|
import makeRunner from '../runner.js';
|
||||||
import sharp from 'sharp';
|
import { optimizeImage } from 'wasm-image-optimization';
|
||||||
|
|
||||||
export default function generateImage(provider) {
|
export default function generateImage(provider) {
|
||||||
const access = resolveCategoryAccess(provider);
|
const access = resolveCategoryAccess(provider);
|
||||||
@@ -148,32 +148,32 @@ export default function generateImage(provider) {
|
|||||||
const TOTAL_SIZE = 1200;
|
const TOTAL_SIZE = 1200;
|
||||||
const tileSize = TOTAL_SIZE / targetSize;
|
const tileSize = TOTAL_SIZE / targetSize;
|
||||||
|
|
||||||
const composites = await Promise.all(
|
const tiles = await Promise.all(
|
||||||
finalPics.map(async (pic, idx) => {
|
finalPics.map(async (pic, idx) => {
|
||||||
const row = Math.floor(idx / targetSize);
|
const row = Math.floor(idx / targetSize);
|
||||||
const col = idx % targetSize;
|
const col = idx % targetSize;
|
||||||
const tileBuffer = await sharp(pic.buffer)
|
const tile = await optimizeImage({
|
||||||
.resize(tileSize, tileSize, { fit: 'cover', position: 'center' })
|
image: pic.buffer,
|
||||||
.toBuffer();
|
width: tileSize,
|
||||||
return {
|
height: tileSize,
|
||||||
input: tileBuffer,
|
fit: 'cover',
|
||||||
left: col * tileSize,
|
format: 'png',
|
||||||
top: row * tileSize,
|
});
|
||||||
};
|
const b64 = Buffer.from(tile.data).toString('base64');
|
||||||
|
return `<image href="data:image/png;base64,${b64}" x="${col * tileSize}" y="${row * tileSize}" width="${tileSize}" height="${tileSize}"/>`;
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const mosaicBuffer = await sharp({
|
const mosaicSvg =
|
||||||
create: {
|
`<svg xmlns="http://www.w3.org/2000/svg" width="${TOTAL_SIZE}" height="${TOTAL_SIZE}">` +
|
||||||
width: TOTAL_SIZE,
|
`<rect width="${TOTAL_SIZE}" height="${TOTAL_SIZE}" fill="#ffffff"/>` +
|
||||||
height: TOTAL_SIZE,
|
tiles.join('') +
|
||||||
channels: 4,
|
`</svg>`;
|
||||||
background: { r: 255, g: 255, b: 255, alpha: 1 },
|
const mosaicRes = await optimizeImage({
|
||||||
},
|
image: mosaicSvg,
|
||||||
})
|
format: 'png',
|
||||||
.composite(composites)
|
});
|
||||||
.png()
|
const mosaicBuffer = Buffer.from(mosaicRes.data);
|
||||||
.toBuffer();
|
|
||||||
|
|
||||||
// Clear existing categorypic rows so the new mosaic becomes the main (first) image
|
// Clear existing categorypic rows so the new mosaic becomes the main (first) image
|
||||||
await runner.query('DELETE FROM categorypic WHERE category_id = @categoryId', { categoryId });
|
await runner.query('DELETE FROM categorypic WHERE category_id = @categoryId', { categoryId });
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { createHash } from 'node:crypto';
|
import { createHash } from 'node:crypto';
|
||||||
import sharp from 'sharp';
|
import { optimizeImage } from 'wasm-image-optimization';
|
||||||
import generateDocumentThumb from '../../util/generateDocumentThumb.js';
|
import generateDocumentThumb from '../../util/generateDocumentThumb.js';
|
||||||
import * as mssqlQueries from '../../providers/mssql/queries/manifestattachment.js';
|
import * as mssqlQueries from '../../providers/mssql/queries/manifestattachment.js';
|
||||||
import * as sqliteQueries from '../../providers/sqlite3/queries/manifestattachment.js';
|
import * as sqliteQueries from '../../providers/sqlite3/queries/manifestattachment.js';
|
||||||
@@ -118,9 +118,9 @@ export default function add(provider) {
|
|||||||
|
|
||||||
if (thumbavif && (!thumbx || !thumby)) {
|
if (thumbavif && (!thumbx || !thumby)) {
|
||||||
try {
|
try {
|
||||||
const meta = await sharp(thumbavif).metadata();
|
const meta = await optimizeImage({ image: thumbavif, format: 'none' });
|
||||||
thumbx = thumbx ?? meta.width ?? null;
|
thumbx = thumbx ?? meta.originalWidth ?? null;
|
||||||
thumby = thumby ?? meta.height ?? null;
|
thumby = thumby ?? meta.originalHeight ?? null;
|
||||||
} catch {
|
} catch {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import sharp from 'sharp';
|
import { optimizeImage } from 'wasm-image-optimization';
|
||||||
import { pdfToPng } from 'pdfconvert-wasm';
|
import { pdfToPng } from 'pdfconvert-wasm';
|
||||||
|
|
||||||
const THUMB_MAX = 200;
|
const THUMB_MAX = 200;
|
||||||
@@ -97,18 +97,27 @@ export default async function generateDocumentThumb(content, mimetype, options =
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const thumbResult = await sharp(imageBuffer)
|
const meta = await optimizeImage({ image: imageBuffer, format: 'none' });
|
||||||
.resize(THUMB_MAX, THUMB_MAX, { fit: 'inside', withoutEnlargement: true })
|
const srcW = meta.originalWidth || 0;
|
||||||
.avif({ effort: 4 })
|
const srcH = meta.originalHeight || 0;
|
||||||
.toBuffer({ resolveWithObject: true });
|
const needsResize = srcW > THUMB_MAX || srcH > THUMB_MAX;
|
||||||
|
const scale = needsResize ? Math.min(THUMB_MAX / srcW, THUMB_MAX / srcH) : 1;
|
||||||
|
const thumbResult = await optimizeImage({
|
||||||
|
image: imageBuffer,
|
||||||
|
width: needsResize ? Math.max(1, Math.round(srcW * scale)) : undefined,
|
||||||
|
height: needsResize ? Math.max(1, Math.round(srcH * scale)) : undefined,
|
||||||
|
fit: 'fill',
|
||||||
|
format: 'avif',
|
||||||
|
speed: 6,
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
thumbavif: thumbResult.data,
|
thumbavif: Buffer.from(thumbResult.data),
|
||||||
thumbx: thumbResult.info.width,
|
thumbx: thumbResult.width,
|
||||||
thumby: thumbResult.info.height,
|
thumby: thumbResult.height,
|
||||||
};
|
};
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn('generateDocumentThumb: sharp thumbnail generation failed:', err.message);
|
console.warn('generateDocumentThumb: thumbnail generation failed:', err.message);
|
||||||
return { thumbavif: null, thumbx: null, thumby: null };
|
return { thumbavif: null, thumbx: null, thumby: null };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import sharp from 'sharp';
|
import { optimizeImage } from 'wasm-image-optimization';
|
||||||
import { rgbaToThumbHash } from 'thumbhash';
|
import { rgbaToThumbHash } from 'thumbhash';
|
||||||
import { encodeRGBA } from 'skelehash-wasm';
|
import { encodeRGBA } from 'skelehash-wasm';
|
||||||
|
|
||||||
@@ -6,63 +6,105 @@ const FULL_MAX = 1000;
|
|||||||
const THUMB_MAX = 200;
|
const THUMB_MAX = 200;
|
||||||
const SMALL_THUMB_MAX = 32;
|
const SMALL_THUMB_MAX = 32;
|
||||||
|
|
||||||
|
function fitInsideDims(srcW, srcH, maxW, maxH) {
|
||||||
|
if (!srcW || !srcH || (srcW <= maxW && srcH <= maxH)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const scale = Math.min(maxW / srcW, maxH / srcH);
|
||||||
|
return {
|
||||||
|
width: Math.max(1, Math.round(srcW * scale)),
|
||||||
|
height: Math.max(1, Math.round(srcH * scale)),
|
||||||
|
fit: 'fill',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function unpremultiplyRgba(data) {
|
||||||
|
const out = new Uint8Array(data.length);
|
||||||
|
for (let i = 0; i < data.length; i += 4) {
|
||||||
|
const a = data[i + 3];
|
||||||
|
if (a === 255 || a === 0) {
|
||||||
|
out[i] = data[i];
|
||||||
|
out[i + 1] = data[i + 1];
|
||||||
|
out[i + 2] = data[i + 2];
|
||||||
|
out[i + 3] = a;
|
||||||
|
} else {
|
||||||
|
const f = 255 / a;
|
||||||
|
out[i] = Math.min(255, Math.round(data[i] * f));
|
||||||
|
out[i + 1] = Math.min(255, Math.round(data[i + 1] * f));
|
||||||
|
out[i + 2] = Math.min(255, Math.round(data[i + 2] * f));
|
||||||
|
out[i + 3] = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
export default async function processAvifImage(inputBuffer) {
|
export default async function processAvifImage(inputBuffer) {
|
||||||
const input = Buffer.isBuffer(inputBuffer)
|
const input = Buffer.isBuffer(inputBuffer)
|
||||||
? inputBuffer
|
? inputBuffer
|
||||||
: Buffer.from(inputBuffer);
|
: Buffer.from(inputBuffer);
|
||||||
|
|
||||||
const meta = await sharp(input).metadata();
|
const meta = await optimizeImage({ image: input, format: 'none' });
|
||||||
const w = meta.width ?? 0;
|
const w = meta.originalWidth ?? 0;
|
||||||
const h = meta.height ?? 0;
|
const h = meta.originalHeight ?? 0;
|
||||||
const isAvif =
|
const isAvif = meta.originalFormat === 'avif';
|
||||||
meta.format === 'avif' ||
|
|
||||||
(meta.format === 'heif' && meta.compression === 'av1');
|
|
||||||
const useOriginalFull =
|
const useOriginalFull =
|
||||||
isAvif && w > 0 && h > 0 && w <= FULL_MAX && h <= FULL_MAX;
|
isAvif && w > 0 && h > 0 && w <= FULL_MAX && h <= FULL_MAX;
|
||||||
|
|
||||||
if (!useOriginalFull) {
|
if (!useOriginalFull) {
|
||||||
console.log(
|
console.log(
|
||||||
`processAvifImage: converting full image (format=${meta.format ?? 'unknown'}, ${w}×${h}, avif=${isAvif})`,
|
`processAvifImage: converting full image (format=${meta.originalFormat ?? 'unknown'}, ${w}×${h}, avif=${isAvif})`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const thumbPipeline = sharp(input)
|
const fullDims = fitInsideDims(w, h, FULL_MAX, FULL_MAX);
|
||||||
.resize(THUMB_MAX, THUMB_MAX, { fit: 'inside', withoutEnlargement: true });
|
const thumbDims = fitInsideDims(w, h, THUMB_MAX, THUMB_MAX);
|
||||||
const smallThumbPipeline = sharp(input)
|
const rgbaDims = fitInsideDims(w, h, 100, 100);
|
||||||
.resize(SMALL_THUMB_MAX, SMALL_THUMB_MAX, { fit: 'inside', withoutEnlargement: true });
|
const smallThumbDims = fitInsideDims(w, h, SMALL_THUMB_MAX, SMALL_THUMB_MAX);
|
||||||
|
|
||||||
const [full, thumb, thumbRgba, smallThumb] = await Promise.all([
|
const [full, thumb, thumbRgba, smallThumb] = await Promise.all([
|
||||||
useOriginalFull
|
useOriginalFull
|
||||||
? Promise.resolve({
|
? Promise.resolve({
|
||||||
info: { width: w, height: h },
|
width: w,
|
||||||
|
height: h,
|
||||||
data: input,
|
data: input,
|
||||||
})
|
})
|
||||||
: sharp(input)
|
: optimizeImage({
|
||||||
.resize(FULL_MAX, FULL_MAX, { fit: 'inside', withoutEnlargement: true })
|
image: input,
|
||||||
.avif({ effort: 2 })
|
...fullDims,
|
||||||
.toBuffer({ resolveWithObject: true }),
|
format: 'avif',
|
||||||
thumbPipeline.clone().avif({ effort: 2 }).toBuffer({ resolveWithObject: true }),
|
speed: 8,
|
||||||
thumbPipeline
|
}),
|
||||||
.clone()
|
optimizeImage({
|
||||||
.resize(100, 100, { fit: 'inside', withoutEnlargement: true })
|
image: input,
|
||||||
.ensureAlpha()
|
...thumbDims,
|
||||||
.raw()
|
format: 'avif',
|
||||||
.toBuffer({ resolveWithObject: true }),
|
speed: 8,
|
||||||
smallThumbPipeline
|
}),
|
||||||
.avif({ effort: 2 })
|
optimizeImage({
|
||||||
.toBuffer({ resolveWithObject: true }),
|
image: input,
|
||||||
|
...rgbaDims,
|
||||||
|
format: 'raw',
|
||||||
|
}),
|
||||||
|
optimizeImage({
|
||||||
|
image: input,
|
||||||
|
...smallThumbDims,
|
||||||
|
format: 'avif',
|
||||||
|
speed: 8,
|
||||||
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const rgbaPixels = unpremultiplyRgba(thumbRgba.data);
|
||||||
|
|
||||||
const [thumbHashBytes, skele] = await Promise.all([
|
const [thumbHashBytes, skele] = await Promise.all([
|
||||||
rgbaToThumbHash(
|
rgbaToThumbHash(
|
||||||
thumbRgba.info.width,
|
thumbRgba.width,
|
||||||
thumbRgba.info.height,
|
thumbRgba.height,
|
||||||
thumbRgba.data,
|
rgbaPixels,
|
||||||
),
|
),
|
||||||
encodeRGBA(
|
encodeRGBA(
|
||||||
thumbRgba.info.width,
|
thumbRgba.width,
|
||||||
thumbRgba.info.height,
|
thumbRgba.height,
|
||||||
thumbRgba.data,
|
rgbaPixels,
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -70,24 +112,28 @@ export default async function processAvifImage(inputBuffer) {
|
|||||||
throw new Error('encodeRGBA failed to produce a base62 skelehash');
|
throw new Error('encodeRGBA failed to produce a base62 skelehash');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fullBuf = Buffer.isBuffer(full.data) ? full.data : Buffer.from(full.data);
|
||||||
|
const thumbBuf = Buffer.from(thumb.data);
|
||||||
|
const smallThumbBuf = Buffer.from(smallThumb.data);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
full: {
|
full: {
|
||||||
w: full.info.width,
|
w: full.width,
|
||||||
h: full.info.height,
|
h: full.height,
|
||||||
size: full.data.length,
|
size: fullBuf.length,
|
||||||
buffer: full.data,
|
buffer: fullBuf,
|
||||||
},
|
},
|
||||||
thumb: {
|
thumb: {
|
||||||
w: thumb.info.width,
|
w: thumb.width,
|
||||||
h: thumb.info.height,
|
h: thumb.height,
|
||||||
size: thumb.data.length,
|
size: thumbBuf.length,
|
||||||
buffer: thumb.data,
|
buffer: thumbBuf,
|
||||||
hash: Buffer.from(thumbHashBytes).toString('base64'),
|
hash: Buffer.from(thumbHashBytes).toString('base64'),
|
||||||
},
|
},
|
||||||
smallThumb: {
|
smallThumb: {
|
||||||
w: smallThumb.info.width,
|
w: smallThumb.width,
|
||||||
h: smallThumb.info.height,
|
h: smallThumb.height,
|
||||||
buffer: smallThumb.data,
|
buffer: smallThumbBuf,
|
||||||
},
|
},
|
||||||
skelehash: skele.base62,
|
skelehash: skele.base62,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { mkdtempSync, rmSync } from 'node:fs';
|
import { mkdtempSync, rmSync } from 'node:fs';
|
||||||
import { tmpdir } from 'node:os';
|
import { tmpdir } from 'node:os';
|
||||||
import { join } from 'node:path';
|
import { join } from 'node:path';
|
||||||
import sharp from 'sharp';
|
import { optimizeImage } from 'wasm-image-optimization';
|
||||||
import LibDashStore from '../src/index.js';
|
import LibDashStore from '../src/index.js';
|
||||||
import { BetterSqlite3Provider } from '../src/providers/sqlite3/index.js';
|
import { BetterSqlite3Provider } from '../src/providers/sqlite3/index.js';
|
||||||
|
|
||||||
@@ -79,11 +79,9 @@ export async function createCustomer(store, tenant, name = 'Customer') {
|
|||||||
|
|
||||||
/** Generates a small solid-color PNG buffer for image tests. */
|
/** Generates a small solid-color PNG buffer for image tests. */
|
||||||
export async function makePng({ width = 64, height = 48, r = 200, g = 30, b = 60 } = {}) {
|
export async function makePng({ width = 64, height = 48, r = 200, g = 30, b = 60 } = {}) {
|
||||||
return sharp({
|
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}"><rect width="${width}" height="${height}" fill="rgb(${r},${g},${b})"/></svg>`;
|
||||||
create: { width, height, channels: 3, background: { r, g, b } },
|
const res = await optimizeImage({ image: svg, format: 'png' });
|
||||||
})
|
return Buffer.from(res.data);
|
||||||
.png()
|
|
||||||
.toBuffer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isoNow = () => new Date().toISOString();
|
export const isoNow = () => new Date().toISOString();
|
||||||
|
|||||||
Reference in New Issue
Block a user