![]() |
Languages »
C# »
PInvoke
Beginner
License: The Code Project Open License (CPOL)
How To Convert PDF to Image Using Ghostscript APIBy Lord TaGoHHow to use Ghostscript library to create an image (or images) from a PDF file |
C# (C# 1.0), Windows (Win2K, WinXP, Win2003, Vista), Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
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.
The program REQUIRES the DLL of Ghostscript, it can be retrieved from the Ghostscript website.
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.
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.
The functions that are needed to call the library must be invoked using P/Invoke:
/// <summary>Create a new instance of Ghostscript.</summary>
/// <param name="pinstance"></param>
/// <param name="caller_handle"></param>
/// <returns>The instance passed to other GS function</returns>
[DllImport("gsdll32.dll", EntryPoint="gsapi_new_instance")]
private static extern int gsapi_new_instance (out IntPtr pinstance,
IntPtr caller_handle);
/// <summary>This will make the conversion</summary>
/// <param name="instance"></param><param name="argc"></param><param name="argv"></param>
/// <returns>0 if is ok</returns>
[DllImport("gsdll32.dll", EntryPoint="gsapi_init_with_args")]
private static extern int gsapi_init_with_args (IntPtr instance, int argc, IntPtr argv);
/// <summary>Exit the interpreter</summary>
/// <param name="instance"></param><returns></returns>
[DllImport("gsdll32.dll", EntryPoint="gsapi_exit")]
private static extern int gsapi_exit (IntPtr instance);
/// <summary>Destroy an instance of Ghostscript.</summary>
/// <param name="instance"></param>
[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):
/// <summary>Convert a single file!</summary>
/// <param name="inputFile">The file PDf to convert</param>
/// <param name="outputFile">The image file that will be created</param>
/// <returns>True if the conversion succeeds!</returns>
public bool Convert(string inputFile,string outputFile)
{
//These are the variables that I'm going to use
int intReturn,intCounter,intElementCount;
IntPtr intGSInstanceHandle;
object[] aAnsiArgs;
IntPtr[] aPtrArgs;
GCHandle[] aGCHandle;
IntPtr callerHandle, intptrArgs;
GCHandle gchandleArgs;
//Generate the list of the parameters
string[] sArgs = GetGeneratedArgs(inputFile,outputFile);
// Convert the Unicode strings to null terminated ANSI byte arrays
// then get pointers to the byte arrays.
intElementCount = sArgs.Length;
aAnsiArgs = new object[intElementCount];
aPtrArgs = new IntPtr[intElementCount];
aGCHandle = new GCHandle[intElementCount];
//Convert the parameters
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();
//Create a new instance of the library!
try
{
intReturn = gsapi_new_instance(out intGSInstanceHandle, _objHandle);
//Be sure that we create an instance!
if (intReturn < 0)
{
MessageBox.Show("I can't create a new instance of Ghostscript
please verify no other instance are running!");
//Here you should also clean the memory
ClearParameters(ref aGCHandle,ref gchandleArgs);
return false; }
}
catch (DllNotFoundException ex)
{//in this case the DLL we are using isn't the DLL we expect
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;//remove unwanted handler
intReturn = -1;//if nothing changes, it is an error!
//Ok now is the time to call the interesting module
try {intReturn =
gsapi_init_with_args(intGSInstanceHandle, intElementCount, intptrArgs);}
catch (Exception ex) { MessageBox.Show(ex.Message);}
finally//No matter what happens, I MUST close the instance!
{ //free all the memory
ClearParameters(ref aGCHandle,ref gchandleArgs);
gchandleArgs.Free();
gsapi_exit(intGSInstanceHandle);//Close the instance
gsapi_delete_instance(intGSInstanceHandle);//delete it
}
//Conversion was successful if return code was 0 or e_Quit
return (intReturn == 0) | (intReturn == e_Quit);//e_Quit = -101
}
Using this library is pretty simple.
Convert" with input and output name (optionally even the parameters) Here there is an example:
/// <summary>Convert a single file</summary>
/// <remarks>this function PRETEND that the filename is right!</remarks>
private void ConvertSingleImage(string filename)
{
//Setup the converter
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);
//If the output file exists already, be sure to add a
//random name at the end until it is unique!
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());
}
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.
Since I have seen a lot of requests about it, I added an easy way to use this project as an already made .NET library. You just need to add this project to your solution (right click on solution -> Add -> Existing Solution) and then change the Output Type to "Class Library" (right click on ConvertPDF Solution -> Properties).
Now all you have to set is 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 ConvertPDF.dll and gs32dll.dll in the BIN directory of your solution!
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!
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 10 Apr 2009 Editor: Deeksha Shenoy |
Copyright 2009 by Lord TaGoH Everything else Copyright © CodeProject, 1999-2009 Web21 | Advertise on the Code Project |