diff --git a/src/codecs/rotate/processor.ts b/src/codecs/rotate/processor.ts index 6aa80081..0f795e51 100644 --- a/src/codecs/rotate/processor.ts +++ b/src/codecs/rotate/processor.ts @@ -1,23 +1,30 @@ import wasmUrl from '../../../codecs/rotate/rotate.wasm'; import { RotateOptions, RotateModuleInstance } from './processor-meta'; +const instancePromise = (WebAssembly as any).instantiateStreaming(fetch(wasmUrl)); + export async function rotate( data: ImageData, opts: RotateOptions, ): Promise { - const flipDimensions = opts.rotate % 180 !== 0; + const { instance } = (await instancePromise) as {instance: 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 / (64 * 1024)); - const { instance } = (await (WebAssembly as any).instantiateStreaming( - fetch(wasmUrl), - )) as { instance: RotateModuleInstance }; + const numPagesNeeded = Math.ceil(bytesPerImage * 2 / (64 * 1024) + 4); + // Only count full pages, just to be safe. + const numPagesAvailable = Math.floor(instance.exports.memory.buffer.byteLength / (64 * 1024)); + const additionalPagesToAllocate = numPagesNeeded - numPagesAvailable; - instance.exports.memory.grow(numPagesNeeded); + if (additionalPagesToAllocate > 0) { + instance.exports.memory.grow(additionalPagesToAllocate); + } const view = new Uint8ClampedArray(instance.exports.memory.buffer); view.set(data.data); instance.exports.rotate(data.width, data.height, opts.rotate); + + const flipDimensions = opts.rotate % 180 !== 0; return new ImageData( view.slice(bytesPerImage, bytesPerImage * 2), flipDimensions ? data.height : data.width,