/*******************************************************************************
* Copyright (c) 2009, Adobe Systems Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* · Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* · Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* · Neither the name of Adobe Systems Incorporated nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
package com.adobe.dp.office.conv;
import com.adobe.dp.css.*;
import com.adobe.dp.epub.conv.Version;
import com.adobe.dp.epub.io.ContainerSource;
import com.adobe.dp.epub.opf.NCXResource;
import com.adobe.dp.epub.opf.OPSResource;
import com.adobe.dp.epub.opf.Publication;
import com.adobe.dp.epub.opf.StyleResource;
import com.adobe.dp.epub.otf.FontEmbeddingReport;
import com.adobe.dp.epub.style.Stylesheet;
import com.adobe.dp.office.word.*;
import com.adobe.dp.otf.DefaultFontLocator;
import com.adobe.dp.otf.FontLocator;
import com.adobe.dp.xml.util.StringUtil;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Date;
import java.util.Hashtable;
import java.util.Iterator;
public class DOCXConverter {
WordDocument doc;
Publication epub;
NCXResource toc;
StyleResource global;
StyleConverter styleConverter;
// maps Footnote IDs to Footnote XRef
Hashtable footnoteMap = new Hashtable();
Hashtable convResources = new Hashtable();
ContainerSource wordResources;
FontLocator fontLocator;
double defaultFontSize;
PrintWriter log = new PrintWriter(new OutputStreamWriter(System.out));
boolean useWordPageBreaks;
String lang;
public DOCXConverter(WordDocument doc, Publication epub) {
this.doc = doc;
this.epub = epub;
this.fontLocator = DefaultFontLocator.getInstance(DefaultFontLocator.BUILT_IN_DIRS);
global = epub.createStyleResource("OPS/global.css");
Stylesheet globalStylesheet = global.getStylesheet();
styleConverter = new StyleConverter(false);
toc = epub.getTOC();
Style rs = doc.getDefaultParagraphStyle();
if (rs != null) {
RunProperties rp = rs.getRunProperties();
if (rp != null)
lang = (String) rp.get("lang");
}
// default font size - have to happen early
RunProperties rp = doc.getDocumentDefaultRunStyle().getRunProperties();
if (rp != null) {
Object sz = rp.get("sz");
if (sz instanceof Number)
defaultFontSize = ((Number) sz).doubleValue();
StylingResult res = styleConverter.styleElement(rp, false, 1, false, false);
if (res.elementRule != null && !res.elementRule.isEmpty()) {
SelectorRule bodyRule = globalStylesheet.getRuleForSelector(globalStylesheet.getSimpleSelector("body", null),
true);
Iterator it = res.elementRule.properties();
while (it.hasNext()) {
String property = (String) it.next();
bodyRule.set(property, res.elementRule.get(property));
}
}
if (lang == null)
lang = (String) rp.get("lang");
}
if (defaultFontSize < 1)
defaultFontSize = 20;
SelectorRule bodyEmbedRule = globalStylesheet.getRuleForSelector(globalStylesheet.getSimpleSelector("body", "embed"),
true);
bodyEmbedRule.set("font-size", new CSSLength(defaultFontSize / 2, "px"));
styleConverter.setDefaultFontSize(defaultFontSize);
styleConverter.setDocumentDefaultParagraphStyle(doc.getDocumentDefaultParagraphStyle());
// default table styles
SelectorRule tableRule = globalStylesheet.getRuleForSelector(globalStylesheet.getSimpleSelector("table", null), true);
tableRule.set("border-collapse", new CSSName("collapse"));
tableRule.set("border-spacing", new CSSLength(0, "px"));
// default paragraph styles
// unlike XHTML, Word's default spacing/margings are zero
SelectorRule pRule = globalStylesheet.getRuleForSelector(globalStylesheet.getSimpleSelector("p", null), true);
pRule.set("margin-top", new CSSLength(0, "px"));
pRule.set("margin-bottom", new CSSLength(0, "px"));
SelectorRule ulRule = globalStylesheet.getRuleForSelector(globalStylesheet.getSimpleSelector("ul", null), true);
// Word puts margins on li, not ul elements
ulRule.set("padding-left", new CSSLength(0, "px")); // most CSS engines
// have default
// padding on ul element
ulRule.set("margin", new CSSLength(0, "px")); // left margin override
// needed for older
// Digital Editions
SelectorRule nestedLiRule = globalStylesheet.getRuleForSelector(globalStylesheet.getSimpleSelector("li", "nested"),
true);
nestedLiRule.set("display", new CSSName("block"));
}
public void setFontLocator(FontLocator fontLocator) {
this.fontLocator = fontLocator;
}
public void setLog(PrintWriter log) {
this.log = log;
}
public void convert() {
OPSResource footnotes = null;
if (doc.getFootnotes() != null) {
// process footnotes first to build footnote map
BodyElement fbody = doc.getFootnotes();
footnotes = epub.createOPSResource("OPS/footnotes.xhtml");
WordMLConverter footnoteConv = new WordMLConverter(doc, epub, styleConverter, log);
footnoteConv.setFootnoteMap(footnoteMap);
footnoteConv.setWordResources(wordResources);
footnoteConv.convert(fbody, footnotes, false);
if (footnoteMap.size() > 0) {
Stylesheet ss = global.getStylesheet();
Selector selector = ss.getSimpleSelector(null, "footnote-ref");
SelectorRule rule = ss.getRuleForSelector(selector, true);
rule.set("font-size", new CSSLength(0.7, "em"));
rule.set("vertical-align", new CSSName("super"));
rule.set("line-height", new CSSNumber(0.2));
selector = ss.getSimpleSelector(null, "footnote-title");
rule = ss.getRuleForSelector(selector, true);
rule.set("margin", new CSSLength(0, "px"));
CSSValue[] padvals = { new CSSLength(1, "em"), new CSSLength(0, "px"), new CSSLength(0.5, "em"),
new CSSLength(2, "em") };
rule.set("padding", new CSSValueList(' ', padvals));
} else {
epub.removeResource(footnotes);
}
}
BodyElement body = doc.getBody();
WordMLConverter bodyConv = new WordMLConverter(doc, epub, styleConverter, log);
bodyConv.setFootnoteMap(footnoteMap);
bodyConv.setWordResources(wordResources);
bodyConv.findLists(body);
OPSResource ops = epub.createOPSResource("OPS/document.xhtml");
if (useWordPageBreaks) {
epub.getTOC().addPage(null, ops.getDocument().getRootXRef());
bodyConv.useWordPageBreaks();
}
bodyConv.convert(body, ops, true);
if (footnotes != null)
epub.addToSpine(footnotes);
if (bodyConv.includeWordMetadata) {
// add EPUB metadata from Word metadata, do it in the end, so that
// metadata from commands comes first
Iterator metadata = doc.metadata();
while (metadata.hasNext()) {
MetadataItem item = (MetadataItem) metadata.next();
epub.addMetadata(item.getNS(), item.getName(), item.getValue());
if (item.getNS().equals("http://purl.org/dc/terms/") && item.getName().equals("modified")) {
epub.addDCMetadata("date", item.getValue());
}
}
}
if (lang != null && epub.getDCMetadata("language") == null) {
epub.addDCMetadata("language", lang);
}
epub.addMetadata(null, "DOCX2EPUB.version", Version.VERSION);
epub.addMetadata(null, "DOCX2EPUB.conversionDate", StringUtil.dateToW3CDTF(new Date()));
epub.generateTOCFromHeadings(5);
epub.generateStyles(global);
epub.splitLargeChapters();
epub.cascadeStyles();
log.flush();
}
public void useWordPageBreaks() {
useWordPageBreaks = true;
}
public FontEmbeddingReport embedFonts() {
return epub.addFonts(global, fontLocator);
}
public void setWordResources(ContainerSource source) {
wordResources = source;
}
}