dlemstra / magick-wasm

The WASM library for ImageMagick
Apache License 2.0
562 stars 38 forks source link

RuntimeError: memory access out of bounds on _MagickImageCollection_Coalesce #173

Open geocine opened 2 months ago

geocine commented 2 months ago

magick-wasm version

0.0.30

Description

Running coalesce inside readCollection on a huge GIF causes the native module to throw a memory access out of bounds exception

VM2835:1 Error processing GIF: RuntimeError: memory access out of bounds
    at magick.dfc94ac5f18be68f99c9.wasm:0x8f67
    at magick.dfc94ac5f18be68f99c9.wasm:0x2809f3
    at magick.dfc94ac5f18be68f99c9.wasm:0x80938
    at magick.dfc94ac5f18be68f99c9.wasm:0x151a9d
    at magick.dfc94ac5f18be68f99c9.wasm:0x384918
    at magick.dfc94ac5f18be68f99c9.wasm:0x8e91f3
    at e._MagickImageCollection_Coalesce (magick.js:8:1)
    at magick-image-collection.ts:439:1
    at magick-image-collection.ts:811:1
    at exception.ts:39:1
    at Ge.use (int-pointer.ts:18:1)
    at T.use (exception.ts:38:1)
    at magick-image-collection.ts:809:1
    at Me.attachImages (magick-image-collection.ts:729:1)
    at Me.replaceImages (magick-image-collection.ts:809:1)
    at Me.coalesce (magick-image-collection.ts:439:1)

Steps to Reproduce

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>ImageMagick WASM Demo</title>
  </head>
  <body>
    <h1>Upload a GIF File</h1>
    <input type="file" id="fileInput" accept="image/gif" />
    <div id="output"></div>
    <script type="module">
      import { ImageMagick, MagickFormat, initializeImageMagick } from "https://esm.sh/@imagemagick/magick-wasm@0.0.30/dist/index.mjs";

      // Initialize
      async function start() {
        try {
          const wasmUrl = "https://esm.sh/@imagemagick/magick-wasm@0.0.30/dist/magick.wasm";
          const wasmBinary = await fetch(wasmUrl).then(response => response.arrayBuffer());

          await initializeImageMagick(wasmBinary);

          const fileInput = document.getElementById('fileInput');
          fileInput.addEventListener('change', async (event) => {
            const file = event.target.files[0];
            if (file) {
              const arrayBuffer = await file.arrayBuffer();
              const uint8Array = new Uint8Array(arrayBuffer);

              // Wait for the ImageMagick WASM module to initialize
              ImageMagick.readCollection(uint8Array, MagickFormat.Gif, (images) => {
                images.coalesce(); // Process images with coalesce
              });
            }
          });
        } catch (error) {
          console.error("Failed to initialize ImageMagick:", error);
        }
      }

      start();
    </script>
  </body>
</html>

Images

https://drive.google.com/file/d/1jeToienatAO07jRmZYpLMlK0MJgBFUcx/view?usp=sharing

This is a zipped file with the GIF image used.

Format                                   : GIF
Format/Info                              : Graphics Interchange Format
File size                                : 90.7 MiB

Image
Format                                   : GIF
Format/Info                              : Graphics Interchange Format
Format profile                           : 89a
Width                                    : 1 331 pixels
Height                                   : 1 331 pixels
Compression mode                         : Lossless

The GIF has 201 frames as read by ImageMagick.readCollection

dlemstra commented 2 months ago

I suspect that you are running out of memory because wasm only runs in 32-bit and has a memory limit. But I will need some time to investigate this.