Search code examples
pdfimagemagickgraphicsmagick

Converting ImageMagick command to GraphicsMagick


In order to increase speed of a conversion, and avoid bugs, I'd like to convert the following ImageMagick command to a GraphicsMagick command.

This upcasts a PDF of any size to 300 DPI, then converts that PDF to a high quality 8.5x11 PDF in ImageMagick.

convert -density 300 ~/Desktop/10x11.pdf -density 300 -resize 2550x3300 -gravity center -extent 2550x3300 -colorspace Gray ~/Desktop/8.5x11.pdf

Running the same command in GraphicsMagick yields a PDF that is 35x45 inches. This is because the interpreted density of the final PDF is 72 (rather than 300) for some reason.

gm convert -density 300 ~/Desktop/10x11.pdf -density 300 -resize 2550x3300 -gravity center -extent 2550x3300 -colorspace Gray ~/Desktop/35x45.pdf

The following yields a (blurry) 8.5x11inch PDF.

gm convert -density 300 ~/Desktop/10x11.pdf -density 300 -resize 612x792 -gravity center -extent 612x792 -colorspace Gray ~/Desktop/8.5x11.pdf

Any ideas on what I am doing wrong here? The aim to generate crisp 8.5x11 inch PDFs using GraphicsMagick.


Solution

  • I realize you asked for a graphicsmagick solution, but if you're open to other libraries, libvips is usually faster at tasks like this.

    Imagemagick and Graphicsmagick use Ghostscript for PDF rendering. libvips uses poppler instead: this library can generate high-quality anti-aliased bitmaps from PDFs at any size. You don't need to render at high resolution and then downsize.

    On this laptop, I see:

    $ /usr/bin/time -f %M:%e convert -density 300 ISO_12233-reschart.pdf -density 300 -resize 2550x3300 -gravity center -extent 2550x3300 -colorspace Gray x.pdf
    250460:2.51
    

    So 250MB of memory and 2.5s to generate your PDF.

    The libvips equivalent would be:

    #!/bin/bash
    
    vips thumbnail $1 t1.v 2550 --height 3300 
    vips colourspace t1.v t2.v b-w
    # drop any alpha channels
    if [ $(vipsheader -f bands t2.v) -gt 1 ]; then
            vips extract_band t2.v t3.v 0
            mv t3.v t2.v
    fi
    vips gravity t2.v t3.v centre 2550 3300 --extend white
    vips magicksave t3.v $2
    

    I see:

    $ /usr/bin/time -f %M:%e ./process.sh ISO_12233-reschart.pdf x.pdf
    110168:1.05
    

    110MB of memory and 1.05s.

    Are you sure you need PDF output? The PDFs you are generating are not "real" PDFs, they are bitmaps with a PDF wrapper. I would use PNG instead:

    #!/bin/bash
    
    vips thumbnail $1 t1.v 2550 --height 3300 
    vips colourspace t1.v t2.v b-w
    # drop any alpha channels
    if [ $(vipsheader -f bands t2.v) -gt 1 ]; then
            vips extract_band t2.v t3.v 0
            mv t3.v t2.v
    fi
    vips gravity t2.v $2 centre 2550 3300 --extend white
    

    I now see:

    $ /usr/bin/time -f %M:%e ./process.sh ~/pics/ISO_12233-reschart.pdf x.png
    58324:0.59
    

    60MB of memory and 0.6s.

    If you're able to use something like Python instead of bash, you can get it a bit quicker still.

    #!/usr/bin/python3
    
    import sys
    import pyvips
    
    x = pyvips.Image.thumbnail(sys.argv[1], 2550, height=3300)
    x = x.colourspace("b-w")
    if x.bands > 1:
        x = x.extract_band(0)
    x = x.gravity("centre", 2550, 3300, extend="white")
    x.write_to_file(sys.argv[2])
    

    Now 0.5s because there are no temporary files.