In developing one of my more popular WordPress plugins, Document Gallery, I was faced with a challenge that stumped me for a bit. Recently, some of my users had asked for additional functionality to support auto-generation of thumbnails for the documents in their gallery. These documents could be any number of filetypes, but for this particular post we’ll be discussing PDF thumbnail generation.
PDFs are actually quite simple to thumbnail and the process is well-documented across the web. If I had been content with simply using the PHP Imagick extension to wrap my access to Ghostscript (GS), which does the actual conversion for PDFs, then the process of generating a thumbnail would have been quite straightforward, but I was not content with this solution, the primary reason being inefficiency. The way that Imagick processes PDFs before passing it down to GS is very slow. Thus, I went about setting up a framework to directly execute GS from PHP’s
exec() with Imagick as a fallback in the event that I was unable to find a GS executable.
This all should have been quite simple, but it wasn’t. In order to accurately find and execute GS in a platform-agnostic way is actually quite challenging, and surprisingly poorly documented on the web. First, one must determine whether
exec() is available. This is quite a convoluted thing to determine in-and-of-itself, but thankfully I found someone else’s solution for this and did not have to develop it myself. Finding the GS executable, however, was another story entirely.
For Unix servers, the process is as simple as running
exec('which gs'). On a Windows server, however, the process is awful, and even the solution I developed is less than perfect. If the script is running on a Windows server, the first thing done is look for an environment variable named GSC. If set, this should include the GS executable location. If not, the next checks search for either gswin32c or gswin64c in the system path. Finally, if neither of those are set, we directly access the filesystem and look in “Program Files” and “Program Files (x86)” for gswin32c or gswin64c. All in all, it’s a very exhausting process for what should be straightforward. For anyone who questions my preference of Linux over Windows, this experience will henceforth be near the top of my list of reasons.
In any event, I’ve included the final result of my code below. If you have any thoughts or recommendations for improvement, I’d love to read them in the comments below!