org.docx4j.convert.in.xhtml.XHTMLImageHandlerDefault Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of docx4j-ImportXHTML Show documentation
Show all versions of docx4j-ImportXHTML Show documentation
docx4j-ImportXHTML converts XHTML to OpenXML WordML (docx) using docx4j
package org.docx4j.convert.in.xhtml;
import java.text.MessageFormat;
import java.util.HashMap;
import org.apache.commons.codec.binary.Base64;
import org.docx4j.dml.wordprocessingDrawing.Inline;
import org.docx4j.jaxb.Context;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage;
import org.docx4j.org.xhtmlrenderer.docx.Docx4JFSImage;
import org.docx4j.org.xhtmlrenderer.docx.Docx4jUserAgent;
import org.docx4j.wml.CTTblCellMar;
import org.docx4j.wml.CTTblPrBase;
import org.docx4j.wml.P;
import org.docx4j.wml.Style;
import org.docx4j.wml.Style.BasedOn;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
public class XHTMLImageHandlerDefault implements XHTMLImageHandler {
public static Logger log = LoggerFactory.getLogger(XHTMLImageHandlerDefault.class);
private int maxWidth = -1;
private String tableStyle;
public int getMaxWidth() {
return maxWidth;
}
@Override
public void setMaxWidth(int maxWidth, String tableStyle) {
this.maxWidth = maxWidth;
this.tableStyle = tableStyle;
}
protected HashMap imagePartCache = new HashMap();
private XHTMLImporterImpl importer;
public XHTMLImageHandlerDefault(XHTMLImporterImpl importer) {
this.importer = importer;
}
/**
* @param docx4jUserAgent
* @param wordMLPackage
* @param p
* @param e
* @param cx width of image itself (ie excluding CSS margin, padding) in EMU
* @param cy
*/
public void addImage(Docx4jUserAgent docx4jUserAgent, WordprocessingMLPackage wordMLPackage, P p, Element e, Long cx, Long cy) {
BinaryPartAbstractImage imagePart = null;
boolean isError = false;
try {
byte[] imageBytes = null;
if (e.getAttribute("src").startsWith("data:image")) {
// Supports
// data:[][;charset=][;base64],
// eg data:image/png;base64,iVBORw0KGgo...
// http://www.greywyvern.com/code/php/binary2base64 is a convenient online encoder
String base64String = e.getAttribute("src");
int commaPos = base64String.indexOf(",");
if (commaPos < 6) { // or so ...
// .. its broken
org.docx4j.wml.R run = Context.getWmlObjectFactory().createR();
p.getContent().add(run);
org.docx4j.wml.Text text = Context.getWmlObjectFactory().createText();
text.setValue("[INVALID DATA URI: " + e.getAttribute("src"));
run.getContent().add(text);
return;
}
base64String = base64String.substring(commaPos + 1);
log.debug(base64String);
imageBytes = Base64.decodeBase64(base64String.getBytes("UTF8"));
} else {
imagePart = imagePartCache.get(e.getAttribute("src"));
if (imagePart==null) {
String url = e.getAttribute("src");
// Workaround for cannot resolve the URL C:\... with base URL file:/C:/...
// where @src points to a raw file path
if (url.substring(1,2).equals(":")) {
url = "file:/" + url;
}
Docx4JFSImage docx4JFSImage = docx4jUserAgent.getDocx4JImageResource(url);
if (docx4JFSImage != null) {// in case of wrong URL - docx4JFSImage will be null
imageBytes = docx4JFSImage.getBytes();
}
}
}
if (imageBytes == null
&& imagePart==null) {
isError = true;
} else {
if (imagePart==null) {
// Its not cached
imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, imageBytes);
if (e.getAttribute("src").startsWith("data:image")) {
// don't bother caching
} else {
// cache it
imagePartCache.put(e.getAttribute("src"), imagePart);
}
}
Inline inline=null;
if (cx == null && cy == null) {
if (maxWidth>0) {
log.debug("image maxWidth:" + maxWidth + ", table style: " + tableStyle);
long excessWidth = getTblCellMargins(tableStyle);
if(excessWidth > 0) {
log.debug("table style margins subtracted (twips): " + excessWidth);
}
inline = imagePart.createImageInline(null, e.getAttribute("alt"), 0, 1, false, maxWidth - (int)excessWidth);
} else {
inline = imagePart.createImageInline(null, e.getAttribute("alt"), 0, 1, false);
}
} else {
if (cx == null) {
cx = imagePart.getImageInfo().getSize().getWidthPx() *
(cy / imagePart.getImageInfo().getSize().getHeightPx());
} else if (cy == null) {
cy = imagePart.getImageInfo().getSize().getHeightPx() *
(cx / imagePart.getImageInfo().getSize().getWidthPx());
}
inline = imagePart.createImageInline(null, e.getAttribute("alt"), 0, 1, cx, cy, false);
/*
* That sets text wrapping distance from text to 0.
*
* Parameter tableStyle can be null - 0 will be returned.
* @return left margin plus right margin (twips)
*/
private long getTblCellMargins(String tableStyle) {
Style s = null;
if(tableStyle != null && !tableStyle.isEmpty()) {
s = importer.getStyleByIdOrName(tableStyle);
}
if(s != null && importer.getTableHelper().isTableStyle(s)) {
CTTblCellMar cellMar = getTblCellMar(s);
if(cellMar == null) {
//try "based on" style
CTTblCellMar bsCellMar = getBasedOnTblCellMar(s);
if(bsCellMar != null) {
return getLeftPlusRightMarginsValue(bsCellMar);
}
} else {
return getLeftPlusRightMarginsValue(cellMar);
}
}
return 0;
}
private long getLeftPlusRightMarginsValue(CTTblCellMar cellMar) {
return cellMar.getLeft().getW().longValue() + cellMar.getRight().getW().longValue();
}
/**
* Get cell margins from "based on" style.
*
Search recursively while possible.
*/
private CTTblCellMar getBasedOnTblCellMar(Style s) {
BasedOn bo = s.getBasedOn();
if(bo != null) {
String basedOn = bo.getVal();
if(basedOn != null && !basedOn.isEmpty()) {
Style bs = importer.getStyleByIdOrName(basedOn);
if(bs != null) {
CTTblCellMar bsCellMar = getTblCellMar(bs);
if(bsCellMar != null) {
return bsCellMar;
} else {
return getBasedOnTblCellMar(bs);
}
}
}
}
return null;
}
private CTTblCellMar getTblCellMar(Style s) {
CTTblPrBase tpb = s.getTblPr();
if(tpb != null) {
return tpb.getTblCellMar();
}
return null;
}
}