Python Wand: MagickReadImage returns false, but did not raise ImageMagick exception

I've got some long-standing code in a Django code base that reads in a PDF and uses Wand to take a screenshot of the first page of the PDF, which is then displayed on the website. We recently migrated servers (an upgrade from Ubuntu 22 LTS to 24 LTS), and something broke, and I can't for the life of me figure it out.

First, some potentially useful information:

  • OS: Ubuntu 24 LTS
  • Python 3.12.3
  • Django 5.2.4
  • Wand 0.6.13
  • Web server: nginx 1.24.0
  • gunicorn version: 23.0.0
  • We are not using Docker. This Django app is running directly on the server with a local virtual environment.

The PDF-to-PNG code is on the admin side of the web app. Here's the heart of it:

with Image(filename=pdf_location) as pdf:
  with Image(pdf.sequence[0]) as first_page_pdf:
    with first_page_pdf.convert('png') as first_page_png:
      first_page_png.background_color = Color('white')
      first_page_png.alpha_channel = 'remove'
      return first_page_png.make_blob()

When I upload a PDF to the admin site for processing, I'm getting this error:

MagickReadImage returns false, but did not raise ImageMagick exception. This can occur when a delegate is missing, or returns EXIT_SUCCESS without generating a raster.

I have tried everything I can think of after a ton of searching, but nothing is working:

  • I do have ghostscript installed:
$ gs --version
10.02.1
$ which gs
/usr/bin/gs
  • My ImageMagick policy.xml contains the default content found in the policy-debian.xml file that's included with the ImageMagick package, with the notable exception of ensuring that <policy domain="coder" rights="read|write" pattern="PDF" /> is in the policy.xml. I can verify that the PDF policy is properly set:
$ identify -list policy

Path: /etc/ImageMagick-6/policy.xml
  Policy: Resource
    name: disk
    value: 2GiB
  Policy: Resource
    name: map
    value: 2048MiB
  Policy: Resource
    name: memory
    value: 1024MiB
  Policy: Resource
    name: area
    value: 256MP
  Policy: Resource
    name: height
    value: 32KP
  Policy: Resource
    name: width
    value: 32KP
  Policy: Undefined
    rights: None
  Policy: Path
    rights: None
    pattern: @*
  Policy: Delegate
    rights: None
    pattern: URL
  Policy: Delegate
    rights: None
    pattern: HTTPS
  Policy: Delegate
    rights: None
    pattern: HTTP
  Policy: Coder
    rights: Read Write
    pattern: PDF

Path: [built-in]
  Policy: Undefined
    rights: None
  • Conversion of the same PDF file does work when I do it manually with both ghostscript and imagemagick (as suggested here):
$ gs -sDEVICE=pngalpha -o page-%03d.png -r120 pdf-test.pdf
GPL Ghostscript 10.02.1 (2023-11-01)
Copyright (C) 2023 Artifex Software, Inc.  All rights reserved.
This software is supplied under the GNU AGPLv3 and comes with NO WARRANTY:
see the file COPYING for details.
Processing pages 1 through 1.
Page 1
Loading font ArialMT (or substitute) from /usr/share/ghostscript/10.02.1/Resource/Font/NimbusSans-Regular

and

$ convert -density 120 pdf-test.pdf page-%03d.png

Both correctly create page-001.png when using this test PDF.

  • And finally, when doing this manually within my Django shell (i.e., within the same venv that nginx uses), it also works properly:
$ ./manage_dev.py shell
19 objects imported automatically (use -v 2 for details).

Python 3.12.3 (main, Jun 18 2025, 17:59:45) [GCC 13.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from wand.image import Image, Color
>>> with Image(filename='pdf-test.pdf') as pdf:
...   with Image(pdf.sequence[0]) as first_page_pdf:
...     with first_page_pdf.convert('png') as first_page_png:
...       first_page_png.background_color = Color('white')
...       first_page_png.alpha_channel = 'remove'
...       blob = first_page_png.make_blob()
...       with open('screenshot.png', 'wb') as png:
...         png.write(blob)
...
24420
  • One thing that is a bit bizarre is that when I list the ImageMagick delegates, gs is not listed. This is the only thing I can think of that might be causing the issue, but I can't figure out how to get it listed:
$ convert -list configure | grep DELEGATES
DELEGATES      bzlib djvu fftw fontconfig freetype heic jbig jng jpeg lcms lqr lzma openexr openjp2 pango png ps raw tiff webp wmf x xml zlib zstd
DELEGATES      bzlib djvu fftw fontconfig freetype heic jbig jng jp2 jpeg lcms lqr ltdl lzma openexr pangocairo png raw tiff webp wmf x xml zlib

Note that this is not a typo; there are 2 DELEGATES lines here, and neither contains gs.

To reiterate, this code has worked perfectly for many years prior to this server migration/upgrade, so all this leads me to believe that it must be some configuration file (ImageMagick, nginx?) somewhere outside of my code, but I just can't nail it down. I'm really hoping that one of you might have some insights.

Thanks in advance!

Вернуться на верх