这一章将详细讲解 fz_load_page接口的实现流程。此接口主要实现了根据页面索引加载指定页面资源,填充fz_page对象。
1,获取文档章节数 fz_count_chapters(ctx, doc);//n = 1
2,计算每个章节的页码数,int m = fz_count_chapter_pages(ctx, doc, i);
3,加载页面资源,fz_load_chapter_page(ctx, doc, i, number - start);
3.1)遍历所有已加载的页面链表
for (page = doc->open; page; page = page->next)
if (page->chapter == chapter && page->number == number)
{//指定页面已经加载
fz_unlock(ctx, FZ_LOCK_ALLOC);
return fz_keep_page(ctx, page);//增加引用计数,返回已加载页面
}
3.2)实际加载页面资源 page = doc->load_page(ctx, doc, chapter, number);//pdf_load_page_imp-->pdf_load_page
3.2.1)pageobj = pdf_lookup_page_obj(ctx, doc, number);//Kids 查找页面对象,具体实现见附录一。
3.2.2)page = pdf_new_page(ctx, doc);//创建页面结构对象,具体实现见附录四。
page->obj = pdf_keep_obj(ctx, pageobj);//增加引用计数,赋值page->obj
3.2.3)page kid 中查找是否有Annots 具体实现见附录二。
3.2.4)扫描页面透明和套印设置 具体实现见附录三。
3.3)头部插入加载的页面链表
fz_lock(ctx, FZ_LOCK_ALLOC);
//头部插入
if ((page->next = doc->open) != NULL)//page.next->head
doc->open->prev = &page->next;//head.prev->page->next
doc->open = page;//head->page
page->prev = &doc->open;//page.prev->head
fz_unlock(ctx, FZ_LOCK_ALLOC);
附录一
pdf_obj *
pdf_lookup_page_obj(fz_context *ctx, pdf_document *doc, int needle)
{
return pdf_lookup_page_loc(ctx, doc, needle, NULL, NULL);
}
//从Pages页面树中查找页面
pdf_obj *
pdf_lookup_page_loc(fz_context *ctx, pdf_document *doc, int needle, pdf_obj **parentp, int *indexp)
{
pdf_obj *root = pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME(Root));//Root
pdf_obj *node = pdf_dict_get(ctx, root, PDF_NAME(Pages));//Pages
int skip = needle;
pdf_obj *hit;
if (!node)
fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find page tree");
hit = pdf_lookup_page_loc_imp(ctx, doc, node, &skip, parentp, indexp);
if (!hit)
fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find page %d in page tree", needle+1);
return hit;
}
附录二
obj = pdf_dict_get(ctx, pageobj, PDF_NAME(Annots));
if (obj)
{
fz_rect page_mediabox;
fz_matrix page_ctm;
pdf_page_transform(ctx, page, &page_mediabox, &page_ctm);//页面尺寸和旋转矩阵
page->links = pdf_load_link_annots(ctx, doc, obj, number, page_ctm);//加载链接对象
pdf_load_annots(ctx, page, obj);//加载标注
}
附录三
pdf_obj *resources = pdf_page_resources(ctx, page);
//透明组XObject:子类型Transparency
if (pdf_name_eq(ctx, pdf_dict_getp(ctx, pageobj, "Group/S"), PDF_NAME(Transparency)))
page->transparency = 1;
else if (pdf_resources_use_blending(ctx, resources))
page->transparency = 1;
for (annot = page->annots; annot && !page->transparency; annot = annot->next)
if (annot->ap && pdf_resources_use_blending(ctx, pdf_xobject_resources(ctx, annot->ap)))
page->transparency = 1;
//指示图像是套印(true)还是镂空(false)在其他分色上的底层标记
if (pdf_resources_use_overprint(ctx, resources))
page->overprint = 1;
for (annot = page->annots; annot && !page->overprint; annot = annot->next)
if (annot->ap && pdf_resources_use_overprint(ctx, pdf_xobject_resources(ctx, annot->ap)))
page->overprint = 1;
附录四
static pdf_page *
pdf_new_page(fz_context *ctx, pdf_document *doc)
{
pdf_page *page = fz_new_derived_page(ctx, pdf_page);
page->doc = (pdf_document*) fz_keep_document(ctx, &doc->super);
page->super.drop_page = (fz_page_drop_page_fn*)pdf_drop_page_imp;//销毁页面
page->super.load_links = (fz_page_load_links_fn*)pdf_load_links;//加载链接
page->super.bound_page = (fz_page_bound_page_fn*)pdf_bound_page;//页面尺寸
page->super.run_page_contents = (fz_page_run_page_fn*)pdf_run_page_contents;//加载页面元素,渲染用
page->super.run_page_annots = (fz_page_run_page_fn*)pdf_run_page_annots;//注释元素
page->super.run_page_widgets = (fz_page_run_page_fn*)pdf_run_page_widgets;//小部件
page->super.page_presentation = (fz_page_page_presentation_fn*)pdf_page_presentation;//演示文稿
page->super.separations = (fz_page_separations_fn *)pdf_page_separations;//分色
page->super.overprint = (fz_page_uses_overprint_fn *)pdf_page_uses_overprint;//套印
page->obj = NULL;
page->transparency = 0;
page->links = NULL;
page->annots = NULL;
page->annot_tailp = &page->annots;
page->widgets = NULL;
page->widget_tailp = &page->widgets;
return page;
}