Click here to Skip to main content
Click here to Skip to main content

How To Convert PDF to Image Using Ghostscript API

By , 28 Mar 2010
 
ConvertPdf.png

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:

/// <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:

  1. gsapi_new_instance
  2. gsapi_init_with_args
  3. gsapi_exit
  4. 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 is not 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
}

How to Call the Library We Just Created

Using this library is pretty simple.

  1. Create an instance of the class
  2. Provide the parameters that are passed as properties (this is optional now)
  3. Call the function: "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());
}

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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Lord TaGoH
Web Developer
Italy Italy
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralRe: size zoomed out?memberLord TaGoH11 Apr '09 - 6:57 
I agree with smesser i think you have a problem with the DPI.
 
try to force the DPI (they are genereted with the -d switch) to what you find more usefull.
 
Default Ghostscript is 72dpi
go to Ghostscript device website
 
search for "72 dpi" and u will find the spot.
GeneralRe: size zoomed out?memberUnruled Boy13 Apr '09 - 16:11 
yes, I use wide screen, the default dpi is 96, after I changed it to 96, the "zoom" is solved.
 
but the text seems a little bit "not smooth", like has been "carved".Confused | :confused:
 
Regards,
unruledboy_at_gmail_dot_com
http://www.xnlab.com

GeneralRe: size zoomed out?memberLord TaGoH14 Apr '09 - 8:55 
did u try the text anti aliasing? does it help?
GeneralRe: size zoomed out?memberUnruled Boy14 Apr '09 - 15:53 
I did not change the text anti aliasing, leave it as the default -1
 
what will be the best value?
 
Regards,
unruledboy_at_gmail_dot_com
http://www.xnlab.com

GeneralRe: size zoomed out?memberLord TaGoH16 Apr '09 - 22:44 
Try 4.
 
or 2 if thats too much Smile | :)
AnswerRe: size zoomed out?membersmesser11 Apr '09 - 4:27 
I don't know what is happening here and I don't know what the default DPI of ghostscript is but I will second the idea that it's probably a DPI issue.
GeneralMuiltipage hintmembersmesser9 Apr '09 - 3:14 
For me when using multipage output it makes since to zero pad the number.
I use PDF's with many pages and looking for one that is not zero padded is a pain.
 
Instead of using %d you can use %02d or %0nd where n is the desired number of padding.
 
for example
 
page01.jpg
page02.jpg
 
instead of
 
page1.jpg
page10.jpg
...
page2.jpg
page20.jpg
 
You can either build this functionality into the GUI or people can just hard code Smile | :)
GeneralRe: Muiltipage hintmemberLord TaGoH11 Apr '09 - 1:49 
It could be a good idea, as soon as i get enough bugs i will update and provide this also as an option Smile | :)
GeneralImage Qualitymembersmesser8 Apr '09 - 12:20 
I get poor image quality unless I add the following:
 
lstExtraArgs.Add("-dGraphicsAlphaBits=4 -dTextAlphaBits=4");
 
This is from the docs:
 
dTextAlphaBits=n
-dGraphicsAlphaBits=n
 
These options control the use of subsample antialiasing. Their use is highly recommended for producing high quality rasterizations. The subsampling box size n should be 4 for optimum output, but smaller values can be used for faster rendering. Antialiasing is enabled separately for text and graphics content. Allowed values are 1, 2 or 4.
 
Note that because of the way antialiasing blends the edges of shapes into the background when they are drawn some files that rely on joining separate filled polygons together to cover an area may not render as expected with GraphicsAlphaBits at 2 or 4. If you encounter strange lines within solid areas, try rendering that file again with -dGraphicsAlphaBits=1.
GeneralRe: Image QualitymemberLord TaGoH9 Apr '09 - 1:29 
Hi, i know i already made a patch to add this very important options
but i can no longer edit my project so i can't update the article.
 
When it will be updated you will have it aviable
with multithreading too. Smile | :)
GeneralRe: Image Qualitymembersmesser9 Apr '09 - 3:07 
How did you make it thread-safe?
 
