如何使用 Ghostscript API 将 PDF 转换为图像






4.89/5 (72投票s)
如何使用 Ghostscript 库从 PDF 文件创建图像(或多个图像)。

在哪里下载所需的库
您至少需要 GhostScript 8.64(其他版本在 Vista 上有问题)。安装程序后,只需将gs32dll.dll从安装目录(bin子目录)复制到您放置我的 EXE 程序的目录。
要求
该程序需要 Ghostscript 的 DLL,可以从 Ghostscript 网站检索。
引言
我经常发现需要将 PDF 转换为图像格式。
无论是 TIF、JPG 还是其他格式(我强烈建议将 PDF 转换为 PNG 而不是 JPEG,因为 PNG 文件要小得多,而且要好得多(因为它没有信息损失)。自己尝试一下,您就会明白!)
我发现许多程序和控件可以做到这一点,但它们都太贵或不符合我的需求。由于我知道 Ghostscript 在这方面做得很好,所以我寻找一种方法来自动化简单的转换。
背景
要执行转换,我需要向 Ghostscript 解释器传递几个命令。我必须将 Unicode 字符串转换为以 null 结尾的 ANSI 字符串才能用于 Ghostscript。结果存储在字节数组中。
我们将提供给库的参数与我们应该从命令行提供的参数相同,并且顺序也相同。因此,如果此项目中的任何修改尝试失败,请确保它们在命令行中运行正常!
要获取所有参数及其含义的完整列表,我建议您阅读:如何使用 Ghostscript。
如何与 Ghostscript 库交互
需要调用库的函数必须使用 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);
现在我们有了这个函数,我们必须按照此顺序调用它们
gsapi_new_instance
gsapi_init_with_args
gsapi_exit
gsapi_delete_instance
注意最后两个,颠倒它们是一个常见的错误!
现在是如何调用它。(在实际代码中,还有参数检查,但我在此为了简化而跳过了)
/// <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
}
如何调用我们刚刚创建的库
使用此库非常简单。
- 创建类的实例
- 提供作为属性传递的参数(现在这是可选的)
- 调用函数:“Convert”,并传入输入和输出名称(可选地也可以传入参数)
这里有一个例子
/// <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 不是线程安全的,如果您调用它多次,您必须提供一个锁定系统,以确保您不会同时调用两个实例。
如何将此用作库
由于我看到了许多关于如何使用此库的问题,因此我将我的项目拆分为 2 个主要项目,一个是 DLL(PDFToImage.dll),另一个是 DLL 的简单 GUI。
要在 ASP 页面中使用它,您必须将“ThrowException
”属性设置为true
,现在该库仅在出错时抛出异常,而不会显示任何Messagebox
(例如,在 ASP 页面中您可能不想要它)。
如果您的需求与我的不同,我添加了一种直接将您想要的参数传递给库的方法。在这种情况下,您只需要提供输入、输出名称和一个包含参数的字符串,就像通常那样,以与您在命令行中提供相同的形式和顺序。
如果您想在 ASP.NET 页面中使用此库,您必须将 PDFToImage.dll 和 gs32dll.dll 复制到您解决方案的 BIN 目录中!
如何调试问题
该程序显示了一个不错的参数列表,这将帮助您找到文件为何无法转换!打开命令提示符,进入您安装 Ghostscript 的目录,然后使用文本框中表示的参数执行文件 gs32win.exe(您只需要添加引号来包含作为最后两个参数的文件路径)。
您将看到真正的 Ghostscript 会如何响应,这样您就能理解为什么会发生错误!
历史
- 1.0.3 (2008年1月): 初始版本
- 1.1.0 (2009年3月25日): 使其可以用作 DLL 并传递其他参数
- 1.1.1 (2009年3月26日): 修复了国际化问题,感谢 tchu_2000
- 1.1.2b (2009年3月27日): 修复了多页输出问题,并清理了国际化约定
- 1.1.3 (2009年4月4日): 修复了重复参数,添加了新参数选项(
PageSize
、多线程支持、抗锯齿等) - 1.2 (2009年11月17日): 修复了参数中的错误(感谢 Barabara),添加了更多字体选项(感谢 Davalv),添加了 Mutex 以避免并发问题(感谢 Davalv),添加了 64 位问题识别