前段时间开发一个项目,需要用到PDF转图片,并在MFC开发界面中显示图片。经过google,找到几个可用的方法,分别是GhostScript、imageMagic和MuPDF,由于使用MFC做界面开发,因此需要在VC++中使用。
首先用到的是GhostScript,网络上有一些C#的使用方法,如下面的链接:
http://www.codeproject.com/Articles/317700/Convert-a-PDF-into-a-series-of-images-using-Csharp
http://www.codeproject.com/Articles/32274/How-To-Convert-PDF-to-Image-Using-Ghostscript-API
http://blog.csdn.net/ljsspace/article/details/6530046
参考以上的方法,可以在VC++中使用GhostScript的gsdll32.dll(在ghostscript的安装路径下可以找到)把PDF转为图片,但实际使用中会遇到一些问题,某些PDF转为图片后长宽比例出现错误,顶部和底部会出现额外的白边,用GhostScript去显示这些PDF,显示效果也一样会出现同样的问题。改用imageMagic去打开PDF,显示效果一样,顶部和底部也会出现额外的白边。我猜测两个软件使用了相同的算法,或者使用了同一个库。
后来我改用MuPDF,PDF转图片的效果非常好,而且速度比GhostScript更快。
同样,在codeproject上有C#的使用方法:http://www.codeproject.com/Articles/498317/Rendering-PDF-Documents-with-Mupdf-and-P-Invoke-in
英文不好的朋友,可以看这里,有人把文章翻译并提出了自己的见解:http://www.cnblogs.com/pdfpatcher/archive/2012/11/25/2785154.html
由于我是使用C++,对于c开源库的MuPDF来说,使用起来更直接方便。接下来重点介绍一下MuPDF转图片的方法。
获得MuPDF开源库,如果去官方下载MuPDF,编译后是一些exe及静态链接库,地址在这里:http://code.google.com/p/mupdf/downloads/list
很幸运,我们还是能方便能找到动态链接库,有人已经把MuPDF集成到另外一个开源的sumatrapdf中,在下面的地址下载,编译后,在obj-dbg文件夹下可以找到libmupdf.dll、libmupdf.lib、fitz.h。下载地址:http://code.google.com/p/sumatrapdf/downloads/list
为了方便大家下载DLL,我贴出CSDN下载地址,不需要积分可下载:http://download.csdn.net/detail/arthurfangmc/4948658
具体怎么要用哪些函数,及函数的介绍,我就不再重复介绍,上面2篇文章都做了介绍,我直接贴出几个重要的代码。
我的代码直接从MuPDF源代码中修改而来,写了一个简单的类,变量名基本上没改,成员变量没有改成类似“myValue”或“m_value”,大家随便看看吧。
MuPDFConvert.h:
#ifndef MY_MUPDF_CONVERT_PDF_PNG
#define MY_MUPDF_CONVERT_PDF_PNG
extern "C"
{
#include "mupdf/fitz.h"
#include "mupdf/fitz-internal.h"
}
class CMuPDFConvert
{
public:
CMuPDFConvert(void);
~CMuPDFConvert(void);
bool Pdf2Png(const wchar_t* pdfFileName/*,const char* imageOutputPath*/,const char* imageName, int &pageNum);
private:
void drawpage(fz_context *ctx, fz_document *doc, int pagenum);
private:
static const fz_matrix fz_identity;
static fz_colorspace k_device_rgb;
fz_colorspace *fz_device_rgb;
fz_document *m_doc;
fz_stream *m_pStream;
fz_context *m_ctx;
int uselist;
int alphabits;
char output[1024];
float resolution;
float rotation;
int res_specified;
int width;
int height;
int fit;
fz_colorspace *colorspace;
int savealpha;
int invert;
float gamma_value;
char filename[1024];
};
#endif
MuPDFConvert.cpp:
#include "StdAfx.h"
#include "MuPDFConvert.h"
void fz_free_colorspace_imp(fz_context *ctx, fz_storable *cs_)
{
fz_colorspace *cs = (fz_colorspace *)cs_;
if (cs->free_data && cs->data)
cs->free_data(ctx, cs);
fz_free(ctx, cs);
}
static void rgb_to_rgb(fz_context *ctx, fz_colorspace *cs, float *rgb, float *xyz)
{
xyz[0] = rgb[0];
xyz[1] = rgb[1];
xyz[2] = rgb[2];
}
const fz_matrix CMuPDFConvert::fz_identity = { 1, 0, 0, 1, 0, 0 };
fz_colorspace CMuPDFConvert::k_device_rgb = { {-1, fz_free_colorspace_imp}, 0, "DeviceRGB", 3, rgb_to_rgb, rgb_to_rgb };
CMuPDFConvert::CMuPDFConvert(void)
{
fz_device_rgb = &k_device_rgb;
uselist = 1;
alphabits = 8;
//output = NULL;
resolution = 72;
rotation = 0;
res_specified = 0;
width = 0;
height = 0;
fit = 0;
colorspace = NULL;
savealpha = 0;
invert = 0;
gamma_value = 1;
m_doc = NULL;
m_ctx = NULL;
}
CMuPDFConvert::~CMuPDFConvert(void)
{
if (m_pStream)
{
fz_close(m_pStream);
m_pStream = NULL;
}
if (m_doc)
{
fz_close_document(m_doc);
m_doc = NULL;
}
if (m_ctx)
{
fz_free_context(m_ctx);
m_ctx = NULL;
}
}
bool CMuPDFConvert::Pdf2Png(const wchar_t* wcharPdfFile/*,const char* imageOutputPath*/,const char* imageName, int &pageNum)
{
char tempPath[1024];
//strcpy_s(tempPath, imageOutputPath);
//strcat_s(tempPath, imageName);
strcpy_s(tempPath, imageName);
strcat_s(tempPath, "%d.png");
strcpy_s(output, (strlen(tempPath)+1)*sizeof(char), tempPath);
m_ctx = fz_new_context(NULL, NULL, FZ_STORE_DEFAULT);
if (!m_ctx)
{
#if _DEBUG
fprintf(stderr, "mupdf cannot initialise context\n");
#endif
return false;
}
fz_try(m_ctx)
{
fz_set_aa_level(m_ctx, alphabits);
colorspace = fz_device_rgb;
m_pStream = fz_open_file_w(m_ctx, wcharPdfFile);
if (m_pStream)
{
m_doc = fz_open_document_with_stream(m_ctx, ".pdf", m_pStream);
}
if (!m_doc)
{
#if _DEBUG
fprintf(stderr, "mupdf cannot open pdf\n");
#endif
return false;
}
if (fz_needs_password(m_doc))
{
#if _DEBUG
fprintf(stderr, "mupdf cannot authenticate password\n");
fz_throw(m_ctx, "mupdf cannot authenticate password: %s", filename);
#endif
return false;
}
int pn = fz_count_pages(m_doc);
pageNum = pn;
for (int i=0; iPNG
drawpage(m_ctx, m_doc, i+1);
fz_free_page(m_doc, page);
page = NULL;
}
}
fz_catch(m_ctx)
{
return false;
}
if (m_pStream)
{
fz_close(m_pStream);
m_pStream = NULL;
}
if (m_doc)
{
fz_close_document(m_doc);
m_doc = NULL;
}
if (m_ctx)
{
fz_free_context(m_ctx);
m_ctx = NULL;
}
return true;
}
void CMuPDFConvert::drawpage(fz_context *ctx, fz_document *doc, int pagenum)
{
fz_page *page;
fz_display_list *list = NULL;
fz_device *dev = NULL;
int start;
fz_var(list);
fz_var(dev);
fz_try(ctx)
{
page = fz_load_page(doc, pagenum - 1);
}
fz_catch(ctx)
{
fz_throw(ctx, "cannot load page %d in file '%s'", pagenum, filename);
}
if (uselist)
{
fz_try(ctx)
{
list = fz_new_display_list(ctx);
dev = fz_new_list_device(ctx, list);
fz_run_page(doc, page, dev, fz_identity, NULL);
}
fz_catch(ctx)
{
fz_free_device(dev);
fz_free_display_list(ctx, list);
fz_free_page(doc, page);
fz_throw(ctx, "cannot draw page %d in file '%s'", pagenum, filename);
}
fz_free_device(dev);
dev = NULL;
}
if (output)
{
float zoom;
fz_matrix ctm;
fz_rect bounds, bounds2;
fz_bbox bbox;
fz_pixmap *pix = NULL;
int w, h;
fz_var(pix);
bounds = fz_bound_page(doc, page);
zoom = resolution / 72;
ctm = fz_scale(zoom, zoom);
ctm = fz_concat(ctm, fz_rotate(rotation));
bounds2 = fz_transform_rect(ctm, bounds);
bbox = fz_round_rect(bounds2);
/* Make local copies of our width/height */
w = width;
h = height;
/* If a resolution is specified, check to see whether w/h are
* exceeded; if not, unset them. */
if (res_specified)
{
int t;
t = bbox.x1 - bbox.x0;
if (w && t <= w)
w = 0;
t = bbox.y1 - bbox.y0;
if (h && t <= h)
h = 0;
}
/* Now w or h will be 0 unless then need to be enforced. */
if (w || h)
{
float scalex = w/(bounds2.x1-bounds2.x0);
float scaley = h/(bounds2.y1-bounds2.y0);
if (fit)
{
if (w == 0)
scalex = 1.0f;
if (h == 0)
scaley = 1.0f;
}
else
{
if (w == 0)
scalex = scaley;
if (h == 0)
scaley = scalex;
}
if (!fit)
{
if (scalex > scaley)
scalex = scaley;
else
scaley = scalex;
}
ctm = fz_concat(ctm, fz_scale(scalex, scaley));
bounds2 = fz_transform_rect(ctm, bounds);
}
bbox = fz_round_rect(bounds2);
/* TODO: banded rendering and multi-page ppm */
fz_try(ctx)
{
pix = fz_new_pixmap_with_bbox(ctx, colorspace, bbox);
if (savealpha)
fz_clear_pixmap(ctx, pix);
else
fz_clear_pixmap_with_value(ctx, pix, 255);
dev = fz_new_draw_device(ctx, pix);
if (list)
fz_run_display_list(list, dev, ctm, bbox, NULL);
else
fz_run_page(doc, page, dev, ctm, NULL);
fz_free_device(dev);
dev = NULL;
if (invert)
fz_invert_pixmap(ctx, pix);
if (gamma_value != 1)
fz_gamma_pixmap(ctx, pix, gamma_value);
if (savealpha)
fz_unmultiply_pixmap(ctx, pix);
if (output)
{
char buf[512];
sprintf(buf, output, pagenum);
if (strstr(output, ".png"))
{
fz_write_png(ctx, pix, buf, savealpha);
}
}
fz_drop_pixmap(ctx, pix);
}
fz_catch(ctx)
{
fz_free_device(dev);
fz_drop_pixmap(ctx, pix);
fz_free_display_list(ctx, list);
fz_free_page(doc, page);
fz_rethrow(ctx);
}
}
if (list)
fz_free_display_list(ctx, list);
fz_free_page(doc, page);
fz_flush_warnings(ctx);
}
#include "stdafx.h"
#include "MuPDFConvert.h"
int _tmain(int argc, _TCHAR* argv[])
{
CMuPDFConvert pdfConvert;
int nNum = 0;
pdfConvert.Pdf2Png(L"test.pdf", "test", nNum);
return 0;
}
另外,在MFC中可以直接使用CImage来显示PNG及其它格式图片,使用方法非常简单。
定义一个变量
CImage m_img;
导入图片
if(!m_img.IsNull())
{
m_img.Destroy();
}
m_img.Load(strImagePath);
在OnPaint()函数中:
if(!m_img.IsNull())
{
CPaintDC dc(GetDlgItem(IDC_CHILD_PIC));
dc.SetStretchBltMode(HALFTONE);
m_img.Draw(dc.m_hDC, 0, 0, m_nFitWidth, m_nFitHeight, 0, 0, m_nRegionWidth, m_nRegionHeight);
//透明显示PNG图片
//m_img.TransparentBlt(dc.m_hDC, 0, 0, m_nFitWidth, m_nFitHeight,
// 0, 0, m_nRegionWidth, m_nRegionHeight, RGB(255,255,255));
}
使用过程中,PDF转图片还是需要花费一定的时间,如果你需要实时显示图片,而PDF页数又非常多,最好另开一个线程来做PDF转图片的工作。ghostScript和MuPDF我都在项目中使用过,PDF页数很多或者图片分辨率很大的时候,MuPDF的速度优势还是十分明显的。
附PDF转PNG图片下载代码,辛苦劳动,大家给点分吧,如果你没分,又需要下载,给我消息,我发给你。
http://download.csdn.net/detail/arthurfangmc/4948833