It was my understanding that ghostscript itself is not thread-safe and never would be. I believe I read that on their site.
 
Edit: Hum I may be thinging about iTextSharp, so I could be wrong. Smile | :)
GeneralRe: Image QualitymemberLord TaGoH10 Apr '09 - 2:37 
I didn't made it thread safe, i just made it use more then 1 thread for the conversion Smile | :) is a simple line command :P
GeneralRe: Image Qualitymembersmesser10 Apr '09 - 3:11 
Hum.. I will look once you get it posted.
GeneralRe: Image QualitymemberLord TaGoH11 Apr '09 - 1:47 
updated Smile | :)
 
check it out! Smile | :)
GeneralRe: Image Quality [modified]membersmesser13 Apr '09 - 5:54 
In your GraphicsAlphaBit and TextAlphaBit properties you have:
 
(value > 4) | (value == 3)
 
don't you mean ?
 
(value > 4) || (value == 3)
 
EDIT: Well I guess it doesn't matter I have just never seen | used in an if condition.
 

PS: Also a small GUI issue. You have the max value of the quality NumericUpDown set to 10 when it should be 100. The default quality value for jpeg is 75.
 
modified on Monday, April 13, 2009 1:10 PM

GeneralRe: Image QualitymemberLord TaGoH14 Apr '09 - 9:05 
about the GUI issue:
you are right next update i will do (hopefull with the convert to stream) i will fix them!
 
about the |
 
their meaning is different, | is a normal OR
|| mean or but it also will not perform the second comparison if the first was false
 
it have the related & and && with the AND operator
with the same description (at least this is my understanding of it)
 
but in this case i think their use can be exchanged Smile | :)
GeneralRe: Image QualitymemberS.B.7 Jun '09 - 19:40 
I think you are slightly confused about the usage of these operators.
 
| and & are bitwise operators. They are useful for applying masks among other things or checking individual bits.
E.g.
Int8 mask = 1 | 2 | 4; // mask will equal the eight bit number binary 0000 0111 ( == 7 decimal)
Int8 justBit2 = mask & 2; // justBit2 will equal 2 if bit 2 is set, or 0 if bit 2 is unset.
 

|| and && are logical operators.
if (value1 == true || value2 == true)
do something
 

In your particular example the bitwise OR operator happens to do the job of the logical OR operator 'by accident'.
QuestionImage sizememberDeWet van Rooyen2 Apr '09 - 16:44 
Im creating images from pdf to use with MODI to OCR the image.
How can I double the image size to have clearer text for the OCR to be more accurate ?
AnswerRe: Image sizememberDeWet van Rooyen2 Apr '09 - 17:03 
nvm. I hardcoded values to represent A4 porpotions :
 
lstExtraArgs.Add(string.Format(GS_PageSizeFormat, 924, 1302.4));
GeneralRe: Image sizememberLord TaGoH3 Apr '09 - 3:03 
But i think the best way to set the paper size to A4 with papersize option and then
increase the resolutoin with -r
 
I create a new version with support for this but i'm unable to edit this article...
as soon as i find out why i will post the update!
GeneralRe: Image sizememberabhidipsa11 Jan '10 - 9:06 
Hi
 
I can see so much of white spces next to mu pdf page's image file.
 
I tried gsview and opened same pdf ,which also shows 75% white space next to my pdf page.
 
I tried some paid software which egnerated image file.
 
any thoughts
 
Thanks
abhi
GeneralAbout version 1.1.2bmemberBarbara Post2 Apr '09 - 2:42 
Hi TaGoH,
 
You really did a great job since I played with the first version you provided.
 
Just wanted to notice, I would have worded the "DLL not found" explicit error message this way :
 
"The gsdll32.dll wasn't found in default dlls search path or is not in correct version (doesn't expose the required methods). Please download the version 8.64 from the original website"
 
Please note I corrected "gsdll32.dll" and not "gs32dll.dll" in this sentence.
 
It also seems that I can get "-dNOPAUSE" option twice in args when using this call :
 
