java/cewolf-1.0/src/main/java/de/laures/cewolf/util/Renderer.java
author František Kučera <franta-hg@frantovo.cz>
Sat, 28 Feb 2009 21:31:02 +0100
changeset 1 639991d0808a
permissions -rw-r--r--
Rozbalená knihovna verze 1.0
franta-hg@1
     1
/* ================================================================
franta-hg@1
     2
 * Cewolf : Chart enabling Web Objects Framework
franta-hg@1
     3
 * ================================================================
franta-hg@1
     4
 *
franta-hg@1
     5
 * Project Info:  http://cewolf.sourceforge.net
franta-hg@1
     6
 * Project Lead:  Guido Laures (guido@laures.de);
franta-hg@1
     7
 *
franta-hg@1
     8
 * (C) Copyright 2002, by Guido Laures
franta-hg@1
     9
 *
franta-hg@1
    10
 * This library is free software; you can redistribute it and/or modify it under the terms
franta-hg@1
    11
 * of the GNU Lesser General Public License as published by the Free Software Foundation;
franta-hg@1
    12
 * either version 2.1 of the License, or (at your option) any later version.
franta-hg@1
    13
 *
franta-hg@1
    14
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
franta-hg@1
    15
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
franta-hg@1
    16
 * See the GNU Lesser General Public License for more details.
franta-hg@1
    17
 *
franta-hg@1
    18
 * You should have received a copy of the GNU Lesser General Public License along with this
franta-hg@1
    19
 * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
franta-hg@1
    20
 * Boston, MA 02111-1307, USA.
franta-hg@1
    21
 */
franta-hg@1
    22
franta-hg@1
    23
package de.laures.cewolf.util;
franta-hg@1
    24
franta-hg@1
    25
import java.awt.Color;
franta-hg@1
    26
import java.awt.Dimension;
franta-hg@1
    27
import java.awt.Graphics2D;
franta-hg@1
    28
import java.awt.Rectangle;
franta-hg@1
    29
import java.awt.geom.Rectangle2D;
franta-hg@1
    30
import java.awt.image.BufferedImage;
franta-hg@1
    31
import java.io.ByteArrayOutputStream;
franta-hg@1
    32
import java.io.IOException;
franta-hg@1
    33
import java.io.OutputStreamWriter;
franta-hg@1
    34
import java.util.Iterator;
franta-hg@1
    35
import java.util.List;
franta-hg@1
    36
franta-hg@1
    37
import org.apache.batik.dom.GenericDOMImplementation;
franta-hg@1
    38
import org.apache.batik.svggen.SVGGeneratorContext;
franta-hg@1
    39
import org.apache.batik.svggen.SVGGraphics2D;
franta-hg@1
    40
import org.apache.commons.logging.Log;
franta-hg@1
    41
import org.apache.commons.logging.LogFactory;
franta-hg@1
    42
import org.jfree.chart.ChartRenderingInfo;
franta-hg@1
    43
import org.jfree.chart.ChartUtilities;
franta-hg@1
    44
import org.jfree.chart.JFreeChart;
franta-hg@1
    45
import org.jfree.chart.block.RectangleConstraint;
franta-hg@1
    46
import org.jfree.chart.entity.StandardEntityCollection;
franta-hg@1
    47
import org.jfree.chart.title.LegendTitle;
franta-hg@1
    48
import org.jfree.ui.RectangleEdge;
franta-hg@1
    49
import org.w3c.dom.DOMImplementation;
franta-hg@1
    50
import org.w3c.dom.Document;
franta-hg@1
    51
franta-hg@1
    52
import com.sun.image.codec.jpeg.JPEGCodec;
franta-hg@1
    53
import com.sun.image.codec.jpeg.JPEGEncodeParam;
franta-hg@1
    54
import com.sun.image.codec.jpeg.JPEGImageEncoder;
franta-hg@1
    55
franta-hg@1
    56
import de.laures.cewolf.CewolfException;
franta-hg@1
    57
import de.laures.cewolf.ChartImage;
franta-hg@1
    58
import de.laures.cewolf.ChartRenderingException;
franta-hg@1
    59
import de.laures.cewolf.ConfigurationException;
franta-hg@1
    60
import de.laures.cewolf.WebConstants;
franta-hg@1
    61
franta-hg@1
    62
