epub4j
| Language | Java (also Android) |
|---|---|
| License | Apache-2.0 |
| Repository | github.com/documentnode/epub4j |
| Documentation | README and source |
| Depends on | zip4j, kxml2, xmlpull, minilog |
| Read / write | yes / yes (writes EPUB 2 package files) |
epub4j reads an EPUB into a Book object with Metadata, Resources (every file in the book), a Spine (reading order) and a TableOfContents, and writes a Book back to an EPUB file. You can load a book, change it (title, authors, cover, chapters) and save it again. It’s a fork of epublib with the same design, a Gradle build and no SLF4J dependency, maintained by Document Node.
The writer produces EPUB 2 package files (OPF 2.0 and an NCX table of contents). These open in all current readers, but if you need EPUB 3 features (navigation document, fixed layout, accessibility metadata) you have to add them yourself.
Installation#
Gradle:
dependencies {
implementation("io.documentnode:epub4j-core:4.2.2")
}
Maven:
<dependency>
<groupId>io.documentnode</groupId>
<artifactId>epub4j-core</artifactId>
<version>4.2.2</version>
</dependency>
On Android exclude the xmlpull group, which Android already provides: implementation("io.documentnode:epub4j-core:4.2.2") { exclude(group = "xmlpull") }.
Basic usage: read an EPUB#
import io.documentnode.epub4j.domain.Author;
import io.documentnode.epub4j.domain.Book;
import io.documentnode.epub4j.domain.SpineReference;
import io.documentnode.epub4j.epub.EpubReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
public class ReadEpub {
public static void main(String[] args) throws IOException {
try (InputStream in = new FileInputStream("book.epub")) {
Book book = new EpubReader().readEpub(in);
System.out.println("Title: " + book.getTitle());
for (Author a : book.getMetadata().getAuthors()) {
System.out.println("Author: " + a.getFirstname() + " " + a.getLastname());
}
System.out.println("Language: " + book.getMetadata().getLanguage());
// chapters in reading order
for (SpineReference ref : book.getSpine().getSpineReferences()) {
String html = new String(ref.getResource().getData(), StandardCharsets.UTF_8);
System.out.println(ref.getResource().getHref() + ": " + html.length() + " chars");
}
}
}
}
How to print the table of contents#
import io.documentnode.epub4j.domain.TOCReference;
import java.util.List;
static void printToc(List<TOCReference> refs, int level) {
for (TOCReference ref : refs) {
System.out.println(" ".repeat(level) + ref.getTitle() + " -> " + ref.getCompleteHref());
printToc(ref.getChildren(), level + 1);
}
}
// ...
printToc(book.getTableOfContents().getTocReferences(), 0);
How to create an EPUB#
import io.documentnode.epub4j.domain.Author;
import io.documentnode.epub4j.domain.Book;
import io.documentnode.epub4j.domain.Resource;
import io.documentnode.epub4j.epub.EpubWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
public class CreateEpub {
static Resource html(String body, String href) {
String xhtml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title>" + href + "</title></head>"
+ "<body>" + body + "</body></html>";
return new Resource(xhtml.getBytes(StandardCharsets.UTF_8), href);
}
public static void main(String[] args) throws IOException {
Book book = new Book();
book.getMetadata().addTitle("My Book");
book.getMetadata().addAuthor(new Author("Jane", "Doe"));
book.getMetadata().setLanguage("en");
book.addSection("Chapter 1", html("<h1>Chapter 1</h1><p>First chapter.</p>", "chapter1.xhtml"));
book.addSection("Chapter 2", html("<h1>Chapter 2</h1><p>Second chapter.</p>", "chapter2.xhtml"));
try (OutputStream out = new FileOutputStream("book.epub")) {
new EpubWriter().write(book, out);
}
}
}
addSection adds the resource, a table of contents entry and a spine entry. The media type is guessed from the file extension.
How to set the cover image#
import java.nio.file.Files;
import java.nio.file.Path;
byte[] jpg = Files.readAllBytes(Path.of("cover.jpg"));
book.setCoverImage(new Resource(jpg, "images/cover.jpg"));
How to change the title of an existing EPUB#
Book book;
try (InputStream in = new FileInputStream("in.epub")) {
book = new EpubReader().readEpub(in);
}
book.getMetadata().setTitles(java.util.List.of("New Title"));
try (OutputStream out = new FileOutputStream("out.epub")) {
new EpubWriter().write(book, out);
}
Tips#
- For large books use
readEpubLazy(new net.lingala.zip4j.ZipFile("book.epub"), "UTF-8")(epub4j uses zip4j, notjava.util.zip): resources are loaded only when you callgetData(). - The
epub4j-toolsmodule has a command line tool to set the author or cover of an existing EPUB and a Swing viewer. - Code written for epublib usually works after replacing the package
nl.siegmann.epublibwithio.documentnode.epub4j.