Image export improvements and bugfixes

git-svn-id: svn://svn.code.sf.net/p/writer2latex/code/trunk@177 f0f2a975-2e09-46c8-9428-3b39399b9f3c
This commit is contained in:
henrikjust 2014-09-24 18:15:35 +00:00
parent 2f5ab8c518
commit 0746282f26
8 changed files with 84 additions and 40 deletions
source
distro
java
org/openoffice/da/comp/writer2xhtml
writer2latex
oxt/writer2xhtml
W2XDialogs2
help/en/org.openoffice.da.writer2xhtml.oxt/Configuration

View file

@ -2,6 +2,13 @@ Changelog for Writer2LaTeX version 1.2 -> 1.4
---------- version 1.4 beta ----------
[w2x] Bugfix: Avoid null pointer exception in HTML5 export if embed_svg is true and an image is used more than once
[all] An image that is used more than once in the source document is now only exported once. This was already the
case for the package format (since 1.3.2), but now also for flat XML.
[w2x] The The option inline_svg has been renamed (again) to embed_svg, and the default is changed to false
[w2x] The experimental option zen_hack has been removed
[w2x] For templates it is no longer required that the footer, header and panel are contained in a div element.

Binary file not shown.

View file

@ -20,7 +20,7 @@
*
* All Rights Reserved.
*
* Version 1.4 (2014-09-19)
* Version 1.4 (2014-09-23)
*
*/
@ -495,14 +495,14 @@ public class ConfigurationDialog extends ConfigurationDialogBase implements XSer
listBoxFromConfig(dlg, "Formulas", "formulas", sFormulaValues, (short) 0);
textFieldFromConfig(dlg, "EndnotesHeading", "endnotes_heading");
textFieldFromConfig(dlg, "FootnotesHeading", "footnotes_heading");
checkBoxFromConfig(dlg, "InlineSvg", "inline_svg");
checkBoxFromConfig(dlg, "EmbedSvg", "embed_svg");
}
@Override protected void getControls(DialogAccess dlg) {
listBoxToConfig(dlg, "Formulas", "formulas", sFormulaValues);
textFieldToConfig(dlg, "EndnotesHeading", "endnotes_heading");
textFieldToConfig(dlg, "FootnotesHeading", "footnotes_heading");
checkBoxToConfig(dlg, "InlineSvg", "inline_svg");
checkBoxToConfig(dlg, "EmbedSvg", "embed_svg");
}
@Override protected boolean handleEvent(DialogAccess dlg, String sMethod) {

View file

@ -20,17 +20,22 @@
*
* All Rights Reserved.
*
* Version 1.4 (2014-09-16)
* Version 1.4 (2014-09-24)
*
*/
package writer2latex.base;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import javax.xml.bind.DatatypeConverter;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
@ -181,12 +186,6 @@ public final class ImageConverter {
// The file name was not used
nImageCount--;
}
else if (node.hasAttribute(XMLString.XLINK_HREF)) {
// This is an embedded image we meet for the first time.
// Recycle it on behalf of the original image node.
String sHref = node.getAttribute(XMLString.XLINK_HREF);
recycledImages.put(sHref, new BinaryGraphicsDocument(bgd));
}
return bgd;
}
@ -197,6 +196,7 @@ public final class ImageConverter {
String sExt = null;
String sMIME = null;
byte[] blob = null;
String sId = null;
// First try to extract the image using the xlink:href attribute
if (node.hasAttribute(XMLString.XLINK_HREF)) {
@ -224,6 +224,8 @@ public final class ImageConverter {
if (bDestructive) {
object.dispose();
}
// We got an image, define ID for recycling
sId = sHref;
}
else {
// This is a linked image
@ -249,11 +251,18 @@ public final class ImageConverter {
}
}
blob = Base64.decode(buf.toString());
sMIME = MIMETypes.getMagicMIMEType(blob);
// We may have seen this image before, return the recycled version
String sId1 = createId(blob);
if (recycledImages.containsKey(sId1)) {
return recycledImages.get(sId1);
}
sMIME = MIMETypes.getMagicMIMEType(blob);
sExt = MIMETypes.getFileExtension(sMIME);
if (bDestructive) {
node.removeChild(obd);
}
// We got an image, define ID for recycling
sId = sId1;
}
else {
// There is no image data
@ -303,11 +312,13 @@ public final class ImageConverter {
}
// Create the result
if (isAcceptedFormat(sMIME) || bAcceptOtherFormats) {
String sFileName = sName+sExt;
BinaryGraphicsDocument bgd = new BinaryGraphicsDocument(sFileName,sMIME);
bgd.setData(blob,isAcceptedFormat(sMIME));
if (sId!=null) {
recycledImages.put(sId, new BinaryGraphicsDocument(bgd));
}
return bgd;
}
else {
@ -323,4 +334,17 @@ public final class ImageConverter {
return null;
}
// Create a fingerprint of a blob. The fingerprint concatenates the MD5 hash with the first 10 bytes of the blob.
private String createId(byte[] blob) {
MessageDigest md;
try {
md = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
// This would be surprising
return null;
}
return DatatypeConverter.printHexBinary(md.digest(blob))
+DatatypeConverter.printHexBinary(Arrays.copyOf(blob, 10));
}
}

View file

@ -20,7 +20,7 @@
*
* All Rights Reserved.
*
* Version 1.4 (2014-09-05)
* Version 1.4 (2014-09-24)
*
*/
@ -38,9 +38,9 @@
* export notes (part of draw-page)
* export list-style-image for image bullets!
*/
package writer2latex.xhtml;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Vector;
@ -54,8 +54,6 @@ import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Element;
//import writer2latex.xmerge.EmbeddedBinaryObject;
import writer2latex.util.Misc;
import writer2latex.util.CSVList;
import writer2latex.util.SimpleXMLParser;
@ -101,7 +99,10 @@ public class DrawConverter extends ConverterHelper {
private int nImageSize;
private String sImageSplit;
private boolean bCoverImage;
private boolean bUseSVG;
private boolean bEmbedSVG;
// Embedded SVG images for recycling are collected here
private HashMap<String,Element> svgImages = new HashMap<String,Element>();
// Frames in spreadsheet documents are collected here
private Vector<Element> frames = new Vector<Element>();
@ -128,7 +129,7 @@ public class DrawConverter extends ConverterHelper {
nImageSize = config.imageSize();
sImageSplit = config.imageSplit();
bCoverImage = config.coverImage();
bUseSVG = config.inlineSVG();
bEmbedSVG = config.embedSVG();
}
///////////////////////////////////////////////////////////////////////
@ -486,26 +487,38 @@ public class DrawConverter extends ConverterHelper {
// Create the image (sFileName contains the file name)
Element imageElement = null;
if (converter.nType==XhtmlDocument.HTML5 && bUseSVG && bgd!=null && MIMETypes.SVG.equals(bgd.getMIMEType())) {
if (converter.nType==XhtmlDocument.HTML5 && bEmbedSVG && bgd!=null && MIMETypes.SVG.equals(bgd.getMIMEType())) {
// In HTML5 we may embed SVG images directly in the document
byte[] blob = bgd.getData();
try {
Document dom = SimpleXMLParser.parse(new ByteArrayInputStream(blob));
if (dom!=null) {
if (bgd.isRecycled()) {
// Get from the cache (actually we are certain it is there)
if (svgImages.containsKey(bgd.getFileName())) {
Element elm = hnodeInline!=null ? hnodeInline : hnodeBlock;
imageElement = (Element) elm.getOwnerDocument().importNode(dom.getDocumentElement(), true);
imageElement = (Element) elm.getOwnerDocument().importNode(svgImages.get(bgd.getFileName()), true);
}
}
else {
// Parse the data
byte[] blob = bgd.getData();
try {
Document dom = SimpleXMLParser.parse(new ByteArrayInputStream(blob));
if (dom!=null) {
Element elm = hnodeInline!=null ? hnodeInline : hnodeBlock;
imageElement = (Element) elm.getOwnerDocument().importNode(dom.getDocumentElement(), true);
// Store in cache in case we need to recycle
svgImages.put(bgd.getFileName(), imageElement);
}
else {
System.out.println("Failed to parse SVG");
}
} catch (IOException e) {
// Will not happen with a byte array
System.out.println("IOException parsing SVG");
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
System.out.println("SAXException parsing SVG");
}
else {
System.out.println("Failed to parse SVG");
}
} catch (IOException e) {
// Will not happen with a byte array
System.out.println("IOException parsing SVG");
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
System.out.println("SAXException parsing SVG");
}
}
}
else {
// In all other cases, create an img element

View file

@ -143,7 +143,7 @@ public class XhtmlConfig extends writer2latex.base.ConfigBase {
private static final int SPLIT_AFTER = 40;
private static final int IMAGE_SPLIT = 41;
private static final int COVER_IMAGE = 42;
private static final int INLINE_SVG = 43;
private static final int EMBED_SVG = 43;
private static final int USE_MATHJAX = 44;
private static final int CALC_SPLIT = 45;
private static final int DISPLAY_HIDDEN_SHEETS = 46;
@ -273,7 +273,7 @@ public class XhtmlConfig extends writer2latex.base.ConfigBase {
};
options[IMAGE_SPLIT] = new Option("image_split","none");
options[COVER_IMAGE] = new BooleanOption("cover_image","false");
options[INLINE_SVG] = new BooleanOption("inline_svg","true");
options[EMBED_SVG] = new BooleanOption("embed_svg","false");
options[USE_MATHJAX] = new BooleanOption("use_mathjax","false");
options[CALC_SPLIT] = new BooleanOption("calc_split","false");
options[DISPLAY_HIDDEN_SHEETS] = new BooleanOption("display_hidden_sheets", "false");
@ -399,7 +399,7 @@ public class XhtmlConfig extends writer2latex.base.ConfigBase {
public int splitAfter() { return ((IntegerOption) options[SPLIT_AFTER]).getValue(); }
public String imageSplit() { return options[IMAGE_SPLIT].getString(); }
public boolean coverImage() { return ((BooleanOption) options[COVER_IMAGE]).getValue(); }
public boolean inlineSVG() { return ((BooleanOption) options[INLINE_SVG]).getValue(); }
public boolean embedSVG() { return ((BooleanOption) options[EMBED_SVG]).getValue(); }
public boolean useMathJax() { return ((BooleanOption) options[USE_MATHJAX]).getValue(); }
public boolean xhtmlCalcSplit() { return ((BooleanOption) options[CALC_SPLIT]).getValue(); }
public boolean xhtmlDisplayHiddenSheets() { return ((BooleanOption) options[DISPLAY_HIDDEN_SHEETS]).getValue(); }

View file

@ -18,6 +18,6 @@
<dlg:text dlg:id="FootnotesHeadingLabel" dlg:tab-index="6" dlg:left="10" dlg:top="64" dlg:width="110" dlg:height="12" dlg:value="Footnotes heading"/>
<dlg:textfield dlg:id="FootnotesHeading" dlg:tab-index="7" dlg:left="130" dlg:top="62" dlg:width="120" dlg:height="12" dlg:help-url="org.openoffice.da.writer2xhtml.oxt:FootnotesHeading"/>
<dlg:text dlg:id="SvgLabel" dlg:tab-index="8" dlg:left="5" dlg:top="80" dlg:width="245" dlg:height="12" dlg:value="SVG images (HTML5 only)"/>
<dlg:checkbox dlg:id="InlineSvg" dlg:tab-index="9" dlg:left="10" dlg:top="92" dlg:width="240" dlg:height="12" dlg:value="Embed SVG images in the HTML document" dlg:checked="false" dlg:help-url="org.openoffice.da.writer2xhtml.oxt:InlineSvg"/>
<dlg:checkbox dlg:id="EmbedSvg" dlg:tab-index="9" dlg:left="10" dlg:top="92" dlg:width="240" dlg:height="12" dlg:value="Embed SVG images in the HTML document" dlg:checked="false" dlg:help-url="org.openoffice.da.writer2xhtml.oxt:EmbedSvg"/>
</dlg:bulletinboard>
</dlg:window>

View file

@ -54,7 +54,7 @@
<paragraph role="heading" level="2" xml-lang="en-US">SVG images</paragraph>
<bookmark xml-lang="en-US" branch="hid/org.openoffice.da.writer2xhtml.oxt:InlineSvg" id="bm_configinlinesvg"/>
<bookmark xml-lang="en-US" branch="hid/org.openoffice.da.writer2xhtml.oxt:EmbedSvg" id="bm_configembedsvg"/>
<paragraph role="heading" level="3" xml-lang="en-US">Embed SVG images in the HTML document</paragraph>
<paragraph role="paragraph" xml-lang="en-US">If you check this option, SVG images will be embedded directly