summaryrefslogtreecommitdiff
path: root/reportbuilder/java/com/sun/star/report/pentaho/output/ImageProducer.java
diff options
context:
space:
mode:
Diffstat (limited to 'reportbuilder/java/com/sun/star/report/pentaho/output/ImageProducer.java')
-rw-r--r--reportbuilder/java/com/sun/star/report/pentaho/output/ImageProducer.java498
1 files changed, 498 insertions, 0 deletions
diff --git a/reportbuilder/java/com/sun/star/report/pentaho/output/ImageProducer.java b/reportbuilder/java/com/sun/star/report/pentaho/output/ImageProducer.java
new file mode 100644
index 000000000000..b3d6485d9195
--- /dev/null
+++ b/reportbuilder/java/com/sun/star/report/pentaho/output/ImageProducer.java
@@ -0,0 +1,498 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+package com.sun.star.report.pentaho.output;
+
+import com.sun.star.report.ImageService;
+import com.sun.star.report.InputRepository;
+import com.sun.star.report.OutputRepository;
+import com.sun.star.report.ReportExecutionException;
+import com.sun.star.report.pentaho.DefaultNameGenerator;
+
+import java.awt.Dimension;
+import java.awt.Image;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+
+import java.sql.Blob;
+import java.sql.SQLException;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.jfree.layouting.input.style.values.CSSNumericType;
+import org.jfree.layouting.input.style.values.CSSNumericValue;
+
+import org.pentaho.reporting.libraries.base.util.IOUtils;
+import org.pentaho.reporting.libraries.base.util.PngEncoder;
+import org.pentaho.reporting.libraries.base.util.WaitingImageObserver;
+
+
+/**
+ * This class manages the images embedded in a report.
+ *
+ * @author Thomas Morgner
+ * @since 31.03.2007
+ */
+public class ImageProducer
+{
+
+ private static final Log LOGGER = LogFactory.getLog(ImageProducer.class);
+
+ public static class OfficeImage
+ {
+
+ private final CSSNumericValue width;
+ private final CSSNumericValue height;
+ private final String embeddableLink;
+
+ public OfficeImage(final String embeddableLink, final CSSNumericValue width, final CSSNumericValue height)
+ {
+ this.embeddableLink = embeddableLink;
+ this.width = width;
+ this.height = height;
+ }
+
+ public CSSNumericValue getWidth()
+ {
+ return width;
+ }
+
+ public CSSNumericValue getHeight()
+ {
+ return height;
+ }
+
+ public String getEmbeddableLink()
+ {
+ return embeddableLink;
+ }
+ }
+
+ private static class ByteDataImageKey
+ {
+
+ private final byte[] keyData;
+ private Integer hashCode;
+
+ protected ByteDataImageKey(final byte[] keyData)
+ {
+ if (keyData == null)
+ {
+ throw new NullPointerException();
+ }
+ this.keyData = keyData;
+ }
+
+ public boolean equals(final Object o)
+ {
+ if (this != o)
+ {
+ if (o == null || getClass() != o.getClass())
+ {
+ return false;
+ }
+
+ final ByteDataImageKey key = (ByteDataImageKey) o;
+ if (!Arrays.equals(keyData, key.keyData))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public int hashCode()
+ {
+ if (hashCode != null)
+ {
+ return hashCode;
+ }
+
+ final int length = Math.min(keyData.length, 512);
+ int hashValue = 0;
+ for (int i = 0; i < length; i++)
+ {
+ final byte b = keyData[i];
+ hashValue = b + hashValue * 23;
+ }
+ this.hashCode = hashValue;
+ return hashValue;
+ }
+ }
+ private final Map imageCache;
+ private final InputRepository inputRepository;
+ private final OutputRepository outputRepository;
+ private final ImageService imageService;
+
+ public ImageProducer(final InputRepository inputRepository,
+ final OutputRepository outputRepository,
+ final ImageService imageService)
+ {
+ if (inputRepository == null)
+ {
+ throw new NullPointerException();
+ }
+ if (outputRepository == null)
+ {
+ throw new NullPointerException();
+ }
+ if (imageService == null)
+ {
+ throw new NullPointerException();
+ }
+
+ this.inputRepository = inputRepository;
+ this.outputRepository = outputRepository;
+ this.imageService = imageService;
+ this.imageCache = new HashMap();
+ }
+
+ /**
+ * Image-Data can be one of the following types: String, URL, URI, byte-array, blob.
+ *
+ * @param imageData
+ * @param preserveIRI
+ * @return
+ */
+ public OfficeImage produceImage(final Object imageData,
+ final boolean preserveIRI)
+ {
+
+ LOGGER.debug("Want to produce image " + imageData);
+ if (imageData instanceof String)
+ {
+ return produceFromString((String) imageData, preserveIRI);
+ }
+
+ if (imageData instanceof URL)
+ {
+ return produceFromURL((URL) imageData, preserveIRI);
+ }
+
+ if (imageData instanceof Blob)
+ {
+ return produceFromBlob((Blob) imageData);
+ }
+
+ if (imageData instanceof byte[])
+ {
+ return produceFromByteArray((byte[]) imageData);
+ }
+
+ if (imageData instanceof Image)
+ {
+ return produceFromImage((Image) imageData);
+ }
+ // not usable ..
+ return null;
+ }
+
+ private OfficeImage produceFromImage(final Image image)
+ {
+ // quick caching ... use a weak list ...
+ final WaitingImageObserver obs = new WaitingImageObserver(image);
+ obs.waitImageLoaded();
+
+ final PngEncoder encoder = new PngEncoder(image, PngEncoder.ENCODE_ALPHA, PngEncoder.FILTER_NONE, 5);
+ final byte[] data = encoder.pngEncode();
+ return produceFromByteArray(data);
+ }
+
+ private OfficeImage produceFromBlob(final Blob blob)
+ {
+ try
+ {
+ final InputStream inputStream = blob.getBinaryStream();
+ final int length = (int) blob.length();
+
+ final ByteArrayOutputStream bout = new ByteArrayOutputStream(length);
+ try
+ {
+ IOUtils.getInstance().copyStreams(inputStream, bout);
+ } finally
+ {
+ inputStream.close();
+ }
+ return produceFromByteArray(bout.toByteArray());
+ }
+ catch (IOException e)
+ {
+ LOGGER.warn("Failed to produce image from Blob", e);
+ }
+ catch (SQLException e)
+ {
+ LOGGER.warn("Failed to produce image from Blob", e);
+ }
+ return null;
+ }
+
+ private OfficeImage produceFromByteArray(final byte[] data)
+ {
+ final ByteDataImageKey imageKey = new ByteDataImageKey(data);
+ final OfficeImage o = (OfficeImage) imageCache.get(imageKey);
+ if (o != null)
+ {
+ return o;
+ }
+
+ try
+ {
+ final String mimeType = imageService.getMimeType(data);
+ final Dimension dims = imageService.getImageSize(data);
+
+ // copy the image into the local output-storage
+ // todo: Implement data-fingerprinting so that we can detect the mime-type
+ final OutputRepository storage = outputRepository.openOutputRepository("Pictures", null);
+ final DefaultNameGenerator nameGenerator = new DefaultNameGenerator(storage);
+ final String name = nameGenerator.generateName("image", mimeType);
+ final OutputStream outputStream = storage.createOutputStream(name, mimeType);
+ final ByteArrayInputStream bin = new ByteArrayInputStream(data);
+
+ try
+ {
+ IOUtils.getInstance().copyStreams(bin, outputStream);
+ } finally
+ {
+ outputStream.close();
+ storage.closeOutputRepository();
+ }
+
+ final CSSNumericValue widthVal = CSSNumericValue.createValue(CSSNumericType.MM, dims.getWidth() / 100.0);
+ final CSSNumericValue heightVal = CSSNumericValue.createValue(CSSNumericType.MM, dims.getHeight() / 100.0);
+ final OfficeImage officeImage = new OfficeImage("Pictures/" + name, widthVal, heightVal);
+ imageCache.put(imageKey, officeImage);
+ return officeImage;
+ }
+ catch (IOException e)
+ {
+ LOGGER.warn("Failed to load image from local input-repository", e);
+ }
+ catch (ReportExecutionException e)
+ {
+ LOGGER.warn("Failed to create image from local input-repository", e);
+ }
+ return null;
+ }
+
+ private OfficeImage produceFromString(final String source,
+ final boolean preserveIRI)
+ {
+
+ try
+ {
+ final URL url = new URL(source);
+ return produceFromURL(url, preserveIRI);
+ }
+ catch (MalformedURLException e)
+ {
+ // ignore .. but we had to try this ..
+ }
+
+ final OfficeImage o = (OfficeImage) imageCache.get(source);
+ if (o != null)
+ {
+ return o;
+ }
+
+ // Next, check whether this is a local path.
+ if (inputRepository.isReadable(source))
+ {
+ // cool, the file exists. Let's try to read it.
+ try
+ {
+ final ByteArrayOutputStream bout = new ByteArrayOutputStream(8192);
+ final InputStream inputStream = inputRepository.createInputStream(source);
+ try
+ {
+ IOUtils.getInstance().copyStreams(inputStream, bout);
+ } finally
+ {
+ inputStream.close();
+ }
+ final byte[] data = bout.toByteArray();
+ final Dimension dims = imageService.getImageSize(data);
+ final String mimeType = imageService.getMimeType(data);
+
+ final CSSNumericValue widthVal = CSSNumericValue.createValue(CSSNumericType.MM, dims.getWidth() / 100.0);
+ final CSSNumericValue heightVal = CSSNumericValue.createValue(CSSNumericType.MM, dims.getHeight() / 100.0);
+
+ final String filename = copyToOutputRepository(mimeType, data);
+ final OfficeImage officeImage = new OfficeImage(filename, widthVal, heightVal);
+ imageCache.put(source, officeImage);
+ return officeImage;
+ }
+ catch (IOException e)
+ {
+ LOGGER.warn("Failed to load image from local input-repository", e);
+ }
+ catch (ReportExecutionException e)
+ {
+ LOGGER.warn("Failed to create image from local input-repository", e);
+ }
+ }
+ else
+ {
+ try
+ {
+ URI rootURI = new URI(inputRepository.getRootURL());
+ final URI uri = rootURI.resolve(source);
+ return produceFromURL(uri.toURL(), preserveIRI);
+ }
+ catch (URISyntaxException ex)
+ {
+ }
+ catch (MalformedURLException e)
+ {
+ // ignore .. but we had to try this ..
+ }
+ }
+
+ // Return the image as broken image instead ..
+ final OfficeImage officeImage = new OfficeImage(source, null, null);
+ imageCache.put(source, officeImage);
+ return officeImage;
+ }
+
+ private OfficeImage produceFromURL(final URL url,
+ final boolean preserveIRI)
+ {
+ final String urlString = url.toString();
+ URI uri = null;
+ try
+ {
+ uri = new URI(urlString);
+ }
+ catch (URISyntaxException ex)
+ {
+ Logger.getLogger(ImageProducer.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ final OfficeImage o = (OfficeImage) imageCache.get(uri);
+ if (o != null)
+ {
+ return o;
+ }
+
+ try
+ {
+ final ByteArrayOutputStream bout = new ByteArrayOutputStream(8192);
+ final URLConnection urlConnection = url.openConnection();
+ final InputStream inputStream = new BufferedInputStream(urlConnection.getInputStream());
+ try
+ {
+ IOUtils.getInstance().copyStreams(inputStream, bout);
+ } finally
+ {
+ inputStream.close();
+ }
+ final byte[] data = bout.toByteArray();
+
+ final Dimension dims = imageService.getImageSize(data);
+ final String mimeType = imageService.getMimeType(data);
+ final CSSNumericValue widthVal = CSSNumericValue.createValue(CSSNumericType.MM, dims.getWidth() / 100.0);
+ final CSSNumericValue heightVal = CSSNumericValue.createValue(CSSNumericType.MM, dims.getHeight() / 100.0);
+
+ if (preserveIRI)
+ {
+ final OfficeImage retval = new OfficeImage(urlString, widthVal, heightVal);
+ imageCache.put(uri, retval);
+ return retval;
+ }
+
+ final String name = copyToOutputRepository(mimeType, data);
+ final OfficeImage officeImage = new OfficeImage(name, widthVal, heightVal);
+ imageCache.put(uri, officeImage);
+ return officeImage;
+ }
+ catch (IOException e)
+ {
+ LOGGER.warn("Failed to load image from local input-repository" + e);
+ }
+ catch (ReportExecutionException e)
+ {
+ LOGGER.warn("Failed to create image from local input-repository" + e);
+ }
+
+ if (!preserveIRI)
+ {
+ final OfficeImage image = new OfficeImage(urlString, null, null);
+ imageCache.put(uri, image);
+ return image;
+ }
+
+ // OK, everything failed; the image is not - repeat it - not usable.
+ return null;
+ }
+
+ private String copyToOutputRepository(final String urlMimeType, final byte[] data)
+ throws IOException, ReportExecutionException
+ {
+ final String mimeType;
+ if (urlMimeType == null)
+ {
+ mimeType = imageService.getMimeType(data);
+ }
+ else
+ {
+ mimeType = urlMimeType;
+ }
+
+ // copy the image into the local output-storage
+ final OutputRepository storage = outputRepository.openOutputRepository("Pictures", null);
+ final DefaultNameGenerator nameGenerator = new DefaultNameGenerator(storage);
+ final String name = nameGenerator.generateName("image", mimeType);
+ final OutputStream outputStream = storage.createOutputStream(name, mimeType);
+ final ByteArrayInputStream bin = new ByteArrayInputStream(data);
+
+ try
+ {
+ IOUtils.getInstance().copyStreams(bin, outputStream);
+ } finally
+ {
+ outputStream.close();
+ storage.closeOutputRepository();
+ }
+ return "Pictures/" + name;
+ }
+}