quarto

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 18, 2026 License: MIT Imports: 19 Imported by: 0

README

quarto

quarto-go

Turn HTML into EPUB3 and Kobo kepub files, entirely in memory, with no external binaries. This is a Go port of @voidberg/quarto (TypeScript). It is pure Go with no cgo, so it cross-compiles to a static ARM binary and runs natively on e-readers like Kobo and reMarkable, as well as in any other Go program.

Go Reference

Install

go get github.com/voidberg/quarto-go

The module path ends in quarto-go, but the package is named quarto, so you call quarto.Generate(...):

import "github.com/voidberg/quarto-go"

Quick start

package main

import (
	"context"
	"os"

	"github.com/voidberg/quarto-go"
)

func main() {
	in := quarto.Input{
		Title:   "On the Shortness of Life",
		Authors: []string{"Seneca"},
		Chapters: []quarto.Chapter{
			{Title: "I", HTML: "<p>It is not that we have a short time to live...</p>"},
		},
	}

	epub, err := quarto.Generate(context.Background(), in)
	if err != nil {
		panic(err)
	}
	os.WriteFile("seneca.epub", epub, 0o644)

	// A Kobo kepub in one call (Generate + ToKepub):
	kepub, err := quarto.GenerateKepub(context.Background(), in)
	if err != nil {
		panic(err)
	}
	os.WriteFile("seneca.kepub.epub", kepub, 0o644)
}

What it does

  • Valid EPUB3, checked against EPUBCheck.
  • Native kepub conversion (ToKepub): Kobo reading-location spans and the book-columns/book-inner wrappers, with no kepubify binary.
  • Optional table of contents (on by default, off with NoToc).
  • Parses messy HTML fragments and re-serializes them as well-formed XHTML.
  • Downloads and embeds remote images so the book is self-contained, or drops them with NoDownloadImages.
  • Deterministic: the same input always produces the same bytes (a stable FNV-1a id, no wall-clock or randomness).
  • One non-stdlib dependency, golang.org/x/net.

API

func Generate(ctx context.Context, in Input) ([]byte, error)       // HTML -> EPUB3
func ToKepub(data []byte) ([]byte, error)                          // EPUB3 -> kepub
func GenerateKepub(ctx context.Context, in Input) ([]byte, error)  // Generate then ToKepub
func ImageSize(data []byte, mime string) (width, height int, ok bool)

context.Context is the first argument so image downloads honor cancellation and deadlines. Functions return errors; they never panic (an empty Chapters is an error, for example).

Options

Build a book from an Input. The zero value picks quarto's defaults, so you only set what you need.

Field Default Notes
Title (required) Book title.
Authors none Zero or more dc:creator values.
Publisher, Description none Dublin Core metadata.
Language "en" BCP-47 tag.
ID deterministic urn:uuid Derived from title and authors when unset.
Date none ISO-8601 publication date.
Series, SeriesIndex none Emits both EPUB3 belongs-to-collection and Calibre series metadata. SeriesIndex is a *float64 because 0 is a valid index.
NoToc TOC on Set to suppress the visible table of contents.
TocTitle "Table of Contents" Heading for the TOC page.
CSS, NoCSS bundled stylesheet Override with your own CSS, or ship none.
NoDownloadImages downloads on Set to drop every non-data: image instead of fetching.
Client http.DefaultClient Inject your own *http.Client for timeouts, transport, or fixed bytes in tests.

Per chapter (Chapter):

Field Notes
Title Used in the nav/TOC and as the page <h1>.
HTML The body fragment; need not be well-formed.
Author Optional byline under the title.
ExcludeFromToc Keep the chapter in reading order but out of the nav and NCX (useful for front matter).
SkipTitle Don't generate the <h1> heading; render only your HTML.

Covers and images

  • Supply a cover by URL (CoverURL) or raw bytes (CoverData); bytes win when both are set. CoverBackground sets the letterbox color on the cover page.
  • CoverFromLeadImage promotes a chapter's leading image to the cover when no explicit cover is given.
  • TransformImage runs on each fetched image before it is embedded, so you can transcode, resize, or drop it. TransformCover builds the final cover and runs even when there is no source image, so you can compose one from metadata.

Running on e-readers

With no cgo and no external binaries, a CGO_ENABLED=0 cross-build produces a static binary you can copy straight onto an ARM Linux device and run:

# 32-bit ARMv7 — every Kobo (all models), reMarkable 1 / 2:
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -o quarto .

# ARM64 — reMarkable Paper Pro, Paper Pro Move, Paper Pure:
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o quarto .

Every Kobo ships a 32-bit userspace, even newer models (Sage, Elipsa, Libra / Clara Colour) whose chips are 64-bit capable, so GOARCH=arm is right for any Kobo. When in doubt, run uname -m on the device over SSH: armv7l → the first build, aarch64 → the second.

Pick the output format per device:

  • Kobo: call GenerateKepub for the Kobo-optimised kepub.
  • reMarkable (and any standard EPUB reader): call Generate. reMarkable reads EPUB natively; the Kobo-specific kepub extensions aren't needed.

