dlemstra / magick-wasm

The WASM library for ImageMagick

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

PDF rendering from PNG or GIF not working

lancejpollard opened this issue · comments

magick-wasm version

0.0.27

Description

I have this running in the browser locally (thanks for all your guides!) and have been testing converting GIF/PNG/JPG to other formats to see what happens.

The PNG and animated GIF conversion to PDF makes it so when I open the PDF, it says "failed to load PDF" and no pages or anything are shown. However, when I run convert input.gif output.pdf on the CLI, it outputs 100+ pages for each frame of the animated GIF, and the PNG also works as a PDF from the CLI. Any ideas why this is not working?

I am afraid that I would have to test all 260 formats, converted to <= 260 outputs each, but that's too intensive, to make sure it is at parity with the CLI. How do I know how it compares? Was it compiled with certain limited subset of ImageMagick or something? Or how does it work?

If it was compiled, how did you generate the .wasm file? Perhaps we could generate a robust version that is at parity with the ImageMagick CLI? Looking forward to learning better what you think! I am brand new to wasm :)

Thank you in advance for your help.

Best,
Lance

Steps to Reproduce

I literally have a demo close to what you have here, but I do it in the browser and download the Blob like this:

const a = document.createElement('a')
a.style.display = 'none'
document.body.appendChild(a)

export function downloadBlob(blob: Blob, fileName: string) {
  const url = URL.createObjectURL(blob)
  a.href = url
  a.download = fileName
  a.click()
  window.URL.revokeObjectURL(url)
}

file.arrayBuffer().then(data => {
  if (!isTooLarge(data.byteLength)) {
    readWithImageMagickCallback(new Uint8Array(data), image => {
      writeWithImageMagick(image, outputFormat)
        .then(out => {
          setInputError(undefined)
          const path = file.name.split('.')
          if (path.length > 1) {
            path.pop()
          }
          const blob = new Blob([out])
          downloadBlob(
            blob,
            `${path.join('.')}.${outputFormat.toLowerCase()}`,
          )
        })
        .catch(error => {
          setInputError(error.message as string)
        })
    })
  } else {
    setInputError(
      `File should be less than 10mb so it doesn't crash the browser.`,
    )
  }
})

async function readWithImageMagickCallback(
  file: Uint8Array,
  callback: (image: IMagickImage) => void,
) {
  ImageMagick.read(file, callback)
}

async function writeWithImageMagick(
  image: IMagickImage,
  format: MagickFormat,
): Promise<Uint8Array> {
  return new Promise((res, rej) => {
    image.write(format, data => {
      res(data)
    })
  })
}

Images

2024-01-06 19 21 59
Screenshot 2024-01-06 at 10 03 50 PM

I see you have a module @dlemstra/magick-native but it is unpublished, is there any way you could publish that as well, or host on GitHub? I assume that is where you do all the magic of creating the .wasm file :)

I have only read your latest message. Will get back to you on the rest. You can find that project here: https://github.com/dlemstra/Magick.Native. Not all delegates are supported PDF requires Ghostscript that is licensed as GPL so I cannot just include that in this project. You can see which delegates are supported here: https://dlemstra.github.io/magick-wasm-docs/classes/magick.

Looking at your code I don't understand the problem you are describing. I don't see you writing a PDF file? And when you want to read all frames from a gif file you will need to use a MagickImageCollection:

ImageMagick.readCollection(bytes, (images) => {
    images.write(MagickFormat.Pdf, bytes => {
    });
});

Closing this issue because I got no response in two weeks. Feel free to respond and I will open the issue again.

@dlemstra how do I know when to use readCollection vs. just read?

You should use readCollection for formats that contain multiple pages/frames. With read you will only read the first image in the file.