diff --git a/docx4j-ImportXHTML-core/src/main/java/org/docx4j/convert/in/xhtml/ListHelper.java b/docx4j-ImportXHTML-core/src/main/java/org/docx4j/convert/in/xhtml/ListHelper.java
index 2c1caf6..1f4ccf3 100644
--- a/docx4j-ImportXHTML-core/src/main/java/org/docx4j/convert/in/xhtml/ListHelper.java
+++ b/docx4j-ImportXHTML-core/src/main/java/org/docx4j/convert/in/xhtml/ListHelper.java
@@ -124,6 +124,7 @@ protected BlockBox popListStack() {
return box;
}
protected BlockBox peekListStack() {
+ if(listStack.peek() == null) return new BlockBox();
return listStack.peek();
}
@@ -184,6 +185,7 @@ void init() {
}
protected ListItemContentState peekListItemStateStack() {
+ if(listItemStateStack.peek() == null) return new ListItemContentState();
return listItemStateStack.peek();
}
private void pushListItemStateStack() {
diff --git a/docx4j-ImportXHTML-core/src/main/java/org/docx4j/convert/in/xhtml/XHTMLImageHandlerDefault.java b/docx4j-ImportXHTML-core/src/main/java/org/docx4j/convert/in/xhtml/XHTMLImageHandlerDefault.java
index 4f58e21..402c579 100644
--- a/docx4j-ImportXHTML-core/src/main/java/org/docx4j/convert/in/xhtml/XHTMLImageHandlerDefault.java
+++ b/docx4j-ImportXHTML-core/src/main/java/org/docx4j/convert/in/xhtml/XHTMLImageHandlerDefault.java
@@ -173,7 +173,7 @@ public void addImage(Docx4jUserAgent docx4jUserAgent, WordprocessingMLPackage wo
drawing.getAnchorOrInline().add(inline);
}
} catch (Exception e1) {
- log.error(MessageFormat.format("Error during image processing: ''{0}'', insert default text.", new Object[] {e.getAttribute("alt")}), e1);
+ log.error(MessageFormat.format("Error during image processing: ''{0}'', insert default text.", e.getAttribute("alt")), e1);
isError = true;
}
diff --git a/docx4j-ImportXHTML-core/src/main/java/org/docx4j/convert/in/xhtml/XHTMLImageHandlerDifferentTarget.java b/docx4j-ImportXHTML-core/src/main/java/org/docx4j/convert/in/xhtml/XHTMLImageHandlerDifferentTarget.java
new file mode 100644
index 0000000..22b43c6
--- /dev/null
+++ b/docx4j-ImportXHTML-core/src/main/java/org/docx4j/convert/in/xhtml/XHTMLImageHandlerDifferentTarget.java
@@ -0,0 +1,258 @@
+package org.docx4j.convert.in.xhtml;
+
+import org.apache.commons.codec.binary.Base64;
+import org.docx4j.convert.in.xhtml.renderer.Docx4JFSImage;
+import org.docx4j.convert.in.xhtml.renderer.Docx4jUserAgent;
+import org.docx4j.dml.wordprocessingDrawing.Inline;
+import org.docx4j.jaxb.Context;
+import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
+import org.docx4j.openpackaging.parts.Part;
+import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage;
+import org.docx4j.wml.CTTblCellMar;
+import org.docx4j.wml.CTTblPrBase;
+import org.docx4j.wml.P;
+import org.docx4j.wml.Style;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Element;
+
+import java.text.MessageFormat;
+import java.util.HashMap;
+
+public class XHTMLImageHandlerDifferentTarget implements XHTMLImageHandler{
+
+
+
+
+ public static Logger log = LoggerFactory.getLogger(org.docx4j.convert.in.xhtml.XHTMLImageHandlerDifferentTarget.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;
+ }
+
+ public void setMaxWidth(int maxWidth) {
+ this.maxWidth = maxWidth;
+ }
+
+ protected HashMap imagePartCache = new HashMap();
+
+ private XHTMLImporterImpl importer;
+ private Part targetPart;
+
+ public XHTMLImageHandlerDifferentTarget(XHTMLImporterImpl importer, Part targetPart) {
+ this.importer = importer;
+ this.targetPart = targetPart;
+ }
+
+ /**
+ * @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
+ log.error("Couldn't fetch " + url);
+ } else {
+ 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);
+ }
+ }
+
+
+ long docPrId = wordMLPackage.getDrawingPropsIdTracker().generateId();
+
+ 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"), docPrId, 1, false, maxWidth - (int)excessWidth);
+ } else {
+ inline = imagePart.createImageInline(null, e.getAttribute("alt"), docPrId, 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"),
+ docPrId, 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) {
+ Style.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;
+ }
+ }
+
+
diff --git a/docx4j-ImportXHTML-core/src/main/java/org/docx4j/convert/in/xhtml/XHTMLImporterImpl.java b/docx4j-ImportXHTML-core/src/main/java/org/docx4j/convert/in/xhtml/XHTMLImporterImpl.java
index 0efe4f0..efec7c1 100644
--- a/docx4j-ImportXHTML-core/src/main/java/org/docx4j/convert/in/xhtml/XHTMLImporterImpl.java
+++ b/docx4j-ImportXHTML-core/src/main/java/org/docx4j/convert/in/xhtml/XHTMLImporterImpl.java
@@ -65,6 +65,7 @@
import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.openpackaging.exceptions.InvalidFormatException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
+import org.docx4j.openpackaging.parts.Part;
import org.docx4j.openpackaging.parts.WordprocessingML.NumberingDefinitionsPart;
import org.docx4j.openpackaging.parts.WordprocessingML.StyleDefinitionsPart;
import org.docx4j.openpackaging.parts.relationships.Namespaces;
@@ -232,8 +233,13 @@ public void setHyperlinkStyle (
public void setXHTMLImageHandler(XHTMLImageHandler xHTMLImageHandler) {
this.xHTMLImageHandler = xHTMLImageHandler;
}
+ public void setDefaultHandler(){
+ xHTMLImageHandler = defaultHandler;
+ }
- private XHTMLImageHandler xHTMLImageHandler = new XHTMLImageHandlerDefault(this);
+ private XHTMLImageHandler xHTMLImageHandler;
+
+ private XHTMLImageHandlerDefault defaultHandler = new XHTMLImageHandlerDefault(this);
@Override
public void setMaxWidth(int maxWidth, String tableStyle) {
@@ -492,7 +498,7 @@ private String stylesToCSS() {
* @throws IOException
*/
public List