Skip to content

Instantly share code, notes, and snippets.

@themerius
Last active November 17, 2021 10:58
Show Gist options
  • Select an option

  • Save themerius/e92cd767340d11d2b80276e48c397e30 to your computer and use it in GitHub Desktop.

Select an option

Save themerius/e92cd767340d11d2b80276e48c397e30 to your computer and use it in GitHub Desktop.
Generate a simple epub file with scala / java containing video and images
package services
import java.io._
import java.nio.charset.StandardCharsets
import java.util.zip.{ZipEntry, ZipOutputStream}
object EPubGenerator extends App {
// based on examples found here https://idpf.github.io/epub3-samples/30/samples.html
val zipFile = File.createTempFile("ecard-epub-", ".epub")
val zipOut = new ZipOutputStream(new FileOutputStream(zipFile))
addFileToZip(zipOut, "application/epub+zip", "mimetype")
addFileToZip(zipOut, containerXml.toString(), "META-INF/container.xml")
addFileToZip(zipOut, packageOpf.toString(), "EPUB/package.opf")
addFileToZip(zipOut, coverHtml.toString(), "EPUB/xhtml/package.xhtml")
addFileToZip(zipOut, tocHtml.toString(), "EPUB/xhtml/toc.xhtml")
addFileToZip(zipOut, p30Html.toString(), "EPUB/xhtml/p30.xhtml")
// add multimedia files
//addFileToZip(zipOut, new File("path/to/video.mp4"), "EPUB/video/shared-culture.mp4")
//addFileToZip(zipOut, new File("path/to/image.jpg"), "EPUB/images/326261902_3fa36f548d.jpg")
zipOut.close()
println("generated zip file")
println(zipFile.getAbsolutePath)
// upload or whatever ...
// zipFile.delete()
def addFileToZip(zipOut: ZipOutputStream, content: String, fileName: String) = {
val stream = new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8))
addFileToZip(zipOut, stream, fileName)
}
def addFileToZip(zipOut: ZipOutputStream, content: File, fileName: String) = {
val stream = new FileInputStream(content)
addFileToZip(zipOut, stream, fileName)
}
def addFileToZip(zipOut: ZipOutputStream, content: InputStream, fileName: String) = {
try {
val zipEntry = new ZipEntry(fileName)
zipOut.putNextEntry(zipEntry)
var reading = true
while (reading) {
content.read() match {
case -1 => reading = false
case data => zipOut.write(data)
}
}
zipOut.closeEntry()
} finally {
content.close()
}
}
def xmlHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
def htmlHeader = "<!DOCTYPE html>"
def containerXml = <container xmlns="urn:oasis:names:tc:opendocument:xmlns:container" version="1.0">
<rootfiles>
<rootfile full-path="EPUB/package.opf" media-type="application/oebps-package+xml"/>
</rootfiles>
</container>
def packageOpf = <package xmlns="http://www.idpf.org/2007/opf" version="3.0" xml:lang="en" unique-identifier="uid" prefix="cc: http://creativecommons.org/ns#">
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/">
<dc:title id="title">...</dc:title>
<dc:creator>...</dc:creator>
<dc:identifier id="uid">...</dc:identifier>
<dc:language>en-US</dc:language>
<meta property="dcterms:modified">2012-01-20T12:47:00Z</meta>
<dc:publisher>....</dc:publisher>
<dc:contributor>...</dc:contributor>
<dc:description>...</dc:description>
<dc:rights>...</dc:rights>
<link rel="cc:license" href="https://...."/>
</metadata>
<manifest>
<item id="img1" href="images/326261902_3fa36f548d.jpg" media-type="image/jpeg" properties="cover-image"/>
<item id="video1" href="video/shared-culture.mp4" media-type="video/mp4"/>
<item id="cover" href="xhtml/cover.xhtml" media-type="application/xhtml+xml"/>
<item id="toc" properties="nav" href="xhtml/toc.xhtml" media-type="application/xhtml+xml"/>
<item id="p30" href="xhtml/p30.xhtml" media-type="application/xhtml+xml"/>
</manifest>
<spine>
<itemref idref="cover" linear="no"/>
<itemref idref="toc"/>
<itemref idref="p30"/>
</spine>
</package>
def coverHtml = <html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8"/>
</head>
<body style="text-align: center;">
<hgroup id="covertitle">
<h1>lorem ipsum</h1>
<h2>lorem ipsum</h2>
</hgroup>
<img id="img-cover" src="../images/326261902_3fa36f548d.jpg" alt="the description"/>
</body>
</html>
def tocHtml = <html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">
<head>
<meta charset="utf-8"/>
</head>
<body>
<section class="base" id="toc">
<h1>lorem ipsum</h1>
<nav epub:type="toc">
<h2>table of contents</h2>
<ol>
<li>
<a href="p30.xhtml">
<span class="toc-label">lorem ipsum</span>
<span class="toc-desc">Unscripted autoplay video in mp4</span>
</a>
</li>
</ol>
</nav>
<nav epub:type="landmarks">
<h2>guide</h2>
<ol>
<li>
<a epub:type="toc" href="#toc">Table of Contents</a>
</li>
<li>
<a epub:type="bodymatter" href="p30.xhtml">Begin Reading</a>
</li>
</ol>
</nav>
</section>
</body>
</html>
def p30Html = <html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8"/>
</head>
<body>
<section class="base">
<h2>lorem ipsum</h2>
<p>lorem ipsum</p>
<video id="video1" autoplay="" role="button" aria-controls="video1" controls="">
<source src="../video/shared-culture.mp4" type="video/mp4"/>
<div class="errmsg">
<p>Your Reading System does not support (this) video.</p>
</div>
</video>
<p>Lorem ipsum</p>
</section>
</body>
</html>
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment