Skip to main content

A book's journey

A book is downloaded once and prepared for the panel, kept in a folder on the reader, drawn page by page into memory, pushed to the e-ink screen, and its progress goes back to the server.

Before looking at any one part of Inkshelf, follow a single book all the way. Each stop on the way is a chapter of this site; this page is the map that ties them together.

Think of a train line. The book is the passenger; each station is a part of the code that does one job and hands the book on. Two kinds of passenger take slightly different tracks: comics (pictures of pages) and EPUBs (text that must be laid out).

The whole trip​

InteractiveOne book, from the server to your eyes
🗄️1. Server👆2. Tap⬇️3. Fetch⑂⚙️4. Prepare⑂📚5. Shelf📖6. Open🧩7. Page⑂🖼️8. Canvas⚡9. Refresh🔄10. Sync backpages
station 1/10
🗄️ Server. The book starts on a server: here a comic on Komga, sent page by page as images. The app does not know Komga itself: it only talks to the servers.Server interface (Books, OpenBook, OpenFile, SetProgress…).
Try this: Press Play and watch the book travel. Then switch to An EPUB and step through again: stations 3, 4 and 7 (marked ⑂) change. Click any station to jump to it.

Two kinds of book, two roads​

The big difference between a comic and an EPUB is when the hard work happens.

Recipes from Mealie take the comic road: the app lays a recipe out into page pictures, which are then prepared like a comic's. A Fixed layoutFixed layout: A book whose pages have a set size and position for everything, like a PDF; Inkshelf draws each page whole. EPUB does too: its pages are drawn whole at download time.

Why so much happens at download time​

Three constraints shape the trip, and you will meet them again in every part:

  1. The reader is slow. A page turn must feel instant, so anything that can be done in advance is: page images are prepared while downloading, and the pages around the one you read are prepared in the background.
  2. The panel is slow too. An e-ink refresh takes a visible moment, and fast refreshes leave GhostingGhosting: A faint trace of the previous image left after a partial refresh. A full (flashing) refresh clears it.. So Inkshelf refreshes only the area that changed, and every few pages flashes the whole screen clean.
  3. Wi-Fi comes and goes. A download can stop halfway, so files are written whole or not at all (Atomic renameAtomic rename: Write a file under a temporary name, then rename it: other code sees the old file or the whole new one, never half.), and book.json comes last. Progress waits on the reader until the server can take it.
Going deeper: what the shelf folder looks like

Each book has a folder named after its id, under inkshelf/servers/<server name>/books/ on the reader:

A book of pages (comic, recipe, fixed-layout EPUB)A reflowable EPUB
0001.pg4, 0002.pg4, … one per pagebook.epub, the file as the server sent it
index.json, its chapters and table of contents
cover.pg4, its cover, prepared for the panel
book.json, written lastbook.json, written last

A CBZ is first downloaded whole, its pages are prepared into .pg4 files, then the archive is deleted: only the pages take space.

The EPUB's page count in book.json is a Virtual pageVirtual page: 1500 characters of an EPUB. A stable “page number” for progress and the server, whatever the font size. count: 1500 characters a page (CharsPerPage), since the real pages depend on the font size.

Where it lives in the code​

The full story is spread over Architecture, The image pipeline and Files on the reader.

Next: the stations of this trip are parts of the code. The layer cake shows how they are stacked.

Check yourself​

Why are comic pages dithered to 16 grays at download time, not when you turn the page?
An EPUB download stops halfway when Wi-Fi drops. How does the app know the book is not complete?
You turn ten pages in quick succession. How many times is the progress sent to the server?