使用C#开发pdf阅读器初探(基于WPF,没有使用开源库)
前言 pdf是最流行的版式格式文件标准,已成为国际标准。pdf相关的开源软件非常多,也基本能满足日常需要了。相关商业软件更是林林总总,几乎应有尽有!似乎没必要自己再独立自主开发!但,本人基于以下考虑,决定自主研发一款pdf阅读器。
1)通过编写pdf阅读器,可以迅速的熟悉pdf文件的处理。pdf格式包含的内容非常多,仅仅通过查资料,很难掌握其内容。
2)任何技术,只有自主可控,才能到达气定神闲!使用开源软件是简单,万一遇到问题,就是个坑!
3)解决pdf与ofd互转问题。ofd是国家标准,相关的处理软件非常少。为了解决两种格式文件互转,必须了解pdf。
4)本人此前开发了一款ofd阅读器,积累了一些经验。为开发pdf阅读器增添了信心。
特别说明 本人花了几周写了这款阅读器,验证了pdf不同类型的数据处理,还远远到不了商用的要求。不积跬步无以至千里!本人会慢慢完善这款软件,敬请期待。本人的参考资料有两本英文书籍和pdf英文标准文档。
程序界面: 点击下载程序
pdf相关参考资料:
pdf文件结构简介
pdf总的内容结构如下:
1)header: 有关pdf版本信息。最新版为 %PDF−1. 7
2)Body:存储具体数据,pdf就是由很多object组成的。每个object由dictionary和stream组成。dictionary存储就是key、value字符对。dictionary是可以嵌套的,就是value有可能也是一个dictionary。
3)Cross-Reference Table:交叉索引表。可以快速定位到具体object。便于随机读取object。
4)Trailer:给出交叉索引表的位置。读取pdf文件都是从最后开始读的,所以Trailer一定是在文件最后。
pdf处理总体结构
object内容读取
交叉索引表能快速定位到某个object的位置,读取object内容不难,关键是分析dictionary。dictionary是可以嵌套,就是dictionary的内容还有dictionary。快速解析出所有的dictionary是处理的关键。典型的dictionary结构如下:
<<
/Annots R
/BleedBox [ 661.5]
/Contents [ R]
/CropBox [ 661.5]
/MediaBox [ 661.5]
/Parent R /Resources
<< //嵌套dictionary
/ColorSpace <</CS1 R>> //2次嵌套dictionary
/Font <</F1 R/F2 R/F3 R/F4 R>> //2次嵌套dictionary
/ProcSet [/PDF/Text/ImageB/ImageC] //数组
/XObject <</I1 R/I2 R/I3 R>>//2次嵌套dictionary
>> /Type /Page
>>
页面内容分析
页面内容由系列操作数和操作符组成。所有的操作数和操作符在同一个文本中,所以要快速的将操作数和操作符组成可以执行的操作对。
0 0 515.95 728.6 re
W* n
0 w
2 M
2 J
2 j
0 0 0 RG
BT
0 0 0 rg
/FT8 180 Tf
/GS13 gs
0.05 0 0 -0.05 187.68 676.49 Tm
<35BE>Tj 180 0 TD<1D5F>Tj 180 0 TD<4205>Tj 180 0 TD<4EC8>Tj
ET
字符都是存在()或<>中,除去字符和数字,就是操作符。如上文W*、n都是操作符;<35BE>为16进制字符对应的key,具体代表哪个字,需要到查字符表。这里的35BE并不是unicode字符对应的值,还需要再查表。如下图:
beginbfchar
<0019> <0036>
<35BE> <0037>
<001B> <0038>
<001C> <0039>
endbfchar
<35BE>对应的是<0037>。该表存在字体资源文件object中。
页面显示
坐标系变换
理清不同坐标系之间的关系是处理的关键。坐标系分为:Device Space(设备坐标空间)、User Space(设备坐标空间)、text space(文本坐标空间)等。
绘画上下文设置
当前绘画的状态(画笔、画刷等)是保存在栈中,会有入栈出栈操作。
特殊画刷处理
pdf有一种画刷,比如渐变色,这个很难找到现成的画刷使用。我使用的是ImageBrush,就是使用图片作为画刷。在内存中创建可擦写的图片,可以精确控制每个像素的值。根据pdf标准提供的算法,计算每个像素的值。
pdf的显示大体分为三种:曲线、文本、图片。其中曲线的显示是比较麻烦的,关键是将pdf标准的描述与wpf曲线操作对应起来。
pdf阅读器开发说明
如果完全参数标准文件开发,是比较枯燥,感觉慢慢长路看不到尽头。我采用是单个功能各个击破的方法,能很快见到开发成果。我使用的参考书是《PDF Explained》,100多页,只是对pdf做大体介绍,但是各个功能点都有所提及。我就参照该书提供的示例文件,逐步验证每个文件。
每种显示都有多种处理方法,每个软件生成pdf的风格是不同的。对特定的软件生成的pdf做几次验证后,基本可以保证该软件生成的pdf都可以正常显示。
wps是可以直接将doc文件转换为pdf的。我对wps生成的pdf做了测试,经过几次调试,现在基本可以正常处理wps生成的pdf文件。
后记 对于开发pdf阅读器这类软件,以前都是不敢想象的。像这种复杂的软件,必须遵循一定的设计模式、正确建立域模型。所以开发这类软件,对pdf标准的理解是否深刻并非关键,关键还是编程的功底。软件的外在表现千奇百态,但内在逻辑具有类比性的。继承、封装、多态、SOLID设计准则这些并不难理解,但是要达到应用自如还需要反复锤炼。把握好每个细节,正确运用设计准则,一步一个脚印,最终会将不可能变成可能!
使用C#开发pdf阅读器初探(基于WPF,没有使用开源库)的更多相关文章
- 关于linux上pdf阅读器
今天也是倒腾linux 上pdf阅读器好久. 1.okular是挺好的,但是却太大了,好多功能,我没有细看.我简单的打开了几个pdf文件,发现加载速度还是太慢了.所以基于种种,我给卸载掉了. 安装直接 ...
- Ubuntu 18.10 安装PDF阅读器
======================================== 软件开发转移到了 Linux上,使用Ubuntu 18.10作为桌面开发环境 下面介绍 安装PDF阅读器 1.下载 福 ...
- Linux下pdf阅读器推荐
由于需要在pdf文件上做标记,所以自带的文档查看器根本满足了需求,之前去网上查了查,Okular评价挺高,就安装了一个,确实能基本满足我的需求,但是 1.界面感觉还是不太友好,书签栏一直在那. 2.而 ...
- Foix_Reader_6.0|PDF阅读器
福晰PDF阅读器,是阅读器中的精品.此版本是优化版本. 00:风格前卫 01:使用简洁 下载地址: http://yunpan.cn/cHvyUfCdMKZz6 访问密码 ead7
- Foxit Reader(福昕PDF阅读器) v4.3.1.218 绿色专业版
软件名称:Foxit Reader(福昕PDF阅读器) v4.3.1.218 绿色专业版 软件语言: 简体中文 授权方式: 免费软件 运行环境: Win 32位/64位 软件大小: 4.40MB 图片 ...
- PDF阅读器中如何改变线条颜色、线宽和线型等
1.打开PDF阅读器过后,点击菜单栏"注释"这一栏,找到绘图区域中的线条或铅笔: 2.分别用线条和铅笔随意画两条直线,然后选中直线,右键点击直线并打开"属性": ...
- Ubuntu下好的PDF阅读器介绍
我们经常要学习,看论文,如果有好的PDF阅读器,可以做笔记,对以后查看和记忆是有帮助的 这里推荐用:okular 这里是基本操作哦 1: 安装 sudo apt-get install okular ...
- Ubuntu安装Foxit PDF阅读器
最近使用Ubuntu自带的PDF阅读器,发现使用体验较差,打算安装FoxitReader(可能是我习惯了Foxit和Adobe) Foxit官网 对系统平台要求如下:(支持Linux) 继续摸索了一下 ...
- Linux下一款可以使用命令行的pdf阅读器
Zathura是linux下一款用命令行控制打pdf阅读器,并且基本打使用方法和vim很相似.对于喜欢键盘操作的用户来说的确是一个不错的选择. ubuntu下的安装命令: sudo apt-get i ...
随机推荐
- JS中的0b00与0x00表示什么
换成二进制表示:(0b表示二进制数,0x表示16进制数)
- [原]C++新标准之std::chrono::duration
原 总结 C++11 chrono duration ratio 概览 std::chrono::duration 描述 类定义 duration_cast()分析 预定义的duration 示例代 ...
- TPO3-2Deletion of Ogallala Aquifer
In the face of the upcoming water supply crisis, a number of grandiose schemes have been developed t ...
- std::string和ctime之间的转换
int year, month, day, hour, minute, second; string strTime: sscanf(strTime.c_str(), "%d-%d-%d % ...
- 如何查看iOS系统版本在iPhone设备上的占有率
我们平时开发的时候有时要考虑到系统的兼容版本,但是怎么知道各个版本的系统占有率,其实这个苹果官方是有提供的.进入如下链接到的页面就可以知道各大系统版本的占有率了,不过说实在的iPhone用户的系统更新 ...
- 1)PHP,数据库操作类网址
(1)脚本之家 http://www.jb51.net/article/94347.htm (2)一个博客 http://www.cnblogs.com/lvchenfeng/p/5003629.ht ...
- Seikimatsu Occult Tonneru(网络流,状态数(建不建边)不多时,可考虑直接进行枚举
http://acm.hdu.edu.cn/showproblem.php?pid=4309 总结:边可存东西时,可新建一个点x连接u.v,x再连向汇点: #include<iostream&g ...
- 执行PHP -m报错Xdebug MUST be loaded as a Zend extension
Xdebug扩展安装后执行PHP -m报错: <br /><b>Warning</b>: Xdebug MUST be loaded as a Zend exten ...
- 83)PHP,配置文件功能
首选配置文件应该在 我们的应用application目录中,这样针对每一应用,都有自己的配置文件. 我觉得配置文件的名字很有意思,首先是 名字.config.php 格式就是 return arr ...
- JAVA专业术语面试100问
前言:面试技巧另外开篇再说,先上面试干货吧.Redis.消息队列.SQL不要走开,关注后更精彩! 1.面向对象的特点有哪些? 抽象.继承.封装.多态. 2.接口和抽象类有什么联系和区别? 3.重载和重 ...