[Keith Vetter] 2014-03-14 : I've been working with eBooks for over a decade now, so I thought I'd share a simple command line tool I use to create an epub from a single text or xhtml file. You need to specify the epub's title, author and content, which can be either an xhtml file or raw text (which will get converted into xhtml). You can also specify a cover image. If the xhtml source has images, you can include them also. The command line usage is: epubCreator "Pride and Prejudice" "Jane Austen" p_and_p.xhtml cover.jpg img1.jpg img2.jpg An http://www.idpf.org/epub/30/spec/epub30-publications.html%|%epub file%|% is essentially a zip file with some metadata files and one or more xhtml files with the book's content. ====== ##+########################################################################## # # epubCreator.tsh -- command line tool to create an epub version 3.0 # file from a single text or xhmtml file, an optional cover image and # a list of 0 or more images # by Keith Vetter 2014-03-14 # # usage: epubCreator Title Author BookContent ?CoverImage? OtherImages... # package require uuid package require fileutil array set EXT {"" "" .png image/png .gif image/gif .jpg image/jpeg .jpeg image/jpeg .svg image/svg+xml} ################################################################ proc Init {rawname title author cover images} { global E set guid [::uuid::uuid generate] set E(rawname) $rawname set E(basename) [file tail [file rootname $E(rawname)]] set E(dirname) [file normalize [file dirname $E(rawname)]] set E(output,tempdir) [file join [::fileutil::tempdir] "epub_$guid"] set E(output,final) [file join $E(dirname) "$E(basename).epub"] set E(epub) EPUB set E(epub,tempdir) [file join $E(output,tempdir) $E(epub)] set E(html,name) "$E(basename).xhtml" set E(html,tempname) [file join $E(epub,tempdir) "$E(html,name)"] set E(opf,name) [file join $E(epub) package.opf] set E(opf,tempname) [file join $E(output,tempdir) $E(opf,name)] set E(mimetype) mimetype set E(mimetype,tempname) [file join $E(output,tempdir) $E(mimetype)] set E(meta-inf) META-INF set E(meta-inf,tempdir) [file join $E(output,tempdir) $E(meta-inf)] set E(meta-inf,tempname) [file join $E(meta-inf,tempdir) container.xml] set E(nav,name) nav.xhtml set E(nav,tempname) [file join $E(epub,tempdir) $E(nav,name)] set E(cover,source) $cover set E(cover,name) [file tail $cover] set E(cover,format) $::EXT([file extension $cover]) set E(images) $images set E(date) [clock format [clock seconds] -gmt 1 -format "%Y-%m-%dT%TZ"] file mkdir $E(output,tempdir) file mkdir $E(meta-inf,tempdir) file mkdir $E(epub,tempdir) set E(guid) "ebook:$guid" set E(title) $title set E(author) $author } proc MakeEpubFiles {} { global E WriteAllData $E(html,tempname) [TextToHtml] WriteAllData $E(mimetype,tempname) "application/epub+zip" WriteAllData $E(meta-inf,tempname) [subst $::CONTAINER_XML] WriteAllData $E(opf,tempname) [MakeOPF] WriteAllData $E(nav,tempname) [subst $::NAV_XHTML] } proc TextToHtml {} { global E set fin [open $E(rawname) r] set data [read $fin] ; list close $fin if {[string first " > \x22 " ' '} $data] ; list regsub -all -line {^$} $data {

} data set data "[subst $::HTML_TEMPLATE]" ; list } return $data } proc MakeOPF {} { global E set opf [subst $::CONTENT_OPF] if {$E(cover,source) eq ""} { regsub -all -line {^.*id_cover.*$} $opf "" opf } else { file copy $E(cover,source) $E(epub,tempdir) } ;# Copy any additional images set image_items "" for {set i 0} {$i < [llength $E(images)]} {incr i} { set iname [lindex $E(images) $i] file copy $iname $E(epub,tempdir) set tailname [file tail $iname] set media $::EXT([file extension $iname]) set id "id_image_$i" set line "\n" append image_items $line } if {$image_items ne ""} { regsub -line {^.*other images go here.*$} $opf $image_items opf } return $opf } proc ZipEpub {} { global E cd $E(output,tempdir) exec zip -rX $E(output,final) $E(mimetype) $E(meta-inf)/ $E(epub)/ } proc WriteAllData {fname data} { set fout [open $fname w]; puts -nonewline $fout $data; close $fout; } proc Cleanup {} { global E file delete -force -- $E(output,tempdir) } ################################################################ set HTML_TEMPLATE { $E(title)

$data

} set CONTAINER_XML { } set CONTENT_OPF { $E(title) $E(author) $E(guid) en $E(date) } set NAV_XHTML { } ################################################################ puts "\nepubCreator v0.3\nby Keith Vetter\n" if {[llength $argv] < 3} { puts stderr "usage: epubCreator <author> <data file> ?<cover image>? ?<other images>...?" puts stderr "for example:" puts stderr " epubCreator \"Pride and Prejudice\" \"Jane Austen\" p_and_p.xhtml cover.jpg chapter1.jpg" return } set images [lassign $argv title author fname cover] Init $fname $title $author $cover $images MakeEpubFiles ZipEpub Cleanup puts "created $E(output,final)" return ====== ---- '''[ak] - 2014-03-14 23:42:26''' [Tcllib] contains a package [https://core.tcl.tk/tcllib/doc/trunk/embedded/www/tcllib/files/modules/zip/encode.html%|%"zipfile::encode (doc)"] which can obviate the need for 'exec zip'. It requires [Trf] and [zlibtcl] tough. Note that while Tcl 8.6 provides zip functionality in-core the Tcllib package currently makes no use of that). <<categories>>Enter Category Here