[原]mupdf源码分析
时间:2010-12-17 来源:帅得不敢出门
作者:帅得不敢出门 C++哈哈堂 31843264 转载请保留此信息
只是粗略地说了下,其实谈上不分析,先列几个比较主要的结构体struct fz_obj_s
{
int refs;
fz_objkind kind;
union
{
int b;
int i;
float f;
struct {
unsigned short len;
char buf[1];
} s;
char n[1];
struct {
int len;
int cap;
fz_obj **items;
} a;
struct {
char sorted;
int len;
int cap;
fz_keyval *items;
} d;
struct {
int num;
int gen;
struct pdf_xref_s *xref;
} r;
} u;
};
pdf_xref
struct pdf_xref_s
{
fz_stream *file;
int version; //pdf第一行就是PDF对应的版本,比如%PDF-1.4
int startxref; //pdf尾部的”startxref“文本的下一行 比如266812,为交叉引用表xref table的偏移地址
int filesize; //通过fseek ftell计算出来
pdf_crypt *crypt;
fz_obj *trailer; //文件尾trailer对象 包含PDF文件的对象数目,及根对象的obj号
int len;
int cap;
pdf_xrefentry *table; //交叉引用表xref table
int pagelen;
int pagecap;
fz_obj **pageobjs; //按顺序存放了各个页的obj地址(fz_obj*)
fz_obj **pagerefs;
struct pdf_store_s *store;
char scratch[65536];
};
struct pdf_xrefentry_s
{
int ofs; /* file offset / objstm object number */
int gen; /* generation / objstm index */
int stmofs; /* on-disk stream */
fz_obj *obj; /* stored/cached object */
int type; /* 0=unset (f)ree i(n)use (o)bjstm */
};
xref table(每个元素用pdf_xrefentry_s表示)交叉引用表,通过对交叉引用表的查询可以找到目录对象(Catalog)。这个目录对象是该PDF文档的根对象
,包含PDF文档的大纲(outline)和页面组对象(pages)的引用。大纲对象是指PDF文件的书签树;页面组对象(pages)包含该文件的页面数.
如:
xref
0 182 obj(对象) id由0开始一共有182个
0000000000 65535 f 偏移地址 产生号 类型
0000259122 00000 n
0000000019 00000 n
void pdfapp_open(pdfapp_t *app, char *filename, int fd)总体流程是这样的:
pdf_openxrefwithstream(&app->xref, file, NULL); 由pdf文件的第一行判断pdf版本,跳到尾,查找文本"startxref",得到xref表的偏移地址,读取xref table,
当然还要判断是否是加密的if (pdf_needspassword(app->xref)),若加密则得密码
,pdf_loadoutline函数通过trailer信息(紧接在xref表的后面)得到Root(根) obj的id 如:
trailer
<</Size 182/Root 180 0 R
....
>>
<</ >>结构为字典类型,字典由键与值两部分组成,如上面键Size对应值182
可以知道对应的Root id为180
就可以用这个号去xref table中查找此obj的位置,
由这个obj信息中的“Outlines”字符串后的信息,得到Outlines(大纲)的obj位置
如:
180 0 obj
<</Type/Catalog/Pages 142 0 R
/OpenAction[1 0 R /XYZ null null 0]
>>
endobj
上面的142对应的是Pages(页)信息的obj id,Pages信息包括总页数
通过为catalog对象添加一个/OpenAction键,我们可以让PDF文档在打开时无需人工介入就执行某个动作。
以下这个例子就不同,有Outlines字符串:
1 0 obj
<<
/Type /Catalog
/Pages 3 0 R
/Outlines 2 0 R
>>
endobj
再接着上面180 0 obj的例子,下面是140 Pages的obj,由pdf_loadpagetree(app->xref);处理
142 0 obj
<</Type/Pages
/Resources 179 0 R
/MediaBox[ 0 0 595 842 ]
/Kids[ 1 0 R 4 0 R 7 0 R 10 0 R 13 0 R 16 0 R 19 0 R 22 0 R 25 0 R 28 0 R 31 0 R 34 0 R 37 0 R 40 0 R 43 R 46 0 R
49 0 R 52 0 R 55 0 R 58 0 R 61 0 R 64 0 R 67 0 R 70 0 R 73
R 76 0 R 79 0 R 82 0 R 85 0 R 88 0 R 91 0 R 94 0 R 97 0 R 100 0 R 103
R 106 0 R 109 0 R 112 0 R 115 0 R 118 0 R 121 0 R 124 0 R 127 0 R 130 0 R 133 0 R 136 0 R 139 0 R ]
/Count 47>>
endobj
/Count说明有47页,/Kids后面跟的是页的obj id,上面第一页为1第二页为4,以此类推。Pages信息由pdf_loadpagetreenode函数处理。
pdf_xref结构中的pageobjs数组中存按顺序存放了各个页的obj地址(fz_obj*),到此便对可以提供某个特定页的信息了。
obj =pdf_getpageobject(app->xref, app->pageno); 得到第app->pageno页的obj地址(fz_obj*) 我们假设为pageno为1,对应上面我们知道第一页对应obj id为1
现在我们可以得到如下的信息:
1 0 obj
<</Type/Page/Parent 142 0 R/Resources 179 0 R/MediaBox[0 0 595 842]/Group<</S/Transparency/CS/DeviceRGB/I true>>/Contents 2 0 R>>
endobj
error = pdf_loadpage(&app->page, app->xref, obj); 根据上面的obj,再进行分解,
/MediaBox 是页面的尺寸 /Resources资源包括字体等信息, /Contents 页面内容
结构体pdf_page代表的是页
struct pdf_page_s
{
fz_rect mediabox;
int rotate;
int transparency;
fz_obj *resources;
fz_buffer *contents;
fz_displaylist *list;
fz_textspan *text;
pdf_link *links;
pdf_annot *annots;
};
pdfapp_showpage(app, 1, 1); 由上面信息生成窗体的tittle,页面文本,图像
这样描述一个pdf页的信息基本都全了,接下来就是把数据交给前端去画了。
pdf格式的分析大家可以参考这个http://blog.csdn.net/pdfMaker/archive/2006/01/09/573990.aspx
相关阅读 更多 +