36

I have a 100 page PDF that is about 50 MBs. I am running the script below against it and it's taking about 23 seconds per page. The PDF is a scan of a paper document.

gswin32.exe -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dCompatibilityLevel=1.3 
            -dPDFSETTINGS=/screen -sOutputFile=out4.pdf 09.pdf

Is there anything I can do to speed this up? I've determined that the -dPDFSettings=/screen is what is making it so slow, but i'm not getting good compression without it...

UPDATE: OK I tried updating it to what I have below. Am i using the -c 30000000 setvmthreshold portion correctly?

gswin32.exe -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dCompatibilityLevel=1.3 
            -dPDFSETTINGS=/screen -dNumRenderingThreads=2 -sOutputFile=out7.pdf 
            -c 30000000 setvmthreshold -f 09.pdf
Abe Miessler
  • 82,532
  • 99
  • 305
  • 486
  • Compression does take time, ensure you have the images going in reduced as far as possible before it begins. – Orbling Dec 28 '10 at 19:43
  • Unfortunately the issue i'm trying to resolve is that about 600GB worth of over-sized images are already in our DB. I was hoping I could reduce the size using Ghostscript but it looks like I might be retired before it finishes. – Abe Miessler Dec 28 '10 at 19:45
  • OCR it, then there is less image and less to raster, and everything goes faster :-) – user502515 Dec 28 '10 at 20:21

4 Answers4

39

If you are on a multicore system, make it use multiple CPU cores with:

-dNumRenderingThreads=<number of cpus>

Let it use up to 30mb of RAM:

-c "30000000 setvmthreshold"

Try disabling the garbage collector:

-dNOGC

Fore more details, see Improving Performance section from Ghoscript docs.

Community
  • 1
  • 1
ismail
  • 46,010
  • 9
  • 86
  • 95
  • Thanks for the info @Ismail. I updated my question to include what I added to utilize the RAM and CPU cores. Could you take a look at the RAM portion and see if it looks right? – Abe Miessler Dec 28 '10 at 20:14
  • Looks like -c parameter needs double quotes, also added garbage collector hint, also please try giving it more RAM and see if it helps. – ismail Dec 28 '10 at 20:21
  • 3
    I'm invariably getting a **Unable to open the initial device, quitting.** error when trying to include variations of `-c "30000000 setvmthreshold"` in my script. Why? How to avoid this error? Does it require sudo-rights?? – nutty about natty Mar 10 '13 at 11:13
  • 5
    @nuttyaboutnatty I think you must put it just before the input file name(s) and add `-f`, like this: `gs ... -c "30000000 setvmthreshold" -f input_file.pdf` – Olivier 'Ölbaum' Scherler May 24 '13 at 16:19
  • 1
    "Please note that this discussion relates to devices which produce a bitmap format as the output. These parameters have no effect on the vector devices, such as `pdfwrite`", said https://ghostscript.com/doc/current/Use.htm#Improving_performance – SOUser Aug 23 '22 at 06:43
14

I was crunching a ~300 page PDF on a core i7 and found that adding the following options provided a significant speedup:

                            %-> comments to the right 
-dNumRenderingThreads=8     % increasing up to 64 didn't make much difference
-dBandHeight=100            % didn't matter much
-dBandBufferSpace=500000000 % (500MB)
-sBandListStorage=memory    % may or may not need to be set when gs is compiled
-dBufferSpace=1000000000    % (1GB)

The -c 1000000000 setnvmthreshold -f thing didn't make much difference for me, FWIW.

Mihai Iorga
  • 39,330
  • 16
  • 106
  • 107
wpgalle3
  • 141
  • 1
  • 2
  • Could you give a hint about how much you could increase the performance by those parameter? Have you experiences with improving the pdf->ps conversion speed? – Lukas Aug 29 '17 at 06:40
  • 1
    wow! -dBandBufferSpace=500000000 and -dBufferSpace=1000000000 in particular took the conversion of a pdf with large bitmap graphics to a 300 ppi png from a snails pace of over 14 minutes to just 50 seconds, and 20 seconds with -dNumRenderingThreads=4 – Roman Scher Aug 13 '20 at 04:38
  • From further testing, I found that setting `-dBandBufferSpace` alongside `-dBufferSpace` is actually counterproductive in some cases and slows down the rasterization process significantly for larger pdfs. The ghostscript docs actually suggest this as well: "if you only want to allocate more memory for banding, to increase band size and improve performance, use the BufferSpace parameter, not BandBufferSpace." – Roman Scher Aug 16 '20 at 01:15
7

You don't say what CPU and what amount of RAM your computer is equipped with.

Your situation is this:

  • A scanned document as PDF, sized about 500 kB per page on avarage. That means each page basically is a picture, using the scan resolution (at least 200 dpi, maybe even 600 dpi).
  • You are re-distilling it with Ghostscript, using -dPDFSETTINGS=/screen. This setting will do quite a few things to make the file size smaller. Amongst the most important are:
    1. Re-sample all (color or grayscale) images to 72dpi
    2. Convert all colors to sRGB

Both these operations can quite "expensive" in terms of CPU and/or RAM usage.

