PDF转图片

      前段时间开发一个项目,需要用到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;
}

      这里生成的图片是PNG格式,如果你需要其他格式的图片,可以再选择其它库,如果编译器版本支持CImage,可以使用CImage来转其它图片格式,

另外,在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

你可能感兴趣的:(mfc,PDF,图片,MuPDF,vc++)