1. 程式人生 > >C++ PDF文件相關操作

C++ PDF文件相關操作

    人生總是在趕著一個又一個的期限,直到最後的大限。

    近來基本沒更新過部落格,實在是準備雅思看英語加上調節老看英語後的煩躁心情鬧的。本來以為考完研就與大考再也不見了,這種想法實在是 Too young,Too naive。之前做過一個專案,是關於在Windows平臺下用C++實現PDF文件製作的相關操作的,今天有點心情拿來總結下。

    關於PDF的庫其實有不少,本人因為一開始用神器搜到的是PDFlib,就用這個庫做了。這就是所謂的緣分吧。

    PDFlib並非是開源庫,要使用需要付費,否則會有一個讓人不要不要的水印在頁面的後頭。當然,我大天朝從來無需理會這些,有壓迫的地方就總會有雷鋒站出來搞個破解版,該庫也不例外,有需要可以到這位雷鋒的

部落格地點去下載。如果實在是懶也可以下載本人的DEMO工程,裡面已經配置好了該庫,不過由於本人本著折騰到死的心態做程式設計師,該工程的環境是最新的VS2015,如果你的版本不是最新的,下載了請自己默哀,十分我是不會還回去的哈哈。

    PDFlib是一個標準的動態連結庫,跟其他的動態連結庫的配置方法一樣,把pdflib.lib、pdflib.dll和pdflib.h放到工程目錄下並放入pdflib.lib這個附加依賴項,在工程中包含pdflib.h這個現有項就算完成配置了。接下來就是如何去用這個庫了,一開始在檔案中包含pdflib.h標頭檔案這事應該都是瞭然的。

    具體的使用,網上有一些現成的例子,然而沒有見過能解決好中英文交雜在一起的問題的。因為網上百分之八九十都是建議用PDFlib自帶的字型檔,而很遺憾的是這些字型檔對中文支援的都不怎麼好且字型也就那麼幾種,在一般情況下能分開去呼叫中英文也就算了,然而在一些中英文同時出現的情況下單單是排版的間隙問題就給跪了,要寫程式去遍歷裡面的字元再區分出來對待,勞民傷財,要死要活。這個工作本人是做了的,後來無意間發現某些部落格偶然提及的可以呼叫本地字型檔,於是決心嘗試一番。真是不試不知道,一試一口老血差點吐出來,本地字型檔完美支援中英文不說,字型也是要什麼有什麼。。。有時一些部落格真是誤導死人。。。所以本人在此強烈建議要用這個庫的程式猿直接去

C:\Windows\Fonts這個路徑下找到你喜歡的字型弄出來,然後放到你的工程目錄下拿來呼叫,什麼自帶字型完全是坑爹的!!!下面直接上程式碼,輸出一個頁面上是《將進酒》的PDF檔案。(建一個win32控制檯空白工程並配置好環境後把下面這串程式碼拷進去理論上來說你也是可以執行的。)

#include "pdflib.h"
#include <afx.h> 

void String2text(PDF *p, int &TextFlow, CString &mPagenameAndDate, int fontsize)
{
	char characteristic_cn[100];
	int mPagenameAndDateSize = mPagenameAndDate.GetLength();//字串長度
	PDF_set_parameter(p, "FontOutline", "a=./font/STXINGKA.TTF");//這裡的“./font/STXINGKA.TTF”為字型檔案的存放路徑,也就是說需要將字型檔檔案放到相應的位置,不然會造成錯誤
	sprintf_s(characteristic_cn, "fontname=a:0 fontsize = %d encoding = unicode textlen = %d", fontsize, mPagenameAndDateSize * 2);//中文字元
	PDF_add_textflow(p, TextFlow, (char *)(mPagenameAndDate).AllocSysString(), mPagenameAndDateSize * 2, characteristic_cn);//新增字元段內容
}

