- 在VisualStudio中部署GDAL库的C++版本(包括SQLite、PROJ等依赖)
- Android开机流程介绍
- STM32CubeMX教程31USB_DEVICE-HID外设_模拟键盘或鼠标
- 深入浅出Java多线程(五):线程间通信
已经很久没有写博客记录自己学到的一些东西了。但是在过去一年的时间中自己确实又学到了一些东西。一直攒着没有系统化成一篇篇的文章,所以今年的博客打算也是以去年学到的一系列内容为主。通过之前Vim系列教程的启发,我发现还是写一些系列文章对自己的帮助最大。它能最大化自己的学习成果,并强迫自己深入了解一些内容。所以今年我想还是以系列文章为主,如果中间有需要穿插一些bug处理或者语言特性相关的,可能也会有这方面的内容吧.
好了,废话就到这里,下面开始正式介绍PDF相关的内容 。
PDF的全称是 Portable document format(可移植文档格式),是描述打印页面的世界领先语言。最早于1990年代由Adobe Systems创造。早期是Adobe专有格式,直到2008年作为开放标准发布。后续经过一系列的发展,目前已经发展到了2.0版本,由于PDF完全向后兼容,并且大部分都是向前兼容的,因此,这里不打算固定在某个具体的版本,而是介绍一些PDF通用的标准和规则.
PDF主要由四个部分构成,文件头、文件体、交叉引用表以及文件尾 文件头将文件标识为PDF并给出它的版本号,例如 。
%PDF-1.0 % PDF 版本号为 1.0 的文件头
文件体是PDF文档的主体内容,主要由对象组成,它规定了页面信息和页面内容元素等信息 。
交叉引用表给出了每个对象距离文件首部的地址偏移,这样在解析PDF的时候就不用从头到尾解析每个对象,而是根据需要通过交叉引用表来寻址到具体的对象地址,只单独解析某个对象,提高了解析效率 。
文件尾给出交叉引用表的位置并且以 。
%%EOF
作为结尾 。
一个标准的PDF文档需要在文件体中包含下列元素对象:
它们之间的关系如下图:
说了这么多,我们来试试来自己编辑一个hello world文档,首先建立一个文本文件,将后缀改为.PDF 。 我们先写上文件头:
%PDF-1.0 % PDF 版本号为 1.0 的文件头
我们按照之前的分析的PDF文档中需要包含的对象,来逐一定义 首先给出Pages节点的定义 。
1 0 obj % 对象1
<< /Type /Pages % 这是一个页面列表
/Count 1 % 只有一页
/Kids [2 0 R] % 页面对象编号列表。这里只是对象2
>>
endobj % 对象1结束
对象的内容我们在后续会专门介绍,所以这里不需要额外关注它的语法,这里只需要知道 。
1 0 obj
定义了一个对象1,后续通过1 这个编号可以找到这个对象。这个对象中定义了他的类型是 Pages表示它是一个pages对象,/Count表示整个PDF文档只有一页,Kids是一个数组,表示每一页的页面对象,这里它只有一个页面对象,就是对象2 。
接着我们定义页面对象 。
2 0 obj
<< /Type /Page % 这是一个页面
/MediaBox [0 0 612 792] % 纸张尺寸为美国信肖像(612点x792点)
/Resources 3 0 R % 对象3的资源引用
/Contents [4 0 R] % 图形内容在对象4中
>>
endobj
页面对象中我们定义了页面纸张的大小,单位是磅。因为PDF是可移植文档,它需要在不同设备上显示同样的内容,这里不能使用像素,如果使用像素,在同样尺寸的显示器上如果显示器的像素分辨率不同,那么显示的结果将会不同。所以这里一般使用磅作为单位.
同时在页面对象中定义了页面中将要使用的资源以及将要显示的内容 。
接着我们来定义资源对象 。
3 0 obj
<< /Font % 字体字典
<< /F0 % 只有一种字体,称为/F0
<< /Type /Font % 这三行引用了内置字体Times Italic
/BaseFont /Times-Italic
/Subtype /Type1 >>
>>
>>
endobj
资源对象中,我们定义了一个字体资源,字体为 Times Italic,并且定义了这种字体资源的名称为 F0, 后面可以通过F0 这个名称来直接引用这个字体 。
然后我们来定义页面内容对象 。
4 0 obj % 页面内容流
<< >>
stream % 流的开始
1. 0. 0. 1. 50. 700. cm % 位置在(50,700)
BT % 开始文本块
/F0 36. Tf % 在36pt选择/F0字体
(Hello, World!) Tj % 放置文本字符串
ET % 结束文本块
endstream % 流结束
endobj
通过stream来定义一个流对象,在这个流对象中,我们定义它在页面的 (50, 700) 坐标位置显示字符,显示字符内容通过后面的 (Hello, World!) Tj来定义,并且定义了字符采用F0 字体,也就是上面定义的Times-Italic字体 。
页面相关的内容我们已经定义完了,接着我们需要定义一些结构相关的对象,方便PDF解析器找到并解析页面内容.
我们来定义根节点 。
5 0 obj
<< /Type /Catalog %文件目录
/Pages 1 0 R %参考页面列表
>>
endobj
根节点包含了一个Pages定义,通过根节点就可以找到Pages节点 。
接着我们来定义交叉引用表 。
xref %这里我们跳过了交叉引用表的开始
0 6
交叉引用表包含一些偏移地址信息,我们单纯的通过文本文档很难计算各个对象的偏移,所以这里我们只给出文档中对象数量为6,具体的地址我们先不给出,这样PDF解析器也能解析出各个对象 。
之前我们给出了5个对象的定义,但是交叉引用表的条目却是6,这是因为交叉引用表的第一条一般是一个没有什么用处的,有效的对象从第二条定义开始.
下面给出 Trailer 字典的定义 。
trailer
<< /Size 6 %交叉引用表的行数
/Root 5 0 R % 参考文档目录
>>
Trailer 字典以 trailer关键字开始。条目下面包括了交叉引用表的行数以及根节点的对象 。
最后我们给出交叉引用表在PDF文档中的偏移,由于交叉引用表的内容为空,所以这里我们直接给0 。
startxref
0 %xref表开始的字节偏移量,这里设置成0
最后我们以 。
%%EOF
结尾来表示整个PDF文档结束 。
到这里我们已经得到了一个PDF阅读器可以打开的PDF文档。我们使用PDF阅读器可以得到如下的页面 。
不知道各位小伙伴们是否能看懂上面 Hello World 文档的定义。下面我们通过一个完整的 PDF文档来将上面所有定义的对象串起来,希望各位能对PDF文档有一个完整的认识。我们不用纠结各个部分的写法,以及为什么要这么写,只需要明白各个对象的功能即可。具体对象定义相关的语法和每个对象的详细解释将会在后面一系列文章中给出,相信那个时候再来看这个 Hello Word 文档一定会有一个更清晰的认识.
再说明文档读取的过程前,我们先使用一些工具来补全这个文档,这里使用 pdftk 工具。可以在这里 进行下载,完成之后,使用如下命令进行补全 。
pdftk hello.pdf output hello-full.pdf
成功后会得到如下内容 。
%PDF-1.0
%忏嫌
1 0 obj
<<
/Kids [2 0 R]
/Count 1
/Type /Pages
>>
endobj
2 0 obj
<<
/Resources 3 0 R
/MediaBox [0 0 612 792]
/Contents [4 0 R]
/Type /Page
>>
endobj
3 0 obj
<<
/Font
<<
/F0
<<
/BaseFont /Times-Italic
/Subtype /Type1
/Type /Font
>>
>>
>>
endobj
4 0 obj
<<
/Length 202
>>
stream
% 娴佺殑寮€濮?
1. 0. 0. 1. 50. 700. cm % 浣嶇疆鍦紙50,700锛?
BT % 寮€濮嬫枃鏈潡
/F0 36. Tf % 鍦?6pt閫夋嫨/F0瀛椾綋
(Hello, World!) Tj % 鏀剧疆鏂囨湰瀛楃涓?
ET % 缁撴潫鏂囨湰鍧?
endstream
endobj
5 0 obj
<<
/Pages 1 0 R
/Type /Catalog
>>
endobj xref
0 6
0000000000 65535 f
0000000015 00000 n
0000000074 00000 n
0000000168 00000 n
0000000267 00000 n
0000000523 00000 n
trailer
<<
/Root 5 0 R
/Size 6
>>
startxref
573
%%EOF
这个我将整个PDF文档都粘贴了出来,从这里我们可以看到,它已经为我们补全了交叉引用表。下面通过整个文档来说明一般读取过程 。
Times-Italic
字体显示 hello world
字符串最后此篇关于PDF标准详解(一)——PDF文档结构的文章就讲到这里了,如果你想了解更多关于PDF标准详解(一)——PDF文档结构的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
全称“Java Virtual Machine statistics monitoring tool”(statistics 统计;monitoring 监控;tool 工具) 用于监控虚拟机的各种运
主要是讲下Mongodb的索引的查看、创建、删除、类型说明,还有就是Explain执行计划的解释说明。 可以转载,但请注明出处。  
1>单线程或者单进程 相当于短链接,当accept之后,就开始数据的接收和数据的发送,不接受新的连接,即一个server,一个client 不存在并发。 2>循环服务器和并发服务器
详解 linux中的关机和重启命令 一 shutdown命令 shutdown [选项] 时间 选项: ?
首先,将json串转为一个JObject对象: ? 1
matplotlib官网 matplotlib库默认英文字体 添加黑体(‘SimHei')为绘图字体 代码: plt.rcParams['font.sans-serif']=['SimHei'
在并发编程中,synchronized关键字是常出现的角色。之前我们都称呼synchronized关键字为重量锁,但是在jdk1.6中对synchronized进行了优化,引入了偏向锁、轻量锁。本篇
一般我们的项目中会使用1到2个数据库连接配置,同程艺龙的数据库连接配置被收拢到统一的配置中心,由DBA统一配置和维护,业务方通过某个字符串配置拿到的是Connection对象。  
实例如下: ? 1
1. MemoryCahe NetCore中的缓存和System.Runtime.Caching很相似,但是在功能上做了增强,缓存的key支持object类型;提供了泛型支持;可以读缓存和单个缓存
argument是javascript中函数的一个特殊参数,例如下文,利用argument访问函数参数,判断函数是否执行 复制代码 代码如下: <script
一不小心装了一个Redis服务,开了一个全网的默认端口,一开始以为这台服务器没有公网ip,结果发现之后悔之莫及啊 某天发现cpu load高的出奇,发现一个minerd进程 占了大量cpu,googl
今天写这个是为了 提醒自己 编程过程 不仅要有逻辑 思想 还有要规范 代码 这样可读性 1、PHP 编程规范与编码习惯最主要的有以下几点: 1 文件说明 2 funct
摘要:虚拟机安装时一般都采用最小化安装,默认没有lspci工具。一台测试虚拟网卡性能的虚拟机,需要lspci工具来查看网卡的类型。本文描述了在一个虚拟机中安装lspci工具的具体步骤。 由于要测试
1、修改用户进程可打开文件数限制 在Linux平台上,无论编写客户端程序还是服务端程序,在进行高并发TCP连接处理时,最高的并发数量都要受到系统对用户单一进程同时可打开文件数量的限制(这是因为系统
目录 算术运算符 基本四则运算符 增量赋值运算符 自增/自减运算符 关系运算符 逻
如下所示: ? 1
MapperScannerConfigurer之sqlSessionFactory注入方式讲解 首先,Mybatis中的有一段配置非常方便,省去我们去写DaoImpl(Dao层实现类)的时间,这个
Linux的网络虚拟化是LXC项目中的一个子项目,LXC包括文件系统虚拟化,进程空间虚拟化,用户虚拟化,网络虚拟化,等等,这里使用LXC的网络虚拟化来模拟多个网络环境。 本文从基本的网络设备讲
? 1
我是一名优秀的程序员,十分优秀!