PDFConvert converter = new PDFConvert();
                    converter.JPEGQuality = 75;
                    converter.OutputFormat = "jpeg";
                    //converter.ResolutionX = 72; // dpi
                    converter.FirstPageToConvert = 1;
                    converter.LastPageToConvert = 1;
                    converter.Width = 200;
                    converter.Height = 200;
                    converter.FitPage = true;
                    converter.ThrowOnlyException = true;
 
Best regards,
 
Barbara Post
GeneralRe: About version 1.1.2bmemberLord TaGoH3 Apr '09 - 3:01 
Of course i duplicate the parameter always :P
My mistake i correct the issue but i'm unable to edit my article..
 
it seems i have been locked out...
 
I no longer see an edit button...
 
I even add Multithread options... :(
GeneralRe: About version 1.1.2bmemberBarbara Post9 Apr '09 - 2:37 
Hello again,
 
I hope your troubles finally went away...
 
I noticed a tiny bug when calling the converted providing every option as a string, you loose last parameter :
 
           {//3 arguments MUST be added 0 (meaningless) and at the end the output and the inputfile
                args = new string[presetParameters.Length + 3];
                //now use the parameters i receive (thanks CrucialBT to point this out!)
                // Barbara Post : correction : "i < presetParameters.Length + 1"
                for (int i = 1; i < presetParameters.Length + 1; i++)
                    args[i] = presetParameters[i - 1];
            }
 
 
Around line 520.
 
Barbara
GeneralYou right! i will fix it in version 1.1.4memberLord TaGoH11 Apr '09 - 2:05 
Well nope, but at least they update my article, just after i read ur commet! :P
 
So for a while this little bug will remain :P
 
Thanks you very much for your debugging!
 
to everyone reading in case you are passing a string with all the parameters to the dll use the fix provided here from barbara!
 
I will correct it as:
//now use the parameters i receive (thanks CrucialBT to point this out!)
//and thanks to Barbara who pointout that i was skipping the last parameter
for (int i = 1; i <= presetParameters.Length; i++)
    args[i] = presetParameters[i - 1];
Thanks Again Barbara!
Ps are u using the dll on a real project or just for fun?
GeneralRe: You right! i will fix it in version 1.1.4memberBarbara Post13 Apr '09 - 10:00 
Hello,
 
I'm using this great teaching piece of code/dll for a company's project, an intranet application that allows to browse a file tree via a web interface, and provides previsualisation of PDF files (for people to preview them before printing).
 
I enjoyed realizing this project, as well as coming back here to savour updated code Wink | ;)
 
Barbara (who was a Java programmer but likes C# a lot after some time practicing it. First reason : development "standard" IDE is less resource-consuming. Throwing a troll hahaha, there are some nice full featured lightweight Java IDE around of course).
GeneralParameter Concatenation Missing in methodmemberCrucialBT26 Mar '09 - 10:57 
In the file: PDFConvert.cs
Line: 487
The method GetGeneratedArgs(string, string, string[]) seems to have an incomplete else statement.
 
else
	args = new string[presetParameters.Length + 3];
should read something like
{	//3 arguments MUST be added 0 (meaningless) and at the end the output and the inputfile
	args = new string[presetParameters.Length + 3];
	// for every parameter add it to the args list after pdf2img (start index 1)
	for (int xi = 0; xi < presetParameters.Length; xi++)
	{
		args[xi + 1] = presetParameters[xi];
	}
}

GeneralRe: Parameter Concatenation Missing in methodmemberLord TaGoH27 Mar '09 - 3:40 
Thanks you!
 
I just realize how lazy i was! Shucks | :->
 
I update the code in version 1.1.2b
thanks for the time you spend on my code Smile | :)
GeneralOnly the first page is convertedmemberSpillie26 Mar '09 - 8:17 
pdf2img -dNOPAUSE -dNOPAUSE -dBATCH -sDEVICE=png16m -dFirstPage=1 -dLastPage=22 -sOutputFile=C:\Users\test.pdf.png C:\Users\test.pdf
GeneralRe: Only the first page is convertedmemberLord TaGoH26 Mar '09 - 9:33 
What would the command line version of Ghostscript do with the same parameters for your file?
GeneralRe: Only the first page is convertedmemberSpillie26 Mar '09 - 9:40 
Is the result show in txtArguments.
GeneralRe: Only the first page is converted [modified]memberSpillie26 Mar '09 - 10:15 
Check this !
 