BTW, your setting of -dCompatibilityLevel=1.3 is not required; it's already implicitely set by -dPDFSETTINGS=/screen already.

Try this:

gswin32.exe ^
 -o output.pdf ^
 -sDEVICE=pdfwrite ^
 -dPDFSETTINGS=/screen ^
 -dNumRenderingThreads=2 ^
 -dMaxPatternBitmap=1000000 ^
 -c "60000000 setvmthreshold" ^
 -f input.pdf

Also, if you are on a 64bit system, try to install the most recent 32bit Ghostscript version (9.00). It performs better than the 64bit version.

Let me tell you that downsampling a 600dpi scanned page image to 72dpi usually does not take 23 seconds for me, but less than 1.

Kurt Pfeifle
  • 86,724
  • 23
  • 248
  • 345
  • I have a 2.79 GHz processor and 3.5 gigs of ram. I tried your method and it's still hovering around 20 seconds. My documents are typically 750k per page. Can you think of anything else I can try? – Abe Miessler Dec 29 '10 at 15:54
  • Also, even with the setvmthreshold set, the process only uses a max of 16Mb of memory. Am i doing something wrong? – Abe Miessler Dec 29 '10 at 15:55
  • @Abe Miessler: if the process uses a max of 16 Mb of memory it probably means that it doesn't **need** more than that for the particular file. To double-check that the setting works at all, try to set its value to a lower figure, like 200000. Then look at the memory usage again. – Kurt Pfeifle Dec 29 '10 at 17:04
  • @Abe Miessler: can you rule out that it is not I/O harddisk performance issues making it slow? (I remember having had such problems before -- I tested this by creating a ramdisk and reading/writing files from/to the ramdisk, and suddenly performance was going through the roof...) – Kurt Pfeifle Dec 29 '10 at 17:07
  • Interesting, i've never heard of a RAMDisk before. Can you recommend a good/free one? – Abe Miessler Dec 29 '10 at 17:23
  • @Abe Miessler: You don't *buy* a ramdisk, you simply set it up. It's a technique where you set aside a part of your physically installed RAM so that the OS thinks it is a harddrive partition (or letter, on Windows). The net effect is that writing to (ram)disk or reading from (ram)disk is basically as fast as accessing RAM (i.e. a factor of 100-1000 faster than real harddisk operations). – Kurt Pfeifle Dec 29 '10 at 22:25
  • @Abe Miessler: http://en.wikipedia.org/wiki/RAMDisk and http://memory.dataram.com/products-and-services/software/ramdisk – Kurt Pfeifle Dec 29 '10 at 22:38
5

To speed up rasterizing a pdf with large bitmap graphics to a high-quality 300 ppi png image, I found that setting -dBufferSpace as high as possible and -dNumRenderingThreads to as many cores as available was the most effective for most files, with -dBufferSpace providing the most significant lift.

The specific values that worked the best were:

  • -dBufferSpace=2000000000 for 2 gigabytes of buffer space. This took the rasterization of one relatively small file from 14 minutes to just 50 seconds. For smaller files, there wasn't much difference from setting this to 1 gigabyte, but for larger files, it made a significant difference (sometimes 2x faster). Trying to go to 3 gigabytes or above for some reason resulted in an error on startup "Unrecoverable error: rangecheck in .putdeviceprops".

  • -dNumRenderingThreads=8 for a machine with 8 cores. This took the rasterization of that same file from 14 minutes to 4 minutes (and 8 minutes if using 4 threads). Combining this with the -dBufferSpace option above took it from 50 seconds to 25 seconds. When combined with -dBufferSpace however, there appeared to be diminishing returns as the number threads were increased, and for some files there was little effect at all. Strangely for some larger files, setting the number of threads to 1 was actually faster than any other number.

The command overall looked like:

gs -sDEVICE=png16m -r300 -o document.png -dNumRenderingThreads=8 -dBufferSpace=2000000000 -f document.pdf

This was tested with Ghostscript 9.52, and came out of testing the suggestions in @wpgalle3's answer as well as the Improving performance section in the Ghostscript documentation.

A key takeaway from the documentation was that when ghostscript uses "banding mode" due to the raster image output being larger than the value for -dMaxBitmap, it can take advantage of multiple cores to speed up the process.

Options that were ineffective or counterproductive:

Setting -c "2000000000 setvmthreshold" (2 gigabytes) either alone or with -dBufferSpace didn't appear to make a difference.

Setting -sBandListStorage=memory resulted in a segmentation fault.

Setting -dMaxBitmap=2000000000 (2 gigabytes) significantly slowed down the process and apparently caused it to go haywire, writing hundreds of gigabytes of temporary files without any sign of stopping, prompting me to kill the process short.

Setting -dBandBufferSpace to half of -dBufferSpace didn't make a difference for smaller files, but actually slowed down the process rather significantly for larger files by 1.5-1.75x. In the Banding parameters section of the Ghostscript documentation, it's actually suggested not to use -dBandBufferSpace: "if you only want to allocate more memory for banding, to increase band size and improve performance, use the BufferSpace parameter, not BandBufferSpace."

Roman Scher
  • 1,162
  • 2
  • 14
  • 18