Adding the api
This commit is contained in:
parent
77562f2f77
commit
8ad9c996f9
22 changed files with 2976 additions and 0 deletions
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
/target
|
||||
test.epub
|
||||
nb-configuration.xml
|
||||
nbactions.xml
|
55
pom.xml
Normal file
55
pom.xml
Normal file
|
@ -0,0 +1,55 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>coza.opencollab</groupId>
|
||||
<artifactId>epub-creator</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.10</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.htmlcleaner</groupId>
|
||||
<artifactId>htmlcleaner</artifactId>
|
||||
<version>2.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-collections</groupId>
|
||||
<artifactId>commons-collections</artifactId>
|
||||
<version>3.2.1</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>1.7</maven.compiler.source>
|
||||
<maven.compiler.target>1.7</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>oc-nexus-releases</id>
|
||||
<name>OpenCollab Nexus Release Repo</name>
|
||||
<url>
|
||||
http://nexus.opencollab.co.za/nexus/content/repositories/releases
|
||||
</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>oc-nexus-snapshot</id>
|
||||
<name>OpenCollab Nexus Snapshot Repo</name>
|
||||
<url>
|
||||
http://nexus.opencollab.co.za/nexus/content/repositories/snapshots
|
||||
</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
|
||||
</project>
|
100
src/main/java/coza/opencollab/epub/creator/EpubConstants.java
Normal file
100
src/main/java/coza/opencollab/epub/creator/EpubConstants.java
Normal file
|
@ -0,0 +1,100 @@
|
|||
/* Copyright 2014 OpenCollab.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package coza.opencollab.epub.creator;
|
||||
|
||||
/**
|
||||
* Constants used as default values in the EpubCreator and EpubBook. This is set
|
||||
* according to the EPUB 3 standards.
|
||||
*
|
||||
* @author OpenCollab
|
||||
*/
|
||||
public class EpubConstants {
|
||||
|
||||
private EpubConstants() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to wrap plain text in a valid XHTML document
|
||||
*/
|
||||
public static final String HTML_WRAPPER = "<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title>{0}</title></head><body>{1}</body></html>";
|
||||
|
||||
/**
|
||||
* Template of the OPF file
|
||||
*/
|
||||
public static final String OPF_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
+ "<package xmlns=\"http://www.idpf.org/2007/opf\" version=\"3.0\" unique-identifier=\"uid\">\n"
|
||||
+ " <metadata xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n"
|
||||
+ " <dc:identifier id=\"uid\"></dc:identifier>\n"
|
||||
+ " <dc:title></dc:title>\n"
|
||||
+ " <dc:language></dc:language>\n"
|
||||
+ " <meta property=\"dcterms:modified\"></meta>"
|
||||
+ " </metadata>\n"
|
||||
+ " <manifest>\n"
|
||||
+ " </manifest>\n"
|
||||
+ " <spine>\n"
|
||||
+ " </spine>\n"
|
||||
+ "</package>";
|
||||
|
||||
/**
|
||||
* Template of a valid table of contents navigation(TOC) XHTML document
|
||||
*/
|
||||
public static final String TOC_XML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
|
||||
+ "<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\">\n"
|
||||
+ " <head>\n"
|
||||
+ " <meta charset=\"utf-8\" />\n"
|
||||
+ " <title>{0}</title> \n"
|
||||
+ " </head>\n"
|
||||
+ " <body>\n"
|
||||
+ " <nav epub:type=\"toc\" id=\"toc\">\n"
|
||||
+ " <ol></ol>\n"
|
||||
+ " </nav>\n"
|
||||
+ " <nav epub:type=\"landmarks\" hidden=\"\">\n"
|
||||
+ " <ol></ol>\n"
|
||||
+ " </nav>\n"
|
||||
+ " </body>\n"
|
||||
+ "</html>";
|
||||
|
||||
/**
|
||||
* Template of a valid EPUB3 container XML
|
||||
*/
|
||||
public static final String CONTAINER_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
+ "<container xmlns=\"urn:oasis:names:tc:opendocument:xmlns:container\" version=\"1.0\">\n"
|
||||
+ " <rootfiles>\n"
|
||||
+ " <rootfile full-path=\"{0}/book.opf\" media-type=\"application/oebps-package+xml\"/>\n"
|
||||
+ " </rootfiles>\n"
|
||||
+ "</container>";
|
||||
|
||||
/**
|
||||
* Default folder used to save content in
|
||||
*/
|
||||
public static final String CONTENT_FOLDER = "content";
|
||||
|
||||
/**
|
||||
* The default href of the toc file
|
||||
*/
|
||||
public static final String TOC_FILE_NAME = "toc.xhtml";
|
||||
|
||||
/**
|
||||
* The default href of the opf file
|
||||
*/
|
||||
public static final String OPF_FILE_NAME = "book.opf";
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/* Copyright 2014 OpenCollab.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package coza.opencollab.epub.creator.api;
|
||||
|
||||
import coza.opencollab.epub.creator.model.EpubBook;
|
||||
|
||||
/**
|
||||
* Service to create the Package Document that carries bibliographic and
|
||||
* structural meta data about an EPUB Publication
|
||||
*
|
||||
* @author OpenCollab
|
||||
*/
|
||||
public interface OpfCreator {
|
||||
|
||||
/**
|
||||
* Creates the OPF file text from the EpubBook data
|
||||
*
|
||||
* @param book the ePub book to generate the OPF for
|
||||
* @return the generated OPF markup
|
||||
*/
|
||||
public String createOpfString(EpubBook book);
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/* Copyright 2014 OpenCollab.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package coza.opencollab.epub.creator.api;
|
||||
|
||||
import coza.opencollab.epub.creator.model.Content;
|
||||
import coza.opencollab.epub.creator.model.EpubBook;
|
||||
|
||||
/**
|
||||
* Service to create the EPUB navigation document
|
||||
*
|
||||
* @author OpenCollab
|
||||
*/
|
||||
public interface TocCreator {
|
||||
|
||||
/**
|
||||
* Creates the EPUB TOC navigation document Content object
|
||||
*
|
||||
* @param book the EpubBook to create the TOC for
|
||||
* @return the TOC Content object
|
||||
*/
|
||||
public Content createTocFromBook(EpubBook book);
|
||||
|
||||
}
|
|
@ -0,0 +1,202 @@
|
|||
/* Copyright 2014 OpenCollab.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package coza.opencollab.epub.creator.impl;
|
||||
|
||||
import coza.opencollab.epub.creator.EpubConstants;
|
||||
import coza.opencollab.epub.creator.api.OpfCreator;
|
||||
import coza.opencollab.epub.creator.model.Content;
|
||||
import coza.opencollab.epub.creator.model.EpubBook;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import org.htmlcleaner.CleanerProperties;
|
||||
import org.htmlcleaner.ContentNode;
|
||||
import org.htmlcleaner.HtmlCleaner;
|
||||
import org.htmlcleaner.PrettyXmlSerializer;
|
||||
import org.htmlcleaner.Serializer;
|
||||
import org.htmlcleaner.TagNode;
|
||||
|
||||
/**
|
||||
* Default implementation of the OpfCreator. This follows EPUB3 standards to
|
||||
* create the OPF file content.
|
||||
*
|
||||
* @author OpenCollab
|
||||
*/
|
||||
public class OpfCreatorDefault implements OpfCreator {
|
||||
|
||||
/**
|
||||
* The template XML used to create the OPF file. This is settable if a
|
||||
* different template needs to be used.
|
||||
*/
|
||||
private String opfXML = EpubConstants.OPF_XML;
|
||||
|
||||
/**
|
||||
* HtmlCleaner used to clean the XHTML document
|
||||
*/
|
||||
private final HtmlCleaner cleaner;
|
||||
|
||||
/**
|
||||
* XmlSerializer used to format to XML String output
|
||||
*/
|
||||
private final Serializer htmlSetdown;
|
||||
|
||||
public OpfCreatorDefault() {
|
||||
cleaner = new HtmlCleaner();
|
||||
CleanerProperties htmlProperties = cleaner.getProperties();
|
||||
htmlProperties.setOmitHtmlEnvelope(true);
|
||||
htmlProperties.setAdvancedXmlEscape(false);
|
||||
htmlProperties.setUseEmptyElementTags(true);
|
||||
htmlSetdown = new PrettyXmlSerializer(htmlProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String createOpfString(EpubBook book) {
|
||||
TagNode tagNode = cleaner.clean(opfXML);
|
||||
addMetaDataTags(tagNode, book);
|
||||
addManifestTags(tagNode, book);
|
||||
addSpineTags(tagNode, book);
|
||||
return htmlSetdown.getAsString(tagNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the required meta data
|
||||
*
|
||||
* @param tagNode the HTML tagNode of the OPF template
|
||||
* @param book the EpubBook
|
||||
*/
|
||||
private void addMetaDataTags(TagNode tagNode, EpubBook book) {
|
||||
TagNode metaNode = tagNode.findElementByName("metadata", true);
|
||||
addNodeData(metaNode, "dc:identifier", book.getId());
|
||||
addNodeData(metaNode, "dc:title", book.getTitle());
|
||||
addNodeData(metaNode, "dc:language", book.getLanguage());
|
||||
addNodeData(metaNode, "meta", new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss'Z'").format(new Date()));
|
||||
if (book.getAuthor() != null) {
|
||||
TagNode creatorNode = new TagNode("dc:creator");
|
||||
creatorNode.addChild(new ContentNode(book.getAuthor()));
|
||||
metaNode.addChild(creatorNode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a item tag to the manifest for each Content object.
|
||||
*
|
||||
* The manifest contains all Content that will be added to the EPUB as files
|
||||
*
|
||||
* @param tagNode the HTML tagNode of the OPF template
|
||||
* @param book the EpubBook
|
||||
*/
|
||||
private void addManifestTags(TagNode tagNode, EpubBook book) {
|
||||
TagNode manifestNode = tagNode.findElementByName("manifest", true);
|
||||
for (Content content : book.getContents()) {
|
||||
manifestNode.addChild(buildItemNode(content));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an item tag from the Content object
|
||||
*
|
||||
* @param content
|
||||
* @return
|
||||
*/
|
||||
private TagNode buildItemNode(Content content) {
|
||||
TagNode itemNode = new TagNode("item");
|
||||
itemNode.addAttribute("href", content.getHref());
|
||||
itemNode.addAttribute("id", content.getId());
|
||||
itemNode.addAttribute("media-type", content.getMediaType());
|
||||
if (content.getProperties() != null) {
|
||||
itemNode.addAttribute("properties", content.getProperties());
|
||||
}
|
||||
if (content.hasFallBack()) {
|
||||
itemNode.addAttribute("fallback", content.getFallBack().getId());
|
||||
}
|
||||
return itemNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds item ref tags for all Content objects that must be added to the
|
||||
* spine.
|
||||
*
|
||||
* The spine contains all the resources that will be shown when reading the
|
||||
* book from start to end
|
||||
*
|
||||
* @param tagNode the HTML tagNode of the OPF template
|
||||
* @param book the EpubBook
|
||||
*/
|
||||
private void addSpineTags(TagNode tagNode, EpubBook book) {
|
||||
TagNode spineNode = tagNode.findElementByName("spine", true);
|
||||
for (Content content : book.getContents()) {
|
||||
if (content.isSpine()) {
|
||||
spineNode.addChild(buildItemrefNode(content));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an item ref tag from the Content object
|
||||
*
|
||||
* @param content
|
||||
* @return
|
||||
*/
|
||||
private TagNode buildItemrefNode(Content content) {
|
||||
TagNode itemNode = new TagNode("itemref");
|
||||
itemNode.addAttribute("idref", content.getId());
|
||||
if (!content.isLinear()) {
|
||||
itemNode.addAttribute("linear", "no");
|
||||
}
|
||||
return itemNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a ContentNode (value) with to a child element of the TagNode
|
||||
*
|
||||
* <elementName>{value}<elementName>
|
||||
*
|
||||
* @param tagNode
|
||||
* @param elementName
|
||||
* @param value
|
||||
*/
|
||||
private void addNodeData(TagNode tagNode, String elementName, String value) {
|
||||
TagNode editNode = tagNode.findElementByName(elementName, true);
|
||||
editNode.addChild(new ContentNode(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* The base XML used for the OPF file.
|
||||
*
|
||||
* @return the OPF XML text
|
||||
*/
|
||||
public String getOpfXML() {
|
||||
return opfXML;
|
||||
}
|
||||
|
||||
/**
|
||||
* The base XML used for the OPF file. This is optional as there is a EPUB3
|
||||
* standard default but it can be overridden.
|
||||
*
|
||||
* @param opfXML the OPF XML to set
|
||||
*/
|
||||
public void setOpfXML(String opfXML) {
|
||||
this.opfXML = opfXML;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,220 @@
|
|||
/* Copyright 2014 OpenCollab.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package coza.opencollab.epub.creator.impl;
|
||||
|
||||
import coza.opencollab.epub.creator.EpubConstants;
|
||||
import coza.opencollab.epub.creator.api.TocCreator;
|
||||
import coza.opencollab.epub.creator.model.Content;
|
||||
import coza.opencollab.epub.creator.model.EpubBook;
|
||||
import coza.opencollab.epub.creator.model.Landmark;
|
||||
import coza.opencollab.epub.creator.model.TocLink;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.htmlcleaner.CleanerProperties;
|
||||
import org.htmlcleaner.ContentNode;
|
||||
import org.htmlcleaner.HtmlCleaner;
|
||||
import org.htmlcleaner.PrettyXmlSerializer;
|
||||
import org.htmlcleaner.Serializer;
|
||||
import org.htmlcleaner.TagNode;
|
||||
|
||||
/**
|
||||
* Default implementation of the TocCreator. This follows EPUB3 standards to
|
||||
* create the Navigation Document file content.
|
||||
*
|
||||
* @author OpenCollab
|
||||
*/
|
||||
public class TocCreatorDefault implements TocCreator {
|
||||
|
||||
/**
|
||||
* HtmlCleaner used to alter the XHTML document
|
||||
*/
|
||||
private final HtmlCleaner cleaner;
|
||||
|
||||
private String href = EpubConstants.TOC_FILE_NAME;
|
||||
|
||||
private String tocHtml = EpubConstants.TOC_XML;
|
||||
|
||||
/**
|
||||
* XmlSerializer used to format to XML String output
|
||||
*/
|
||||
private final Serializer htmlSetdown;
|
||||
|
||||
public TocCreatorDefault() {
|
||||
cleaner = new HtmlCleaner();
|
||||
CleanerProperties htmlProperties = cleaner.getProperties();
|
||||
htmlProperties.setOmitHtmlEnvelope(false);
|
||||
htmlProperties.setAdvancedXmlEscape(false);
|
||||
htmlProperties.setUseEmptyElementTags(true);
|
||||
htmlSetdown = new PrettyXmlSerializer(htmlProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Content createTocFromBook(EpubBook book) {
|
||||
List<TocLink> links = book.getTocLinks();
|
||||
if (book.isAutoToc()) {
|
||||
links = generateAutoLinks(book);
|
||||
}
|
||||
List<Landmark> landmarks = book.getLandmarks();
|
||||
String tocString = createTocHtml(links, landmarks, getTocHtml());
|
||||
Content toc = new Content("application/xhtml+xml", getHref(), tocString.getBytes());
|
||||
toc.setProperties("nav");
|
||||
toc.setId("toc");
|
||||
toc.setLinear(false);
|
||||
return toc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the TOC HTML content from the EpubBook TocLinks
|
||||
*
|
||||
* @param book the EpubBook
|
||||
* @return the TOC HTML String
|
||||
*/
|
||||
private String createTocHtml(List<TocLink> links, List<Landmark> landmarks, String tocHtml) {
|
||||
TagNode tagNode = cleaner.clean(tocHtml);
|
||||
if (!CollectionUtils.isEmpty(links)) {
|
||||
addTocLinks(tagNode, links);
|
||||
}
|
||||
if (!CollectionUtils.isEmpty(landmarks)) {
|
||||
addLandmarks(tagNode, landmarks);
|
||||
}
|
||||
return htmlSetdown.getAsString(tagNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive method adding links and sub links to the TOC Navigation
|
||||
* Document
|
||||
*
|
||||
* @param tagNode
|
||||
* @param links
|
||||
*/
|
||||
private void addTocLinks(TagNode tagNode, List<TocLink> links) {
|
||||
TagNode navNode = tagNode.findElementByAttValue("epub:type", "toc", true, false);
|
||||
TagNode parentNode = navNode.findElementByName("ol", true);
|
||||
for (TocLink toc : links) {
|
||||
TagNode linkNode = buildLinkNode(toc);
|
||||
if (!CollectionUtils.isEmpty(toc.getTocChildLinks())) {
|
||||
TagNode olNode = new TagNode("ol");
|
||||
addTocLinks(olNode, toc.getTocChildLinks());
|
||||
linkNode.addChild(olNode);
|
||||
}
|
||||
parentNode.addChild(linkNode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds landmarks to the Navigation Document
|
||||
*
|
||||
* @param tagNode
|
||||
* @param links
|
||||
*/
|
||||
private void addLandmarks(TagNode tagNode, List<Landmark> landmarks) {
|
||||
TagNode navNode = tagNode.findElementByAttValue("epub:type", "landmarks", true, false);
|
||||
TagNode parentNode = navNode.findElementByName("ol", true);
|
||||
for (Landmark landmark : landmarks) {
|
||||
TagNode landmarkNode = buildLandMarkNode(landmark);
|
||||
parentNode.addChild(landmarkNode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an link tag for the TOC
|
||||
*
|
||||
* @param content
|
||||
* @return
|
||||
*/
|
||||
private TagNode buildLinkNode(TocLink link) {
|
||||
TagNode linkNode = new TagNode("li");
|
||||
TagNode aNode = new TagNode("a");
|
||||
aNode.addAttribute("href", link.getHref());
|
||||
aNode.addChild(new ContentNode(link.getTitle()));
|
||||
if (link.getAltTitle() != null) {
|
||||
aNode.addAttribute("title", link.getHref());
|
||||
}
|
||||
linkNode.addChild(aNode);
|
||||
return linkNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an link tag for the TOC landmarks
|
||||
*
|
||||
* @param content
|
||||
* @return
|
||||
*/
|
||||
private TagNode buildLandMarkNode(Landmark landmark) {
|
||||
TagNode linkNode = new TagNode("li");
|
||||
TagNode aNode = new TagNode("a");
|
||||
aNode.addAttribute("href", landmark.getHref());
|
||||
aNode.addAttribute("epub:type", landmark.getType());
|
||||
aNode.addChild(new ContentNode(landmark.getTitle()));
|
||||
linkNode.addChild(aNode);
|
||||
return linkNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a list of TocLinks for all Content that should be included in
|
||||
* the Navigation Document. This will only be used when auto TOC is set
|
||||
*
|
||||
* @param book
|
||||
* @return
|
||||
*/
|
||||
private List<TocLink> generateAutoLinks(EpubBook book) {
|
||||
List<TocLink> links = new ArrayList();
|
||||
for (Content content : book.getContents()) {
|
||||
if (content.isToc()) {
|
||||
links.add(new TocLink(content.getHref(), content.getId(), null));
|
||||
}
|
||||
}
|
||||
return links;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the HREF
|
||||
*/
|
||||
public String getHref() {
|
||||
return href;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param href the HREF to set
|
||||
*/
|
||||
public void setHref(String href) {
|
||||
this.href = href;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the tocHtml
|
||||
*/
|
||||
public String getTocHtml() {
|
||||
return tocHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tocHtml the tocHtml to set
|
||||
*/
|
||||
public void setTocHtml(String tocHtml) {
|
||||
this.tocHtml = tocHtml;
|
||||
}
|
||||
|
||||
}
|
336
src/main/java/coza/opencollab/epub/creator/model/Content.java
Normal file
336
src/main/java/coza/opencollab/epub/creator/model/Content.java
Normal file
|
@ -0,0 +1,336 @@
|
|||
/* Copyright 2014 OpenCollab.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package coza.opencollab.epub.creator.model;
|
||||
|
||||
import coza.opencollab.epub.creator.util.MediaTypeUtil;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
/**
|
||||
* Representation of content in the book
|
||||
*
|
||||
* @author OpenCollab
|
||||
*/
|
||||
public class Content {
|
||||
|
||||
/**
|
||||
* The MediaType get set as the media-type attribute value in the OPF
|
||||
* manifest items
|
||||
*/
|
||||
private String mediaType;
|
||||
|
||||
/**
|
||||
* The HREF get set as the HREF attribute value in the OPF manifest items
|
||||
*/
|
||||
private String href;
|
||||
|
||||
/**
|
||||
* The id get set as the id attribute value in the OPF manifest items and
|
||||
* the id ref in the spine. This must be unique
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* The properties get set as the properties attribute value in the OPF
|
||||
* manifest items. This is used for the TOC and cover-image content objects
|
||||
*/
|
||||
private String properties;
|
||||
|
||||
/**
|
||||
* The file content
|
||||
*/
|
||||
private byte[] content;
|
||||
|
||||
/**
|
||||
* Specifies if it is a linear item in the spine
|
||||
*/
|
||||
private boolean linear = true;
|
||||
|
||||
/**
|
||||
* Specifies if it must be added to the spine
|
||||
*/
|
||||
private boolean spine = true;
|
||||
|
||||
/**
|
||||
* Specifies if it must be added to the TOC (Navigation Document)
|
||||
*/
|
||||
private boolean toc = false;
|
||||
|
||||
/**
|
||||
* The fallback content
|
||||
*/
|
||||
private Content fallBack;
|
||||
|
||||
/**
|
||||
* Creates new instance of Content
|
||||
*
|
||||
* @param mediaType the mime type
|
||||
* @param href the link to the content item
|
||||
* @param content the file byte array
|
||||
*/
|
||||
public Content(String mediaType, String href, byte[] content) {
|
||||
if (mediaType == null) {
|
||||
this.mediaType = MediaTypeUtil.getMediaTypeFromFilename(href);
|
||||
} else {
|
||||
this.mediaType = mediaType;
|
||||
}
|
||||
this.href = href;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new instance of Content
|
||||
*
|
||||
* @param href the link to the content item
|
||||
* @param content the file byte array
|
||||
*/
|
||||
public Content(String href, byte[] content) {
|
||||
this(MediaTypeUtil.getMediaTypeFromFilename(href), href, content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of Content
|
||||
*
|
||||
* @param mediaType the mime type
|
||||
* @param href the link to the content item
|
||||
* @param id used as the id attribute value in the OPF manifest items and
|
||||
* the id ref in the spine
|
||||
* @param properties the properties attribute value in the OPF
|
||||
* @param content the file byte array
|
||||
*/
|
||||
public Content(String mediaType, String href, String id, String properties, byte[] content) {
|
||||
this(mediaType, href, content);
|
||||
this.id = id;
|
||||
this.properties = properties;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of Content
|
||||
*
|
||||
* @param href the link to the content item
|
||||
* @param id used as the id attribute value in the OPF manifest items and
|
||||
* the id ref in the spine
|
||||
* @param properties the properties attribute value in the OPF
|
||||
* @param content the file byte array
|
||||
*/
|
||||
public Content(String href, String id, String properties, byte[] content) {
|
||||
this(MediaTypeUtil.getMediaTypeFromFilename(href), href, id, properties, content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new instance of Content
|
||||
*
|
||||
* @param mediaType the mime type
|
||||
* @param href the link to the content item
|
||||
* @param content the file byte array
|
||||
* @throws java.io.IOException if content could not be converted to byte
|
||||
* array
|
||||
*/
|
||||
public Content(String mediaType, String href, InputStream content) throws IOException {
|
||||
this(mediaType, href, IOUtils.toByteArray(content));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new instance of Content
|
||||
*
|
||||
* @param href the link to the content item
|
||||
* @param content the file byte array
|
||||
* @throws java.io.IOException if content could not be converted to byte
|
||||
* array
|
||||
*/
|
||||
public Content(String href, InputStream content) throws IOException {
|
||||
this(MediaTypeUtil.getMediaTypeFromFilename(href), href, IOUtils.toByteArray(content));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of Content
|
||||
*
|
||||
* @param mediaType the mime type
|
||||
* @param href the link to the content item
|
||||
* @param id used as the id attribute value in the OPF manifest items and
|
||||
* the id ref in the spine
|
||||
* @param properties the properties attribute value in the OPF
|
||||
* @param content the file byte array
|
||||
* @throws java.io.IOException if content could not be converted to byte
|
||||
* array
|
||||
*/
|
||||
public Content(String mediaType, String href, String id, String properties, InputStream content) throws IOException {
|
||||
this(mediaType, href, id, properties, IOUtils.toByteArray(content));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of Content
|
||||
*
|
||||
* @param href the link to the content item
|
||||
* @param id used as the id attribute value in the OPF manifest items and
|
||||
* the id ref in the spine
|
||||
* @param properties the properties attribute value in the OPF
|
||||
* @param content the file byte array
|
||||
* @throws java.io.IOException if content could not be converted to byte
|
||||
* array
|
||||
*/
|
||||
public Content(String href, String id, String properties, InputStream content) throws IOException {
|
||||
this(MediaTypeUtil.getMediaTypeFromFilename(href), href, id, properties, IOUtils.toByteArray(content));
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether a fallback content has been set
|
||||
*
|
||||
* @return the fallback flag
|
||||
*/
|
||||
public boolean hasFallBack() {
|
||||
return fallBack != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the mediaType
|
||||
*/
|
||||
public String getMediaType() {
|
||||
return mediaType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mediaType the mediaType to set
|
||||
*/
|
||||
public void setMediaType(String mediaType) {
|
||||
this.mediaType = mediaType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the HREF
|
||||
*/
|
||||
public String getHref() {
|
||||
return href;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param href the HREF to set
|
||||
*/
|
||||
public void setHref(String href) {
|
||||
this.href = href;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id the id to set
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the properties
|
||||
*/
|
||||
public String getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param properties the properties to set
|
||||
*/
|
||||
public void setProperties(String properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the content
|
||||
*/
|
||||
public byte[] getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param content the content to set
|
||||
*/
|
||||
public void setContent(byte[] content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the linear
|
||||
*/
|
||||
public boolean isLinear() {
|
||||
return linear;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param linear the linear to set
|
||||
*/
|
||||
public void setLinear(boolean linear) {
|
||||
this.linear = linear;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the spine
|
||||
*/
|
||||
public boolean isSpine() {
|
||||
return spine;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param spine the spine to set
|
||||
*/
|
||||
public void setSpine(boolean spine) {
|
||||
this.spine = spine;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the TOC
|
||||
*/
|
||||
public boolean isToc() {
|
||||
return toc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param toc the TOC to set
|
||||
*/
|
||||
public void setToc(boolean toc) {
|
||||
this.toc = toc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the fallBack
|
||||
*/
|
||||
public Content getFallBack() {
|
||||
return fallBack;
|
||||
}
|
||||
|
||||
/**
|
||||
* The spine parameter will be set to false as we do not want to add the
|
||||
* fallback content to the spine. To override default behavior call
|
||||
* getFallBack to set spine property.
|
||||
*
|
||||
* @param fallBack the fallBack to set
|
||||
*/
|
||||
public void setFallBack(Content fallBack) {
|
||||
fallBack.setSpine(false);
|
||||
this.fallBack = fallBack;
|
||||
}
|
||||
|
||||
}
|
429
src/main/java/coza/opencollab/epub/creator/model/EpubBook.java
Normal file
429
src/main/java/coza/opencollab/epub/creator/model/EpubBook.java
Normal file
|
@ -0,0 +1,429 @@
|
|||
/* Copyright 2014 OpenCollab.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package coza.opencollab.epub.creator.model;
|
||||
|
||||
import coza.opencollab.epub.creator.EpubConstants;
|
||||
import coza.opencollab.epub.creator.util.EpubWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Representation of an EPUB book
|
||||
*
|
||||
* @author OpenCollab
|
||||
*/
|
||||
public class EpubBook {
|
||||
|
||||
/**
|
||||
* A list of the the content files, this includes the cover, HTML pages, CSS
|
||||
* JavaScript or any other resource
|
||||
*/
|
||||
private List<Content> contents;
|
||||
/**
|
||||
* Indicates whether the TOC must be created automatically. If this is false
|
||||
* the tocLinks must be set
|
||||
*/
|
||||
private boolean autoToc = true;
|
||||
/**
|
||||
* The 2 letter language code set in the dc:language meta data
|
||||
*/
|
||||
private String language;
|
||||
/**
|
||||
* The id used as the meta data dc:identifier
|
||||
*/
|
||||
private String id;
|
||||
/**
|
||||
* The title of the book
|
||||
*/
|
||||
private String title;
|
||||
/**
|
||||
* The author, this is set as the meta data dc:creator value
|
||||
*/
|
||||
private String author;
|
||||
/**
|
||||
* Unique content id that is incremental set on content with no id
|
||||
*/
|
||||
private int contentId = 1;
|
||||
/**
|
||||
* List of the links that must be added to the TOC, they can be nested
|
||||
*/
|
||||
private List<TocLink> tocLinks;
|
||||
/**
|
||||
* List of the landmarks to be added to the TOC
|
||||
*/
|
||||
private List<Landmark> landmarks;
|
||||
/**
|
||||
* Instance of the EpubWriter to write the book to file or stream
|
||||
*/
|
||||
private final EpubWriter epubCreator;
|
||||
|
||||
/**
|
||||
* Unique set of href's used to make sure we do not add duplicates
|
||||
*/
|
||||
private final Set uniqueHrefs;
|
||||
|
||||
/**
|
||||
* The href can not be repeated in the OPF, thus is we want to add the same
|
||||
* content in more than one place we have to create duplicate Content
|
||||
* objects but with different href's
|
||||
*/
|
||||
private int hrefUniquePostfix = 1;
|
||||
|
||||
/**
|
||||
* Constructs EPUBBook
|
||||
*/
|
||||
public EpubBook() {
|
||||
this.epubCreator = new EpubWriter();
|
||||
this.contents = new ArrayList<>();
|
||||
this.tocLinks = new ArrayList<>();
|
||||
this.uniqueHrefs = new HashSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs EPUBBook
|
||||
*
|
||||
* @param language the 2 letter language code set in the dc:language meta
|
||||
* data
|
||||
* @param id the id used as the meta data dc:identifier
|
||||
* @param title the title of the book
|
||||
* @param author the author, this is set as the meta data dc:creator value
|
||||
*/
|
||||
public EpubBook(String language, String id, String title, String author) {
|
||||
this();
|
||||
this.language = language;
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if href unique, adds postfix if not
|
||||
*
|
||||
* @param content
|
||||
*/
|
||||
private void checkHref(Content content) {
|
||||
content.setHref(removeLeadingFileSeparator(content.getHref()));
|
||||
if (uniqueHrefs.contains(content.getHref())) {
|
||||
content.setHref(incrementHref(content.getHref()));
|
||||
}
|
||||
uniqueHrefs.add(content.getHref());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if href unique, adds postfix if not
|
||||
*
|
||||
* @param href
|
||||
*/
|
||||
private String checkHref(String href) {
|
||||
href = removeLeadingFileSeparator(href);
|
||||
if (uniqueHrefs.contains(href)) {
|
||||
return incrementHref(href);
|
||||
}
|
||||
return href;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment href. Checks for file extensions
|
||||
*
|
||||
* @param href
|
||||
* @return
|
||||
*/
|
||||
private String incrementHref(String href) {
|
||||
if (href.contains(".")) {
|
||||
return href.replace(".", "_" + hrefUniquePostfix++ + ".");
|
||||
}
|
||||
return href + "_" + hrefUniquePostfix++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the leading file separator
|
||||
*
|
||||
* @param href
|
||||
* @return
|
||||
*/
|
||||
private String removeLeadingFileSeparator(String href) {
|
||||
if (href.startsWith("/") || href.startsWith("\\")) {
|
||||
return href.substring(1);
|
||||
}
|
||||
return href;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds content to the content list and checks the id. Only adds unique
|
||||
* href's
|
||||
*
|
||||
* @param content the EpubBook content - TOC, pages, files
|
||||
* @return boolean indicating if the content has been added
|
||||
*/
|
||||
public boolean addContent(Content content) {
|
||||
checkContentId(content);
|
||||
checkHref(content);
|
||||
contents.add(content);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts content at a specific index. Only adds unique href's
|
||||
*
|
||||
* @param content the EpubBook content - TOC, pages, files
|
||||
* @param index index where the content will be inserted
|
||||
* @return boolean indicating if the content has been added
|
||||
*/
|
||||
public boolean insertContent(Content content, int index) {
|
||||
checkContentId(content);
|
||||
checkHref(content);
|
||||
contents.add(index, content);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a String in the HTML wrapper and adds create a content object that
|
||||
* is added to the content list. Returns null if the href is not unique
|
||||
*
|
||||
* @param title the title of the page
|
||||
* @param href used as unique link
|
||||
* @param content text content to be added
|
||||
* @return the Content object generated from the text
|
||||
*/
|
||||
public Content addTextContent(String title, String href, String content) {
|
||||
href = checkHref(href);
|
||||
String contentString = MessageFormat.format(EpubConstants.HTML_WRAPPER, title, content);
|
||||
Content textContent = new Content("application/xhtml+xml", href, contentString.getBytes());
|
||||
addContent(textContent);
|
||||
return textContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and adds file Content to the book
|
||||
*
|
||||
* @param contents the byte array content
|
||||
* @param mediaType the mime type
|
||||
* @param href used as unique link
|
||||
* @param toc flag whether it must be added to the TOC
|
||||
* @param spine flag whether it must be added to the spine
|
||||
* @return a reference to the newly created Content object
|
||||
*/
|
||||
public Content addContent(byte[] contents, String mediaType, String href, boolean toc, boolean spine) {
|
||||
Content content = new Content(mediaType, href, contents);
|
||||
content.setToc(toc);
|
||||
content.setSpine(spine);
|
||||
addContent(content);
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and adds an InputStream to the book
|
||||
*
|
||||
* @param contents the InputStream to the content
|
||||
* @param mediaType the mime type
|
||||
* @param href used as unique link
|
||||
* @param toc flag whether it must be added to the TOC
|
||||
* @param spine flag whether it must be added to the spine
|
||||
* @return a reference to the newly created Content object
|
||||
* @throws java.io.IOException if the InputStream can not be converted to
|
||||
* byte[]
|
||||
*/
|
||||
public Content addContent(InputStream contents, String mediaType, String href, boolean toc, boolean spine) throws IOException {
|
||||
Content content = new Content(mediaType, href, contents);
|
||||
content.setToc(toc);
|
||||
content.setSpine(spine);
|
||||
addContent(content);
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if Content object has an id and adds an unique if not
|
||||
*
|
||||
* @param content
|
||||
*/
|
||||
private void checkContentId(Content content) {
|
||||
if (content.getId() == null) {
|
||||
content.setId(id.replaceAll("[^a-zA-Z0-9\\-]", "_") + "_" + (contentId++));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an file as the cover image
|
||||
*
|
||||
* @param coverImage the cover image
|
||||
* @param mediaType the mime type of the cover image
|
||||
* @param href used to name the cover image
|
||||
*/
|
||||
public void addCoverImage(byte[] coverImage, String mediaType, String href) {
|
||||
Content cover = new Content(mediaType, href, coverImage);
|
||||
cover.setProperties("cover-image");
|
||||
cover.setSpine(false);
|
||||
addContent(cover);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the EPUB zip container and writes it to the OutputStream
|
||||
*
|
||||
* @param out the OutputStream
|
||||
* @throws Exception if the content can not be zipped and written
|
||||
*/
|
||||
public void writeToStream(OutputStream out) throws Exception {
|
||||
epubCreator.writeEpubToStream(this, out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the EPUB zip container and writes it to the File
|
||||
*
|
||||
* @param fileName to store as
|
||||
* @throws Exception if the content can not be zipped and stored
|
||||
*/
|
||||
public void writeToFile(String fileName) throws Exception {
|
||||
epubCreator.writeEpubToFile(this, fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the contents
|
||||
*/
|
||||
public List<Content> getContents() {
|
||||
return contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param contents the content to set
|
||||
*/
|
||||
public void setContents(List<Content> contents) {
|
||||
this.contents = contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the autoToc
|
||||
*/
|
||||
public boolean isAutoToc() {
|
||||
return autoToc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param autoToc the autoToc to set
|
||||
*/
|
||||
public void setAutoToc(boolean autoToc) {
|
||||
this.autoToc = autoToc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the language
|
||||
*/
|
||||
public String getLanguage() {
|
||||
return language;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param language the language to set
|
||||
*/
|
||||
public void setLanguage(String language) {
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id the id to set
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the title
|
||||
*/
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param title the title to set
|
||||
*/
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the tocLinks
|
||||
*/
|
||||
public List<TocLink> getTocLinks() {
|
||||
return tocLinks;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tocLinks the tocLinks to set
|
||||
*/
|
||||
public void setTocLinks(List<TocLink> tocLinks) {
|
||||
this.tocLinks = tocLinks;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the landmarks
|
||||
*/
|
||||
public List<Landmark> getLandmarks() {
|
||||
return landmarks;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param landmarks the landmarks to set
|
||||
*/
|
||||
public void setLandmarks(List<Landmark> landmarks) {
|
||||
this.landmarks = landmarks;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the author
|
||||
*/
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param author the author to set
|
||||
*/
|
||||
public void setAuthor(String author) {
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the epubCreator
|
||||
*/
|
||||
public EpubWriter getEpubCreator() {
|
||||
return epubCreator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the uniqueHrefs
|
||||
*/
|
||||
public Set getUniqueHrefs() {
|
||||
return uniqueHrefs;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/* Copyright 2014 OpenCollab.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package coza.opencollab.epub.creator.model;
|
||||
|
||||
/**
|
||||
* Represents a landmark object in the Navigation document landmarks section
|
||||
*
|
||||
* @author OpenCollab
|
||||
*/
|
||||
public class Landmark {
|
||||
|
||||
/**
|
||||
* The href of the referenced landmark
|
||||
*/
|
||||
private String href;
|
||||
/**
|
||||
* The title to display
|
||||
*/
|
||||
private String title;
|
||||
/**
|
||||
* The type (cover,title-page,frontmatter,bodymatter,backmatter,toc, loi,lot
|
||||
* (list of tables),preface,bibliography,index,glossary,acknowledgments
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* @return the href
|
||||
*/
|
||||
public String getHref() {
|
||||
return href;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param href the href to set
|
||||
*/
|
||||
public void setHref(String href) {
|
||||
this.href = href;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the title
|
||||
*/
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param title the title to set
|
||||
*/
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the type
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type the type to set
|
||||
*/
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
}
|
116
src/main/java/coza/opencollab/epub/creator/model/TocLink.java
Normal file
116
src/main/java/coza/opencollab/epub/creator/model/TocLink.java
Normal file
|
@ -0,0 +1,116 @@
|
|||
/* Copyright 2014 OpenCollab.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package coza.opencollab.epub.creator.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a link in the table of contents, this object can have nested child
|
||||
* links
|
||||
*
|
||||
* @author OpenCollab
|
||||
*/
|
||||
public class TocLink {
|
||||
|
||||
/**
|
||||
* The href
|
||||
*/
|
||||
private String href;
|
||||
|
||||
/**
|
||||
* The displayed text
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* Can be set for accessibility if the pronunciation of a link heading may
|
||||
* be ambiguous due to embedded images, math content, or other content
|
||||
* without intrinsic text. Will be included as an 'title' attribute
|
||||
*/
|
||||
private String altTitle;
|
||||
|
||||
/**
|
||||
* Any nested links
|
||||
*/
|
||||
private List<TocLink> tocChildLinks;
|
||||
|
||||
public TocLink(String href, String title, String altTitle) {
|
||||
this.href = href;
|
||||
this.title = title;
|
||||
this.altTitle = altTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the href
|
||||
*/
|
||||
public String getHref() {
|
||||
return href;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param href the href to set
|
||||
*/
|
||||
public void setHref(String href) {
|
||||
this.href = href;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the title
|
||||
*/
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param title the title to set
|
||||
*/
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the altTitle
|
||||
*/
|
||||
public String getAltTitle() {
|
||||
return altTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param altTitle the altTitle to set
|
||||
*/
|
||||
public void setAltTitle(String altTitle) {
|
||||
this.altTitle = altTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the tocChildLinks
|
||||
*/
|
||||
public List<TocLink> getTocChildLinks() {
|
||||
return tocChildLinks;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tocChildLinks the tocChildLinks to set
|
||||
*/
|
||||
public void setTocChildLinks(List<TocLink> tocChildLinks) {
|
||||
this.tocChildLinks = tocChildLinks;
|
||||
}
|
||||
}
|
217
src/main/java/coza/opencollab/epub/creator/util/EpubWriter.java
Normal file
217
src/main/java/coza/opencollab/epub/creator/util/EpubWriter.java
Normal file
|
@ -0,0 +1,217 @@
|
|||
/* Copyright 2014 OpenCollab.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package coza.opencollab.epub.creator.util;
|
||||
|
||||
import coza.opencollab.epub.creator.EpubConstants;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
import coza.opencollab.epub.creator.api.OpfCreator;
|
||||
import coza.opencollab.epub.creator.api.TocCreator;
|
||||
import coza.opencollab.epub.creator.impl.OpfCreatorDefault;
|
||||
import coza.opencollab.epub.creator.impl.TocCreatorDefault;
|
||||
import coza.opencollab.epub.creator.model.Content;
|
||||
import coza.opencollab.epub.creator.model.EpubBook;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The EpubWriter creates the EPUB zip bundle.
|
||||
*
|
||||
* @author OpenCollab
|
||||
*/
|
||||
public class EpubWriter {
|
||||
|
||||
private String containerXML = EpubConstants.CONTAINER_XML;
|
||||
|
||||
private String contentFolder = EpubConstants.CONTENT_FOLDER;
|
||||
|
||||
private String opfFileName = EpubConstants.OPF_FILE_NAME;
|
||||
|
||||
private OpfCreator opfCreator = new OpfCreatorDefault();
|
||||
|
||||
private TocCreator tocCreator = new TocCreatorDefault();
|
||||
|
||||
/**
|
||||
* Writes the EPUB book zip container and contents to a file
|
||||
*
|
||||
* @param book the EpubBook
|
||||
* @param fileName name of the file to be written
|
||||
* @throws IOException if file could not be written
|
||||
*/
|
||||
public void writeEpubToFile(EpubBook book, String fileName) throws IOException {
|
||||
try (FileOutputStream file = new FileOutputStream(new File(fileName))) {
|
||||
writeEpubToStream(book, file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the EPUB book zip container and contents to an OutputStream
|
||||
*
|
||||
* @param book the EpubBook
|
||||
* @param out the OutputStream to write to
|
||||
* @throws IOException if file could not be written
|
||||
*/
|
||||
public void writeEpubToStream(EpubBook book, OutputStream out) throws IOException {
|
||||
try (ZipOutputStream resultStream = new ZipOutputStream(out)) {
|
||||
List<Content> contents = book.getContents();
|
||||
addMimeType(resultStream);
|
||||
contents.add(0, getTocCreator().createTocFromBook(book));
|
||||
addStringToZip(resultStream, "META-INF/container.xml", MessageFormat.format(containerXML, contentFolder));
|
||||
addStringToZip(resultStream, contentFolder + "/" + getOpfFileName(), getOpfCreator().createOpfString(book));
|
||||
addContent(resultStream, contents);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the zip/EPUB mime type to the EPUB zip file
|
||||
*
|
||||
* @param resultStream
|
||||
* @throws IOException
|
||||
*/
|
||||
private void addMimeType(ZipOutputStream resultStream) throws IOException {
|
||||
ZipEntry mimetypeZipEntry = new ZipEntry("mimetype");
|
||||
mimetypeZipEntry.setMethod(ZipEntry.STORED);
|
||||
byte[] mimetypeBytes = "application/epub+zip".getBytes("UTF-8");
|
||||
mimetypeZipEntry.setSize(mimetypeBytes.length);
|
||||
mimetypeZipEntry.setCrc(calculateCrc(mimetypeBytes));
|
||||
resultStream.putNextEntry(mimetypeZipEntry);
|
||||
resultStream.write(mimetypeBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the CRC32 of data for the zip entry
|
||||
*
|
||||
* @param data
|
||||
* @return
|
||||
*/
|
||||
private long calculateCrc(byte[] data) {
|
||||
CRC32 crc = new CRC32();
|
||||
crc.update(data);
|
||||
return crc.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds string content as an zip entry with the specified file name
|
||||
*
|
||||
* @param resultStream
|
||||
* @param fileName
|
||||
* @param content
|
||||
* @throws IOException
|
||||
*/
|
||||
private void addStringToZip(ZipOutputStream resultStream, String fileName, String content) throws IOException {
|
||||
resultStream.putNextEntry(new ZipEntry(fileName));
|
||||
Writer out = new OutputStreamWriter(resultStream, "UTF-8");
|
||||
out.write(content);
|
||||
out.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the content objects zip entries
|
||||
*
|
||||
* @param resultStream
|
||||
* @param contents
|
||||
* @throws IOException
|
||||
*/
|
||||
private void addContent(ZipOutputStream resultStream, List<Content> contents) throws IOException {
|
||||
for (Content content : contents) {
|
||||
resultStream.putNextEntry(new ZipEntry(contentFolder + "/" + content.getHref()));
|
||||
resultStream.write(content.getContent());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the CONTAINER_XML
|
||||
*/
|
||||
public String getContainerXML() {
|
||||
return containerXML;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param containerXML the CONTAINER_XML to set
|
||||
*/
|
||||
public void setContainerXML(String containerXML) {
|
||||
this.containerXML = containerXML;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the CONTENT_FOLDER
|
||||
*/
|
||||
public String getContentFolder() {
|
||||
return contentFolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param contentFolder the CONTENT_FOLDER to set
|
||||
*/
|
||||
public void setContentFolder(String contentFolder) {
|
||||
this.contentFolder = contentFolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the OPF_FILE_NAME
|
||||
*/
|
||||
public String getOpfFileName() {
|
||||
return opfFileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param opfFileName the OPF_FILE_NAME to set
|
||||
*/
|
||||
public void setOpfFileName(String opfFileName) {
|
||||
this.opfFileName = opfFileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the opfCreator
|
||||
*/
|
||||
public OpfCreator getOpfCreator() {
|
||||
return opfCreator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param opfCreator the opfCreator to set
|
||||
*/
|
||||
public void setOpfCreator(OpfCreator opfCreator) {
|
||||
this.opfCreator = opfCreator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the tocCreator
|
||||
*/
|
||||
public TocCreator getTocCreator() {
|
||||
return tocCreator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tocCreator the tocCreator to set
|
||||
*/
|
||||
public void setTocCreator(TocCreator tocCreator) {
|
||||
this.tocCreator = tocCreator;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright 2014 OpenCollab.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package coza.opencollab.epub.creator.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Used to map file extensions to Mime types from a properties file
|
||||
*
|
||||
* @author OpenCollab
|
||||
*/
|
||||
public class MediaTypeUtil {
|
||||
|
||||
private static Map<String, String> mediaTypeMap = setMediaFromProperties();
|
||||
|
||||
/**
|
||||
* Created a map of media types for specific file extensions, read from the
|
||||
* epub-mediatypes.properties file
|
||||
*
|
||||
* @return a map of all the media types in the properties file
|
||||
*/
|
||||
private static Map<String, String> setMediaFromProperties() {
|
||||
Properties properties = new Properties();
|
||||
try {
|
||||
properties.load(MediaTypeUtil.class.getClassLoader().getResourceAsStream("epub-mediatypes.properties"));
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(MediaTypeUtil.class.getName()).log(Level.SEVERE,
|
||||
"Could not read the 'epub-mediatypes.properties' file to populate the media types. "
|
||||
+ "Please use MediaTypeUtil.setMediaTypeMap(Map<String, String> aMediaTypeMap) to set the map.", ex);
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
Map<String, String> mappings = new HashMap<>();
|
||||
|
||||
Enumeration elements = properties.propertyNames();
|
||||
while (elements.hasMoreElements()) {
|
||||
String keyProps = (String) elements.nextElement();
|
||||
String valProps = properties.getProperty(keyProps);
|
||||
mappings.put(keyProps, valProps);
|
||||
}
|
||||
return mappings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the correct media type for a specific file extension
|
||||
*
|
||||
* @param ext the file extension
|
||||
* @return the mime type
|
||||
*/
|
||||
public static String getMediaTypeFromExt(String ext) {
|
||||
return mediaTypeMap.get(ext.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the correct media type for a specific file name
|
||||
*
|
||||
* @param fileName the full filename
|
||||
* @return the mime type
|
||||
*/
|
||||
public static String getMediaTypeFromFilename(String fileName) {
|
||||
String ext = fileName.substring(fileName.lastIndexOf(".") + 1);
|
||||
return getMediaTypeFromExt(ext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to override the media type map
|
||||
*
|
||||
* @param aMediaTypeMap the mediaTypeMap to set
|
||||
*/
|
||||
public static void setMediaTypeMap(Map<String, String> aMediaTypeMap) {
|
||||
mediaTypeMap = aMediaTypeMap;
|
||||
}
|
||||
|
||||
}
|
51
src/main/resources/epub-mediatypes.properties
Normal file
51
src/main/resources/epub-mediatypes.properties
Normal file
|
@ -0,0 +1,51 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright 2014 OpenCollab.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
# Mapping of file extensions to the correct media type, this file will be used
|
||||
# in MediaTypeUtil
|
||||
|
||||
xhtml=application/xhtml+xml
|
||||
html=application/xhtml+xml
|
||||
htm=application/xhtml+xml
|
||||
jpg=image/jpeg
|
||||
jpeg=image/jpeg
|
||||
gif=image/gif
|
||||
png=image/png
|
||||
svg=image/svg+xml
|
||||
ncx=application/x-dtbncx+xml
|
||||
otf=application/vnd.ms-opentype
|
||||
woff=application/font-woff
|
||||
smil=application/smil+xml
|
||||
pls=application/pls+xml
|
||||
mp3=audio/mpeg
|
||||
mp4=audio/mp4
|
||||
css=text/css
|
||||
js=text/javascript
|
||||
epub=application/epub+zip
|
||||
tff=application/x-truetype-font
|
||||
ogg=audio/ogg
|
||||
xpgt=application/adobe-page-template+xml
|
||||
pdf=application/pdf
|
||||
docx=application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
||||
doc=application/msword
|
||||
xls=application/vnd.ms-excel
|
||||
xlsx=application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
|
@ -0,0 +1,41 @@
|
|||
package coza.opencollab.epub.creator;
|
||||
|
||||
import coza.opencollab.epub.creator.model.EpubBook;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import junit.framework.Assert;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author OpenCollab
|
||||
*/
|
||||
public class EpubCreatorTest {
|
||||
|
||||
@Test
|
||||
public void testEpubCreate() {
|
||||
try (FileOutputStream file = new FileOutputStream(new File("test.epub"))) {
|
||||
EpubBook book = new EpubBook("en", "Samuel .-__Id1", "Samuel Test Book", "Samuel Holtzkampf");
|
||||
|
||||
book.addContent(this.getClass().getResourceAsStream("/epub30-overview.xhtml"),
|
||||
"application/xhtml+xml", "xhtml/epub30-overview.xhtml", true, true).setId("Overview");
|
||||
book.addContent(this.getClass().getResourceAsStream("/idpflogo_web_125.jpg"),
|
||||
"image/jpeg", "img/idpflogo_web_125.jpg", false, false);
|
||||
book.addContent(this.getClass().getResourceAsStream("/epub-spec.css"),
|
||||
"text/css", "css/epub-spec.css", false, false);
|
||||
book.addTextContent("TestHtml", "xhtml/samuelTest2.xhtml", "Samuel test one two four!!!!!\nTesting two").setToc(true);
|
||||
book.addTextContent("TestHtml", "xhtml/samuelTest.xhtml", "Samuel test one two three\nTesting two").setToc(true);
|
||||
book.addCoverImage(IOUtils.toByteArray(this.getClass().getResourceAsStream("/P1010832.jpg")),
|
||||
"image/jpeg", "images/P1010832.jpg");
|
||||
|
||||
|
||||
book.writeToStream(file);
|
||||
// TODO : real tests to see if document correct, this is just to test that creation is succesfull
|
||||
Assert.assertEquals("test", "test");
|
||||
} catch (Exception ex) {
|
||||
System.out.println(ex);
|
||||
Assert.assertEquals("test", "test1");
|
||||
}
|
||||
}
|
||||
}
|
BIN
src/test/resources/P1010832.jpg
Normal file
BIN
src/test/resources/P1010832.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 88 KiB |
581
src/test/resources/epub-spec.css
Normal file
581
src/test/resources/epub-spec.css
Normal file
|
@ -0,0 +1,581 @@
|
|||
@charset "utf-8";
|
||||
|
||||
body {
|
||||
margin-top: 2em;
|
||||
margin-left: 6em;
|
||||
margin-right: 15em;
|
||||
margin-bottom: 2em;
|
||||
font-family: arial, helvetica, sans-serif;
|
||||
color: black;
|
||||
background: white;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
/* dl **************************************************************/
|
||||
/***************************************************************************/
|
||||
|
||||
dl dt {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
dt span.term {
|
||||
color: #005A9C;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
dd > dl {
|
||||
margin-top: 1px;
|
||||
padding-top: 0px;
|
||||
margin-bottom: 1px;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
/* ul **************************************************************/
|
||||
/***************************************************************************/
|
||||
|
||||
ul.conformance-list li {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
/* glosslist *********************************************************/
|
||||
/***************************************************************************/
|
||||
|
||||
*.glosslist dl {
|
||||
margin-left: 2em
|
||||
}
|
||||
*.glosslist dl dt {
|
||||
color: #005A9C
|
||||
}
|
||||
|
||||
*.glossentry {
|
||||
font-size: .9em;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
/* misc block ********************************************************/
|
||||
/***************************************************************************/
|
||||
|
||||
p.informative, p.normative {
|
||||
font-weight: bold;
|
||||
font-size: 100%;
|
||||
color: #8B0000;
|
||||
padding: 5px 0px 10px;
|
||||
}
|
||||
|
||||
.biblioentry:target {
|
||||
border: 1px dashed rgb(200,200,225);
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************/
|
||||
/* misc inline *******************************************************/
|
||||
/***************************************************************************/
|
||||
|
||||
code, span.property, a.codelink {
|
||||
color: #660099;
|
||||
font-family: monospace;
|
||||
font-weight: bold
|
||||
}
|
||||
*.RFC2119 {
|
||||
font-style: italic;
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
*.todo, *.TODO {
|
||||
background-color: yellow
|
||||
}
|
||||
|
||||
/* vocab */
|
||||
*.subproplabel, *.subpropref {
|
||||
font-style: italic;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
/* elem-synopsis ****************************************************/
|
||||
/***************************************************************************/
|
||||
|
||||
*.elem-synopsis {
|
||||
border: 1px solid rgb(200,200,225);
|
||||
border-top: 1px solid rgb(210,210,245);
|
||||
border-left: 1px solid rgb(210,210,245);
|
||||
background: rgb(240,240,255);
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
margin-bottom: 2em;
|
||||
-moz-box-shadow: 5px 5px 5px #888;
|
||||
-webkit-box-shadow: 5px 5px 5px #888;
|
||||
}
|
||||
|
||||
/* special case for the code.option fields in elem-synopsis */
|
||||
code.option {
|
||||
color: black;
|
||||
font-family: arial, helvetica, sans-serif;
|
||||
font-weight: normal
|
||||
}
|
||||
/* for the special case when an attlist occurs outside of an elem-synopsis*/
|
||||
div.section > div.elem-synopsis-attlist {
|
||||
border: 2px solid rgb(200,200,225);
|
||||
background: rgb(230,230,255);
|
||||
padding: 1em
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************/
|
||||
/* toc ***************************************************************/
|
||||
/***************************************************************************/
|
||||
|
||||
div.toc dl dt {
|
||||
font-weight: normal
|
||||
}
|
||||
|
||||
*.toc p, div.list-of-examples p {
|
||||
font: small-caps 105% sans-serif;
|
||||
color: #005A9C;
|
||||
}
|
||||
|
||||
*.toc {
|
||||
margin-top: 3em
|
||||
}
|
||||
|
||||
nav#toc li {
|
||||
list-style-type:none;
|
||||
}
|
||||
|
||||
nav#toc > ol > li > span > a {
|
||||
color: #0000ff
|
||||
}
|
||||
nav#toc > ol > li > ol > li > a {
|
||||
color: #0033ff
|
||||
}
|
||||
nav#toc > ol > li > ol > li > ol > li > a {
|
||||
font-size: .9em;
|
||||
color: #0066ff;
|
||||
}
|
||||
nav#toc > ol > li > ol > li > ol > li > ol > li > a {
|
||||
font-size: .9em;
|
||||
color: #0099ff
|
||||
}
|
||||
nav#toc > ol > li > ol > li > ol > li > ol > li > ol > li > a {
|
||||
font-size: .9em;
|
||||
color: #0099ff
|
||||
}
|
||||
nav#toc > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > a {
|
||||
font-size: .9em;
|
||||
color: #0099ff
|
||||
}
|
||||
|
||||
nav#toc > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > a {
|
||||
font-size: .9em;
|
||||
color: #0099ff
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
/* examples **********************************************************/
|
||||
/***************************************************************************/
|
||||
|
||||
div.informalexample {
|
||||
margin: 1.5em auto 2em auto;
|
||||
}
|
||||
|
||||
div.informalexample > p {
|
||||
margin: 0px 20px;
|
||||
font-style: italic;
|
||||
font-size: .8em
|
||||
}
|
||||
|
||||
div.informalexample > p code {
|
||||
color: black;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: "Courier New", Courier, Monospace;
|
||||
color: #000;
|
||||
background-color: #eee;
|
||||
margin: 0;
|
||||
border: 1px solid #ddd;
|
||||
padding: 9px;
|
||||
overflow: auto;
|
||||
white-space: pre-wrap;
|
||||
white-space: -moz-pre-wrap !important;
|
||||
white-space: -pre-wrap;
|
||||
white-space: -o-pre-wrap;
|
||||
word-wrap: break-word;
|
||||
|
||||
}
|
||||
|
||||
pre.synopsis, p.syntax {
|
||||
background-color:rgb(253,253,253);
|
||||
border: 1px solid rgb(220,220,220);
|
||||
border-left: 1px solid rgb(230,230,230);
|
||||
border-top: 1px solid rgb(230,230,230);
|
||||
margin-bottom: 1em;
|
||||
-moz-box-shadow: 5px 5px 5px #888;
|
||||
-webkit-box-shadow: 5px 5px 5px #888;
|
||||
-box-shadow: 5px 5px 5px #888;
|
||||
}
|
||||
|
||||
p.syntax {
|
||||
font-family: courier, fixed, monospace;
|
||||
padding: 9px;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
/* note, caution *****************************************************/
|
||||
/***************************************************************************/
|
||||
|
||||
.caution .note {
|
||||
font-style : italic;
|
||||
font-size : .9em;
|
||||
}
|
||||
|
||||
div.note, div.caution {
|
||||
margin: 2em 1em;
|
||||
border: solid gray 1px;
|
||||
background-color: rgb(255,255,224);
|
||||
padding: .5em
|
||||
}
|
||||
|
||||
|
||||
div.caution {
|
||||
background-color: rgb(255,235,205)
|
||||
}
|
||||
|
||||
div.note > *, div.caution > * {
|
||||
/* margin: .25em 0em;
|
||||
padding: 0em; */
|
||||
}
|
||||
|
||||
div.note > h2, div.note > h3, div.note > h4, div.note > h5,
|
||||
div.caution > h2, div.caution > h3, div.caution > h4, div.caution > h5 {
|
||||
font-size: 1em;
|
||||
font-style: italic;
|
||||
font-variant: small-caps;
|
||||
float: left;
|
||||
padding: .18em .6em .18em .5em;
|
||||
margin: -1em -0.5em -0.5em auto;
|
||||
width: auto;
|
||||
border: solid 1px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
/* headings ************************************************************/
|
||||
/***************************************************************************/
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
text-align: left;
|
||||
color: #005A9C;
|
||||
}
|
||||
h1 {
|
||||
font: 170% sans-serif;
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
h2 {
|
||||
font: 140% sans-serif;
|
||||
padding-top: 2em;
|
||||
border-bottom: 1px solid #005A9C
|
||||
}
|
||||
h3 {
|
||||
font: 120% sans-serif;
|
||||
padding-top: 1.5em;
|
||||
}
|
||||
h4 {
|
||||
font: bold 110% sans-serif;
|
||||
padding-top: 1.2em;
|
||||
}
|
||||
h5 {
|
||||
font: italic 105% sans-serif
|
||||
}
|
||||
h6 {
|
||||
font: italic 100% sans-serif
|
||||
}
|
||||
p.bridgehead {
|
||||
font: 110% sans-serif;
|
||||
padding-top: 0.7em;
|
||||
color: #005A9C;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************/
|
||||
/* links *******************************************************************/
|
||||
/***************************************************************************/
|
||||
|
||||
a.glossterm {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
border-bottom : 1px dotted rgb(210,210,210);
|
||||
}
|
||||
a.biblioref {
|
||||
color: #0000FF;
|
||||
text-decoration: none;
|
||||
}
|
||||
a.glossterm:hover, a.biblioref:hover {
|
||||
text-decoration: underline;
|
||||
background-color: white;
|
||||
color: #0000FF;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
/* "link here" anchor *****************************************************/
|
||||
/***************************************************************************/
|
||||
|
||||
a.hidden-reveal {
|
||||
color: #005A9C;
|
||||
}
|
||||
a.hidden-reveal:link {
|
||||
text-decoration: none;
|
||||
color: #005A9C;
|
||||
}
|
||||
a.hidden-reveal:visited {
|
||||
text-decoration: none;
|
||||
color: #005A9C;
|
||||
}
|
||||
a.hidden-reveal:hover {
|
||||
text-decoration: underline;
|
||||
background-color: #005A9C;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
a.hidden-reveal:active {
|
||||
text-decoration: none;
|
||||
color: #005A9C;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
/* frontmatter ********************************************************/
|
||||
/***************************************************************************/
|
||||
|
||||
*.releaseinfo {
|
||||
font-size: 140%;
|
||||
color: #005A9C;
|
||||
margin-right: 0.4em
|
||||
}
|
||||
*.pubdate {
|
||||
font-size: 140%;
|
||||
color: #005A9C
|
||||
}
|
||||
*.legalnotice {
|
||||
font-size: 90%
|
||||
}
|
||||
dl.printhistory {
|
||||
margin-top: 2em;
|
||||
margin-bottom: 2em
|
||||
}
|
||||
dl.printhistory dt {
|
||||
font: small-caps 105% sans-serif;
|
||||
color: #005A9C;
|
||||
margin-top: 0.4em;
|
||||
margin-bottom: 0.4em
|
||||
}
|
||||
div.authorgroup p.editor {
|
||||
margin-left: 2em;
|
||||
font-size: 90%
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
/* table *************************************************************/
|
||||
/***************************************************************************/
|
||||
|
||||
table {
|
||||
border: 1px solid #005A9C;
|
||||
border-spacing: 0px;
|
||||
padding: 1em;
|
||||
margin-top: 1.5em;
|
||||
margin-bottom: 2em;
|
||||
-moz-box-shadow: 2px 2px 2px rgb(240,240,240);
|
||||
-webkit-box-shadow: 2px 2px 2px rgb(190,190,190);
|
||||
-box-shadow: 2px 2px 2px rgb(190,190,190);
|
||||
}
|
||||
th {
|
||||
border: 1px solid #005A9C;
|
||||
font-weight: bold;
|
||||
padding: 0.5em;
|
||||
font-weight: bold;
|
||||
color: #005A9C;
|
||||
font-size: 90%
|
||||
}
|
||||
td {
|
||||
border: 1px solid #005A9C;
|
||||
padding: 0.5em;
|
||||
text-align: left
|
||||
}
|
||||
td *, td > * {
|
||||
text-align: left;
|
||||
}
|
||||
table, tbody {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
caption {
|
||||
text-align: left;
|
||||
font-size: 90%
|
||||
}
|
||||
/* the xsl renders db:simplelist as single-column tables */
|
||||
table.simplelist, table.simplelist th, table.simplelist td, table.simplelist tr {
|
||||
border-style: none;
|
||||
-moz-box-shadow: none;
|
||||
-webkit-box-shadow: none;
|
||||
-box-shadow: none;
|
||||
}
|
||||
|
||||
/* ensure confomity of width for property tables */
|
||||
div.informaltable > table {
|
||||
border-spacing: 0px;
|
||||
border: 1px solid rgb(210,210,225);
|
||||
font-size: 1em;
|
||||
width: 100%
|
||||
}
|
||||
|
||||
div.informaltable > table td, div.informaltable > table th {
|
||||
border: none;
|
||||
}
|
||||
|
||||
div.informaltable > table td.rdfa-property {
|
||||
padding: 3px;
|
||||
text-indent: 15px;
|
||||
color: rgb(0,90,156);
|
||||
background-color: rgb(240,240,255);
|
||||
border-bottom: 1px solid rgb(210,210,225);
|
||||
}
|
||||
td.rdfa-property > code {
|
||||
color: rgb(0,50,116);
|
||||
font-weight: bold;
|
||||
font-size: 1.1em
|
||||
}
|
||||
div.informaltable > table td.rdfa-property-header {
|
||||
width: 150px;
|
||||
text-align: center;
|
||||
padding: 3px;
|
||||
border-right: 1px solid rgb(210,210,225);
|
||||
color: rgb(0,90,156);
|
||||
background-color: rgb(240,240,255);
|
||||
}
|
||||
td.rdfa-property-desc {
|
||||
padding: 3px
|
||||
}
|
||||
|
||||
td.rdfa-cardinality > p {
|
||||
padding: 0em;
|
||||
margin: 0em
|
||||
}
|
||||
|
||||
/* the core media types table */
|
||||
table#tbl-core-media-types > thead > tr > th,
|
||||
table#tbl-epubReadingSystem-properties > thead > tr > th,
|
||||
table#tbl-epubReadingSystem-features > thead > tr > th {
|
||||
background-color: rgb(240,240,255);
|
||||
text-align: left;
|
||||
white-space:nowrap;
|
||||
}
|
||||
|
||||
table#tbl-core-media-types > tbody > tr > th {
|
||||
text-align: left;
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
table#tbl-core-media-types td, table#tbl-core-media-types th, table#tbl-core-media-types tr {
|
||||
border-color: #005A9C;
|
||||
margin: 0em;
|
||||
}
|
||||
|
||||
table#tbl-core-media-types td code, table#tbl-core-media-types td a {
|
||||
white-space:nowrap;
|
||||
}
|
||||
|
||||
table.productionset, table.productionset td {
|
||||
border : none;
|
||||
background-color : #EEE;
|
||||
}
|
||||
|
||||
td[headers="tbl-cmt-appl"] {
|
||||
font-size: .9em;
|
||||
}
|
||||
|
||||
/* ns prefix table in contentdocs */
|
||||
table#tbl-nspfx {
|
||||
border:none;
|
||||
border-spacing: 0px;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
span.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
span.link-marker {
|
||||
float: left;
|
||||
}
|
||||
|
||||
/* display prop examples as block */
|
||||
|
||||
code.prop-example {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* participant listings */
|
||||
ul.personlist {
|
||||
list-style-type: none;
|
||||
padding-left: 1em;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
*.personlist span.affiliation {
|
||||
color: rgb(75,75,75);
|
||||
}
|
||||
|
||||
*.personlist span.wg-role {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/*
|
||||
span.surname {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
*/
|
||||
|
||||
table.productionset tbody tr {
|
||||
border: none;
|
||||
}
|
||||
|
||||
table.productionset tbody tr td {
|
||||
border: none;
|
||||
border-bottom: 1px solid #CCC;
|
||||
}
|
||||
|
||||
table.productionset tbody tr td a {
|
||||
text-decoration: none;
|
||||
border-bottom: 1px dotted #0000ff;
|
||||
}
|
||||
|
||||
table.productionset tbody tr td a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
table.productionset tbody tr td a:visited,
|
||||
table.productionset tbody tr td a:active,
|
||||
table.productionset tbody tr td a:hover {
|
||||
color: #0000ff;
|
||||
}
|
||||
|
||||
|
||||
p.diff, p.errata {
|
||||
font-size: 0.9em;
|
||||
font-style: italic
|
||||
}
|
||||
|
||||
code {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
div.informalexample > p code {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
/* vocab experimental term labels */
|
||||
strong.experimental {
|
||||
color: rgb(255,0,0)
|
||||
}
|
11
src/test/resources/epub30-overview.xhtml
Normal file
11
src/test/resources/epub30-overview.xhtml
Normal file
File diff suppressed because one or more lines are too long
333
src/test/resources/epub30-publications.xhtml
Normal file
333
src/test/resources/epub30-publications.xhtml
Normal file
File diff suppressed because one or more lines are too long
11
src/test/resources/epub30-terminology.xhtml
Normal file
11
src/test/resources/epub30-terminology.xhtml
Normal file
File diff suppressed because one or more lines are too long
BIN
src/test/resources/epub_logo_color.jpg
Normal file
BIN
src/test/resources/epub_logo_color.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 131 KiB |
BIN
src/test/resources/idpflogo_web_125.jpg
Normal file
BIN
src/test/resources/idpflogo_web_125.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
Loading…
Reference in a new issue