PDFConvert.cs
 
private string[] GetGeneratedArgs(string inputFile, string outputFile,string[] presetParameters)
...
args[2] = GS_Fixed2ndParameter;//"-dBATCH";//stop after
args[3] = GS_Fixed3rdParameter;//"-dSAFER";
 
Convert to tiff all pages converted but no colors , convert to png same problem (only one page)
 
modified on Thursday, March 26, 2009 4:45 PM

GeneralRe: Only the first page is convertedmemberLord TaGoH26 Mar '09 - 23:38 
Please help me to fix it by telling me what ur sistem do if:
 
1st: open command prompt
2nd: go to Ghostscript directory
3rd: execute gs32win.exe with the parameters u r having. (add " to encapsulate the last 2 arguents)
 
tell me the result please.
GeneralRe: Only the first page is convertedmemberSpillie27 Mar '09 - 3:20 
pdf2img -dSAFER -dBATCH -dNOPAUSE -sDEVICE=tifflzw -sOutputFile=C:\Documents and Settings\svjc\Desktop\Nieuwe map\ConvertPDF\ConvertPDF\test.pdf.tif C:\Documents and Settings\svjc\Desktop\Nieuwe map\ConvertPDF\ConvertPDF\test.pdf
 
This works with the windows application.
 

With ghostscript 8.64 (GS> ...) Error : / undefined in pdf2img
 
With my webapplication it doesn't work : Cannot load dll
GeneralRe: Only the first page is convertedmemberSpillie27 Mar '09 - 3:25 
pdf2img -dSAFER -dBATCH -dNOPAUSE -sDEVICE=tifflzw -sOutputFile=C:\Documents and Settings\svjc\Desktop\Nieuwe map\ConvertPDF\ConvertPDF\test.pdf.tif C:\Documents and Settings\svjc\Desktop\Nieuwe map\ConvertPDF\ConvertPDF\test.pdf
 
windows version : OK
 
aspx-version
Unable to load DLL 'gsdll32.dll': Kan opgegeven module niet vinden. (Exception from HRESULT: 0x8007007E)
 
Ghostscript 8.64 (GS> ..) Error: /undefined in pdf2img
GeneralRe: Only the first page is convertedmemberLord TaGoH27 Mar '09 - 3:38 
I just realease version 1.1.2b
try with that, it indeed didn't create multiple file for multiple page with older functions.
(i add a new propriety to the class so set it before call the convert function)
 
The problem of DLL not found is because it can't find the ghostscript DLL.
did u copy it where your binary file are?
i'm not sure about ASP but maybe should be in the same directory of ur pages..
GeneralRe: Only the first page is convertedmembertchu_200029 Mar '09 - 20:41 
FYI. the code just worked for Web application.
I put gsdll32.dll(GhostScript v8.64) and the wrapper dll
under the Bin folder of the Web project, and that's OK Smile | :)
(the wrapper class can be referenced to in your .cs code successfully)
GeneralRe: Only the first page is convertedmemberLord TaGoH30 Mar '09 - 5:23 
Oh thanks you tchu_2000 Smile | :)
GeneralRe: Only the first page is convertedmemberHawkmoth1 Apr '09 - 5:23 
Hi
 
A am also getting on asp.net:-
Unable to load DLL 'gsdll32.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
 
I have got the gsdll32.dll in the bin file.
 
Sry I'm no expert so I would apreciate any help you can give.
 
Thanks
 
All the best
Hawkmoth

GeneralRe: Only the first page is convertedmembertchu_20001 Apr '09 - 20:47 
Hi,
 
