mobi

package module
v0.0.0-...-1f46d50 Latest Latest
Warning

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

Go to latest
Published: Jan 26, 2017 License: BSD-2-Clause Imports: 12 Imported by: 0

README

Mobi

Writer/Reader for Mobi format.

Note: All testing were done on Kindle Previewer (Windows) and Kindle Paperwhite (6th Gen)

Before You Start

  • This is more or less WIP. Use at your own risk.
  • This package was written for a specific task, thus there are certain limitations, such as:
    • img tags are ignored and not embedded.
    • TOC depth does not go beyond 1. Meaning for now you can only have chapters and sub-chapters. But sub-chaper can not have it's own sub-chapters.
  • HTML formatting is supported, but rendering is dependant on your eBook reader. (For Kindle see Supported HTML Tags in Book Content)
  • Cover images should be in JPG (I have not tested GIF, which sould be supported).
    • IMPORTANT: Images resized using image/jpeg package will not display (in Kindle) because JFIF APP0 marker segment is not generated by image/jpeg package.
  • Table of Content is automaticaly generated.

Usage

Writer
m, err := mobi.NewWriter("output.mobi")
if err != nil {
	panic(err)
}

m.Title("Book Title")
m.Compression(mobi.CompressionNone) // LZ77 compression is also possible using  mobi.CompressionPalmDoc

// Add cover image
m.AddCover("data/cover.jpg", "data/thumbnail.jpg")

// Meta data
m.NewExthRecord(mobi.EXTH_DOCTYPE, "EBOK")
m.NewExthRecord(mobi.EXTH_AUTHOR, "Book Author Name")
// See exth.go for additional EXTH record IDs

// Add chapters and subchapters
ch1 := m.NewChapter("Chapter 1", []byte("Some text here"))
ch1.AddSubChapter("Chapter 1-1", []byte("Some text here"))
ch1.AddSubChapter("Chapter 1-2", []byte("Some text here"))

m.NewChapter("Chapter 2", []byte("Some text here")).AddSubChapter("Chapter 2-1", []byte("Some text here")).AddSubChapter("Chapter 2-2", []byte("Some text here"))
m.NewChapter("Chapter 3", []byte("Some text here")).AddSubChapter("Chapter 3-1", []byte("Some text here"))
m.NewChapter("Chapter 4", []byte("Some text here")).AddSubChapter("Chapter 4-1", []byte("Some text here"))

// Output MOBI File
m.Write()
Reader

For now, Reader does not give any useful information.

Documentation

Index

Constants