void OutputStringToPDF(PDF *p, CString &mPagenameAndDate, int Left, int &Top, int Right, int Reduction, int fontsize)//資料輸出
{
	//該函式輸出資料到PDF中,需要注意的是在輸出到頁未的時候會自行進行換頁
	if (Top<130)
	{
		Top = 740;
		PDF_end_page_ext(p, ""); // 關閉頁面並開啟新的頁面
		PDF_begin_page_ext(p, a4_width, a4_height, "");
	}
	int TextFlow = PDF_create_textflow(p, "", 0, "");//建立字元段
	String2text(p, TextFlow, mPagenameAndDate, fontsize);
	while (true)
	{
		const char *returnstring = PDF_fit_textflow(p, TextFlow, Left, Top, Right, Top - Reduction, "");
		Top -= Reduction;
		if (strcmp(returnstring, "_boxfull") != 0)//物件滿了
		{
			break;
		}
		if (Top<130)
		{
			Top = 740;
			PDF_end_page_ext(p, ""); // 關閉頁面並開啟新的頁面
			PDF_begin_page_ext(p, a4_width, a4_height, "");
		}
	}
	PDF_delete_textflow(p, TextFlow);//釋放字串物件
}

void main()
{
	PDF *p = NULL;
	int Left = 85, Top = 740, Right = a4_width - 85;
	//pdf物件建立
	if ((p = PDF_new()) == (PDF *)0)
	{
		printf("Couldn't create PDFlib object (out of memory)!n");
	}
	PDF_TRY(p)
	{
		//先建立PDF文件,名為outout.pdf
		if (PDF_begin_document(p, "output.pdf", 0, "") == -1)
		{
			printf("Error: %sn", PDF_get_errmsg(p));
		}
		//再建立PDF文件裡面的頁面,並填入頁面的內容,這裡本人將其封裝成了兩個函式
		PDF_begin_page_ext(p, a4_width, a4_height, "");
		CString mPagenameAndDate = L"君不見黃河之水天上來  奔流到海不復回\n";
		mPagenameAndDate += L"君不見高堂明鏡悲白髮  朝如青絲暮成雪\n";
		mPagenameAndDate += L"人生得意須盡歡  莫使金樽空對月\n";
		mPagenameAndDate += L"天生我材必有用  千金散盡還復來\n";
		mPagenameAndDate += L"烹羊宰牛且為樂  會須一飲三百杯\n";
		mPagenameAndDate += L"岑夫子  丹丘生  將進酒  杯莫停\n";
		mPagenameAndDate += L"與君歌一曲  請君為我傾耳聽\n";
		mPagenameAndDate += L"鐘鼓饌玉不足貴  但願長醉不復醒\n";
		mPagenameAndDate += L"古來聖賢皆寂寞  惟有飲者留其名\n";
		mPagenameAndDate += L"陳王昔時宴平樂  斗酒十千恣歡謔\n";
		mPagenameAndDate += L"主人何為言少錢  徑須沽取對君酌\n";
		mPagenameAndDate += L"五花馬  千金裘\n";
		mPagenameAndDate += L"呼兒將出換美酒  與爾同銷萬古愁\n";
		//將文字輸出到PDF,第三個引數為輸出的左邊距,第四個引數為輸出的高度,第五個引數為輸出的右邊距,第六個引數為行距,第七個則是字型的大小
		OutputStringToPDF(p, mPagenameAndDate, Left, Top, Right, 45, 24);
		//頁結束
		PDF_end_page_ext(p, "");
		//文件結束
		PDF_end_document(p, "");
	}
	PDF_CATCH(p)//錯誤資訊輸出
	{
		printf("[%d] %s: %sn",PDF_get_errnum(p), PDF_get_apiname(p), PDF_get_errmsg(p));
		PDF_delete(p);
	}
	PDF_delete(p);
	//開啟pdf
	system("output.pdf");
}
    效果如下:
    由於本人做工程只用到了輸出PDF檔案的那個部分,所以關於讀取PDF檔案的部分是沒有寫的,以後如果有做到則會放上來。至於更多的細節,則可以參考PDFlib的手冊,這個手冊我也會跟我的demo一起打包起來,這是demo地址