1.I'm not sure about ur case, but have u also put the wrapper dll
into the bin folder?
* wrapper dll: a C# dll calling the C-style gsdll32.dll.
Lord has already build such a wrapper dll.
 
There must be a public class and method in the wrapper dll.
You would successfully reference to the public class and method,
after including the wrapper dll to the bin folder.
 
2.If you have already done the above and still have problem:
I am using a differnt version of wrapper dll, but the code
should like this (in ur *.aspx.cs):
 
using aaa.bbb; //if the wrapper class has a namespace
protected void Page_Load(object sender, EventArgs e)
{
    WrapperClass test = new WrapperClass(...); //reference to the wrapper class
    test.WrapperMethod(..., ...); //reference to the wrapper method
}

GeneralRe: Only the first page is convertedmemberHawkmoth2 Apr '09 - 4:18 
Hi tchu_2000
thanks for your time!
 
Your are correct, I didn't have a wrapper in the bin File.
I found an example here:-
http://www.mattephraim.com/blog/2009/01/06/a-simple-c-wrapper-for-ghostscript/[^]
 
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
 
namespace GSWrapper
{
    public class GSWrapper
    {
        [DllImport("gsdll32.dll", EntryPoint = "gsapi_new_instance")]
        private static extern int CreateAPIInstance(out IntPtr pinstance, IntPtr caller_handle);
        [DllImport("gsdll32.dll", EntryPoint = "gsapi_init_with_args")]
        private static extern int InitAPI(IntPtr instance, int argc, IntPtr argv);
        [DllImport("gsdll32.dll", EntryPoint = "gsapi_exit")]
        private static extern int ExitAPI(IntPtr instance);
        [DllImport("gsdll32.dll", EntryPoint = "gsapi_delete_instance")]
        private static extern void DeleteAPIInstance(IntPtr instance);
 
        private string[] GetArgs(string inputPath, string outputPath, int firstPage, int lastPage, int width, int height)
        {
            return new string[]    
            {        // Keep gs from writing information to standard output        
                "-q",                             
                "-dQUIET",               
                "-dPARANOIDSAFER", 
                // Run this command in safe mode        
                "-dBATCH", 
                // Keep gs from going into interactive mode        
                "-dNOPAUSE", // Do not prompt and pause for each page        
                "-dNOPROMPT", // Disable prompts for user interaction                   
                "-dMaxBitmap=500000000", // Set high for better performance                
                // Set the starting and ending pages        
                String.Format("-dFirstPage={0}", firstPage),        
                String.Format("-dLastPage={0}", lastPage),                   
                // Configure the output anti-aliasing, resolution, etc        
                "-dAlignToPixels=0",        
                "-dGridFitTT=0",        
                "-sDEVICE=jpeg",        
                "-dTextAlphaBits=4",        
                "-dGraphicsAlphaBits=4",        
                String.Format("-r{0}x{1}", width, height),
                // Set the input and output files        
                String.Format("-sOutputFile={0}", outputPath), inputPath    };
        }
        public void CallAPI(string[] args)
        {
            GCHandle[] argStrHandles = new GCHandle[args.Length];
            IntPtr[] argPtrs = new IntPtr[args.Length];
            // Create a handle for each of the arguments after 
            // they've been converted to an ANSI null terminated
            // string. Then store the pointers for each of the handles
            for (int i = 0; i < args.Length; i++)
            {    
                argStrHandles[i] = GCHandle.Alloc(StringToAnsi(args[i]), GCHandleType.Pinned);
                argPtrs[i] = argStrHandles[i].AddrOfPinnedObject();
            }// Get a new handle for the array of argument pointers
            GCHandle argPtrsHandle = GCHandle.Alloc(argPtrs, GCHandleType.Pinned);
 
            // Get a pointer to an instance of the GhostScript API 
            // and run the API with the current arguments
            IntPtr gsInstancePtr;CreateAPIInstance(out gsInstancePtr, IntPtr.Zero);
            InitAPI(gsInstancePtr, args.Length, argPtrsHandle.AddrOfPinnedObject());
        }
        private void Cleanup(GCHandle[] argStrHandles, GCHandle argPtrsHandle, IntPtr gsInstancePtr) 
        { 
            for (int i = 0; i < argStrHandles.Length; i++)        
                argStrHandles[i].Free(); 
            argPtrsHandle.Free(); 
            ExitAPI(gsInstancePtr); 
            DeleteAPIInstance(gsInstancePtr); 
        }
        public void GeneratePageThumbs(string inputPath, string outputPath, int firstPage, int lastPage, int width, int height) 
        { 
            CallAPI(GetArgs(inputPath, outputPath, firstPage, lastPage, width, height)); 
        }
        public static byte[] StringToAnsi(string original) 
        {
            byte[] strBytes = new byte[original.Length + 1]; 
            for (int i = 0; i < original.Length; i++)            
                strBytes[i] = (byte)original[i]; 
            strBytes[original.Length] = 0; 
            return strBytes; 
        }
    }
 
}
 