View Source
const (
	EXTH_DRMSERVER       uint32 = 1
	EXTH_DRMCOMMERCE            = 2
	EXTH_DRMEBOOKBASE           = 3
	EXTH_TITLE                  = 99  /**< <dc:title> */
	EXTH_AUTHOR                 = 100 /**< <dc:creator> */
	EXTH_PUBLISHER              = 101 /**< <dc:publisher> */
	EXTH_IMPRINT                = 102 /**< <imprint> */
	EXTH_DESCRIPTION            = 103 /**< <dc:description> */
	EXTH_ISBN                   = 104 /**< <dc:identifier opf:scheme="ISBN"> */
	EXTH_SUBJECT                = 105 // Could appear multiple times /**< <dc:subject> */
	EXTH_PUBLISHINGDATE         = 106 /**< <dc:date> */
	EXTH_REVIEW                 = 107 /**< <review> */
	EXTH_CONTRIBUTOR            = 108 /**< <dc:contributor> */
	EXTH_RIGHTS                 = 109 /**< <dc:rights> */
	EXTH_SUBJECTCODE            = 110 /**< <dc:subject BASICCode="subjectcode"> */
	EXTH_TYPE                   = 111 /**< <dc:type> */
	EXTH_SOURCE                 = 112 /**< <dc:source> */
	EXTH_ASIN                   = 113 // Kindle Paperwhite labels books with "Personal" if they don't have this record.
	EXTH_VERSION                = 114
	EXTH_SAMPLE                 = 115 // 0x0001 if the book content is only a sample of the full book
	EXTH_STARTREADING           = 116 // Position (4-byte offset) in file at which to open when first opened /**< Start reading */
	EXTH_ADULT                  = 117 // Mobipocket Creator adds this if Adult only is checked on its GUI; contents: "yes" /**< <adult> */
	EXTH_PRICE                  = 118 // As text, e.g. "4.99" /**< <srp> */
	EXTH_CURRENCY               = 119 // As text, e.g. "USD" /**< <srp currency="currency"> */
	EXTH_KF8BOUNDARY            = 121
	EXTH_FIXEDLAYOUT            = 122 /**< <fixed-layout> */
	EXTH_BOOKTYPE               = 123 /**< <book-type> */
	EXTH_ORIENTATIONLOCK        = 124 /**< <orientation-lock> */
	EXTH_COUNTRESOURCES         = 125
	EXTH_ORIGRESOLUTION         = 126 /**< <original-resolution> */
	EXTH_ZEROGUTTER             = 127 /**< <zero-gutter> */
	EXTH_ZEROMARGIN             = 128 /**< <zero-margin> */
	EXTH_KF8COVERURI            = 129
	EXTH_RESCOFFSET             = 131
	EXTH_REGIONMAGNI            = 132 /**< <region-mag> */

	EXTH_DICTNAME     = 200 // As text /**< <DictionaryVeryShortName> */
	EXTH_COVEROFFSET  = 201 // Add to first image field in Mobi Header to find PDB record containing the cover image/**< <EmbeddedCover> */
	EXTH_THUMBOFFSET  = 202 // Add to first image field in Mobi Header to find PDB record containing the thumbnail cover image
	EXTH_HASFAKECOVER = 203
	EXTH_CREATORSOFT  = 204 //Known Values: 1=mobigen, 2=Mobipocket Creator, 200=kindlegen (Windows), 201=kindlegen (Linux), 202=kindlegen (Mac).
	EXTH_CREATORMAJOR = 205
	EXTH_CREATORMINOR = 206
	EXTH_CREATORBUILD = 207
	EXTH_WATERMARK    = 208
	EXTH_TAMPERKEYS   = 209

	EXTH_FONTSIGNATURE = 300

	EXTH_CLIPPINGLIMIT  = 401 // Integer percentage of the text allowed to be clipped. Usually 10.
	EXTH_PUBLISHERLIMIT = 402
	EXTH_UNK403         = 403
	EXTH_TTSDISABLE     = 404 // 1 - Text to Speech disabled; 0 - Text to Speech enabled
	EXTH_UNK405         = 405 // 1 in this field seems to indicate a rental book
	EXTH_RENTAL         = 406 // If this field is removed from a rental, the book says it expired in 1969
	EXTH_UNK407         = 407
	EXTH_UNK450         = 450
	EXTH_UNK451         = 451
	EXTH_UNK452         = 452
	EXTH_UNK453         = 453

	EXTH_DOCTYPE         = 501 // PDOC - Personal Doc; EBOK - ebook; EBSP - ebook sample;
	EXTH_LASTUPDATE      = 502
	EXTH_UPDATEDTITLE    = 503
	EXTH_ASIN504         = 504 // ?? ASIN in this record.
	EXTH_TITLEFILEAS     = 508
	EXTH_CREATORFILEAS   = 517
	EXTH_PUBLISHERFILEAS = 522
	EXTH_LANGUAGE        = 524 /**< <dc:language> */
	EXTH_ALIGNMENT       = 525 // ?? horizontal-lr in this record /**< <primary-writing-mode> */
	EXTH_PAGEDIR         = 527
	EXTH_OVERRIDEFONTS   = 528 /**< <override-kindle-fonts> */
	EXTH_SORCEDESC       = 529
	EXTH_DICTLANGIN      = 531
	EXTH_DICTLANGOUT     = 532
	EXTH_UNK534          = 534
	EXTH_CREATORBUILDREV = 535
)

EXTH record IDs

View Source
const (
	INDX_TYPE_NORMAL     uint32 = 0
	INDX_TYPE_INFLECTION uint32 = 2
)
View Source
const (
	MOBI_MAX_RECORD_SIZE    = 4096
	MOBI_PALMDB_HEADER_LEN  = 78
	MOBI_INDX_HEADER_LEN    = 192
	MOBI_PALMDOC_HEADER_LEN = 16
	MOBI_MOBIHEADER_LEN     = 232
)
View Source
const (
	MOBI_ENC_CP1252 = 1252  /**< cp-1252 encoding */
	MOBI_ENC_UTF8   = 65001 /**< utf-8 encoding */
	MOBI_ENC_UTF16  = 65002 /**< utf-16 encoding */
)
View Source
const (
	// CompressionNone uint16(1). Text is stored without any compression
	CompressionNone mobiPDHCompression = 1
	// CompressionPalmDoc uint16(2). Text is compressed using simple LZ77 algorithm
	CompressionPalmDoc mobiPDHCompression = 2
	// CompressionHuffCdic uint16(17480). Text is compressed using HuffCdic
	CompressionHuffCdic mobiPDHCompression = 17480
)

