Where to Download the Required Library
You will need at least GhostScript 8.64 (other versions have a problem with Vista). After you have installed the program, just copy the gs32dll.dll from the installation directory (the bin subdirectory) to the directory where you have the EXE of my program.
Requirements
The program REQUIRES the DLL of Ghostscript, it can be retrieved from the Ghostscript website.
Introduction
Often, I found the need to perform a conversion from a PDF to an image format.
Be it TIF, JPG or whatever format (I strongly suggest to convert PDF to PNG and NOT to JPEG since PNG is MUCH smaller and much better (since it has no information losses). Try for yourself and you will see!)
I found many programs and controls that allow me to do it but they are all expensive or incomplete for my needs. Since I know that Ghostscript performs this kind of work pretty well, I looked for a way to automate a simple conversion.
Background
To perform a conversion, I needed to pass several commands to the Ghostscript interpreter. I must convert a Unicode string to a null terminated ANSI string for Ghostscript. The result is stored in a byte array.
The parameters that we will provide the library are the same and in the same order that we should provide from the command line. So in case any modification attempt should fail on this project, be sure that they are working from the command line!
For a comprehensive list of all the parameters and their meanings, I suggest you read: How to use Ghostscript.
How to Interface with the Ghostscript Library
The functions that are needed to call the library must be invoked using P/Invoke:
[DllImport("gsdll32.dll", EntryPoint="gsapi_new_instance")]
private static extern int gsapi_new_instance (out IntPtr pinstance,
IntPtr caller_handle);
[DllImport("gsdll32.dll", EntryPoint="gsapi_init_with_args")]
private static extern int gsapi_init_with_args (IntPtr instance, int argc, IntPtr argv);
[DllImport("gsdll32.dll", EntryPoint="gsapi_exit")]
private static extern int gsapi_exit (IntPtr instance);
[DllImport("gsdll32.dll", EntryPoint="gsapi_delete_instance")]
private static extern void gsapi_delete_instance (IntPtr instance);
Now that we have this function, we MUST call them in this order:
gsapi_new_instance
gsapi_init_with_args
gsapi_exit
gsapi_delete_instance
Pay attention to the last two, it is a common mistake to invert them!
Now how to call it. (In the real code, there are also parameter checks, but I skip them here for simplicity):
public bool Convert(string inputFile,string outputFile)
{
int intReturn,intCounter,intElementCount;
IntPtr intGSInstanceHandle;
object[] aAnsiArgs;
IntPtr[] aPtrArgs;
GCHandle[] aGCHandle;
IntPtr callerHandle, intptrArgs;
GCHandle gchandleArgs;
string[] sArgs = GetGeneratedArgs(inputFile,outputFile);
intElementCount = sArgs.Length;
aAnsiArgs = new object[intElementCount];
aPtrArgs = new IntPtr[intElementCount];
aGCHandle = new GCHandle[intElementCount];
for(intCounter = 0; intCounter< intElementCount; intCounter++)
{
aAnsiArgs[intCounter] = StringToAnsiZ(sArgs[intCounter]);
aGCHandle[intCounter] =
GCHandle.Alloc(aAnsiArgs[intCounter], GCHandleType.Pinned);
aPtrArgs[intCounter] = aGCHandle[intCounter].AddrOfPinnedObject();
}
gchandleArgs = GCHandle.Alloc(aPtrArgs, GCHandleType.Pinned);
intptrArgs = gchandleArgs.AddrOfPinnedObject();
try
{
intReturn = gsapi_new_instance(out intGSInstanceHandle, _objHandle);
if (intReturn < 0)
{
MessageBox.Show("I can't create a new instance of Ghostscript
please verify no other instance are running!");
ClearParameters(ref aGCHandle,ref gchandleArgs);
return false; }
}
catch (DllNotFoundException ex)
{ MessageBox.Show("The gs32dll.dll in the program directory
doesn't expose the methods i need!
\nplease download the version 8.63 from the original website!");
return false;
}
callerHandle = IntPtr.Zero; intReturn = -1; try {intReturn =
gsapi_init_with_args(intGSInstanceHandle, intElementCount, intptrArgs);}
catch (Exception ex) { MessageBox.Show(ex.Message);}
finally { ClearParameters(ref aGCHandle,ref gchandleArgs);
gchandleArgs.Free();
gsapi_exit(intGSInstanceHandle); gsapi_delete_instance(intGSInstanceHandle); }
return (intReturn == 0) | (intReturn == e_Quit);}
How to Call the Library We Just Created
Using this library is pretty simple.
- Create an instance of the class
- Provide the parameters that are passed as properties (this is optional now)
- Call the function: "Convert" with input and output name (optionally even the parameters)
Here there is an example:
private void ConvertSingleImage(string filename)
{
converter.FirstPageToConvert = (int)numericFirstPage.Value;
converter.LastPageToConvert = (int)numericLastPage.Value;
converter.FitPage = checkFitTopage.Checked;
converter.JPEGQuality = (int)numQuality.Value;
converter.OutputFormat = comboFormat.Text;
System.IO.FileInfo input = new FileInfo(filename);
string output = string.Format("{0}\\{1}{2}",
input.Directory,input.Name,txtExtension.Text);
while (File.Exists(output))
output = output.Replace(txtExtension.Text,
string.Format("{1}{0}", txtExtension.Text,DateTime.Now.Ticks));
txtArguments.Text = converter.ParametersUsed;
if (converter.Convert(input.FullName, output) == true)
lblInfo.Text = string.Format("{0}:File converted!",
DateTime.Now.ToShortTimeString());
else
lblInfo.Text = string.Format("{0}:File NOT converted!
Check Args!", DateTime.Now.ToShortTimeString());
}
Remark About the Library
Ghostscript isn't threadsafe, if you call it more than once, you MUST provide a lock system to be sure you are not calling two instances at the same time.
How to Use This as a Library
Since I have seen a lot of problems regarding how to use this library, I split my project in 2 main projects, one is a DLL (PDFToImage.dll) and the other one is the simple GUI of the DLL.
To use it in an ASP page, YOU MUST set the property "ThrowException
" to true
and now the library will only throw an exception on error and not show any Messagebox
(that you could not want on an ASP page for example).
In case your needs are different from mine, I added a way to pass the library directly the parameters you want. In this case, you will only have to provide input, output name and a string with the parameters as usual in the same form and order then you would provide the command line.
If you want to use this library in an ASP.NET page, you MUST copy both PDFToImage.dll and gs32dll.dll in the BIN directory of your solution!
How to Debug Problems
The program displays a nice arguments list that will help you to find why a file doesn't convert! Open a command prompt, enter the directory where you installed Ghostscript and execute the file gs32win.exe with the parameters as expressed in the textbox (you should only add " to enclose the path of the file that are the last 2 arguments).
You will see how the real Ghostscript would react to it, so you will understand why an error occurred!
History
- 1.0.3 (2008 January): Initial version
- 1.1.0 (2009 March 25): Made it possible to use as DLL and to pass other parameters
- 1.1.1 (2009 March 26): Fixed an International issue, thanks to tchu_2000
- 1.1.2b (2009 March 27): Fixed multiple page output, and cleaned up the International convention
- 1.1.3 (2009 April 4): Fixed duplicated parameter, added new parameters option (
PageSize
, Multithreads support, AntiAlaising and so on)
- 1.2 (2009 November 17): Fixed bug in parameter (thanks Barabara), added more font Options (Thanks Davalv), added Mutex to avoid Concurrency issue (Thanks Davalv), added recognition of 64bit problems