change api and fix incorrect caclulation

i changed the api to not have a global wasm instance anymore. now
initWasm returns a WASM instance you have to pass down to the functions.
i feel like this is the best as it means you wont deal with a race
condition if you're messing with it more then once at the same time,
like i'm doing with tests.

i also accounted for the height given as that was the original
calculation that the Blurhash C implmentation used, not width * width,
width * height.
This commit is contained in:
Fries 2023-08-21 18:58:23 -07:00
parent c84aa5cb2c
commit 548ef52ab7
8 changed files with 419 additions and 45 deletions

1
.gitignore vendored
View file

@ -2,3 +2,4 @@ node_modules
src/blurhash-decode.wasm
dist
*.tgz
coverage

View file

@ -14,3 +14,5 @@ pnpm-lock.yaml
rollup.config.js
tsconfig.json
spec
coverage
.nycrc

6
.nycrc Normal file
View file

@ -0,0 +1,6 @@
{
"report-dir": "coverage",
"exclude": [
"spec/"
]
}

View file

@ -1,14 +1,15 @@
{
"type": "module",
"name": "@fries/blurhash-c-wasm",
"version": "0.1.2",
"version": "0.2.0",
"description": "A WASM module using the Blurhash C library",
"main": "dist/blurhash-c-wasm.cjs",
"module": "dist/blurhash-c-wasm.js",
"types": "dist/library.d.ts",
"types": "dist/blurhash-c-wasm.d.ts",
"scripts": {
"build": "make && rollup -c rollup.config.js",
"test": "jasmine",
"test:coverage": "c8 -r html pnpm run test",
"prepublishOnly": "pnpm build && pnpm test"
},
"author": "Fries",
@ -16,6 +17,7 @@
"@rollup/plugin-typescript": "^11.1.2",
"@rollup/plugin-wasm": "^6.1.3",
"@types/jasmine": "^4.3.5",
"c8": "^8.0.1",
"jasmine": "^5.1.0",
"rollup": "^3.28.0",
"tslib": "^2.6.1",

View file

@ -14,6 +14,9 @@ devDependencies:
'@types/jasmine':
specifier: ^4.3.5
version: 4.3.5
c8:
specifier: ^8.0.1
version: 8.0.1
jasmine:
specifier: ^5.1.0
version: 5.1.0
@ -29,6 +32,10 @@ devDependencies:
packages:
/@bcoe/v8-coverage@0.2.3:
resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
dev: true
/@isaacs/cliui@8.0.2:
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
@ -41,6 +48,27 @@ packages:
wrap-ansi-cjs: /wrap-ansi@7.0.0
dev: true
/@istanbuljs/schema@0.1.3:
resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
engines: {node: '>=8'}
dev: true
/@jridgewell/resolve-uri@3.1.1:
resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==}
engines: {node: '>=6.0.0'}
dev: true
/@jridgewell/sourcemap-codec@1.4.15:
resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
dev: true
/@jridgewell/trace-mapping@0.3.19:
resolution: {integrity: sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==}
dependencies:
'@jridgewell/resolve-uri': 3.1.1
'@jridgewell/sourcemap-codec': 1.4.15
dev: true
/@pkgjs/parseargs@0.11.0:
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
@ -99,6 +127,10 @@ packages:
resolution: {integrity: sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==}
dev: true
/@types/istanbul-lib-coverage@2.0.4:
resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==}
dev: true
/@types/jasmine@4.3.5:
resolution: {integrity: sha512-9YHUdvuNDDRJYXZwHqSsO72Ok0vmqoJbNn73ttyITQp/VA60SarnZ+MPLD37rJAhVoKp+9BWOvJP5tHIRfZylQ==}
dev: true
@ -129,12 +161,47 @@ packages:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: true
/brace-expansion@1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
dependencies:
balanced-match: 1.0.2
concat-map: 0.0.1
dev: true
/brace-expansion@2.0.1:
resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
dependencies:
balanced-match: 1.0.2
dev: true
/c8@8.0.1:
resolution: {integrity: sha512-EINpopxZNH1mETuI0DzRA4MZpAUH+IFiRhnmFD3vFr3vdrgxqi3VfE3KL0AIL+zDq8rC9bZqwM/VDmmoe04y7w==}
engines: {node: '>=12'}
hasBin: true
dependencies:
'@bcoe/v8-coverage': 0.2.3
'@istanbuljs/schema': 0.1.3
find-up: 5.0.0
foreground-child: 2.0.0
istanbul-lib-coverage: 3.2.0
istanbul-lib-report: 3.0.1
istanbul-reports: 3.1.6
rimraf: 3.0.2
test-exclude: 6.0.0
v8-to-istanbul: 9.1.0
yargs: 17.7.2
yargs-parser: 21.1.1
dev: true
/cliui@8.0.1:
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
engines: {node: '>=12'}
dependencies:
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi: 7.0.0
dev: true
/color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
@ -146,6 +213,14 @@ packages:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
dev: true
/concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
dev: true
/convert-source-map@1.9.0:
resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}
dev: true
/cross-spawn@7.0.3:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
engines: {node: '>= 8'}
@ -167,10 +242,31 @@ packages:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
dev: true
/escalade@3.1.1:
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
engines: {node: '>=6'}
dev: true
/estree-walker@2.0.2:
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
dev: true
/find-up@5.0.0:
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
engines: {node: '>=10'}
dependencies:
locate-path: 6.0.0
path-exists: 4.0.0
dev: true
/foreground-child@2.0.0:
resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==}
engines: {node: '>=8.0.0'}
dependencies:
cross-spawn: 7.0.3
signal-exit: 3.0.7
dev: true
/foreground-child@3.1.1:
resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==}
engines: {node: '>=14'}
@ -179,6 +275,10 @@ packages:
signal-exit: 4.1.0
dev: true
/fs.realpath@1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
dev: true
/fsevents@2.3.2:
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
@ -191,6 +291,11 @@ packages:
resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
dev: true
/get-caller-file@2.0.5:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
dev: true
/glob@10.3.3:
resolution: {integrity: sha512-92vPiMb/iqpmEgsOoIDvTjc50wf9CCCvMzsi6W0JLPeUKE8TWP1a73PgqSrqy7iAZxaSD1YdzU7QZR5LF51MJw==}
engines: {node: '>=16 || 14 >=14.17'}
@ -203,6 +308,22 @@ packages:
path-scurry: 1.10.1
dev: true
/glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
dependencies:
fs.realpath: 1.0.0
inflight: 1.0.6
inherits: 2.0.4
minimatch: 3.1.2
once: 1.4.0
path-is-absolute: 1.0.1
dev: true
/has-flag@4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
dev: true
/has@1.0.3:
resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
engines: {node: '>= 0.4.0'}
@ -210,6 +331,21 @@ packages:
function-bind: 1.1.1
dev: true
/html-escaper@2.0.2:
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
dev: true
/inflight@1.0.6:
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
dependencies:
once: 1.4.0
wrappy: 1.0.2
dev: true
/inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
dev: true
/is-core-module@2.13.0:
resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==}
dependencies:
@ -225,6 +361,28 @@ packages:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
dev: true
/istanbul-lib-coverage@3.2.0:
resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==}
engines: {node: '>=8'}
dev: true
/istanbul-lib-report@3.0.1:
resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
engines: {node: '>=10'}
dependencies:
istanbul-lib-coverage: 3.2.0
make-dir: 4.0.0
supports-color: 7.2.0
dev: true
/istanbul-reports@3.1.6:
resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==}
engines: {node: '>=8'}
dependencies:
html-escaper: 2.0.2
istanbul-lib-report: 3.0.1
dev: true
/jackspeak@2.2.3:
resolution: {integrity: sha512-pF0kfjmg8DJLxDrizHoCZGUFz4P4czQ3HyfW4BU0ffebYkzAVlBywp5zaxW/TM+r0sGbmrQdi8EQQVTJFxnGsQ==}
engines: {node: '>=14'}
@ -246,11 +404,38 @@ packages:
jasmine-core: 5.1.0
dev: true
/locate-path@6.0.0:
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
engines: {node: '>=10'}
dependencies:
p-locate: 5.0.0
dev: true
/lru-cache@10.0.1:
resolution: {integrity: sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==}
engines: {node: 14 || >=16.14}
dev: true
/lru-cache@6.0.0:
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
engines: {node: '>=10'}
dependencies:
yallist: 4.0.0
dev: true
/make-dir@4.0.0:
resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
engines: {node: '>=10'}
dependencies:
semver: 7.5.4
dev: true
/minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
dependencies:
brace-expansion: 1.1.11
dev: true
/minimatch@9.0.3:
resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==}
engines: {node: '>=16 || 14 >=14.17'}
@ -263,6 +448,36 @@ packages:
engines: {node: '>=16 || 14 >=14.17'}
dev: true
/once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
dependencies:
wrappy: 1.0.2
dev: true
/p-limit@3.1.0:
resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
engines: {node: '>=10'}
dependencies:
yocto-queue: 0.1.0
dev: true
/p-locate@5.0.0:
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
engines: {node: '>=10'}
dependencies:
p-limit: 3.1.0
dev: true
/path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
dev: true
/path-is-absolute@1.0.1:
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
engines: {node: '>=0.10.0'}
dev: true
/path-key@3.1.1:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
@ -285,6 +500,11 @@ packages:
engines: {node: '>=8.6'}
dev: true
/require-directory@2.1.1:
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
engines: {node: '>=0.10.0'}
dev: true
/resolve@1.22.4:
resolution: {integrity: sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==}
hasBin: true
@ -294,6 +514,13 @@ packages:
supports-preserve-symlinks-flag: 1.0.0
dev: true
/rimraf@3.0.2:
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
hasBin: true
dependencies:
glob: 7.2.3
dev: true
/rollup@3.28.0:
resolution: {integrity: sha512-d7zhvo1OUY2SXSM6pfNjgD5+d0Nz87CUp4mt8l/GgVP3oBsPwzNvSzyu1me6BSG9JIgWNTVcafIXBIyM8yQ3yw==}
engines: {node: '>=14.18.0', npm: '>=8.0.0'}
@ -302,6 +529,14 @@ packages:
fsevents: 2.3.2
dev: true
/semver@7.5.4:
resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==}
engines: {node: '>=10'}
hasBin: true
dependencies:
lru-cache: 6.0.0
dev: true
/shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
@ -314,6 +549,10 @@ packages:
engines: {node: '>=8'}
dev: true
/signal-exit@3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
dev: true
/signal-exit@4.1.0:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
@ -351,11 +590,27 @@ packages:
ansi-regex: 6.0.1
dev: true
/supports-color@7.2.0:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'}
dependencies:
has-flag: 4.0.0
dev: true
/supports-preserve-symlinks-flag@1.0.0:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
dev: true
/test-exclude@6.0.0:
resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
engines: {node: '>=8'}
dependencies:
'@istanbuljs/schema': 0.1.3
glob: 7.2.3
minimatch: 3.1.2
dev: true
/tslib@2.6.1:
resolution: {integrity: sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==}
dev: true
@ -366,6 +621,15 @@ packages:
hasBin: true
dev: true
/v8-to-istanbul@9.1.0:
resolution: {integrity: sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==}
engines: {node: '>=10.12.0'}
dependencies:
'@jridgewell/trace-mapping': 0.3.19
'@types/istanbul-lib-coverage': 2.0.4
convert-source-map: 1.9.0
dev: true
/which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
@ -391,3 +655,39 @@ packages:
string-width: 5.1.2
strip-ansi: 7.1.0
dev: true
/wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
dev: true
/y18n@5.0.8:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'}
dev: true
/yallist@4.0.0:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
dev: true
/yargs-parser@21.1.1:
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
engines: {node: '>=12'}
dev: true
/yargs@17.7.2:
resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
engines: {node: '>=12'}
dependencies:
cliui: 8.0.1
escalade: 3.1.1
get-caller-file: 2.0.5
require-directory: 2.1.1
string-width: 4.2.3
y18n: 5.0.8
yargs-parser: 21.1.1
dev: true
/yocto-queue@0.1.0:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
dev: true

