PDF格式详解
pdf(Portable  Document  Format,便携式⽂档结构)是⼀种很有⽤的⽂件格式,其最⼤的特点是
平台⽆关⽽且功能强⼤(⽀持⽂字/图象/⾳乐/视频).今天先讲⼀下pdf的⽂件(物理)结构
PDF⽂件结构可分为以下⼏块:
1.header:
pdf⽂件的第⼀⾏,格式如下:
%PDF-1.3
表⽰当前⽂件的版本是1.3(⽬前最⾼版本为1.5)
2.body:
pdf⽂件中⽤到的所有对象,包括⽂本/图象/⾳乐/视频/字体/超连接/加密信息等等,格式如下:
2  0  obj
.
..
end  obj
其中省略号部分是pdf规定的任意合法对象(⼀共8种)
所有pdf对象的引⽤表,其格式如下:
xref
0  5
0000000000  65535  f
0000000009  00000  n
0000000074  00000  n
0000000120  00000  n
0000000179  00000  n
其中,xref是开始标志,表⽰以下为引⽤表内容;0  5表⽰从对象号为0的开始,
连续有5个对象(0,1,2,3,4),分别⽤5⾏来表⽰.每⾏的前10个数字代表这个
这个对象相对⽂件头的偏移地址,后⾯5个数字只有当这个对象被删除的时
候才有⽤,表⽰这个对象被删除后⼜被重新⽣成后的对象号最后⼀位f或n表
⽰对象是否被使⽤(n表⽰使⽤,f表⽰被删除或没有⽤)
整个pdf⽂件的⼊⼝点,形式如下:
trailer
<<
/Size  8
/
Root  1  0  R
>>
startxref
553
%%EOF
/size  :这个pdf中总共使⽤了多少个对象
/root  :这个pdf⽂件的catalog对象的对象号,这是pdf中最顶层的对象
/startxref:  后⾯的数字表⽰cross  reference  table的开始位置
/%%EOF  :⽂件结束符.
实际⼀个pdf⽂件是很复杂的,但是上⾯⼏个部分是确定的,只能多不能少.下⼀讲我说⼀下pdf⾥⾯8种类型.
1.booleam
⽤关键字true或false表⽰,可以是array对象的⼀个元素,或dictionary对象的⼀个条⽬.
2.numeric
包括整形和实型,不⽀持⾮⼗进制数字,不⽀持指数形式的数字.
例:
1)整数 123 4567 +111 -2
范围:正2的31次⽅-1到负的2的31次⽅
2)实数 12.3 0.8 +6.3 -4.01 -3. +.03
范围:±3.403 × 10的38次⽅    ±1.175 × 10的-38次⽅
注意:如果整数超过表⽰范围将转化成实数,如果实数超过范围就出错了
3.string
由⼀系列0-255之间的字节组成,⼀个string总长度不能超过65535.string有以下两种⽅式:
1)由()包含起来的⼀个字串,中间可以使⽤转义符"/".
例:
(abc)  表⽰abc
array工艺详解(a//)  表⽰a/
2)由<>包含起来的⼀个16进制串,两位表⽰⼀个字符,不⾜两位⽤0补齐
例:
<Aabb>  表⽰AA和BB两个字符
<AAB>  表⽰AA和B0两个字符
4.name
由⼀个前导/和后⾯⼀系列字符组成,最⼤长度为127.和string不同的是,name是不可分割的
和唯⼀的,不可分割就是说⼀个name对象就是⼀个原⼦,⽐如/name,不能说n就是这个name的
⼀个元素;唯⼀就是指两个相同的name⼀定代表同⼀个对象.从pdf1.2开始,除了ascii的0,别
的都可以⽤⼀个#加两个⼗六进制的数字表⽰.
例:
/name  表⽰name
/name#20is 表⽰name is
/name#200 表⽰name 0
5.array
⽤[]包含的⼀组对象,可以是任何pdf对象(包括array).虽然pdf只⽀持⼀维array,但可以通过
array的嵌套实现任意维数的array(但是⼀个array的元素不能超过8191)
例:
[549 3.14 false (Ralph) /SomeName]
6.Dictionary
⽤"<<"和">>"包含的若⼲组条⽬,每组条⽬都由key和value组成,其中key必须是name对象,并且
⼀个dictionary内的key是唯⼀的;value可以是任何pdf的合法对象(包括dictionary对象).
例:
<< /IntegerItem 12
/StringItem (a string)
/Subdictionary << /Item1 0.4
/Item2 true
/LastItem (not!)
/VeryLastItem (OK)
>>
>>
7.stream
由关键字stream和endstream包含⼀系列字节.内容和string很相似,但有区别:stream可以分⼏次
读取,分开使⽤不同的部分,string必须作为⼀个整体⼀次全部读取使⽤;string有长度限制,但
stream却没有这个限制.⼀般较⼤的数据都⽤stream表⽰.
例:(略)
8.NULL
⽤null表⽰,代表空.如果⼀个key的值为null,则这个key可以被忽略;如果引⽤⼀个不存在的
object则等价于引⽤⼀个空对象.
例:(略)
给⼤家说点有⽤的东西:为什么有的pdf不允许打印?
pdf有⾃⼰的加密措施,其中就有限制打印.
到trailer,如果这个pdf是加密的话会有⼀个/Encrypt的name,他的值⼀般形式是n 0 R,表⽰这个pdf
⽂件的加密信息在n 0这个obj⾥⾯记录.到这个obj,其下有⼀个/P的name,他的值是⼀个数字(32位)
其中第三位代表是否有打印权限:)
由于pdf的特殊⽂件结构,注定pdf的⽣成是⼀件很⿇烦的事情。⽬前最常⽤的就是adobe公司提供的sdk了,但是由于其依赖与adobe的环境,所以使⽤起来不是很⽅便。在这⾥我给⼤家介绍另外⼀种⽅法——使⽤pdflib⽣成pdf。
pdflib也提供了⼀组sdk,但和adobe的sdk相⽐,pdflib很⼩,但功能却⼀点也不弱。所以对于开发者来说,pdflib是⼀个明智的选择。你可以从下⾯的⽹址得到到它:
www.pdflib/products/pdflib/download/index.html。如果你没有得到序列号,那么⽣成的pdf将会加上⽔印,其他功能和商业版⼀样。
另外你还可以从下⾯⽹址得到pdflib-lite版:
www.pdflib/products/pdflib/download-source.html
pdflib-lite使⽤协议:
www.pdflib/purchase/license-lite.html
和pdflib相⽐,pdflib-lite最⼤的特点就是你可以拥有完全的源代码,但功能不如pdflib全⾯,⽐如⽀持的字体要⽐pdflib少很多。但是,如果你对pdf⽂件本⾝很了解的话,你完全可以在pdflib-lite的基础上再做发挥,这就要看你的c语⾔功底如何了。如果要⽤做商业产品,请仔细阅读授权协议!
下载pdflib压缩包(⼤约6m)后,在pdflib⽂件夹下有pdflib.dll,pdflib.lib,pdflib.h,。对于我们来说,只要有前3个⽂件就可以了。
下⾯是⼀个⽣成pdf的完整代码:
#include  <stdio.h>
#include  <stdlib.h>
#include  "pdflib.h"
int
main(void)
{
PDF  *p;
int  font;
/*  create  a  new  PDFlib  object  */
if  ((p  =  PDF_new())  ==  (PDF  *)  0)
{
printf("Couldn't  create  PDFlib  object  (out  of  memory)!/n");
return(2);
}
PDF_TRY(p)  {
if  (PDF_begin_document(p,  "hello.pdf",  0,  "")  ==  -1)  {
printf("Error:  %s/n",  PDF_get_errmsg(p));
return(2);
}
/*  This  line  is  required  to  avoid  problems  on  Japanese  systems  */
PDF_set_parameter(p,  "hypertextencoding",  "host");
PDF_set_info(p,  "Creator",  "hello.c");
PDF_set_info(p,  "Author",  "Thomas  Merz");
PDF_set_info(p,  "Title",  "Hello,  world  (C)!");
PDF_begin_page_ext(p,  a4_width,  a4_height,  "");
/*  Change  "host"  encoding  to  "winansi"  or  whatever  you  need!  */
font  =  PDF_load_font(p,  "Helvetica-Bold",  0,  "host",  "");
PDF_setfont(p,  font,  24);
PDF_set_text_pos(p,  50,  700);
PDF_show(p,  "Hello,  world!");
PDF_continue_text(p,  "(says  C)");
PDF_end_page_ext(p,  "");
PDF_end_document(p,  "");
}
PDF_CATCH(p)  {
printf("PDFlib  exception  occurred  in  hello  sample:/n");
printf("[%d]  %s:  %s/n",
PDF_get_errnum(p),  PDF_get_apiname(p),  PDF_get_errmsg(p));
PDF_delete(p);
return(2);
}
PDF_delete(p);
return  0;
}
到现在,⼀个hello.pdf的pdf⽂件就⽣成了,你完全可以⾃⼰发挥,做出很复杂的pdf⽂件,这就看你的想象⼒了:)不过在发挥的时候要注意,pdf的坐标和我们通常理解的坐标是不⼀样的,屏幕坐标的原点在左上⾓,pdf⽂件的原点在左下脚。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。