mupdf源码分析

作者:帅得不敢出门    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

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值