Compression Enum

View Source
const (
	TagEntry_END                uint8 = 0
	TagEntry_Pos                      = 1  // NCX | Position offset for the beginning of NCX record (filepos) Ex: Beginning of a chapter
	TagEntry_Len                      = 2  // NCX | Record lenght. Ex: Chapter lenght
	TagEntry_NameOffset               = 3  // NCX | Label text offset in CNCX
	TagEntry_DepthLvl                 = 4  // NCX | Depth/Level of CNCX
	TagEntry_KOffs                    = 5  // NCX | kind CNCX offset
	TagEntry_PosFid                   = 6  // NCX | pos:fid
	TagEntry_Parent                   = 21 // NCX | Parent
	TagEntry_Child1                   = 22 // NCX | First child
	TagEntry_ChildN                   = 23 // NCX | Last child
	TagEntry_ImageIndex               = 69
	TagEntry_DescOffset               = 70 // Description offset in cncx
	TagEntry_AuthorOffset             = 71 // Author offset in cncx
	TagEntry_ImageCaptionOffset       = 72 // Image caption offset in cncx
	TagEntry_ImgAttrOffset            = 73 // Image attribution offset in cncx
)

Variables

View Source
var ExthMeta = []mobiExthMeta{
	{0, 0, ""},
	{EXTH_SAMPLE, EXTH_TYPE_NUMERIC, "Sample"},
	{EXTH_STARTREADING, EXTH_TYPE_NUMERIC, "Start offset"},
	{EXTH_KF8BOUNDARY, EXTH_TYPE_NUMERIC, "K8 Boundary Offset"},
	{EXTH_COUNTRESOURCES, EXTH_TYPE_NUMERIC, "K8 Resources Count"},
	{EXTH_RESCOFFSET, EXTH_TYPE_NUMERIC, "RESC Offset"},
	{EXTH_COVEROFFSET, EXTH_TYPE_NUMERIC, "Cover Offset"},
	{EXTH_THUMBOFFSET, EXTH_TYPE_NUMERIC, "Thumbnail Offset"},
	{EXTH_HASFAKECOVER, EXTH_TYPE_NUMERIC, "Has Fake Cover"},
	{EXTH_CREATORSOFT, EXTH_TYPE_NUMERIC, "Creator Software"},
	{EXTH_CREATORMAJOR, EXTH_TYPE_NUMERIC, "Creator Major Version"},
	{EXTH_CREATORMINOR, EXTH_TYPE_NUMERIC, "Creator Minor Version"},
	{EXTH_CREATORBUILD, EXTH_TYPE_NUMERIC, "Creator Build Number"},
	{EXTH_CLIPPINGLIMIT, EXTH_TYPE_NUMERIC, "Clipping Limit"},
	{EXTH_PUBLISHERLIMIT, EXTH_TYPE_NUMERIC, "Publisher Limit"},
	{EXTH_TTSDISABLE, EXTH_TYPE_NUMERIC, "Text-to-Speech Disabled"},
	{EXTH_RENTAL, EXTH_TYPE_NUMERIC, "Rental Indicator"},
	{EXTH_DRMSERVER, EXTH_TYPE_STRING, "DRM Server ID"},
	{EXTH_DRMCOMMERCE, EXTH_TYPE_STRING, "DRM Commerce ID"},
	{EXTH_DRMEBOOKBASE, EXTH_TYPE_STRING, "DRM Ebookbase Book ID"},
	{EXTH_TITLE, EXTH_TYPE_STRING, "Title"},
	{EXTH_AUTHOR, EXTH_TYPE_STRING, "Creator"},
	{EXTH_PUBLISHER, EXTH_TYPE_STRING, "Publisher"},
	{EXTH_IMPRINT, EXTH_TYPE_STRING, "Imprint"},
	{EXTH_DESCRIPTION, EXTH_TYPE_STRING, "Description"},
	{EXTH_ISBN, EXTH_TYPE_STRING, "ISBN"},
	{EXTH_SUBJECT, EXTH_TYPE_STRING, "Subject"},
	{EXTH_PUBLISHINGDATE, EXTH_TYPE_STRING, "Published"},
	{EXTH_REVIEW, EXTH_TYPE_STRING, "Review"},
	{EXTH_CONTRIBUTOR, EXTH_TYPE_STRING, "Contributor"},
	{EXTH_RIGHTS, EXTH_TYPE_STRING, "Rights"},
	{EXTH_SUBJECTCODE, EXTH_TYPE_STRING, "Subject Code"},
	{EXTH_TYPE, EXTH_TYPE_STRING, "Type"},
	{EXTH_SOURCE, EXTH_TYPE_STRING, "Source"},
	{EXTH_ASIN, EXTH_TYPE_STRING, "ASIN"},
	{EXTH_VERSION, EXTH_TYPE_STRING, "Version Number"},
	{EXTH_ADULT, EXTH_TYPE_STRING, "Adult"},
	{EXTH_PRICE, EXTH_TYPE_STRING, "Price"},
	{EXTH_CURRENCY, EXTH_TYPE_STRING, "Currency"},
	{EXTH_FIXEDLAYOUT, EXTH_TYPE_STRING, "Fixed Layout"},
	{EXTH_BOOKTYPE, EXTH_TYPE_STRING, "Book Type"},
	{EXTH_ORIENTATIONLOCK, EXTH_TYPE_STRING, "Orientation Lock"},
	{EXTH_ORIGRESOLUTION, EXTH_TYPE_STRING, "Original Resolution"},
	{EXTH_ZEROGUTTER, EXTH_TYPE_STRING, "Zero Gutter"},
	{EXTH_ZEROMARGIN, EXTH_TYPE_STRING, "Zero margin"},
	{EXTH_KF8COVERURI, EXTH_TYPE_STRING, "K8 Masthead/Cover Image"},
	{EXTH_REGIONMAGNI, EXTH_TYPE_STRING, "Region Magnification"},
	{EXTH_DICTNAME, EXTH_TYPE_STRING, "Dictionary Short Name"},
	{EXTH_WATERMARK, EXTH_TYPE_STRING, "Watermark"},
	{EXTH_DOCTYPE, EXTH_TYPE_STRING, "Document Type"},
	{EXTH_LASTUPDATE, EXTH_TYPE_STRING, "Last Update Time"},
	{EXTH_UPDATEDTITLE, EXTH_TYPE_STRING, "Updated Title"},
	{EXTH_ASIN504, EXTH_TYPE_STRING, "ASIN (504)"},
	{EXTH_TITLEFILEAS, EXTH_TYPE_STRING, "Title File As"},
	{EXTH_CREATORFILEAS, EXTH_TYPE_STRING, "Creator File As"},
	{EXTH_PUBLISHERFILEAS, EXTH_TYPE_STRING, "Publisher File As"},
	{EXTH_LANGUAGE, EXTH_TYPE_STRING, "Language"},
	{EXTH_ALIGNMENT, EXTH_TYPE_STRING, "Primary Writing Mode"},
	{EXTH_PAGEDIR, EXTH_TYPE_STRING, "Page Progression Direction"},
	{EXTH_OVERRIDEFONTS, EXTH_TYPE_STRING, "Override Kindle Fonts"},
	{EXTH_SORCEDESC, EXTH_TYPE_STRING, "Original Source description"},
	{EXTH_DICTLANGIN, EXTH_TYPE_STRING, "Dictionary Input Language"},
	{EXTH_DICTLANGOUT, EXTH_TYPE_STRING, "Dictionary output Language"},
	{EXTH_UNK534, EXTH_TYPE_STRING, "Unknown (534)"},
	{EXTH_CREATORBUILDREV, EXTH_TYPE_STRING, "Kindlegen BuildRev Number"},
	{EXTH_TAMPERKEYS, EXTH_TYPE_BINARY, "Tamper Proof Keys"},
	{EXTH_FONTSIGNATURE, EXTH_TYPE_BINARY, "Font Signature"},
	{EXTH_UNK403, EXTH_TYPE_BINARY, "Unknown (403)"},
	{EXTH_UNK405, EXTH_TYPE_BINARY, "Unknown (405)"},
	{EXTH_UNK407, EXTH_TYPE_BINARY, "Unknown (407)"},
	{EXTH_UNK450, EXTH_TYPE_BINARY, "Unknown (450)"},
	{EXTH_UNK451, EXTH_TYPE_BINARY, "Unknown (451)"},
	{EXTH_UNK452, EXTH_TYPE_BINARY, "Unknown (452)"},
	{EXTH_UNK453, EXTH_TYPE_BINARY, "Unknown (453)"}}

