MuPDF
| Language | C (C++, Java, Python, JavaScript and .NET bindings) |
|---|---|
| License | AGPL-3.0 or commercial license from Artifex |
| Repository | github.com/ArtifexSoftware/mupdf |
| Documentation | mupdf.readthedocs.io |
| Depends on | bundled third-party libraries (freetype, harfbuzz, zlib, libjpeg, gumbo and others) |
| Read / write | yes / no (.fb2) |
MuPDF is a document rendering library (PDF, XPS, EPUB, MOBI, CBZ) with an HTML layout engine that also understands FictionBook 2. It maps FB2 elements (sections, titles, epigraphs, poems, notes) to styled blocks, shows the cover page from coverpage, decodes the Base64 binary images, and builds a table of contents from the section titles. After layout, an FB2 book works like a PDF: count pages, render, extract or search text, convert to PDF.
Use it to display FB2 or turn it into images or PDF. To read or change the FB2 XML itself, use an XML parser. MuPDF opens plain .fb2 files; unzip .fb2.zip / .fbz first. The AGPL license requires you to publish your source code if you distribute your program or offer it as a network service.
Installation#
# Debian / Ubuntu
sudo apt install libmupdf-dev
# Fedora
sudo dnf install mupdf-devel
# macOS
brew install mupdf
# Windows (vcpkg)
vcpkg install mupdf
Link with -lmupdf (static builds also need -lmupdf-third).
Basic usage: open an FB2 file and extract text#
#include <mupdf/fitz.h>
#include <stdio.h>
int main(int argc, char **argv) {
if (argc < 2) {
fprintf(stderr, "usage: %s book.fb2\n", argv[0]);
return 1;
}
fz_context *ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED);
if (!ctx) return 1;
fz_document *doc = NULL;
fz_buffer *buf = NULL;
fz_var(doc);
fz_var(buf);
fz_try(ctx) {
fz_register_document_handlers(ctx);
doc = fz_open_document(ctx, argv[1]);
fz_layout_document(ctx, doc, 420, 595, 11); // A5 page in points, 11pt text
char title[256];
if (fz_lookup_metadata(ctx, doc, FZ_META_INFO_TITLE, title, sizeof title) > 0)
printf("Title: %s\n", title);
int n = fz_count_pages(ctx, doc);
for (int i = 0; i < n; i++) {
buf = fz_new_buffer_from_page_number(ctx, doc, i, NULL);
fputs(fz_string_from_buffer(ctx, buf), stdout);
fz_drop_buffer(ctx, buf);
buf = NULL;
}
}
fz_always(ctx) {
fz_drop_buffer(ctx, buf);
fz_drop_document(ctx, doc);
}
fz_catch(ctx) {
fz_report_error(ctx);
fz_drop_context(ctx);
return 1;
}
fz_drop_context(ctx);
return 0;
}
How to get the table of contents of an FB2 book#
static void print_outline(fz_context *ctx, fz_document *doc, fz_outline *o, int level) {
for (; o; o = o->next) {
int page = fz_page_number_from_location(ctx, doc, o->page);
printf("%*s%s ... %d\n", level * 2, "", o->title ? o->title : "", page + 1);
print_outline(ctx, doc, o->down, level + 1);
}
}
fz_outline *outline = fz_load_outline(ctx, doc); // after fz_layout_document
print_outline(ctx, doc, outline, 0);
fz_drop_outline(ctx, outline);
How to render the FB2 cover to PNG#
The first page shows the coverpage image:
fz_pixmap *pix = fz_new_pixmap_from_page_number(ctx, doc, 0, fz_scale(2, 2), fz_device_rgb(ctx), 0);
fz_save_pixmap_as_png(ctx, pix, "cover.png");
fz_drop_pixmap(ctx, pix);
How to convert FB2 to PDF#
fz_document_writer *wri = fz_new_document_writer(ctx, "book.pdf", "pdf", NULL);
int n = fz_count_pages(ctx, doc);
for (int i = 0; i < n; i++) {
fz_page *page = fz_load_page(ctx, doc, i);
fz_device *dev = fz_begin_page(ctx, wri, fz_bound_page(ctx, page));
fz_run_page(ctx, page, dev, fz_identity, NULL);
fz_end_page(ctx, wri);
fz_drop_page(ctx, page);
}
fz_close_document_writer(ctx, wri);
fz_drop_document_writer(ctx, wri);
From the command line: mutool convert -o book.pdf book.fb2.
Tips#
- Change fonts and spacing for all reflowable formats with
fz_set_user_css(ctx, "p { text-indent: 1.5em; }")before opening the document. FZ_META_INFO_AUTHORreturns alltitle-infoauthors joined with commas, andFZ_META_INFO_SUBJECTreturns the annotation text.- To open an FB2 from memory, wrap it in a buffer and call
fz_open_document_with_buffer(ctx, "application/x-fictionbook", buf).