The resulting GSWapper.ddl I put into the bin file of my main asp.net project with the gsdll32.dll.
 
Then called it like this:-
        GSWrapper.GSWrapper myThumbnail = new GSWrapper.GSWrapper();
        
        string strPath = Server.MapPath("~");
        myThumbnail.GeneratePageThumbs(strPath + "SVS.pdf", strPath+"SVS.jpg", 1, 2, 150, 200);
 
 
When I ran it, it seemed to work fine but I had no resulting jpg.
 
I stepped through the code and it doesn't seem to error so I'm at a loss.
 
Am I doing some obviously stupid?
Thanks again
 
All the best
Hawkmoth

GeneralRe: Only the first page is convertedmemberLord TaGoH2 Apr '09 - 9:54 
Do you have both the ConversionPDF.dll and Ghostscript in ur bin directory?
 
PS i don't have IIS installed so i can't test it i'm just giving ideas from other users..
GeneralRe: Only the first page is convertedmembertchu_20002 Apr '09 - 17:16 
This GSWrapper DLL is also a nice stub.
However, I've not tested the code so I'm not sure.
Since you have worked out the wrapper dll problem,
next step, I suggest you replace the GSWrapper with this one?
GSWrapper.cs
http://www.codeproject.com/KB/cs/GhostScriptUseWithCSharp.aspx?fid=1533292&select=2979208#xx2979208xx[^]
 
Then you can test this code:
string strGhostScriptOption = "-dSAFER -dBATCH -dNOPAUSE -r300 -sDEVICE=jpeg -dGraphicsAlphaBits=4 -dFirstPage=1 -dLastPage=1";
string strSrcImagePath = @"...\a.pdf";
string strDestImagePath = @"...\a.jpg";
nRet = GSWrapper.RunGhostScriptAPI(strGhostScriptOption, strSrcImagePath, strDestImagePath);
if (nRet < 0)
    System.Windows.Forms.MessageBox.Show("GSWrapper.RunGhostScriptAPI error");
 
It just works Smile | :) for Web. In fact, there is no difference with desktop application development
except things such like: file access permission, folder security setting.
Good Luck!Thumbs Up | :thumbsup:
GeneralRe: Only the first page is convertedmemberHawkmoth2 Apr '09 - 22:34 
Blimey...That worked great! Thumbs Up | :thumbsup:
 
Without sounding to slushy, it's nice to see there are still some good and kind people in the world.
 
Thank you very much for your help guys!
 
All the best
Hawkmoth

GeneralRe: Only the first page is convertedmembertchu_20003 Apr '09 - 22:25 
Don't mention it. I have also been helped out by others, so i ought to produce the same Wink | ;)
GeneralRe: Only the first page is convertedmemberLord TaGoH11 Apr '09 - 1:55 
I add support for GraphicsAlphaBits and TextAlphaBits. in case you are still interested Smile | :)
GeneralRe: Only the first page is convertedmemberHawkmoth2 Sep '10 - 23:53 
Hi Guys
 
I'm in need of your advice again!
 
Everything has been working fine up till now.
Recently, we had to migrate to a new host for our website.
 