EXTH Tag ID - Name - Type relationship

Functions

This section is empty.

Types

type EmbType

type EmbType int
const (
	EmbCover EmbType = iota
	EmbThumb
)

type EmbeddedData

type EmbeddedData struct {
	Type EmbType
	Data []byte
}

type ExthType

type ExthType uint32

Type of EXTH record. If it's Binary/Numberic then read/write it using BigEndian, String is read/write using LittleEndian

const (
	EXTH_TYPE_NUMERIC ExthType = 0
	EXTH_TYPE_STRING  ExthType = 1
	EXTH_TYPE_BINARY  ExthType = 2
)

type Mint

type Mint int

func (Mint) Int

func (i Mint) Int() int

func (Mint) UInt16

func (i Mint) UInt16() uint16

func (Mint) UInt32

func (i Mint) UInt32() uint32

type Mobi

type Mobi struct {
	Pdf     mobiPDF            // Palm Database Format: http://wiki.mobileread.com/wiki/PDB#Palm_Database_Format
	Offsets []mobiRecordOffset // Offsets for all the records. Starting from beginning of a file.
	Pdh     mobiPDH

	Header mobiHeader
	Exth   mobiExth

	//Index
	Indx  []mobiIndx
	Idxt  mobiIdxt
	Cncx  mobiCncx
	Tagx  mobiTagx
	PTagx []mobiPTagx
	// contains filtered or unexported fields
}