/**
franta-hg@1
    63
 * Renderer for ChartImageDefinitions.
franta-hg@1
    64
 *
franta-hg@1
    65
 * @author glaures
franta-hg@1
    66
 * @author tbardzil
franta-hg@1
    67
 * @see    de.laures.cewolf.ChartImage
franta-hg@1
    68
 */
franta-hg@1
    69
public class Renderer implements WebConstants {
franta-hg@1
    70
	
franta-hg@1
    71
	private final static Log log = LogFactory.getLog(Renderer.class);
franta-hg@1
    72
franta-hg@1
    73
	/** Creates a new instance of Renderer */
franta-hg@1
    74
	private Renderer() {
franta-hg@1
    75
	};
franta-hg@1
    76
franta-hg@1
    77
	/**
franta-hg@1
    78
	 * Renders a chart image
franta-hg@1
    79
	 *
franta-hg@1
    80
	 * @param  cd                  the chart to render
franta-hg@1
    81
	 * @return                     the rendered image
franta-hg@1
    82
	 * @throws CewolfException
franta-hg@1
    83
	 */
franta-hg@1
    84
	public static RenderedImage render(ChartImage cd, Object chart) throws CewolfException {
franta-hg@1
    85
		log.debug("rendering " + cd);
franta-hg@1
    86
		switch (cd.getType()) {
franta-hg@1
    87
			case ChartImage.IMG_TYPE_CHART :
franta-hg@1
    88
				return renderChart(cd, chart);
franta-hg@1
    89
			case ChartImage.IMG_TYPE_LEGEND :
franta-hg@1
    90
				return renderLegend(cd, chart);
franta-hg@1
    91
			default :
franta-hg@1
    92
				throw new ConfigurationException(cd.getType() + " is not a supported image type");
franta-hg@1
    93
		}
franta-hg@1
    94
	}
franta-hg@1
    95
franta-hg@1
    96
	/**
franta-hg@1
    97
	 * Renders a chart
franta-hg@1
    98
	 * @param cd the chart image to be rendered
franta-hg@1
    99
	 * @return the rendered image
franta-hg@1
   100
	 * @throws CewolfException
franta-hg@1
   101
	 */
franta-hg@1
   102
	private static RenderedImage renderChart(ChartImage cd, Object chart) throws CewolfException {
franta-hg@1
   103
		try {
franta-hg@1
   104
			final ByteArrayOutputStream baos = new ByteArrayOutputStream();
franta-hg@1
   105
			final ChartRenderingInfo info = new ChartRenderingInfo(new StandardEntityCollection());
franta-hg@1
   106
			final String mimeType = cd.getMimeType();
franta-hg@1
   107
			if (MIME_PNG.equals(mimeType)) {
franta-hg@1
   108
				handlePNG(baos, (JFreeChart)chart, cd.getWidth(), cd.getHeight(), info);
franta-hg@1
   109
			} else if (MIME_JPEG.equals(mimeType)) {
franta-hg@1
   110
			    handleJPEG(baos, (JFreeChart)chart, cd.getWidth(), cd.getHeight(), info);
franta-hg@1
   111
			} else if (MIME_SVG.equals(mimeType)) {
franta-hg@1
   112
				handleSVG(baos, (JFreeChart)chart, cd.getWidth(), cd.getHeight());
franta-hg@1
   113
			} else {
franta-hg@1
   114
				throw new RenderingException("Mime type " + mimeType + " is unsupported.");
franta-hg@1
   115
			}
franta-hg@1
   116
			baos.close();
franta-hg@1
   117
			return new RenderedImage(baos.toByteArray(), mimeType, info);
franta-hg@1
   118
		} catch (IOException ioe) {
franta-hg@1
   119
			log.error(ioe);
franta-hg@1
   120
			throw new ChartRenderingException(ioe.getMessage(),ioe);
franta-hg@1
   121
		}
franta-hg@1
   122
	}
franta-hg@1
   123
franta-hg@1
   124
	/**
franta-hg@1
   125
	 * Handles rendering a chart as a PNG. Currently this method is synchronized
franta-hg@1
   126
	 * because of concurrency issues with JFreeChart.
franta-hg@1
   127
	 *
franta-hg@1
   128
	 * @param  baos
franta-hg@1
   129
	 * @param  chart
franta-hg@1
   130
	 * @param  width
franta-hg@1
   131
	 * @param  height
franta-hg@1
   132
	 * @param  info
franta-hg@1
   133
	 * @throws IOException
franta-hg@1
   134
	 */
franta-hg@1
   135
	private static synchronized void handlePNG(
franta-hg@1
   136
		ByteArrayOutputStream baos,
franta-hg@1
   137
		JFreeChart chart,
franta-hg@1
   138
		int width,
franta-hg@1
   139
		int height,
franta-hg@1
   140
		ChartRenderingInfo info)
franta-hg@1
   141
		throws IOException {
franta-hg@1
   142
		ChartUtilities.writeChartAsPNG(baos, chart, width, height, info);
franta-hg@1
   143
	}
franta-hg@1
   144
	
franta-hg@1
   145
	/**
franta-hg@1
   146
	 * Handles rendering a chart as a JPEG. Currently this method is synchronized
franta-hg@1
   147
	 * because of concurrency issues with JFreeChart.
franta-hg@1
   148
	 *
franta-hg@1
   149
	 * @param  baos
franta-hg@1
   150
	 * @param  chart
franta-hg@1
   151
	 * @param  width
franta-hg@1
   152
	 * @param  height
franta-hg@1
   153
	 * @param  info
franta-hg@1
   154
	 * @throws IOException
franta-hg@1
   155
	 */
franta-hg@1
   156
	private static synchronized void handleJPEG(
franta-hg@1
   157
		ByteArrayOutputStream baos,
franta-hg@1
   158
		JFreeChart chart,
franta-hg@1
   159
		int width,
franta-hg@1
   160
		int height,
franta-hg@1
   161
		ChartRenderingInfo info)
franta-hg@1
   162
		throws IOException {
franta-hg@1
   163
		ChartUtilities.writeChartAsJPEG(baos, chart, width, height, info);
franta-hg@1
   164
	}			
franta-hg@1
   165
franta-hg@1
   166
	/**
franta-hg@1
   167
	 * Handles rendering a chart as a SVG. Currently this method is synchronized
franta-hg@1
   168
	 * because of concurrency issues with JFreeChart.
franta-hg@1
   169
	 *
franta-hg@1
   170
	 * @param  baos
franta-hg@1
   171
	 * @param  chart
franta-hg@1
   172
	 * @param  width
franta-hg@1
   173
	 * @param  height
franta-hg@1
   174
	 * @throws IOException
franta-hg@1
   175
	 */
franta-hg@1
   176
	private static synchronized void handleSVG(ByteArrayOutputStream baos, JFreeChart chart, int width, int height)
franta-hg@1
   177
		throws IOException {
franta-hg@1
   178
		OutputStreamWriter writer = new OutputStreamWriter(baos, "UTF-8");
franta-hg@1
   179
		DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation();
franta-hg@1
   180
		Document document = domImpl.createDocument("cewolf-svg", "svg", null);
franta-hg@1
   181
		SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(document);
franta-hg@1
   182
		ctx.setComment("Generated by Cewolf using JFreeChart and Apache Batik SVG Generator");
franta-hg@1
   183
		SVGGraphics2D svgGenerator = new SVGGraphics2D(ctx, false);
franta-hg@1
   184
		svgGenerator.setSVGCanvasSize(new Dimension(width, height));
franta-hg@1
   185
		chart.draw(svgGenerator, new Rectangle2D.Double(0, 0, width, height), null);
franta-hg@1
   186
		svgGenerator.stream(writer, false);
franta-hg@1
   187
		writer.close();
franta-hg@1
   188
	}
franta-hg@1
   189
franta-hg@1
   190
  //gets first legend in the list
franta-hg@1
   191
  public static LegendTitle getLegend(JFreeChart chart)
franta-hg@1
   192
  {
franta-hg@1
   193
    //i need to find the legend now.
franta-hg@1
   194
    LegendTitle legend = null;
franta-hg@1
   195
    List subTitles = chart.getSubtitles();
franta-hg@1
   196
    Iterator iter = subTitles.iterator();
franta-hg@1
   197
    while (iter.hasNext())
franta-hg@1
   198
    {
franta-hg@1
   199
      Object o = iter.next();
franta-hg@1
   200
      if (o instanceof LegendTitle)
franta-hg@1
   201
      {
franta-hg@1
   202
        legend = (LegendTitle) o;
franta-hg@1
   203
        break;
franta-hg@1
   204
      }
franta-hg@1
   205
    }
franta-hg@1
   206
    return legend;
franta-hg@1
   207
  }
franta-hg@1
   208
  
franta-hg@1
   209
  //removes first legend in the list
franta-hg@1
   210
  public static void removeLegend(JFreeChart chart)
franta-hg@1
   211
  {
franta-hg@1
   212
    List subTitles = chart.getSubtitles();
franta-hg@1
   213
    Iterator iter = subTitles.iterator();
franta-hg@1
   214
    while (iter.hasNext())
franta-hg@1
   215
    {
franta-hg@1
   216
      Object o = iter.next();
franta-hg@1
   217
      if (o instanceof LegendTitle)
franta-hg@1
   218
      {
franta-hg@1
   219
        iter.remove();
franta-hg@1
   220
        break;
franta-hg@1
   221
      }
franta-hg@1
   222
    }
franta-hg@1
   223
  }
franta-hg@1
   224
  
franta-hg@1
   225
	/**
franta-hg@1
   226
	 * Renders a legend
franta-hg@1
   227
	 * @param cd the chart iamge to be rendred
franta-hg@1
   228
	 * @return the rendered image
franta-hg@1
   229
	 * @throws CewolfException
franta-hg@1
   230
	 */
franta-hg@1
   231
	private static RenderedImage renderLegend(ChartImage cd, Object c) throws CewolfException {
franta-hg@1
   232
		try {
franta-hg@1
   233
		    JFreeChart chart = (JFreeChart) c;
franta-hg@1
   234
			final int width = cd.getWidth();
franta-hg@1
   235
			final int height = cd.getHeight();
franta-hg@1
   236
			LegendTitle legend = getLegend(chart);
franta-hg@1
   237
			boolean haslegend = true;
franta-hg@1
   238
			
franta-hg@1
   239
			// with JFreeChart v0.9.20, the only way to get a valid legend,
franta-hg@1
   240
			// is either to retrieve it from the chart or to assign a new
franta-hg@1
   241
			// one to the chart. In the case where the chart has no legend,
franta-hg@1
   242
			// a new one must be assigned, but just for rendering. After, we
franta-hg@1
   243
			// have to reset the legend to null in the chart.
franta-hg@1
   244
			if (null == legend) {
franta-hg@1
   245
				haslegend = false;
franta-hg@1
   246
				legend = new LegendTitle(chart.getPlot());   
franta-hg@1
   247
			}
franta-hg@1
   248
			legend.setPosition(RectangleEdge.BOTTOM);
franta-hg@1
   249
			BufferedImage bimage = ImageHelper.createImage(width, height);
franta-hg@1
   250
			Graphics2D g = bimage.createGraphics();
franta-hg@1
   251
			g.setColor(Color.white);
franta-hg@1
   252
			g.fillRect(0, 0, width, height);
franta-hg@1
   253
			legend.arrange(g,new RectangleConstraint(width,height));
franta-hg@1
   254
 			legend.draw(g, new Rectangle(width, height));
franta-hg@1
   255
			ByteArrayOutputStream out = new ByteArrayOutputStream();
franta-hg@1
   256
			JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
franta-hg@1
   257
			JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bimage);
franta-hg@1
   258
			param.setQuality(1.0f, true);
franta-hg@1
   259
			encoder.encode(bimage, param);
franta-hg@1
   260
			out.close();
franta-hg@1
   261
franta-hg@1
   262
			// if the chart had no legend, reset it to null in order to give back the
franta-hg@1
   263
			// chart in the state we received it.
franta-hg@1
   264
			if (!haslegend) {
franta-hg@1
   265
				removeLegend(chart);
franta-hg@1
   266
			}
franta-hg@1
   267
			
franta-hg@1
   268
			return new RenderedImage(
franta-hg@1
   269
				out.toByteArray(),
franta-hg@1
   270
				"image/jpeg",
franta-hg@1
   271
				new ChartRenderingInfo(new StandardEntityCollection()));
franta-hg@1
   272
		} catch (IOException ioex) {
franta-hg@1
   273
			log.error(ioex);
franta-hg@1
   274
			throw new ChartRenderingException(ioex.getMessage(), ioex);
franta-hg@1
   275
		}
franta-hg@1
   276
	}
franta-hg@1
   277
franta-hg@1
   278
}