易捷 > PDF教程 > PDF开发/编程技术 >

C语言代码开发PDF转换成TXT,PDF文档提取文本工具

分享到:
发布时间:2013-05-22 08:00   浏览次数:

简介
PDF文档的应用十分普遍,通常它的内容是压缩的。本文提供了一段可以用来从PDF文件中提取文本的简单的C代码

为什么要编写这段代码?
Adobe允许你提交PDF文件,提取成文本或HTML后再通过邮件发送给你。但是假如你需要自己提取文本或在程序中加入这个功能的话,需要花费很多时间。也许你还需要对文本应用某些特殊格式(如,添加tab分隔符)以便它们能够导入到Execl中(比如,你需要将PDF文档中包含的表格数据导入到Excel中,这就是编写这段代码的目的)。

在Code Project上有几个创建PDF文档的项目,但是没有不使用商业PDF库提取文本的免费代码。这段代码可以满足有这方面需要的用户的需求。

有一些读取或创建PDF的开发包,但是你用于商业用途的话必须注册或签署各种协议。这里提供的代码非常简单和基础,但是它是完全免费的。它只用到了免费的ZLIB库。

基础
你可以从adobe网站下载类似DFReference15_v5.pdf的文档,里面解释了PDF文档的内部结构。简单地说,每个PDF文件包含一系列对象。每个对象可能需要一个或多个filter来解压也可能包含流数据。文本流通常使用FlateDecode filter压缩,可以使用ZLib(http://www.zlib.org)的代码来解压。
每个对象的数据位于"stream"和"endstream"标识之间。解压后,需要对数据进行处理以便提取出文本。数据中通常包含一个或多个带有格式指令的text对象(以BT开始,已ET结束),你可以通过一步步的了解这个程序加深对PDF文件结构的理解。

关于代码
这段程序包含了非常简单的基本的C代码。它先将整个PDF文件读到缓冲区中,然后重复搜索"stream" 及 "endstream" 段。它没有检查应该使用那种算法,而是假定使用的FlateDecode(如果PDF中使用的不是FlateDecode的话,通常)。数据流解压后,需要对它进行处理。在处理过程中,程序搜索代表text对象的 BT 和 ET标识,分别进行处理,提取出文本信息,假定是否需要tab分隔符或换行符。

这段代码还很不完善,但是它确实演示了如何从pdf文档中提取出文本。
这段代码是可运行的,所以当用它处理一个PDF文档时,它可以很好的提取出文本。

使用代码
下载中包含一个C文件,使用它的话,创建一个Win32控制台程序,把这个C文件加入到项目中。你也许需要下载免费的"zlib compiled DLL"压缩包。把zdll.lib解压到你的项目目录中并把链接到项目中,您需要把zlib1.dll复制到项目目录下,还要把zconf.h和zlib.h复制到项目目录并添加到项目中。

现在可以看看这个程序了,注意输入输出文件的名称是在main方法中指定的。

改进
如果感兴趣的话,可以编写一个图形界面。这段代码对于从表格中提取数据然后导入到excel中非常有用,由于加入了tab分隔符,可以保持原有的分栏。

部分代码

首先定位Stream段

size_t streamstart = FindStringInBuffer (buffer, "stream", filelen);
size_t streamend = FindStringInBuffer (buffer, "endstream", filelen);
找到数据段后,解压缩

z_stream zstrm; ZeroMemory(&zstrm, sizeof(zstrm));
zstrm.avail_in = streamend - streamstart + 1;
zstrm.avail_out = outsize;
zstrm.next_in = (Bytef*)(buffer + streamstart);
zstrm.next_out = (Bytef*)output;
int rsti = inflateInit(&zstrm);
if (rsti == Z_OK)
{
int rst2 = inflate (&zstrm, Z_FINISH);
if (rst2 >= 0)
{
//Ok, got something, extract the text:
size_t totout = zstrm.total_out;
ProcessOutput(fileo, output, totout);
}
}
主要的工作在ProcessOutput 方法中完成,它处理解压后的流从中提取出text对象。

void ProcessOutput(FILE* file, char* output, size_t len)
{
//Are we currently inside a text object?
bool intextobject = false;
//Is the next character literal
//(e.g. \\ to get a \ character or \( to get ( ):
bool nextliteral = false;

//() Bracket nesting level. Text appears inside ()
int rbdepth = 0;

//Keep previous chars to extract numbers etc.:
char oc[oldchar];
int j=0;
for (j=0; j<oldchar; j++) oc[j]=' ';

for (size_t i=0; i<len; i++)
{
char c = output[i];
if (intextobject)
{
if (rbdepth==0 && seen2("TD", oc))
{
//Positioning.
//See if a new line has to start or just a tab:
float num = ExtractNumber(oc,oldchar-5);
if (num>1.0)
{
fputc(0x0d, file);
fputc(0x0a, file);
}
if (num<1.0)
{
fputc('\t', file);
}
}
if (rbdepth==0 && seen2("ET", oc))
{
//End of a text object, also go to a new line.
intextobject = false;
fputc(0x0d, file);
fputc(0x0a, file);
}
else if (c=='(' && rbdepthSPAN class=cs-literal>0 && !nextliteral)
{
//Start outputting text!
rbdepth=1;
//See if a space or tab (>1000) is called for by looking
//at the number in front of (
int num = ExtractNumber(oc,oldchar-1);
if (num>0)
{
if (num>1000.0)
{
fputc('\t', file);
}
else if (num>100.0)
{
fputc(' ', file);
}
}
}
else if (c==')' && rbdepth==1 && !nextliteral)
{
//Stop outputting text
rbdepth=0;
}
else if (rbdepth==1)
{
//Just a normal text character:

相关文章推荐

易捷服务大全

在线PDF转换工具

Word

在线Word转PDF

http://wordtopdf.yjpdf.com
 
Excel

在线Excel转PDF

http://exceltopdf.yjpdf.com
 
PPT

在线PPT转PDF

http://ppttopdf.yjpdf.com

本类最新文章

本类本月热门

大家在关注…