Now I back to the same error:-
 
Unable to load DLL 'gsdll32.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E) 
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 
 
Exception Details: System.DllNotFoundException: Unable to load DLL 'gsdll32.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
 
Source Error: 
 
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.  
 
Stack Trace: 
 

[DllNotFoundException: Unable to load DLL 'gsdll32.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)]
   module.GSWrapper.gsapi_new_instance(IntPtr& pinstance, IntPtr caller_handle) +0
   module.GSWrapper.RunGhostScriptAPI(String strGhostScriptOption, String strSrcImagePath, String strDestImagePath) +518
   DataPanel_PdfUpload.btnSubmit_Click(Object sender, EventArgs e) +630
   System.Web.UI.WebControls.Button.OnClick(EventArgs e) +111
   System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument) +110
   System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +10
   System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +13
   System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +36
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1565
 
The new host is a Windows system with NFS storage on a Linux system. Not sure if this makes a differance.
 
Any Ideas?
Thanks
All the best
Hawkmoth

GeneralRe: Only the first page is convertedmemberMatthysDT25 Aug '11 - 3:57 
Hey Hawkmoth
Did you ever figure this one out?
I have the same problem.
QuestionUnicode path problemmembertchu_200025 Mar '09 - 0:38 
Useful article which really helped me.
1.Something to share:
  - I've converted the source to a DLL, wrapped the function of gsapi into the form such as:
  RunGhostScriptAPI(string strGhostScriptOption, string strSrcImagePath, string strDestImagePath)
  So that it can be used more freely in many case (include successfully called from WebSite)
  If anyone need this, I'd be glad to share the code in the next post.
  - A version of gsdll32 8.64 rather than 8.63, will settle the imcompatibility probelm occured in Win2003/Vista
  (I have tested it)
2.Problem: If the image files are located in a path comprised of Unicode characters(such as Asian Characters),
  then the calling will never succeed.
  I know that the path will be firstly converted to AnsiZ, and then to GCHandle, and finally fed to the gsapi.
  The problem maybe caused by the Ansi conversion. Is there any safe way to work around the problem?
AnswerRe: Unicode path problem - wrapper DLL code to sharemembertchu_200025 Mar '09 - 0:46 
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
 
namespace module
{
    public class GSWrapper
    {
        #region GhostScript API::Import
 
        /// <summary>Create a new instance of Ghostscript. This instance is passed to most other gsapi functions. The caller_handle will be provided to callback functions.
        ///  At this stage, Ghostscript supports only one instance. </summary>
        /// <param name="pinstance"></param>
        /// <param name="caller_handle"></param>
        /// <returns></returns>
        [DllImport("gsdll32.dll", EntryPoint = "gsapi_new_instance")]
        private static extern int gsapi_new_instance(out IntPtr pinstance, IntPtr caller_handle);
 
        /// <summary>This is the important function that will perform the conversion</summary>
        /// <param name="instance"></param>
        /// <param name="argc"></param>
        /// <param name="argv"></param>
        /// <returns></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. This must be called on shutdown if gsapi_init_with_args() has been called, and just before gsapi_delete_instance(). 
        /// </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. Before you call this, Ghostscript must have finished. If Ghostscript has been initialised, you must call gsapi_exit before gsapi_delete_instance. 
        /// </summary>
        /// <param name="instance"></param>
        [DllImport("gsdll32.dll", EntryPoint = "gsapi_delete_instance")]
        private static extern void gsapi_delete_instance(IntPtr instance);
 
        #endregion
 
        private GSWrapper()
        {
        }
 
