diff --git a/codecs/rotate/rotate.wasm b/codecs/rotate/rotate.wasm index a03bb89d..f5d66ec4 100755 Binary files a/codecs/rotate/rotate.wasm and b/codecs/rotate/rotate.wasm differ diff --git a/src/client/index.tsx b/src/client/index.tsx index 6243dd9b..76bb60a0 100644 --- a/src/client/index.tsx +++ b/src/client/index.tsx @@ -29,13 +29,8 @@ async function demo() { const ctx = canvas.getContext('2d')!; ctx.drawImage(img, 0, 0); const data = ctx.getImageData(0, 0, img.width, img.height); - const result = await api.resize(data, { - fitMethod: 'stretch', - height: 200, - width: 200, - linearRGB: false, - premultiply: true, - method: 'lanczos3', + const result = await api.rotate(data, { + rotate: 180, }); { diff --git a/src/features/preprocessors/rotate/worker/missing-types.d.ts b/src/features/preprocessors/rotate/worker/missing-types.d.ts new file mode 100644 index 00000000..c729fd74 --- /dev/null +++ b/src/features/preprocessors/rotate/worker/missing-types.d.ts @@ -0,0 +1,13 @@ +/** + * Copyright 2020 Google Inc. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/// diff --git a/src/features/preprocessors/rotate/worker/rotate.ts b/src/features/preprocessors/rotate/worker/rotate.ts new file mode 100644 index 00000000..a4491819 --- /dev/null +++ b/src/features/preprocessors/rotate/worker/rotate.ts @@ -0,0 +1,63 @@ +/** + * Copyright 2020 Google Inc. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import wasmUrl from 'url:codecs/rotate/rotate.wasm'; + +export interface RotateOptions { + rotate: 0 | 90 | 180 | 270; +} + +export interface RotateModuleInstance { + exports: { + memory: WebAssembly.Memory; + rotate(width: number, height: number, rotate: 0 | 90 | 180 | 270): void; + }; +} + +// We are loading a 500B module here. Loading the code to feature-detect +// `instantiateStreaming` probably takes longer to load than the time we save by +// using `instantiateStreaming` in the first place. So let’s just use +// `ArrayBuffer`s here. +const instancePromise = fetch(wasmUrl) + .then((r) => r.arrayBuffer()) + .then((buf) => WebAssembly.instantiate(buf)); + +export default async function rotate( + data: ImageData, + opts: RotateOptions, +): Promise { + const instance = (await instancePromise).instance as RotateModuleInstance; + + // Number of wasm memory pages (á 64KiB) needed to store the image twice. + const bytesPerImage = data.width * data.height * 4; + const numPagesNeeded = Math.ceil((bytesPerImage * 2 + 8) / (64 * 1024)); + // Only count full pages, just to be safe. + const numPagesAvailable = Math.floor( + instance.exports.memory.buffer.byteLength / (64 * 1024), + ); + const additionalPagesToAllocate = numPagesNeeded - numPagesAvailable; + + if (additionalPagesToAllocate > 0) { + instance.exports.memory.grow(additionalPagesToAllocate); + } + const view = new Uint8ClampedArray(instance.exports.memory.buffer); + view.set(data.data, 8); + + instance.exports.rotate(data.width, data.height, opts.rotate); + + const flipDimensions = opts.rotate % 180 !== 0; + return new ImageData( + view.slice(bytesPerImage + 8, bytesPerImage * 2 + 8), + flipDimensions ? data.height : data.width, + flipDimensions ? data.width : data.height, + ); +} diff --git a/src/features/preprocessors/rotate/worker/tsconfig.json b/src/features/preprocessors/rotate/worker/tsconfig.json new file mode 100644 index 00000000..bea39d16 --- /dev/null +++ b/src/features/preprocessors/rotate/worker/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../../../../generic-tsconfig.json", + "compilerOptions": { + "lib": ["webworker", "esnext"] + }, + "references": [{ "path": "../../../" }] +}