001: /**
002: * ===========================================
003: * JFreeReport : a free Java reporting library
004: * ===========================================
005: *
006: * Project Info: http://reporting.pentaho.org/
007: *
008: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
009: *
010: * This library is free software; you can redistribute it and/or modify it under the terms
011: * of the GNU Lesser General Public License as published by the Free Software Foundation;
012: * either version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
015: * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016: * See the GNU Lesser General Public License for more details.
017: *
018: * You should have received a copy of the GNU Lesser General Public License along with this
019: * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020: * Boston, MA 02111-1307, USA.
021: *
022: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
023: * in the United States and other countries.]
024: *
025: * ------------
026: * RenderUtility.java
027: * ------------
028: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
029: */package org.jfree.report.layout.output;
030:
031: import java.awt.Font;
032: import java.awt.Graphics2D;
033: import java.awt.Image;
034: import java.awt.Paint;
035: import java.awt.RenderingHints;
036: import java.awt.Stroke;
037: import java.awt.geom.Rectangle2D;
038: import java.awt.image.BufferedImage;
039: import java.io.IOException;
040:
041: import com.keypoint.PngEncoder;
042: import org.jfree.report.DefaultImageReference;
043: import org.jfree.report.ElementAlignment;
044: import org.jfree.report.ImageContainer;
045: import org.jfree.report.layout.model.RenderNode;
046: import org.jfree.report.style.ElementStyleKeys;
047: import org.jfree.report.style.FontSmooth;
048: import org.jfree.report.style.StyleSheet;
049: import org.jfree.report.style.TextStyleKeys;
050: import org.jfree.report.util.ImageUtils;
051: import org.jfree.report.util.geom.StrictBounds;
052: import org.jfree.report.util.geom.StrictGeomUtility;
053: import org.jfree.ui.Drawable;
054: import org.jfree.util.Log;
055: import org.jfree.util.WaitingImageObserver;
056:
057: /**
058: * Creation-Date: 12.05.2007, 15:58:43
059: *
060: * @author Thomas Morgner
061: */
062: public class RenderUtility {
063: private RenderUtility() {
064: }
065:
066: public static boolean isFontSmooth(final StyleSheet styleSheet,
067: final OutputProcessorMetaData metaData) {
068: final double fontSize = styleSheet
069: .getDoubleStyleProperty(
070: TextStyleKeys.FONTSIZE,
071: metaData
072: .getNumericFeatureValue(OutputProcessorFeature.DEFAULT_FONT_SIZE));
073:
074: final FontSmooth smoothing = (FontSmooth) styleSheet
075: .getStyleProperty(TextStyleKeys.FONT_SMOOTH);
076: final boolean antiAliasing;
077: if (FontSmooth.NEVER.equals(smoothing)) {
078: antiAliasing = false;
079: } else if (FontSmooth.AUTO.equals(smoothing)
080: && fontSize <= metaData
081: .getNumericFeatureValue(OutputProcessorFeature.FONT_SMOOTH_THRESHOLD)) {
082: antiAliasing = false;
083: } else {
084: antiAliasing = true;
085: }
086: return antiAliasing;
087: }
088:
089: /**
090: * Encodes the given image as PNG, stores the image in the generated file and returns the name of the new image file.
091: *
092: * @param image the image to be encoded
093: * @return the name of the image, never null.
094: *
095: * @throws IOException if an IO erro occured.
096: */
097: public static byte[] encodeImage(final Image image) {
098: // quick caching ... use a weak list ...
099: final WaitingImageObserver obs = new WaitingImageObserver(image);
100: obs.waitImageLoaded();
101:
102: final PngEncoder encoder = new PngEncoder(image,
103: PngEncoder.ENCODE_ALPHA, PngEncoder.FILTER_NONE, 5);
104: return encoder.pngEncode();
105: }
106:
107: public static Image scaleImage(final Image img,
108: final int targetWidth, final int targetHeight,
109: final Object hintValue, final boolean higherQuality) {
110: final int type = BufferedImage.TYPE_INT_ARGB;
111:
112: Image ret = img;
113: int w;
114: int h;
115: do {
116:
117: if (higherQuality) {
118: final int imageWidth = ret.getWidth(null);
119: final int imageHeight = ret.getHeight(null);
120: if (imageWidth < targetWidth) {
121: // This is a up-scale operation.
122: w = Math.min(imageWidth << 1, targetWidth);
123: } else if (imageWidth > targetWidth) {
124: // downscale
125: w = Math.max(imageWidth >> 1, targetWidth);
126: } else {
127: w = imageWidth;
128: }
129:
130: if (imageHeight < targetHeight) {
131: // This is a up-scale operation.
132: h = Math.min(imageHeight << 1, targetHeight);
133: } else if (imageHeight > targetHeight) {
134: // downscale
135: h = Math.max(imageHeight >> 1, targetHeight);
136: } else {
137: h = imageHeight;
138: }
139: } else {
140: w = targetWidth;
141: h = targetHeight;
142: }
143:
144: final BufferedImage tmp = new BufferedImage(w, h, type);
145: final Graphics2D g2 = tmp.createGraphics();
146: g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
147: hintValue);
148: // this one scales the image ..
149: if (ret instanceof BufferedImage) {
150: if (g2.drawImage(ret, 0, 0, w, h, null) == false) {
151: Log
152: .debug("Failed to scale the image. This should not happen.");
153: }
154: } else {
155: final WaitingImageObserver obs = new WaitingImageObserver(
156: ret);
157: while (g2.drawImage(ret, 0, 0, w, h, null) == false) {
158: obs.waitImageLoaded();
159: if (obs.isError()) {
160: Log
161: .warn("Error while loading the image during the rendering.");
162: break;
163: }
164: }
165:
166: }
167: g2.dispose();
168:
169: ret = tmp;
170: } while (w != targetWidth || h != targetHeight);
171:
172: return ret;
173: }
174:
175: public static ImageContainer createImageFromDrawable(
176: final Drawable drawable, final StrictBounds rect,
177: final RenderNode box, final OutputProcessorMetaData metaData) {
178: final int imageWidth = (int) StrictGeomUtility
179: .toExternalValue(rect.getWidth());
180: final int imageHeight = (int) StrictGeomUtility
181: .toExternalValue(rect.getHeight());
182:
183: if (imageWidth == 0 && imageHeight == 0) {
184: return null;
185: }
186:
187: final double devResolution = metaData
188: .getNumericFeatureValue(OutputProcessorFeature.DEVICE_RESOLUTION);
189: final double scale;
190: if (metaData
191: .isFeatureSupported(OutputProcessorFeature.IMAGE_RESOLUTION_MAPPING)
192: && devResolution > 0) {
193: scale = devResolution / 72.0;
194: } else {
195: scale = 1;
196: }
197:
198: final Image image = ImageUtils
199: .createTransparentImage((int) (imageWidth * scale),
200: (int) (imageHeight * scale));
201: final Graphics2D g2 = (Graphics2D) image.getGraphics();
202: g2.scale(scale, scale);
203: // the clipping bounds are a sub-area of the whole drawable
204: // we only want to print a certain area ...
205:
206: final StyleSheet style = box.getStyleSheet();
207: final String fontName = (String) style
208: .getStyleProperty(TextStyleKeys.FONT);
209: final int fontSize = style.getIntStyleProperty(
210: TextStyleKeys.FONTSIZE, 8);
211: final boolean bold = style
212: .getBooleanStyleProperty(TextStyleKeys.BOLD);
213: final boolean italics = style
214: .getBooleanStyleProperty(TextStyleKeys.ITALIC);
215: if (bold && italics) {
216: g2.setFont(new Font(fontName, Font.BOLD | Font.ITALIC,
217: fontSize));
218: } else if (bold) {
219: g2.setFont(new Font(fontName, Font.BOLD, fontSize));
220: } else if (italics) {
221: g2.setFont(new Font(fontName, Font.ITALIC, fontSize));
222: } else {
223: g2.setFont(new Font(fontName, Font.PLAIN, fontSize));
224: }
225:
226: g2.setStroke((Stroke) style
227: .getStyleProperty(ElementStyleKeys.STROKE));
228: final Paint extPaint = (Paint) style
229: .getStyleProperty(ElementStyleKeys.EXTPAINT);
230: if (extPaint != null) {
231: g2.setPaint(extPaint);
232: } else {
233: g2.setPaint((Paint) style
234: .getStyleProperty(ElementStyleKeys.PAINT));
235: }
236:
237: drawable.draw(g2, new Rectangle2D.Double(0, 0, imageWidth,
238: imageHeight));
239: g2.dispose();
240:
241: try {
242: return new DefaultImageReference(image);
243: } catch (IOException e1) {
244: Log
245: .warn("Unable to fully load a given image. (It should not happen here.)");
246: return null;
247: }
248: }
249:
250: public static long computeHorizontalAlignment(
251: final ElementAlignment alignment, final long width,
252: final long imageWidth) {
253: if (ElementAlignment.RIGHT.equals(alignment)) {
254: return Math.max(0, width - imageWidth);
255: }
256: if (ElementAlignment.CENTER.equals(alignment)) {
257: return Math.max(0, (width - imageWidth) / 2);
258: }
259: return 0;
260: }
261:
262: public static long computeVerticalAlignment(
263: final ElementAlignment alignment, final long height,
264: final long imageHeight) {
265: if (ElementAlignment.BOTTOM.equals(alignment)) {
266: return Math.max(0, height - imageHeight);
267: }
268: if (ElementAlignment.MIDDLE.equals(alignment)) {
269: return Math.max(0, (height - imageHeight) / 2);
270: }
271: return 0;
272: }
273:
274: }
|