        public static int RunGhostScriptAPI(string strGhostScriptOption, string strSrcImagePath, string strDestImagePath)
        {
            int nRet = 0;
            int numArgs;
            object[] ansiArgs;
            GCHandle[] gchArgs;
            IntPtr[] ptrArgs;
            GCHandle gchPtrArgs;
            IntPtr prtGchPtrArgs;
            IntPtr ptrGSInstance;
 
            //1.组合得到参数数组(Unicode字符串)
            string[] strGhostScriptArguments = GetGeneratedArgs(strGhostScriptOption, strSrcImagePath, strDestImagePath);
 
            //2.将参数数组中的每个Unicode字符串、转换成NULL结尾ANSI字节列,得到字节列形式参数数组的指针。
            numArgs = strGhostScriptArguments.Length;
            ansiArgs = new object[numArgs];
            gchArgs = new GCHandle[numArgs];
            ptrArgs = new IntPtr[numArgs];
            for (int i = 0; i < numArgs; i++)
            {
                ansiArgs[i] = StringToAnsiZ(strGhostScriptArguments[i]);
                gchArgs[i] = GCHandle.Alloc(ansiArgs[i], GCHandleType.Pinned);
                ptrArgs[i] = gchArgs[i].AddrOfPinnedObject();
            }
            gchPtrArgs = GCHandle.Alloc(ptrArgs, GCHandleType.Pinned);
            prtGchPtrArgs = gchPtrArgs.AddrOfPinnedObject();
 
            //3.启动GhostScript实例
            nRet = gsapi_new_instance(out ptrGSInstance, IntPtr.Zero);
            if (nRet < 0)
                goto LEVEL_0;
 
            try
            {
                nRet = gsapi_init_with_args(ptrGSInstance, numArgs, prtGchPtrArgs);
                if (nRet < 0)
                    goto LEVEL_0;
            }
            catch (Exception e)
            {
                nRet = -1000;
                goto LEVEL_0;
            }
 
        LEVEL_0:
            for (int i = 0; i < numArgs; i++)
            {
                gchArgs[i].Free();
            }
            gchPtrArgs.Free();
            gsapi_exit(ptrGSInstance);
            gsapi_delete_instance(ptrGSInstance);
 
            return nRet; 
        }
 
        private static readonly string FORMAT_GHOSTSCRIPT_ARGUMENT_FIRST = "pdf2img"; //第一个参数会被忽略
        private static readonly string FORMAT_GHOSTSCRIPT_ARGUMENT_OUTPUTFILE = "-sOutputFile={0}"; //0:FilePathDestImg
        private static string[] GetGeneratedArgs(string strGhostScriptOption, string strSrcImagePath, string strDestImagePath)
        {
            //For a complete option list watch here: http://pages.cs.wisc.edu/~ghost/doc/cvs/Devices.htm
            string[] options = strGhostScriptOption.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
 
            //NOTE: 增加三个参数,第一个参数会被忽略,类似C中main()的风格,最后两个参数分别为输出、输入文件路径
            string[] args = new string[options.Length + 3];
            args[0] = FORMAT_GHOSTSCRIPT_ARGUMENT_FIRST; //Constant.FORMAT_GHOSTSCRIPT_ARGUMENT_FIRST;
            for (int i = 0; i < options.Length; i++)
            {
                args[1 + i] = options[i];
            }
            args[options.Length + 1] = String.Format(FORMAT_GHOSTSCRIPT_ARGUMENT_OUTPUTFILE, strDestImagePath);
            args[options.Length + 2] = strSrcImagePath;
            return args;
        }
 
        private static byte[] StringToAnsiZ(string str)
        {
            //' Convert a Unicode string to a null terminated Ansi string for Ghostscript.
            //' The result is stored in a byte array. Later you will need to convert
            //' this byte array to a pointer with GCHandle.Alloc(XXXX, GCHandleType.Pinned)
            //' and GSHandle.AddrOfPinnedObject()
            int intElementCount;
            int intCounter;
            byte[] aAnsi;
            byte bChar;
 
            intElementCount = str.Length;
            aAnsi = new byte[intElementCount + 1];
            for (intCounter = 0; intCounter < intElementCount; intCounter++)
            {
                bChar = (byte)str[intCounter];
                aAnsi[intCounter] = bChar;
            }
 
            aAnsi[intElementCount] = 0;
            return aAnsi;
        }
    }
}

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 28 Mar 2010
Article Copyright 2009 by Lord TaGoH
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid