All formats

MuPDF

LanguageC (C++, Java, Python, JavaScript and .NET bindings)
LicenseAGPL-3.0 or commercial license from Artifex
Repositorygithub.com/ArtifexSoftware/mupdf
Documentationmupdf.readthedocs.io
Depends onbundled third-party libraries (freetype, harfbuzz, zlib, libjpeg, openjpeg, jbig2dec, gumbo, lcms2)
Read / writeyes / no (EPUB 2 and 3, unencrypted)

MuPDF is a document rendering library best known for PDF. It also opens EPUB, MOBI, FB2, XPS, CBZ and plain HTML through the same API: an EPUB is laid out into pages of the size you choose, and then each page can be rendered, searched or converted like a PDF page. It has its own HTML and CSS layout engine with font fallback for most scripts. SumatraPDF uses MuPDF.

Use MuPDF when you need a page-based view of an EPUB: page images, page count, text extraction or conversion to PDF. It doesn’t write or edit EPUB files, doesn’t run JavaScript in EPUB content, and doesn’t open DRM-protected books. The AGPL license requires you to publish your source code if you distribute your program or offer it as a network service; Artifex sells commercial licenses.

Installation#

Shell
# 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 from source also need -lmupdf-third. To build from source: git clone --recursive https://github.com/ArtifexSoftware/mupdf.git && cd mupdf && make HAVE_X11=no HAVE_GLUT=no prefix=/usr/local install.

Basic usage: open an EPUB and extract text#

EPUB has no fixed pages: call fz_layout_document to set the page size (in points) and font size before counting pages.

C
#include <mupdf/fitz.h>
#include <stdio.h>

int main(int argc, char **argv) {
    if (argc < 2) {
        fprintf(stderr, "usage: %s book.epub\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, 11pt text

        int n = fz_count_pages(ctx, doc);
        printf("%d pages\n", n);
        for (int i = 0; i < n; i++) {
            buf = fz_new_buffer_from_page_number(ctx, doc, i, NULL);
            printf("--- page %d ---\n%s\n", i + 1, fz_string_from_buffer(ctx, buf));
            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 read EPUB title and author#

fz_lookup_metadata returns the dc:title and dc:creator from the OPF file, and "format" returns EPUB:

C
char title[256], author[256];
if (fz_lookup_metadata(ctx, doc, FZ_META_INFO_TITLE, title, sizeof title) > 0)
    printf("Title: %s\n", title);
if (fz_lookup_metadata(ctx, doc, FZ_META_INFO_AUTHOR, author, sizeof author) > 0)
    printf("Author: %s\n", author);

How to get the table of contents#

The outline comes from the EPUB 3 navigation document or the EPUB 2 NCX. Call it after fz_layout_document so the page numbers match the layout:

C
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 (page %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);
print_outline(ctx, doc, outline, 0);
fz_drop_outline(ctx, outline);

How to render an EPUB page to PNG#

C
// page 0 at 2x zoom (144 dpi), RGB without alpha
fz_matrix ctm = fz_scale(2, 2);
fz_pixmap *pix = fz_new_pixmap_from_page_number(ctx, doc, 0, ctm, fz_device_rgb(ctx), 0);
fz_save_pixmap_as_png(ctx, pix, "page1.png");
fz_drop_pixmap(ctx, pix);

The first page usually shows the cover image.

How to convert EPUB to PDF#

Lay out the book, then run every page through a PDF document writer:

C
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_rect box = fz_bound_page(ctx, page);
    fz_device *dev = fz_begin_page(ctx, wri, box);
    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);

(Wrap this in fz_try/fz_catch in real code.) The command line tool does the same: mutool convert -o book.pdf book.epub.

Tips#