type MobiReader

type MobiReader struct {
	Mobi
}

func NewReader

func NewReader(filename string) (out *MobiReader, err error)

func (*MobiReader) ExthParse

func (r *MobiReader) ExthParse() error

Parse reads/parses Exth meta data records from file

func (*MobiReader) MatchMagic

func (r *MobiReader) MatchMagic(magic mobiMagicType) bool

MatchMagic matches next N bytes (based on lenght of magic word)

func (*MobiReader) OffsetToRecord

func (r *MobiReader) OffsetToRecord(nu uint32) (uint32, error)

OffsetToRecord sets reading position to record N, returns total record lenght

func (*MobiReader) Parse

func (r *MobiReader) Parse() (err error)

func (*MobiReader) Peek

func (r *MobiReader) Peek(n int) Peeker

Peek returns next N bytes without advancing the reader.

type MobiWriter

type MobiWriter struct {

	// Text Records
	Records [][]uint8

	Embedded []EmbeddedData
	Mobi
	// contains filtered or unexported fields
}

func NewWriter

func NewWriter(filename string) (writer *MobiWriter, err error)

NewWriter initializes a writer. Takes a pointer to file and book title/database name

func (*MobiWriter) AddCover

func (w *MobiWriter) AddCover(cover, thumbnail string)

func (*MobiWriter) AddRecord

func (w *MobiWriter) AddRecord(data []uint8) Mint

AddRecord adds a new record. Returns Id

func (*MobiWriter) Compression

func (w *MobiWriter) Compression(i mobiPDHCompression) *MobiWriter

func (*MobiWriter) EmbeddedCount

func (w *MobiWriter) EmbeddedCount() Mint

func (*MobiWriter) NewChapter

func (w *MobiWriter) NewChapter(title string, text []byte) *mobiChapter

func (*MobiWriter) NewExthRecord

func (w *MobiWriter) NewExthRecord(recType ExthType, value interface{})

func (*MobiWriter) RecordCount

func (w *MobiWriter) RecordCount() Mint

func (*MobiWriter) Title

func (w *MobiWriter) Title(i string) *MobiWriter

func (*MobiWriter) Write

func (w *MobiWriter) Write()

type Peeker

type Peeker []uint8

func (Peeker) Bytes

func (p Peeker) Bytes() []uint8

func (Peeker) Len

func (p Peeker) Len() int

func (Peeker) Magic

func (p Peeker) Magic() mobiMagicType

func (Peeker) String

func (p Peeker) String() string

Notes

Bugs

  • Check Mac/Unix timestamp format If the time has the top bit set, it's an unsigned 32-bit number counting from 1st Jan 1904 If the time has the top bit clear, it's a signed 32-bit number counting from 1st Jan 1970.

Jump to

Keyboard shortcuts

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