From 111754233cbe97a08105be60523bf2facbc0a037 Mon Sep 17 00:00:00 2001 From: Michael Barry Date: Tue, 10 Oct 2023 06:07:32 -0700 Subject: [PATCH] Use VideoFrame on ios 17 (#85) --- .prettierrc.json | 1 + package-lock.json | 237 +++++++------------------------------------- package.json | 1 + src/decode-image.ts | 78 +++++++++++++-- src/utils.test.ts | 15 +++ src/utils.ts | 31 ++++++ 6 files changed, 152 insertions(+), 211 deletions(-) create mode 100644 .prettierrc.json diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 260cea1..df75243 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "@types/pngjs": "6.0.2", "@typescript-eslint/eslint-plugin": "6.7.2", "benchmark": "2.1.4", + "canvas": "2.11.2", "eslint": "8.51.0", "eslint-config-mourner": "3.0.0", "eslint-config-prettier": "9.0.0", @@ -1226,8 +1227,6 @@ "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz", "integrity": "sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "detect-libc": "^2.0.0", "https-proxy-agent": "^5.0.0", @@ -2030,9 +2029,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/acorn": { "version": "8.9.0", @@ -2170,17 +2167,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/are-we-there-yet": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" @@ -2492,8 +2485,6 @@ "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", "dev": true, "hasInstallScript": true, - "optional": true, - "peer": true, "dependencies": { "@mapbox/node-pre-gyp": "^1.0.0", "nan": "^2.17.0", @@ -2533,8 +2524,6 @@ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", "dev": true, - "optional": true, - "peer": true, "engines": { "node": ">=10" } @@ -2613,8 +2602,6 @@ "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", "dev": true, - "optional": true, - "peer": true, "bin": { "color-support": "bin.js" } @@ -2653,9 +2640,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/convert-source-map": { "version": "2.0.0", @@ -2764,8 +2749,6 @@ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "mimic-response": "^2.0.0" }, @@ -2831,17 +2814,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/detect-libc": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", "dev": true, - "optional": true, - "peer": true, "engines": { "node": ">=8" } @@ -3495,8 +3474,6 @@ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "minipass": "^3.0.0" }, @@ -3509,8 +3486,6 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "yallist": "^4.0.0" }, @@ -3522,9 +3497,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/fs.realpath": { "version": "1.0.0", @@ -3584,8 +3557,6 @@ "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.2", @@ -3882,9 +3853,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/hosted-git-info": { "version": "2.8.9", @@ -5331,8 +5300,6 @@ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "semver": "^6.0.0" }, @@ -5348,8 +5315,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true, - "optional": true, - "peer": true, "bin": { "semver": "bin/semver.js" } @@ -5441,8 +5406,6 @@ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", "dev": true, - "optional": true, - "peer": true, "engines": { "node": ">=8" }, @@ -5467,8 +5430,6 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true, - "optional": true, - "peer": true, "engines": { "node": ">=8" } @@ -5478,8 +5439,6 @@ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -5493,8 +5452,6 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "yallist": "^4.0.0" }, @@ -5506,17 +5463,13 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, - "optional": true, - "peer": true, "bin": { "mkdirp": "bin/cmd.js" }, @@ -5534,9 +5487,7 @@ "version": "2.17.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/natural-compare": { "version": "1.4.0", @@ -5555,8 +5506,6 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "whatwg-url": "^5.0.0" }, @@ -5576,25 +5525,19 @@ "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/node-fetch/node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/node-fetch/node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -5617,8 +5560,6 @@ "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "abbrev": "1" }, @@ -5839,8 +5780,6 @@ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "are-we-there-yet": "^2.0.0", "console-control-strings": "^1.1.0", @@ -5859,8 +5798,6 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, - "optional": true, - "peer": true, "engines": { "node": ">=0.10.0" } @@ -6377,8 +6314,6 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -6667,9 +6602,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/shebang-command": { "version": "2.0.0", @@ -6739,17 +6672,13 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "optional": true, - "peer": true + ] }, "node_modules/simple-get": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "decompress-response": "^4.2.0", "once": "^1.3.1", @@ -6860,8 +6789,6 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "safe-buffer": "~5.2.0" } @@ -7032,8 +6959,6 @@ "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", "integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -7050,9 +6975,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/terser": { "version": "5.17.7", @@ -7376,9 +7299,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/v8-to-istanbul": { "version": "9.1.0", @@ -7536,8 +7457,6 @@ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } @@ -8593,8 +8512,6 @@ "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz", "integrity": "sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==", "dev": true, - "optional": true, - "peer": true, "requires": { "detect-libc": "^2.0.0", "https-proxy-agent": "^5.0.0", @@ -9159,9 +9076,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "acorn": { "version": "8.9.0", @@ -9259,17 +9174,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "are-we-there-yet": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", "dev": true, - "optional": true, - "peer": true, "requires": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" @@ -9489,8 +9400,6 @@ "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", "dev": true, - "optional": true, - "peer": true, "requires": { "@mapbox/node-pre-gyp": "^1.0.0", "nan": "^2.17.0", @@ -9517,9 +9426,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "ci-info": { "version": "3.8.0", @@ -9575,9 +9482,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "combined-stream": { "version": "1.0.8", @@ -9610,9 +9515,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "convert-source-map": { "version": "2.0.0", @@ -9700,8 +9603,6 @@ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", "dev": true, - "optional": true, - "peer": true, "requires": { "mimic-response": "^2.0.0" } @@ -9745,17 +9646,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "detect-libc": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "detect-newline": { "version": "3.1.0", @@ -10251,8 +10148,6 @@ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", "dev": true, - "optional": true, - "peer": true, "requires": { "minipass": "^3.0.0" }, @@ -10262,8 +10157,6 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, - "optional": true, - "peer": true, "requires": { "yallist": "^4.0.0" } @@ -10272,9 +10165,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "optional": true, - "peer": true + "dev": true } } }, @@ -10320,8 +10211,6 @@ "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", "dev": true, - "optional": true, - "peer": true, "requires": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.2", @@ -10530,9 +10419,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "hosted-git-info": { "version": "2.8.9", @@ -11608,8 +11495,6 @@ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "dev": true, - "optional": true, - "peer": true, "requires": { "semver": "^6.0.0" }, @@ -11618,9 +11503,7 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "optional": true, - "peer": true + "dev": true } } }, @@ -11692,9 +11575,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "minimatch": { "version": "3.1.2", @@ -11709,17 +11590,13 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "minizlib": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", "dev": true, - "optional": true, - "peer": true, "requires": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -11730,8 +11607,6 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, - "optional": true, - "peer": true, "requires": { "yallist": "^4.0.0" } @@ -11740,9 +11615,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "optional": true, - "peer": true + "dev": true } } }, @@ -11750,9 +11623,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "ms": { "version": "2.1.2", @@ -11764,9 +11635,7 @@ "version": "2.17.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "natural-compare": { "version": "1.4.0", @@ -11785,8 +11654,6 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", "dev": true, - "optional": true, - "peer": true, "requires": { "whatwg-url": "^5.0.0" }, @@ -11795,25 +11662,19 @@ "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dev": true, - "optional": true, - "peer": true, "requires": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -11838,8 +11699,6 @@ "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", "dev": true, - "optional": true, - "peer": true, "requires": { "abbrev": "1" } @@ -12008,8 +11867,6 @@ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", "dev": true, - "optional": true, - "peer": true, "requires": { "are-we-there-yet": "^2.0.0", "console-control-strings": "^1.1.0", @@ -12027,9 +11884,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "object-inspect": { "version": "1.12.3", @@ -12390,8 +12245,6 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, - "optional": true, - "peer": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -12590,9 +12443,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "shebang-command": { "version": "2.0.0", @@ -12636,17 +12487,13 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "simple-get": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", "dev": true, - "optional": true, - "peer": true, "requires": { "decompress-response": "^4.2.0", "once": "^1.3.1", @@ -12747,8 +12594,6 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, - "optional": true, - "peer": true, "requires": { "safe-buffer": "~5.2.0" } @@ -12871,8 +12716,6 @@ "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", "integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", "dev": true, - "optional": true, - "peer": true, "requires": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -12886,9 +12729,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "optional": true, - "peer": true + "dev": true } } }, @@ -13111,9 +12952,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "v8-to-istanbul": { "version": "9.1.0", @@ -13240,8 +13079,6 @@ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", "dev": true, - "optional": true, - "peer": true, "requires": { "string-width": "^1.0.2 || 2 || 3 || 4" } diff --git a/package.json b/package.json index f882bf4..b64f576 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "@types/pngjs": "6.0.2", "@typescript-eslint/eslint-plugin": "6.7.2", "benchmark": "2.1.4", + "canvas": "2.11.2", "eslint": "8.51.0", "eslint-config-mourner": "3.0.0", "eslint-config-prettier": "9.0.0", diff --git a/src/decode-image.ts b/src/decode-image.ts index 4f0a9bd..ebfd8f0 100644 --- a/src/decode-image.ts +++ b/src/decode-image.ts @@ -1,6 +1,6 @@ /* eslint-disable no-restricted-globals */ import type Actor from "./actor"; -import { offscreenCanvasSupported } from "./utils"; +import { offscreenCanvasSupported, shouldUseVideoFrame } from "./utils"; import type { MainThreadDispatch } from "./remote-dem-manager"; import { CancelablePromise, DemTile, Encoding } from "./types"; @@ -10,8 +10,7 @@ let canvas: HTMLCanvasElement; let canvasContext: CanvasRenderingContext2D | null; /** - * Parses a `raster-dem` image into a DemTile using OffscreenCanvas and createImageBitmap - * only supported on newer browsers. + * Parses a `raster-dem` image into a DemTile using Webcoded VideoFrame API. */ function decodeImageModern( blob: Blob, @@ -20,14 +19,69 @@ function decodeImageModern( let canceled = false; const promise = createImageBitmap(blob).then((img) => { if (canceled) return null as any as DemTile; - if (!offscreenCanvas) { - offscreenCanvas = new OffscreenCanvas(img.width, img.height); - offscreenContext = offscreenCanvas.getContext("2d", { - willReadFrequently: true, - }) as OffscreenCanvasRenderingContext2D; - } + return decodeImageUsingOffscreenCanvas(img, encoding); + }); + return { + value: promise, + cancel: () => { + canceled = true; + }, + }; +} - return getElevations(img, encoding, offscreenCanvas, offscreenContext); +function decodeImageUsingOffscreenCanvas( + img: ImageBitmap, + encoding: Encoding, +): DemTile { + if (!offscreenCanvas) { + offscreenCanvas = new OffscreenCanvas(img.width, img.height); + offscreenContext = offscreenCanvas.getContext("2d", { + willReadFrequently: true, + }) as OffscreenCanvasRenderingContext2D; + } + + return getElevations(img, encoding, offscreenCanvas, offscreenContext); +} + +/** + * Parses a `raster-dem` image into a DemTile using webcodec VideoFrame API which works + * even when browsers disable/degrade the canvas getImageData API as a privacy protection. + */ +function decodeImageVideoFrame( + blob: Blob, + encoding: Encoding, +): CancelablePromise { + let canceled = false; + const promise = createImageBitmap(blob).then(async (img) => { + if (canceled) return null as any as DemTile; + + const vf = new VideoFrame(img, { timestamp: 0 }); + try { + // formats we can handle: BGRX, BGRA, RGBA, RGBX + const valid = + vf?.format?.startsWith("BGR") || vf?.format?.startsWith("RGB"); + if (!valid) { + throw new Error(`Unrecognized format: ${vf?.format}`); + } + const swapBR = vf?.format?.startsWith("BGR"); + const size = vf.allocationSize(); + const data = new Uint8ClampedArray(size); + await vf.copyTo(data); + if (swapBR) { + for (let i = 0; i < data.length; i += 4) { + const tmp = data[i]; + data[i] = data[i + 2]; + data[i + 2] = tmp; + } + } + return decodeParsedImage(img.width, img.height, encoding, data); + } catch (e) { + if (canceled) return null as any as DemTile; + // fall back to offscreen canvas + return decodeImageUsingOffscreenCanvas(img, encoding); + } finally { + vf.close(); + } }); return { value: promise, @@ -103,7 +157,9 @@ function isWorker(): boolean { const defaultDecoder: ( blob: Blob, encoding: Encoding, -) => CancelablePromise = offscreenCanvasSupported() +) => CancelablePromise = shouldUseVideoFrame() + ? decodeImageVideoFrame + : offscreenCanvasSupported() ? decodeImageModern : isWorker() ? decodeImageOnMainThread diff --git a/src/utils.test.ts b/src/utils.test.ts index e259081..db967e3 100644 --- a/src/utils.test.ts +++ b/src/utils.test.ts @@ -7,8 +7,11 @@ import { encodeIndividualOptions, encodeOptions, getOptionsForZoom, + offscreenCanvasSupported, + shouldUseVideoFrame, withTimeout, } from "./utils"; +import { Canvas } from "canvas"; const fullGlobalOptions: GlobalContourTileOptions = { thresholds: { @@ -154,3 +157,15 @@ test("withTimeout - cancel cancels timer", async () => { jest.advanceTimersByTime(10_000); expect(cancel).toBeCalledTimes(1); }); + +test("should use video frame", async () => { + const OffscreenCanvas = ((window as any).OffscreenCanvas = jest.fn( + (width: number, height: number) => new Canvas(width, height), + )); + (window as any).createImageBitmap = () => Promise.resolve(); + (window as any).VideoFrame = {}; + expect(offscreenCanvasSupported()).toBeTruthy(); + OffscreenCanvas.mockClear(); + expect(shouldUseVideoFrame()).toBeFalsy(); + expect(window.OffscreenCanvas).toHaveBeenCalledTimes(1); +}); diff --git a/src/utils.ts b/src/utils.ts index f8c902b..f0b356d 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -154,6 +154,37 @@ export function offscreenCanvasSupported(): boolean { return supportsOffscreenCanvas || false; } +let useVideoFrame: boolean | null = null; + +export function shouldUseVideoFrame(): boolean { + if (useVideoFrame == null) { + useVideoFrame = false; + // if webcodec is supported, AND if the browser mangles getImageData results + // (ie. safari with increased privacy protections) then use webcodec VideoFrame API + if (offscreenCanvasSupported() && typeof VideoFrame !== "undefined") { + const size = 5; + const canvas = new OffscreenCanvas(5, 5); + const context = canvas.getContext("2d", { willReadFrequently: true }); + if (context) { + for (let i = 0; i < size * size; i++) { + const base = i * 4; + context.fillStyle = `rgb(${base},${base + 1},${base + 2})`; + context.fillRect(i % size, Math.floor(i / size), 1, 1); + } + const data = context.getImageData(0, 0, size, size).data; + for (let i = 0; i < size * size * 4; i++) { + if (i % 4 !== 3 && data[i] !== i) { + useVideoFrame = true; + break; + } + } + } + } + } + + return useVideoFrame || false; +} + export function withTimeout( timeoutMs: number, { value, cancel }: CancelablePromise,