girara_tree_node_t* pdf_document_index_generate(zathura_document_t* document, void* data, zathura_error_t* error) { mupdf_document_t* mupdf_document = data; if (document == NULL || mupdf_document == NULL) { if (error != NULL) { *error = ZATHURA_ERROR_INVALID_ARGUMENTS; } return NULL; } /* get outline */ fz_outline* outline = fz_load_outline(mupdf_document->ctx, mupdf_document->document); if (outline == NULL) { if (error != NULL) { *error = ZATHURA_ERROR_UNKNOWN; } return NULL; } /* generate index */ girara_tree_node_t* root = girara_node_new(zathura_index_element_new("ROOT")); build_index(mupdf_document->ctx, mupdf_document->document, outline, root); /* free outline */ fz_drop_outline(mupdf_document->ctx, outline); return root; }
static void reload(void) { fz_drop_outline(ctx, outline); fz_drop_document(ctx, doc); doc = fz_open_document(ctx, filename); if (fz_needs_password(ctx, doc)) { if (!fz_authenticate_password(ctx, doc, password)) { fprintf(stderr, "Invalid password.\n"); exit(1); } } fz_layout_document(ctx, doc, layout_w, layout_h, layout_em); fz_try(ctx) outline = fz_load_outline(ctx, doc); fz_catch(ctx) outline = NULL; pdf = pdf_specifics(ctx, doc); if (pdf) pdf_enable_js(ctx, pdf); currentpage = fz_clampi(currentpage, 0, fz_count_pages(ctx, doc) - 1); render_page(); update_title(); }
void fz_drop_outline(fz_context *ctx, fz_outline *outline) { while (fz_drop_imp(ctx, outline, &outline->refs)) { fz_outline *next = outline->next; fz_drop_outline(ctx, outline->down); fz_free(ctx, outline->title); fz_free(ctx, outline->uri); fz_free(ctx, outline); outline = next; } }
PDFDocument::PDFOutlineItem* PDFDocument::PDFOutlineItem::Build( fz_context* ctx, fz_outline* src) { PDFOutlineItem* root = nullptr; std::vector<std::unique_ptr<OutlineItem>> items; BuildRecursive(src, &items); fz_drop_outline(ctx, src); if (items.empty()) { return nullptr; } else if (items.size() == 1) { root = dynamic_cast<PDFOutlineItem*>(items[0].release()); } else { root = new PDFOutlineItem(nullptr); root->_title = DEFAULT_ROOT_OUTLINE_ITEM_TITLE; root->_children.swap(items); } return root; }
static void epub_drop_document(fz_context *ctx, fz_document *doc_) { epub_document *doc = (epub_document*)doc_; epub_chapter *ch, *next; ch = doc->spine; while (ch) { next = ch->next; fz_drop_html(ctx, ch->html); fz_free(ctx, ch->path); fz_free(ctx, ch); ch = next; } fz_drop_archive(ctx, doc->zip); fz_drop_html_font_set(ctx, doc->set); fz_drop_outline(ctx, doc->outline); fz_free(ctx, doc->dc_title); fz_free(ctx, doc->dc_creator); }
static fz_outline * epub_parse_ncx_imp(fz_context *ctx, epub_document *doc, fz_xml *node, char *base_uri) { char path[2048]; fz_outline *outline, *head, **tailp; head = NULL; tailp = &head; node = fz_xml_find_down(node, "navPoint"); while (node) { char *text = fz_xml_text(fz_xml_down(fz_xml_find_down(fz_xml_find_down(node, "navLabel"), "text"))); char *content = fz_xml_att(fz_xml_find_down(node, "content"), "src"); if (text && content) { fz_strlcpy(path, base_uri, sizeof path); fz_strlcat(path, "/", sizeof path); fz_strlcat(path, content, sizeof path); fz_urldecode(path); fz_cleanname(path); fz_try(ctx) { *tailp = outline = fz_new_outline(ctx); tailp = &(*tailp)->next; outline->title = fz_strdup(ctx, text); outline->uri = fz_strdup(ctx, path); outline->page = -1; outline->down = epub_parse_ncx_imp(ctx, doc, node, base_uri); outline->is_open = 1; } fz_catch(ctx) { fz_drop_outline(ctx, head); fz_rethrow(ctx); } } node = fz_xml_find_next(node, "navPoint"); }
int main(int argc, char **argv) #endif { const GLFWvidmode *video_mode; int c; while ((c = fz_getopt(argc, argv, "p:r:W:H:S:U:X")) != -1) { switch (c) { default: usage(argv[0]); break; case 'p': password = fz_optarg; break; case 'r': currentzoom = fz_atof(fz_optarg); break; case 'W': layout_w = fz_atof(fz_optarg); break; case 'H': layout_h = fz_atof(fz_optarg); break; case 'S': layout_em = fz_atof(fz_optarg); break; case 'U': layout_css = fz_optarg; break; case 'X': layout_use_doc_css = 0; break; } } if (fz_optind < argc) { fz_strlcpy(filename, argv[fz_optind], sizeof filename); } else { #ifdef _WIN32 win_install(); if (!win_open_file(filename, sizeof filename)) exit(0); #else usage(argv[0]); #endif } title = strrchr(filename, '/'); if (!title) title = strrchr(filename, '\\'); if (title) ++title; else title = filename; memset(&ui, 0, sizeof ui); search_input.p = search_input.text; search_input.q = search_input.p; search_input.end = search_input.p; glfwSetErrorCallback(on_error); if (!glfwInit()) { fprintf(stderr, "cannot initialize glfw\n"); exit(1); } video_mode = glfwGetVideoMode(glfwGetPrimaryMonitor()); screen_w = video_mode->width; screen_h = video_mode->height; window = glfwCreateWindow(DEFAULT_WINDOW_W, DEFAULT_WINDOW_H, filename, NULL, NULL); if (!window) { fprintf(stderr, "cannot create glfw window\n"); exit(1); } glfwMakeContextCurrent(window); ctx = fz_new_context(NULL, NULL, 0); fz_register_document_handlers(ctx); if (layout_css) { fz_buffer *buf = fz_read_file(ctx, layout_css); fz_set_user_css(ctx, fz_string_from_buffer(ctx, buf)); fz_drop_buffer(ctx, buf); } fz_set_use_document_css(ctx, layout_use_doc_css); has_ARB_texture_non_power_of_two = glfwExtensionSupported("GL_ARB_texture_non_power_of_two"); if (!has_ARB_texture_non_power_of_two) fz_warn(ctx, "OpenGL implementation does not support non-power of two texture sizes"); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); ui.fontsize = DEFAULT_UI_FONTSIZE; ui.baseline = DEFAULT_UI_BASELINE; ui.lineheight = DEFAULT_UI_LINEHEIGHT; ui_init_fonts(ctx, ui.fontsize); reload(); shrinkwrap(); glfwSetFramebufferSizeCallback(window, on_reshape); glfwSetCursorPosCallback(window, on_mouse_motion); glfwSetMouseButtonCallback(window, on_mouse_button); glfwSetScrollCallback(window, on_scroll); glfwSetCharModsCallback(window, on_char); glfwSetKeyCallback(window, on_key); glfwSetWindowRefreshCallback(window, on_display); glfwGetFramebufferSize(window, &window_w, &window_h); ui_needs_update = 1; while (!glfwWindowShouldClose(window)) { glfwWaitEvents(); if (ui_needs_update) run_main_loop(); } ui_finish_fonts(ctx); fz_drop_link(ctx, links); fz_drop_page(ctx, page); fz_drop_outline(ctx, outline); fz_drop_document(ctx, doc); fz_drop_context(ctx); glfwTerminate(); return 0; }
static fz_outline * pdf_load_outline_imp(fz_context *ctx, pdf_document *doc, pdf_obj *dict) { fz_outline *node, **prev, *first; pdf_obj *obj; pdf_obj *odict = dict; fz_var(dict); fz_var(first); fz_try(ctx) { first = NULL; prev = &first; while (dict && pdf_is_dict(ctx, dict)) { if (pdf_mark_obj(ctx, dict)) break; node = fz_new_outline(ctx); *prev = node; prev = &node->next; obj = pdf_dict_get(ctx, dict, PDF_NAME_Title); if (obj) node->title = pdf_to_utf8(ctx, obj); if ((obj = pdf_dict_get(ctx, dict, PDF_NAME_Dest)) != NULL) node->uri = pdf_parse_link_dest(ctx, doc, obj); else if ((obj = pdf_dict_get(ctx, dict, PDF_NAME_A)) != NULL) node->uri = pdf_parse_link_action(ctx, doc, obj); else node->uri = NULL; if (node->uri) node->page = pdf_resolve_link(ctx, doc, node->uri, NULL, NULL); else node->page = -1; obj = pdf_dict_get(ctx, dict, PDF_NAME_First); if (obj) { node->down = pdf_load_outline_imp(ctx, doc, obj); obj = pdf_dict_get(ctx, dict, PDF_NAME_Count); if (pdf_to_int(ctx, obj) > 0) node->is_open = 1; } dict = pdf_dict_get(ctx, dict, PDF_NAME_Next); } } fz_always(ctx) { for (dict = odict; dict && pdf_obj_marked(ctx, dict); dict = pdf_dict_get(ctx, dict, PDF_NAME_Next)) pdf_unmark_obj(ctx, dict); } fz_catch(ctx) { fz_drop_outline(ctx, first); fz_rethrow(ctx); } return first; }
std::string PDFDocument::GetPageText(int page, int line_sep) { // 1. Init MuPDF structures. pdf_page* page_struct = GetPage(page); #if MUPDF_VERSION < 10012 fz_stext_sheet* text_sheet = fz_new_stext_sheet(_fz_context); #endif // 2. Render page. #if MUPDF_VERSION >= 10012 fz_stext_options stext_options = {0}; // See #elif MUPDF_VERSION >= 10009 block below. fz_stext_page* text_page = fz_new_stext_page_from_page( _fz_context, &(page_struct->super), &stext_options); #elif MUPDF_VERSION >= 10010 fz_stext_options stext_options = {0}; // See #elif MUPDF_VERSION >= 10009 block below. fz_stext_page* text_page = fz_new_stext_page_from_page( _fz_context, &(page_struct->super), text_sheet, &stext_options); #elif MUPDF_VERSION >= 10009 // The function below is a wrapper around fz_run_page that uses a fresh // device. We can't use pdf_run_page to gather the text for us. // These notes are also left in here in case MuPDF's API changes again. fz_stext_page* text_page = fz_new_stext_page_from_page( _fz_context, &(page_struct->super), text_sheet); #else fz_stext_page* text_page = fz_new_text_page(_fz_context); fz_device* dev = fz_new_stext_device(_fz_context, text_sheet, text_page); // I've no idea what fz_{begin,end}_page do, but without them pdf_run_page // segfaults :-/ fz_begin_page(_fz_context, dev, &fz_infinite_rect, &fz_identity); pdf_run_page( _fz_context, _pdf_document, page_struct, dev, &fz_identity, nullptr); fz_end_page(_fz_context, dev); #endif // 3. Build text. std::string r; #if MUPDF_VERSION >= 10012 for (fz_stext_block* text_block = text_page->first_block; text_block != nullptr; text_block = text_block->next) { if (text_block->type != FZ_STEXT_BLOCK_TEXT) { continue; } for (fz_stext_line* text_line = text_block->u.t.first_line; text_line != nullptr; text_line = text_line->next) { for (fz_stext_char* text_char = text_line->first_char; text_char != nullptr; text_char = text_char->next) { { const int c = text_char->c; #else for (fz_page_block* page_block = text_page->blocks; page_block < text_page->blocks + text_page->len; ++page_block) { assert(page_block != nullptr); if (page_block->type != FZ_PAGE_BLOCK_TEXT) { continue; } fz_stext_block* const text_block = page_block->u.text; assert(text_block != nullptr); for (fz_stext_line* text_line = text_block->lines; text_line < text_block->lines + text_block->len; ++text_line) { assert(text_line != nullptr); for (fz_stext_span* text_span = text_line->first_span; text_span != nullptr; text_span = text_span->next) { for (int i = 0; i < text_span->len; ++i) { const int c = text_span->text[i].c; #endif // A single UTF-8 character cannot take more than 4 bytes, but let's // go for 8. char buffer[8]; const int num_bytes = fz_runetochar(buffer, c); assert(num_bytes <= static_cast<int>(sizeof(buffer))); buffer[num_bytes] = '\0'; r += buffer; } } if (!isspace(r.back())) { r += line_sep; } } } // 4. Clean up. fz_drop_stext_page(_fz_context, text_page); #if MUPDF_VERSION < 10012 fz_drop_stext_sheet(_fz_context, text_sheet); #endif return r; } PDFDocument::PDFOutlineItem::~PDFOutlineItem() {} PDFDocument::PDFOutlineItem::PDFOutlineItem(fz_outline* src) { if (src == nullptr) { _dest_page = -1; } else { _title = src->title; #if MUPDF_VERSION >= 10010 _dest_page = src->page; #else _dest_page = src->dest.ld.gotor.page; #endif } } int PDFDocument::PDFOutlineItem::GetDestPage() const { return _dest_page; } PDFDocument::PDFOutlineItem* PDFDocument::PDFOutlineItem::Build( fz_context* ctx, fz_outline* src) { PDFOutlineItem* root = nullptr; std::vector<std::unique_ptr<OutlineItem>> items; BuildRecursive(src, &items); fz_drop_outline(ctx, src); if (items.empty()) { return nullptr; } else if (items.size() == 1) { root = dynamic_cast<PDFOutlineItem*>(items[0].release()); } else { root = new PDFOutlineItem(nullptr); root->_title = DEFAULT_ROOT_OUTLINE_ITEM_TITLE; root->_children.swap(items); } return root; } void PDFDocument::PDFOutlineItem::BuildRecursive( fz_outline* src, std::vector<std::unique_ptr<Document::OutlineItem>>* output) { assert(output != nullptr); for (fz_outline* i = src; i != nullptr; i = i->next) { PDFOutlineItem* item = new PDFOutlineItem(i); if (i->down != nullptr) { BuildRecursive(i->down, &(item->_children)); } output->push_back(std::unique_ptr<Document::OutlineItem>(item)); } } PDFDocument::PDFPageCache::PDFPageCache(int cache_size, PDFDocument* parent) : Cache<int, pdf_page*>(cache_size), _parent(parent) {} PDFDocument::PDFPageCache::~PDFPageCache() { Clear(); } pdf_page* PDFDocument::PDFPageCache::Load(const int& page) { std::unique_lock<std::mutex> lock(_mutex); return pdf_load_page(_parent->_fz_context, _parent->_pdf_document, page); } void PDFDocument::PDFPageCache::Discard( const int& page, pdf_page* const& page_struct) { std::unique_lock<std::mutex> lock(_mutex); pdf_drop_page(_parent->_fz_context, _parent->_pdf_document, page_struct); }