Requirements

Go 1.25 or newer.

Status and versioning

This is a v0.x release: the API may still change. It will stabilize at v1.0.0 once the first consumer (instakobo) has integrated it.

quarto-go and the TypeScript @voidberg/quarto are parallel packages. The Go port was validated byte-for-byte against the published TypeScript library across a fixture corpus, but the two might evolve independently in the future.

License

MIT. See LICENSE.

Documentation

Overview

Package quarto generates EPUB3 files and converts them to Kobo kepub. It is a Go port of the @voidberg/quarto TypeScript library.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Generate

func Generate(ctx context.Context, in Input) ([]byte, error)

Generate builds a complete, valid EPUB3 publication in memory from HTML chapters. The returned bytes are a ready-to-write .epub. Pass the result to ToKepub to produce a Kobo-optimised .kepub.epub.

func GenerateKepub

func GenerateKepub(ctx context.Context, in Input) ([]byte, error)

GenerateKepub is a convenience that builds an EPUB3 from in and converts it to a Kobo kepub in one call (equivalent to ToKepub(Generate(ctx, in))). It is the common path for callers targeting Kobo devices; use Generate and ToKepub separately when you need the intermediate EPUB3.

func ImageSize

func ImageSize(data []byte, mime string) (width, height int, ok bool)

ImageSize reads the pixel dimensions from PNG, GIF or JPEG headers without decoding the image. ok is false for other formats or malformed data.

func ToKepub

func ToKepub(data []byte) ([]byte, error)

ToKepub converts a standard EPUB into a Kobo kepub in memory. It's the equivalent of running kepubify, with no external binary required.

Every content document is rewritten with Kobo reading-location spans and the book-columns/book-inner wrappers. The navigation document is left untouched. The returned bytes should be written with a .kepub.epub extension so Kobo devices recognise the enhanced format.

Types

type Chapter

type Chapter struct {
	// Title is used in the nav/TOC and rendered as the page <h1> heading.
	Title string
	// HTML is the chapter body fragment. It need not be well-formed; it is
	// parsed and re-serialized to valid XHTML.
	HTML string
	// Author, when set, renders as a byline under the title heading.
	Author string
	// ExcludeFromToc keeps the chapter in the spine (reading order) but omits
	// it from the nav doc and NCX.
	ExcludeFromToc bool
	// SkipTitle omits the auto-generated <h1> heading (and author line).
	SkipTitle bool
}

Chapter is one content document.

type CoverMeta

type CoverMeta struct {
	Title  string
	Author string
}

CoverMeta is the book metadata handed to a CoverTransform.

type CoverTransform

type CoverTransform func(ctx context.Context, cover *RawImage, meta CoverMeta) (*RawImage, error)

CoverTransform builds the final cover after the source image has been downloaded and transformed. It is called even when there is no cover source (cover == nil), so it can compose a cover from metadata alone. Return (nil, nil) for no cover.

type ImageTransform

type ImageTransform func(ctx context.Context, img RawImage) (*RawImage, error)

ImageTransform is a hook run on each fetched image (and the cover source) after download, before the core-media-type check, so it can transcode, resize or drop (return nil, nil) the image.

type Input

type Input struct {
	// Title is the required book title.
	Title string
	// Authors is zero or more dc:creator values.
	Authors     []string
	Publisher   string
	Description string
	// Language is a BCP-47 tag; defaults to "en".
	Language string
	// ID is the unique book id; defaults to a deterministic urn:uuid derived
	// from title and authors.
	ID string
	// CoverURL is a remote cover image to download; CoverData supplies raw
	// bytes instead. CoverData wins when both are set.
	CoverURL  string
	CoverData []byte
	// CoverFromLeadImage promotes the first chapter's leading image (one that
	// appears before any text) to the cover and removes it from the body, but
	// only when no explicit cover is given.
	CoverFromLeadImage bool
	// IncludeToc controls the visible TOC page; quarto defaults to true, so
	// this field is inverted to keep the zero value meaning "default".
	NoToc bool
	// TocTitle defaults to "Table of Contents".
	TocTitle string
	// CoverBackground is a CSS color filling the letterbox bands around the
	// cover page.
	CoverBackground string
	// CSS overrides the bundled stylesheet; NoCSS ships none at all.
	CSS   string
	NoCSS bool
	// NoDownloadImages skips fetching: every non-data: <img> is dropped.
	NoDownloadImages bool
	// Date is an ISO-8601 publication date.
	Date string
	// Series and SeriesIndex emit both EPUB3 belongs-to-collection and legacy
	// calibre:series metadata. SeriesIndex is a pointer because 0 is valid.
	Series      string
	SeriesIndex *float64
	// Client is used for image downloads; defaults to http.DefaultClient.
	Client *http.Client
	// TransformImage and TransformCover are optional hooks; see their types.
	TransformImage ImageTransform
	TransformCover CoverTransform

	Chapters []Chapter
}

Input describes one book. Zero values pick the quarto defaults.

type RawImage

type RawImage struct {
	Data []byte
	Mime string
}

RawImage is an image as bytes plus its MIME type.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL