- Fix mindmap img export support. Now images are embedded in the SVG.
This commit is contained in:
@@ -1,86 +1,78 @@
|
||||
/*
|
||||
* Copyright [2011] [wisemapping]
|
||||
*
|
||||
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
|
||||
* It is basically the Apache License, Version 2.0 (the "License") plus the
|
||||
* "powered by wisemapping" text requirement on every single page;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the license at
|
||||
*
|
||||
* http://www.wisemapping.org/license
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.wisemapping.exporter;
|
||||
|
||||
public class ExportProperties {
|
||||
private ExportFormat format;
|
||||
private String baseImgPath;
|
||||
|
||||
public ExportFormat getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
private ExportProperties(final ExportFormat format) {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
public static ExportProperties create(final ExportFormat format) {
|
||||
ExportProperties result;
|
||||
if (format == ExportFormat.JPG || format == ExportFormat.PNG) {
|
||||
result = new ImageProperties(format);
|
||||
} else {
|
||||
result = new GenericProperties(format);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setBaseImagePath(String baseUrl) {
|
||||
this.baseImgPath = baseUrl;
|
||||
}
|
||||
|
||||
public String getBaseImgPath() {
|
||||
return baseImgPath;
|
||||
}
|
||||
|
||||
static public class GenericProperties extends ExportProperties {
|
||||
private GenericProperties(ExportFormat format) {
|
||||
super(format);
|
||||
}
|
||||
}
|
||||
|
||||
static public class ImageProperties extends ExportProperties {
|
||||
private Size size;
|
||||
|
||||
public Size getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public void setSize(Size size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public ImageProperties(ExportFormat format) {
|
||||
super(format);
|
||||
}
|
||||
|
||||
public enum Size {
|
||||
SMALL(100), MEDIUM(800), XMEDIUM(1024), LARGE(2048);
|
||||
private int width;
|
||||
|
||||
Size(int width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
public Float getWidth() {
|
||||
return (float) width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright [2011] [wisemapping]
|
||||
*
|
||||
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
|
||||
* It is basically the Apache License, Version 2.0 (the "License") plus the
|
||||
* "powered by wisemapping" text requirement on every single page;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the license at
|
||||
*
|
||||
* http://www.wisemapping.org/license
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.wisemapping.exporter;
|
||||
|
||||
public class ExportProperties {
|
||||
private ExportFormat format;
|
||||
private String baseImgPath;
|
||||
|
||||
public ExportFormat getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
private ExportProperties(final ExportFormat format) {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
public static ExportProperties create(final ExportFormat format) {
|
||||
ExportProperties result;
|
||||
if (format == ExportFormat.JPG || format == ExportFormat.PNG) {
|
||||
result = new ImageProperties(format);
|
||||
} else {
|
||||
result = new GenericProperties(format);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static public class GenericProperties extends ExportProperties {
|
||||
private GenericProperties(ExportFormat format) {
|
||||
super(format);
|
||||
}
|
||||
}
|
||||
|
||||
static public class ImageProperties extends ExportProperties {
|
||||
private Size size;
|
||||
|
||||
public Size getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public void setSize(Size size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public ImageProperties(ExportFormat format) {
|
||||
super(format);
|
||||
}
|
||||
|
||||
public enum Size {
|
||||
SMALL(100), MEDIUM(800), XMEDIUM(1024), LARGE(2048);
|
||||
private int width;
|
||||
|
||||
Size(int width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
public Float getWidth() {
|
||||
return (float) width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -31,7 +31,9 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.w3c.dom.*;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import sun.misc.BASE64Encoder;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
@@ -48,16 +50,19 @@ public class ExporterFactory {
|
||||
private static final String GROUP_NODE_NAME = "g";
|
||||
private static final String RECT_NODE_NAME = "rect";
|
||||
private static final String IMAGE_NODE_NAME = "image";
|
||||
private File baseImgDir;
|
||||
|
||||
|
||||
private ExporterFactory() throws ParserConfigurationException {
|
||||
|
||||
public ExporterFactory(@NotNull final ServletContext servletContext) throws ParserConfigurationException {
|
||||
this.baseImgDir = new File(servletContext.getRealPath("/"));
|
||||
}
|
||||
|
||||
public static void export(@NotNull ExportProperties properties, @Nullable String xml, @NotNull OutputStream output, @Nullable String mapSvg) throws TranscoderException, IOException, ParserConfigurationException, SAXException, XMLStreamException, TransformerException, JAXBException, ExportException {
|
||||
public ExporterFactory(@NotNull final File baseImgDir) throws ParserConfigurationException {
|
||||
this.baseImgDir = baseImgDir;
|
||||
}
|
||||
|
||||
public void export(@NotNull ExportProperties properties, @Nullable String xml, @NotNull OutputStream output, @Nullable String mapSvg) throws TranscoderException, IOException, ParserConfigurationException, SAXException, XMLStreamException, TransformerException, JAXBException, ExportException {
|
||||
final ExportFormat format = properties.getFormat();
|
||||
|
||||
final String imgPath = properties.getBaseImgPath();
|
||||
switch (format) {
|
||||
case PNG: {
|
||||
// Create a JPEG transcoder
|
||||
@@ -68,7 +73,7 @@ public class ExporterFactory {
|
||||
transcoder.addTranscodingHint(ImageTranscoder.KEY_WIDTH, size.getWidth());
|
||||
|
||||
// Create the transcoder input.
|
||||
final Document document = normalizeSvg(mapSvg, imgPath);
|
||||
final Document document = normalizeSvg(mapSvg, false);
|
||||
final String svgString = domToString(document);
|
||||
final TranscoderInput input = new TranscoderInput(new CharArrayReader(svgString.toCharArray()));
|
||||
|
||||
@@ -89,7 +94,7 @@ public class ExporterFactory {
|
||||
transcoder.addTranscodingHint(ImageTranscoder.KEY_WIDTH, size.getWidth());
|
||||
|
||||
// Create the transcoder input.
|
||||
final Document document = normalizeSvg(mapSvg, imgPath);
|
||||
final Document document = normalizeSvg(mapSvg, false);
|
||||
final String svgString = domToString(document);
|
||||
final TranscoderInput input = new TranscoderInput(new CharArrayReader(svgString.toCharArray()));
|
||||
|
||||
@@ -104,7 +109,7 @@ public class ExporterFactory {
|
||||
final Transcoder transcoder = new PDFTranscoder();
|
||||
|
||||
// Create the transcoder input.
|
||||
final Document document = normalizeSvg(mapSvg, imgPath);
|
||||
final Document document = normalizeSvg(mapSvg, false);
|
||||
final String svgString = domToString(document);
|
||||
final TranscoderInput input = new TranscoderInput(new CharArrayReader(svgString.toCharArray()));
|
||||
|
||||
@@ -115,7 +120,7 @@ public class ExporterFactory {
|
||||
break;
|
||||
}
|
||||
case SVG: {
|
||||
final Document dom = normalizeSvg(mapSvg, imgPath);
|
||||
final Document dom = normalizeSvg(mapSvg, true);
|
||||
output.write(domToString(dom).getBytes("UTF-8"));
|
||||
break;
|
||||
}
|
||||
@@ -129,7 +134,7 @@ public class ExporterFactory {
|
||||
}
|
||||
}
|
||||
|
||||
private static Document normalizeSvg(@NotNull String svgXml, final String imgBaseUrl) throws XMLStreamException, ParserConfigurationException, IOException, SAXException, TransformerException {
|
||||
private Document normalizeSvg(@NotNull String svgXml, boolean embedImg) throws XMLStreamException, ParserConfigurationException, IOException, SAXException, TransformerException {
|
||||
|
||||
final DocumentBuilder documentBuilder = getDocumentBuilder();
|
||||
svgXml = svgXml.replaceFirst("<svg ", "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" ");
|
||||
@@ -155,7 +160,8 @@ public class ExporterFactory {
|
||||
|
||||
fitSvg(document);
|
||||
|
||||
fixImageTagHref(document, imgBaseUrl);
|
||||
final Node child = document.getFirstChild();
|
||||
fixImageTagHref(document, (Element) child);
|
||||
|
||||
return document;
|
||||
|
||||
@@ -187,12 +193,7 @@ public class ExporterFactory {
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private static void fixImageTagHref(Document document, String imgBaseUrl) {
|
||||
final Node child = document.getFirstChild();
|
||||
fixImageTagHref(document, (Element) child, imgBaseUrl);
|
||||
}
|
||||
|
||||
private static void fixImageTagHref(@NotNull Document document, @NotNull Element element, String imgBaseUrl) {
|
||||
private void fixImageTagHref(@NotNull Document document, @NotNull Element element) {
|
||||
|
||||
final NodeList list = element.getChildNodes();
|
||||
|
||||
@@ -201,7 +202,7 @@ public class ExporterFactory {
|
||||
// find all groups
|
||||
if (GROUP_NODE_NAME.equals(node.getNodeName())) {
|
||||
// Must continue looking ....
|
||||
fixImageTagHref(document, (Element) node, imgBaseUrl);
|
||||
fixImageTagHref(document, (Element) node);
|
||||
|
||||
} else if (IMAGE_NODE_NAME.equals(node.getNodeName())) {
|
||||
|
||||
@@ -209,20 +210,63 @@ public class ExporterFactory {
|
||||
|
||||
// Cook image href ...
|
||||
final String imgUrl = elem.getAttribute("href");
|
||||
int index = imgUrl.lastIndexOf("/");
|
||||
elem.removeAttribute("href");
|
||||
if (index != -1) {
|
||||
final String iconName = imgUrl.substring(index + 1);
|
||||
// Hack for backward compatibility . This can be removed in 2012. :)
|
||||
String imgPath;
|
||||
imgPath = imgBaseUrl + "/" + imgUrl;
|
||||
elem.setAttribute("xlink:href", imgPath);
|
||||
FileInputStream fis = null;
|
||||
|
||||
// Obtains file name ...
|
||||
try {
|
||||
final File iconFile = iconFile(imgUrl);
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
fis = new FileInputStream(iconFile);
|
||||
BASE64Encoder encoder = new BASE64Encoder();
|
||||
encoder.encode(fis, bos);
|
||||
|
||||
elem.setAttribute("xlink:href", "data:image/png;base64," + bos.toString("8859_1"));
|
||||
elem.appendChild(document.createTextNode(" "));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
close(fis);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private File iconFile(@NotNull final String imgUrl) throws IOException {
|
||||
int index = imgUrl.lastIndexOf("/");
|
||||
final String iconName = imgUrl.substring(index + 1);
|
||||
final File iconsDir = new File(baseImgDir, "icons");
|
||||
|
||||
File iconFile = new File(iconsDir, iconName);
|
||||
if (!iconFile.exists()) {
|
||||
// It's not a icon, must be a note, attach image ...
|
||||
final File legacyIconsDir = new File(baseImgDir, "images");
|
||||
iconFile = new File(legacyIconsDir, iconName);
|
||||
}
|
||||
|
||||
if (!iconFile.exists()) {
|
||||
final File legacyIconsDir = new File(iconsDir, "legacy");
|
||||
iconFile = new File(legacyIconsDir, iconName);
|
||||
}
|
||||
|
||||
if (!iconFile.exists()) {
|
||||
throw new IOException("Icon could not be found:" + imgUrl);
|
||||
}
|
||||
|
||||
return iconFile;
|
||||
}
|
||||
|
||||
|
||||
private void close(Closeable fis) {
|
||||
if (fis != null) {
|
||||
try {
|
||||
fis.close();
|
||||
} catch (IOException e) {
|
||||
// Ignore ...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void fitSvg(Document document) {
|
||||
// viewBox size
|
||||
int mapWidth = 1024;
|
||||
|
@@ -18,30 +18,21 @@
|
||||
|
||||
package com.wisemapping.rest.view;
|
||||
|
||||
import com.wisemapping.exporter.ExportException;
|
||||
import com.wisemapping.exporter.ExportFormat;
|
||||
import com.wisemapping.exporter.ExportProperties;
|
||||
import com.wisemapping.exporter.ExporterFactory;
|
||||
import com.wisemapping.mail.NotificationService;
|
||||
import com.wisemapping.security.Utils;
|
||||
import org.apache.batik.transcoder.TranscoderException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.oxm.XmlMappingException;
|
||||
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
|
||||
import org.springframework.web.servlet.view.AbstractView;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
public class TransformView extends AbstractView {
|
||||
@@ -53,8 +44,9 @@ public class TransformView extends AbstractView {
|
||||
@Autowired
|
||||
private Jaxb2Marshaller jaxbMarshaller;
|
||||
|
||||
public TransformView(@NotNull final String contentType) {
|
||||
public TransformView(@NotNull final String contentType,@NotNull NotificationService notificationService) {
|
||||
this.contentType = contentType;
|
||||
this.notificationService = notificationService;
|
||||
this.exportFormat = ExportFormat.fromContentType(contentType);
|
||||
}
|
||||
|
||||
@@ -86,19 +78,19 @@ public class TransformView extends AbstractView {
|
||||
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
|
||||
|
||||
// Change image link URL.
|
||||
setBaseBaseImgUrl(exportFormat, properties);
|
||||
|
||||
final ServletContext servletContext = request.getSession().getServletContext();
|
||||
final ExporterFactory factory = new ExporterFactory(servletContext);
|
||||
try {
|
||||
// Write the conversion content ...
|
||||
final ServletOutputStream outputStream = response.getOutputStream();
|
||||
if (exportFormat == ExportFormat.FREEMIND) {
|
||||
ExporterFactory.export(properties, content, outputStream, null);
|
||||
factory.export(properties, content, outputStream, null);
|
||||
} else if (exportFormat == ExportFormat.WISEMAPPING) {
|
||||
final Object mindmap = viewMap.get("mindmap");
|
||||
final StreamResult result = new StreamResult(outputStream);
|
||||
jaxbMarshaller.marshal(mindmap, result);
|
||||
} else {
|
||||
ExporterFactory.export(properties, null, outputStream, content);
|
||||
factory.export(properties, null, outputStream, content);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
notificationService.reportMindmapExportError(content, Utils.getUser(), request.getHeader("User-Agent"),e);
|
||||
@@ -109,19 +101,5 @@ public class TransformView extends AbstractView {
|
||||
public String getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
private void setBaseBaseImgUrl(@NotNull ExportFormat format, @NotNull ExportProperties properties) {
|
||||
|
||||
final String baseUrl;
|
||||
if (format == ExportFormat.SVG) {
|
||||
baseUrl = "http://www.wisemapping.com/images";
|
||||
} else {
|
||||
final ServletContext servletContext = this.getServletContext();
|
||||
baseUrl = "file://" + servletContext.getRealPath("/");
|
||||
}
|
||||
properties.setBaseImagePath(baseUrl);
|
||||
}
|
||||
|
||||
private static final String IMG_SIZE_PARAMETER = "imgSize";
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user