EPUB export + a bugfix

git-svn-id: svn://svn.code.sf.net/p/writer2latex/code/trunk@56 f0f2a975-2e09-46c8-9428-3b39399b9f3c
This commit is contained in:
henrikjust 2010-03-31 07:25:24 +00:00
parent ce61f7bc3b
commit 7644cf2eba
14 changed files with 122 additions and 81 deletions

View file

@ -20,7 +20,7 @@
*
* All Rights Reserved.
*
* Version 1.2 (2010-03-29)
* Version 1.2 (2010-03-31)
*
*/
@ -33,7 +33,7 @@ public class ConverterFactory {
// Version information
private static final String VERSION = "1.1.2";
private static final String DATE = "2010-03-29";
private static final String DATE = "2010-03-31";
/** Return the Writer2LaTeX version in the form
* (major version).(minor version).(patch level)<br/>

View file

@ -38,11 +38,11 @@ import org.w3c.dom.Element;
import writer2latex.xmerge.NewDOMDocument;
/** This class creates the required META-INF/container.xml file for an EPUB package
* (see http://www.idpf.org/ocf/ocf1.0/download/ocf10.htm)
* (see http://www.idpf.org/ocf/ocf1.0/download/ocf10.htm).
*/
public class ContainerWriter extends NewDOMDocument {
public ContainerWriter(String sRootFile) {
public ContainerWriter() {
super("container", "xml");
// create DOM
@ -67,7 +67,7 @@ public class ContainerWriter extends NewDOMDocument {
container.appendChild(rootfiles);
Element rootfile = contentDOM.createElement("rootfile");
rootfile.setAttribute("full-path", sRootFile);
rootfile.setAttribute("full-path", "OEBPS/book.opf");
rootfile.setAttribute("media-type", "application/oebps-package+xml");
rootfiles.appendChild(rootfile);

View file

@ -44,6 +44,7 @@ public final class EPUBConverter extends Xhtml11Converter {
}
@Override public ConverterResult convert(InputStream is, String sTargetFileName) throws IOException {
setOPS(true);
ConverterResult xhtmlResult = super.convert(is, sTargetFileName);
ConverterResultImpl epubResult = new ConverterResultImpl();

View file

@ -20,7 +20,7 @@
*
* All Rights Reserved.
*
* version 1.2 (2010-03-29)
* version 1.2 (2010-03-31)
*
*/
@ -30,6 +30,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@ -37,8 +38,9 @@ import writer2latex.api.ConverterResult;
import writer2latex.api.OutputFile;
import writer2latex.util.Misc;
/** This class repackages an XHTML document into EPUB format
*
/** This class repackages an XHTML document into EPUB format.
* Some filenames are hard wired in this implementation: The main directory is OEBPS and
* the OPF and NCX files are book.opf and book.ncx respectively
*/
public class EPUBWriter implements OutputFile {
@ -66,9 +68,12 @@ public class EPUBWriter implements OutputFile {
}
public void write(OutputStream os) throws IOException {
// Create a universal unique ID
String sUUID = UUID.randomUUID().toString();
ZipOutputStream zos = new ZipOutputStream(os);
// Write MIME type as first entry
// Write uncompressed MIME type as first entry
ZipEntry mimeEntry = new ZipEntry("mimetype");
mimeEntry.setMethod(ZipEntry.STORED);
mimeEntry.setCrc(0x2CAB616F);
@ -78,27 +83,27 @@ public class EPUBWriter implements OutputFile {
zos.closeEntry();
// Write container entry next
OutputFile containerWriter = new ContainerWriter("OEBPS/book.opf");
OutputFile containerWriter = new ContainerWriter();
ZipEntry containerEntry = new ZipEntry("META-INF/container.xml");
zos.putNextEntry(containerEntry);
writeZipEntry(containerWriter,zos);
zos.closeEntry();
// Then manifest
OutputFile manifest = new OPFWriter(xhtmlResult, "xxx", "book.ncx", "book.opf");
OutputFile manifest = new OPFWriter(xhtmlResult, sUUID);
ZipEntry manifestEntry = new ZipEntry("OEBPS/book.opf");
zos.putNextEntry(manifestEntry);
writeZipEntry(manifest,zos);
zos.closeEntry();
// And content table
OutputFile ncx = new NCXWriter(xhtmlResult, "xxx", "book.ncx");
OutputFile ncx = new NCXWriter(xhtmlResult, sUUID);
ZipEntry ncxEntry = new ZipEntry("OEBPS/book.ncx");
zos.putNextEntry(ncxEntry);
writeZipEntry(ncx,zos);
zos.closeEntry();
// Finally XHTML content in the OEBPS sub directory
// Finally XHTML content
Iterator<OutputFile> iter = xhtmlResult.iterator();
while (iter.hasNext()) {
OutputFile file = iter.next();

View file

@ -20,7 +20,7 @@
*
* All Rights Reserved.
*
* version 1.2 (2010-03-29)
* version 1.2 (2010-03-30)
*
*/
@ -39,17 +39,15 @@ import org.w3c.dom.Element;
import writer2latex.api.ContentEntry;
import writer2latex.api.ConverterResult;
import writer2latex.util.Misc;
import writer2latex.xmerge.NewDOMDocument;
/** This class creates the required NXC file for an EPUB document
* (see http://www.idpf.org/2007/opf/OPF_2.0_final_spec.html#Section2.4)
*
* (see http://www.idpf.org/2007/opf/OPF_2.0_final_spec.html#Section2.4).
*/
public class NCXWriter extends NewDOMDocument {
public NCXWriter(ConverterResult cr, String sUUID, String sFileName) {
super(Misc.removeExtension(sFileName), "ncx");
public NCXWriter(ConverterResult cr, String sUUID) {
super("book", "ncx");
// create DOM
Document contentDOM = null;
@ -64,8 +62,6 @@ public class NCXWriter extends NewDOMDocument {
throw new RuntimeException(t);
}
System.out.println("populating the ncx");
// Populate the DOM tree
Element ncx = contentDOM.getDocumentElement();
ncx.setAttribute("version", "2005-1");
@ -83,7 +79,7 @@ public class NCXWriter extends NewDOMDocument {
Element depth = contentDOM.createElement("meta");
depth.setAttribute("name","dtb:depth");
depth.setAttribute("content", "1");
// Setting the content attribute later
head.appendChild(depth);
Element totalPageCount = contentDOM.createElement("meta");
@ -107,35 +103,57 @@ public class NCXWriter extends NewDOMDocument {
Element navMap = contentDOM.createElement("navMap");
ncx.appendChild(navMap);
Element currentContainer = ncx;
int nCurrentLevel = 0;
int nDepth = 0;
int nPlayOrder = 0;
Iterator<ContentEntry> content = cr.getContent().iterator();
while (content.hasNext()) {
ContentEntry entry = content.next();
//if (entry.getLevel()==1) {
System.out.println("Found content entry "+entry.getTitle());
Element navPoint = contentDOM.createElement("navPoint");
navPoint.setAttribute("playOrder", Integer.toString(++nPlayOrder));
navPoint.setAttribute("id", "text"+nPlayOrder);
navMap.appendChild(navPoint);
Element navLabel = contentDOM.createElement("navLabel");
navPoint.appendChild(navLabel);
Element navLabelText = contentDOM.createElement("text");
navLabel.appendChild(navLabelText);
navLabelText.appendChild(contentDOM.createTextNode(entry.getTitle()));
Element navPointContent = contentDOM.createElement("content");
String sHref = entry.getFile().getFileName();
if (entry.getTarget()!=null) { sHref+="#"+entry.getTarget(); }
navPointContent.setAttribute("src", sHref);
navPoint.appendChild(navPointContent);
//}
int nEntryLevel = Math.max(entry.getLevel(), 1);
if (nEntryLevel<nCurrentLevel) {
// Return to higher level
for (int i=nEntryLevel; i<nCurrentLevel; i++) {
currentContainer = (Element) currentContainer.getParentNode();
}
nCurrentLevel = nEntryLevel;
}
else if (nEntryLevel>nCurrentLevel) {
// To lower level (always one step; a jump from e.g. heading 1 to heading 3 in the document
// is considered an error)
currentContainer = (Element) currentContainer.getLastChild();
nCurrentLevel++;
}
Element navPoint = contentDOM.createElement("navPoint");
navPoint.setAttribute("playOrder", Integer.toString(++nPlayOrder));
navPoint.setAttribute("id", "text"+nPlayOrder);
currentContainer.appendChild(navPoint);
Element navLabel = contentDOM.createElement("navLabel");
navPoint.appendChild(navLabel);
Element navLabelText = contentDOM.createElement("text");
navLabel.appendChild(navLabelText);
navLabelText.appendChild(contentDOM.createTextNode(entry.getTitle()));
Element navPointContent = contentDOM.createElement("content");
String sHref = entry.getFile().getFileName();
if (entry.getTarget()!=null) { sHref+="#"+entry.getTarget(); }
navPointContent.setAttribute("src", sHref);
navPoint.appendChild(navPointContent);
nDepth = Math.max(nDepth, nCurrentLevel);
}
if (nDepth==0) {
// TODO: We're in trouble: The document has no headings
}
depth.setAttribute("content", Integer.toString(nDepth));
setContentDOM(contentDOM);
System.out.println("finished populating the ncx");
}
}

View file

@ -41,16 +41,14 @@ import org.w3c.dom.Element;
import writer2latex.api.ContentEntry;
import writer2latex.api.ConverterResult;
import writer2latex.api.OutputFile;
import writer2latex.util.Misc;
import writer2latex.xmerge.NewDOMDocument;
/** This class writes an OPF-file for an EPUB document (see http://www.idpf.org/2007/opf/OPF_2.0_final_spec.html)
*
/** This class writes an OPF-file for an EPUB document (see http://www.idpf.org/2007/opf/OPF_2.0_final_spec.html).
*/
public class OPFWriter extends NewDOMDocument {
public OPFWriter(ConverterResult cr, String sUUID, String sNcxFileName, String sFileName) {
super(Misc.removeExtension(sFileName), "opf");
public OPFWriter(ConverterResult cr, String sUUID) {
super("book", "opf");
// create DOM
Document contentDOM = null;
@ -123,7 +121,7 @@ public class OPFWriter extends NewDOMDocument {
}
Element item = contentDOM.createElement("item");
item.setAttribute("href", sNcxFileName);
item.setAttribute("href", "book.ncx");
item.setAttribute("media-type", "application/x-dtbncx+xml");
item.setAttribute("id", "ncx");
manifest.appendChild(item);

View file

@ -20,7 +20,7 @@
*
* All Rights Reserved.
*
* Version 1.2 (2010-03-15)
* Version 1.2 (2010-03-29)
*
*/
@ -343,11 +343,7 @@ public class DrawConverter extends ConverterHelper {
if (node.hasAttribute(XMLString.XLINK_HREF) && !ofr.isInPackage(sHref)) {
// Linked image is not yet handled by ImageLoader. This is a temp.
// solution (will go away when ImageLoader is finished)
sFileName = sHref;
// In OpenDocument package format ../ means "leave the package"
if (ofr.isOpenDocument() && ofr.isPackageFormat() && sFileName.startsWith("../")) {
sFileName=sFileName.substring(3);
}
sFileName = ofr.fixRelativeLink(sHref);
int nExtStart = sHref.lastIndexOf(".");
String sExt = nExtStart>=0 ? sHref.substring(nExtStart).toLowerCase() : "";
// Accept only relative filenames and supported filetypes:

View file

@ -16,11 +16,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2008 by Henrik Just
* Copyright: 2002-2010 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.2 (2008-09-30)
* Version 1.2 (2010-03-29)
*
*/
@ -334,6 +334,19 @@ public class OfficeReader {
if (sUrl.startsWith("./")) { sUrl=sUrl.substring(2); }
return oooDoc.getEmbeddedObject(sUrl)!=null;
}
/** In OpenDocument package format ../ means "leave the package".
* Consequently this prefix must be removed to obtain a valid link
*
* @param sLink
* @return the corrected link
*/
public String fixRelativeLink(String sLink) {
if (isOpenDocument() && isPackageFormat() && sLink.startsWith("../")) {
return sLink.substring(3);
}
return sLink;
}
///////////////////////////////////////////////////////////////////////////
// Accessor methods

View file

@ -20,7 +20,7 @@
*
* All Rights Reserved.
*
* Version 1.2 (2010-03-25)
* Version 1.2 (2010-03-31)
*
*/
@ -44,7 +44,6 @@ import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import writer2latex.api.Config;
import writer2latex.api.ContentEntry;
import writer2latex.api.ConverterFactory;
//import writer2latex.api.ConverterResult;
import writer2latex.base.ContentEntryImpl;
@ -83,6 +82,7 @@ public class Converter extends ConverterBase {
// The xhtml output file(s)
protected int nType = XhtmlDocument.XHTML10; // the doctype
private boolean bOPS = false; // Do we need to be OPS conforming?
Vector<XhtmlDocument> outFiles;
private int nOutFileIndex;
private XhtmlDocument htmlDoc; // current outfile
@ -157,15 +157,18 @@ public class Converter extends ConverterBase {
protected Node importNode(Node node, boolean bDeep) { return htmlDOM.importNode(node,bDeep); }
protected L10n getL10n() { return l10n; }
public void setOPS(boolean b) { bOPS = true; }
public boolean isOPS() { return bOPS; }
// override
public void convertInner() throws IOException {
@Override public void convertInner() throws IOException {
sTargetFileName = Misc.trimDocumentName(sTargetFileName,XhtmlDocument.getExtension(nType));
outFiles = new Vector<XhtmlDocument>();
nOutFileIndex = -1;
bNeedHeaderFooter = ofr.isSpreadsheet() || ofr.isPresentation() || config.getXhtmlSplitLevel()>0 || config.getXhtmlUplink().length()>0;
bNeedHeaderFooter = !bOPS && (ofr.isSpreadsheet() || ofr.isPresentation() || config.getXhtmlSplitLevel()>0 || config.getXhtmlUplink().length()>0);
l10n = new L10n();
@ -612,6 +615,8 @@ public class Converter extends ConverterBase {
}
else { // external link
anchor = htmlDOM.createElement("a");
sHref = ofr.fixRelativeLink(sHref);
// Workaround for an OOo problem:
if (sHref.indexOf("?")==-1) { // No question mark

View file

@ -20,7 +20,7 @@
*
* All Rights Reserved.
*
* Version 1.2 (2010-03-26)
* Version 1.2 (2010-03-29)
*
*/
@ -571,11 +571,14 @@ public class TextConverter extends ConverterHelper {
// Add to toc
if (!bInToc) {
converter.addTarget(heading,"toc"+(++nTocIndex));
String sTarget = "toc"+(++nTocIndex);
converter.addTarget(heading,sTarget);
// Add in external content
if (nLevel<=nSplit) {
converter.addContentEntry(sLabel+(sLabel.length()>0 ? " " : "")+Misc.getPCDATA(onode), nLevel, null);
// Add in external content. For single file output we include all level 1 headings + their target
// For multi-file output, the included heading levels depends on the split leve, and we don't include targets
if (nLevel<=Math.max(nSplit,1)) {
converter.addContentEntry(sLabel+(sLabel.length()>0 ? " " : "")+Misc.getPCDATA(onode), nLevel,
nSplit==0 ? sTarget : null);
}
// Add to real toc