View file

@ -9,7 +9,7 @@ const dirname = path.dirname(url.fileURLToPath(import.meta.url));
export default [
defineConfig({
plugins: [Typescript(), Wasm({ targetEnv: "auto-inline" })],
input: path.resolve(dirname, "src/library.ts"),
input: path.resolve(dirname, "src/blurhash-c-wasm.ts"),
output: [
{
name: "blurhash-c-wasm",
@ -22,7 +22,7 @@ export default [
}),
defineConfig({
plugins: [Typescript(), Wasm({ targetEnv: "auto-inline" })],
input: path.resolve(dirname, "src/library.ts"),
input: path.resolve(dirname, "src/blurhash-c-wasm.ts"),
output: [
{
name: "blurhash-c-wasm",

View file

@ -3,48 +3,102 @@
import * as blurhash from "../dist/blurhash-c-wasm.js";
describe("blurhash-c-wasm tests", () => {
/** @type {import("../dist/blurhash-c-wasm").BlurhashInstanceType} */
let instance;
beforeAll(async () => {
await blurhash.initWasm();
instance =
/** @type {import("../dist/blurhash-c-wasm").BlurhashInstanceType} */ (
/** @type {unknown} */ await blurhash.initWasm()
);
});
it("detects valid blurhash", () => {
expect(blurhash.isValidBlurhash("LEHLk~WB2yk8pyo0adR*.7kCMdnj")).toBe(true);
expect(blurhash.isValidBlurhash("LGF5]+Yk^6#M@-5c,1J5@[or[Q6.")).toBe(true);
expect(blurhash.isValidBlurhash("L6PZfSjE.AyE_3t7t7R**0o#DgR4")).toBe(true);
expect(blurhash.isValidBlurhash("LKO2:N%2Tw=w]~RBVZRi};RPxuwH")).toBe(true);
expect(
blurhash.isValidBlurhash(instance, "LEHLk~WB2yk8pyo0adR*.7kCMdnj")
).toBe(true);
expect(
blurhash.isValidBlurhash(instance, "LGF5]+Yk^6#M@-5c,1J5@[or[Q6.")
).toBe(true);
expect(
blurhash.isValidBlurhash(instance, "L6PZfSjE.AyE_3t7t7R**0o#DgR4")
).toBe(true);
expect(
blurhash.isValidBlurhash(instance, "LKO2:N%2Tw=w]~RBVZRi};RPxuwH")
).toBe(true);
});
it("generates valid blurhash images", () => {
expect(blurhash.decode("LEHLk~WB2yk8pyo0adR*.7kCMdnj", 1, 1)).toEqual(
Uint8ClampedArray.of(134, 164, 176, 255)
);
expect(blurhash.decode("LGF5]+Yk^6#M@-5c,1J5@[or[Q6.", 1, 1)).toEqual(
Uint8ClampedArray.of(176, 118, 163, 255)
);
expect(blurhash.decode("L6PZfSjE.AyE_3t7t7R**0o#DgR4", 1, 1)).toEqual(
Uint8ClampedArray.of(229, 228, 226, 255)
);
expect(blurhash.decode("LKO2:N%2Tw=w]~RBVZRi};RPxuwH", 1, 1)).toEqual(
Uint8ClampedArray.of(251, 192, 161, 255)
);
it("generates valid 1:1 blurhash images", () => {
expect(
blurhash.decode(instance, "LEHLk~WB2yk8pyo0adR*.7kCMdnj", 1, 1)
).toEqual(Uint8ClampedArray.of(134, 164, 176, 255));
expect(
blurhash.decode(instance, "LGF5]+Yk^6#M@-5c,1J5@[or[Q6.", 1, 1)
).toEqual(Uint8ClampedArray.of(176, 118, 163, 255));
expect(
blurhash.decode(instance, "L6PZfSjE.AyE_3t7t7R**0o#DgR4", 1, 1)
).toEqual(Uint8ClampedArray.of(229, 228, 226, 255));
expect(
blurhash.decode(instance, "LKO2:N%2Tw=w]~RBVZRi};RPxuwH", 1, 1)
).toEqual(Uint8ClampedArray.of(251, 192, 161, 255));
});
it("generates valid non 1:1 blurhash images", () => {
expect(
blurhash.decode(instance, "LEHLk~WB2yk8pyo0adR*.7kCMdnj", 1, 2)
).toEqual(Uint8ClampedArray.of(134, 164, 176, 255, 119, 148, 161, 255));
expect(
blurhash.decode(instance, "LGF5]+Yk^6#M@-5c,1J5@[or[Q6.", 1, 2)
).toEqual(Uint8ClampedArray.of(176, 118, 163, 255, 137, 155, 177, 255));
expect(
blurhash.decode(instance, "L6PZfSjE.AyE_3t7t7R**0o#DgR4", 1, 2)
).toEqual(Uint8ClampedArray.of(229, 228, 226, 255, 226, 223, 223, 255));
expect(
blurhash.decode(instance, "LKO2:N%2Tw=w]~RBVZRi};RPxuwH", 1, 2)
).toEqual(Uint8ClampedArray.of(251, 192, 161, 255, 200, 187, 180, 255));
});
it("detects invalid blurhash", () => {
expect(blurhash.isValidBlurhash("1234")).toBe(false);
expect(blurhash.isValidBlurhash("sus")).toBe(false);
expect(blurhash.isValidBlurhash(instance, "1234")).toBe(false);
expect(blurhash.isValidBlurhash(instance, "sus")).toBe(false);
});
it("fails on invalid blurhash", () => {
const decodingHasFailed = "Decoding the Blurhash string has failed.";
expect(() => blurhash.decode(instance, "1234", 1, 1)).toThrow(
new Error(decodingHasFailed)
);
expect(() => blurhash.decode(instance, "sus", 1, 1)).toThrow(
new Error(decodingHasFailed)
);
});
it("don't accept less then the required parameters in the isValidBlurhash function", () => {
// @ts-expect-error
expect(() => blurhash.isValidBlurhash(undefined)).toThrow(
new Error("You are required to give the WASM Module.")
);
// @ts-expect-error
expect(() => blurhash.isValidBlurhash(instance, undefined)).toThrow(
new Error("You are required to give the Blurhash string.")
);
});
it("don't accept less then the required paramaters in the decode function", () => {
// @ts-expect-error
expect(() => blurhash.decode(undefined)).toThrow(
new Error("You are required to give the WASM Module.")
);
// @ts-expect-error
expect(() => blurhash.decode(instance, undefined)).toThrow(
new Error("You are required to give the Blurhash string.")
);
// @ts-expect-error
expect(() => blurhash.decode("test")).toThrow(
expect(() => blurhash.decode(instance, "test")).toThrow(
new Error("You are required to give the width.")
);
// @ts-expect-error
expect(() => blurhash.decode("test", 32)).toThrow(
expect(() => blurhash.decode(instance, "test", 32)).toThrow(
new Error("You are required to give the height.")
);
});

View file

@ -1,7 +1,7 @@
// @ts-ignore
import wasm from "./blurhash-decode.wasm";
type InstanceType = {
export type BlurhashInstanceType = {
memory: WebAssembly.Memory;
malloc: (bytes: number) => number;
free: (ptr: number) => void;
@ -16,16 +16,16 @@ type InstanceType = {
isValidBlurhash: (stringPtr: number) => number;
};
const wasmInitializationError = "The WASM module has not been initialized";
const failed = -1;
const youAreRequiredToGiveThe = (thing: string) =>
`You are required to give the ${thing}.`;
const blurHashStringRequiredError = youAreRequiredToGiveThe("Blurhash string");
let wasmInstance: WebAssembly.Instance | undefined;
let instance: InstanceType | undefined;
const blurhashStringRequiredError = youAreRequiredToGiveThe("Blurhash string");
const wasmMissingError = youAreRequiredToGiveThe("WASM Module");
function encodeStringToWasmArray(string: string): number {
if (!instance) throw Error(wasmInitializationError);
function encodeStringToWasmArray(
instance: BlurhashInstanceType,
string: string
): number {
const encoder = new TextEncoder();
const encodedString = encoder.encode(string);
const stringPtr: number = instance.malloc(encodedString.byteLength + 1);
@ -42,49 +42,55 @@ function encodeStringToWasmArray(string: string): number {
}
/**
* Initialize the WASM instance. This is to support browsers without top level await.
* Initialize a WASM instance.
* @returns A Blurhash WASM instance.
*/
export async function initWasm() {
wasmInstance = await WebAssembly.instantiate(
export async function initWasm(): Promise<BlurhashInstanceType> {
const wasmInstance = await WebAssembly.instantiate(
(await wasm()) as WebAssembly.Module,
{
env: {
// stub for a emscripten import
/* c8 ignore next */
emscripten_notify_memory_growth: () => {},
},
}
);
instance = wasmInstance.exports as InstanceType;
return wasmInstance.exports as unknown as BlurhashInstanceType;
}
/**
* Decode a Blurhash string into a Pixel Array that you can use to generate a Blurhash image.
* @param instance A Blurhash WASM instance.
* @param blurhashString A valid Blurhash string.
* @param width The width of the image you want to generate.
* @param height The height of the image you want to generate.
* @returns A `Uint8ClampedArray` pixel array.
*/
export function decode(
instance: BlurhashInstanceType,
blurhashString: string,
width: number,
height: number
): Uint8ClampedArray {
if (!instance) throw Error(wasmInitializationError);
if (!instance) throw Error(wasmMissingError);
if (!blurhashString) {
throw Error(blurHashStringRequiredError);
throw Error(blurhashStringRequiredError);
}
if (!width) {
throw Error(youAreRequiredToGiveThe("width"));
}
if (!height) {
throw Error(youAreRequiredToGiveThe("height"));
}
const pixelsPtrSize = width * 4 * width;
const pixelsPtrSize = width * 4 * height;
const pixelsPtr = instance.malloc(pixelsPtrSize);
const stringPtr = encodeStringToWasmArray(blurhashString);
const stringPtr = encodeStringToWasmArray(instance, blurhashString);
const result = instance.decodeToArray(
stringPtr,
@ -118,14 +124,17 @@ export function decode(
* @param blurhashString A Blurhash string.
* @returns `true` if your string is valid, `false` elsewise.
*/
export function isValidBlurhash(blurhashString: string) {
if (!instance) throw Error(wasmInitializationError);
export function isValidBlurhash(
instance: BlurhashInstanceType,
blurhashString: string
) {
if (!instance) throw Error(wasmMissingError);
if (!blurhashString) {
throw Error(blurHashStringRequiredError);
throw Error(blurhashStringRequiredError);
}
const stringPtr = encodeStringToWasmArray(blurhashString);
const stringPtr = encodeStringToWasmArray(instance, blurhashString);
const result: number = instance.isValidBlurhash(stringPtr);
instance.free(stringPtr);
return Boolean(result);