All formats

mobi (Go)

LanguageGo
LicenseMIT
Repositorygithub.com/leotaku/mobi
Documentationpkg.go.dev/github.com/leotaku/mobi
Depends ongolang.org/x/text
Read / writeno / yes (KF8 / AZW3)

leotaku/mobi builds Kindle books in pure Go, without KindleGen or Calibre. You describe a mobi.Book (title, authors, language, chapters of HTML, CSS, images, cover) and call Realize(), which returns a Palm database (pdb.Database) that you write to a .azw3 file. The output is KF8 only: it opens on Kindle devices and apps that support KF8, but not on the Kindle 1, Kindle 2 and Kindle DX.

The package also exports its building blocks: pdb (Palm database reader and writer), records (PalmDOC, MOBI, EXTH, index and image records) and jfif, so you can implement other PalmDB-based formats. Known limits: chapters can’t have subchapters, and a book without any text is malformed.

Installation#

Shell
go get github.com/leotaku/mobi

Basic usage: create an AZW3 book#

Go
package main

import (
	"log"
	"math/rand"
	"os"
	"time"

	"github.com/leotaku/mobi"
	"golang.org/x/text/language"
)

func main() {
	book := mobi.Book{
		Title:       "My Book",
		Authors:     []string{"Jane Doe"},
		Language:    language.English,
		CreatedDate: time.Now(),
		UniqueID:    rand.Uint32(),
		Chapters: []mobi.Chapter{
			{Title: "Chapter 1", Chunks: mobi.Chunks("<h1>Chapter 1</h1><p>First chapter.</p>")},
			{Title: "Chapter 2", Chunks: mobi.Chunks("<h1>Chapter 2</h1><p>Second chapter.</p>")},
		},
	}

	db := book.Realize()

	f, err := os.Create("book.azw3")
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()
	if err := db.Write(f); err != nil {
		log.Fatal(err)
	}
}

Each chapter becomes an entry in the Kindle’s table of contents. mobi.Chunks takes one or more HTML strings; long chapters can be split into several chunks.

How to add a cover image#

CoverImage takes any image.Image; it’s stored as JPEG and marked as the cover in the EXTH header:

Go
import (
	"image"
	_ "image/jpeg"
	_ "image/png"
)

f, err := os.Open("cover.jpg")
if err != nil {
	log.Fatal(err)
}
cover, _, err := image.Decode(f)
f.Close()
if err != nil {
	log.Fatal(err)
}
book.CoverImage = cover
book.ThumbImage = cover // small thumbnail for the library view

How to add images to chapters#

Images in Book.Images are referenced as kindle:embed:XXXX, where XXXX is the 1-based index in base 32, padded to 4 digits:

Go
book.Images = []image.Image{photo} // first image: kindle:embed:0001
book.Chapters = append(book.Chapters, mobi.Chapter{
	Title:  "Photos",
	Chunks: mobi.Chunks(`<p><img src="kindle:embed:0001?mime=image/jpeg"/></p>`),
})

How to add CSS#

Go
book.CSSFlows = []string{"body { font-family: serif; } h1 { text-align: center; }"}

The default page template links every CSS flow from each chapter.

How to show the cover on a Kindle for sideloaded books#

Newer Kindles download covers from Amazon and ignore the embedded thumbnail of sideloaded books. Copy a JPEG to the Kindle’s thumbnails folder with the name the library expects:

Go
name := book.GetThumbFilename() // thumbnail_<ASIN>_EBOK_portrait.jpg
// copy the cover JPEG to <Kindle>/system/thumbnails/<name>

Tips#