1 24 package org.riotfamily.website.txt2img; 25 26 import java.awt.Color ; 27 import java.awt.Dimension ; 28 import java.awt.Font ; 29 import java.awt.FontFormatException ; 30 import java.awt.Graphics ; 31 import java.awt.Graphics2D ; 32 import java.awt.Image ; 33 import java.awt.RenderingHints ; 34 import java.awt.font.FontRenderContext ; 35 import java.awt.font.LineBreakMeasurer ; 36 import java.awt.font.TextAttribute ; 37 import java.awt.font.TextLayout ; 38 import java.awt.image.BufferedImage ; 39 import java.io.IOException ; 40 import java.io.OutputStream ; 41 import java.text.AttributedCharacterIterator ; 42 import java.text.AttributedString ; 43 44 import javax.imageio.ImageIO ; 45 46 import org.riotfamily.common.collection.FlatMap; 47 import org.riotfamily.common.util.ColorUtils; 48 import org.riotfamily.common.util.FormatUtils; 49 import org.springframework.beans.factory.InitializingBean; 50 import org.springframework.core.io.Resource; 51 52 56 public class ImageGenerator implements InitializingBean { 57 58 private Font font = Font.getFont("Serif"); 59 60 private float size = 22; 61 62 private int paddingTop = 0; 63 64 private int paddingRight = 0; 65 66 private int paddingBottom = 0; 67 68 private int paddingLeft = 0; 69 70 private int lineSpacing = 0; 71 72 private Integer maxWidth; 73 74 private Color color = Color.BLACK; 75 76 private boolean antiAlias = true; 77 78 private boolean resample = false; 79 80 private int internalFontSize = 120; 81 82 private int scale = 1; 83 84 private FlatMap attributes = new FlatMap(); 85 86 93 public void setFont(Resource res) throws FontFormatException , IOException { 94 String ext = FormatUtils.getExtension(res.getFilename()).toLowerCase(); 95 int format = Font.TRUETYPE_FONT; 96 if (ext.equals("pfa") || ext.equals("pfb")) { 97 format = Font.TYPE1_FONT; 98 } 99 this.font = Font.createFont(format, res.getInputStream()); 100 } 101 102 111 public void setColor(String color) { 112 this.color = ColorUtils.parseColor(color); 113 } 114 115 118 public void setSize(float size) { 119 this.size = size; 120 } 121 122 125 public void setAntiAlias(boolean antiAlias) { 126 this.antiAlias = antiAlias; 127 } 128 129 133 public void setLineSpacing(int lineSpacing) { 134 this.lineSpacing = lineSpacing; 135 } 136 137 140 public void setMaxWidth(Integer maxWidth) { 141 this.maxWidth = maxWidth; 142 } 143 144 148 public void setPaddingTop(int paddingTop) { 149 this.paddingTop = paddingTop; 150 } 151 152 156 public void setPaddingRight(int paddingRight) { 157 this.paddingRight = paddingRight; 158 } 159 160 164 public void setPaddingBottom(int paddingBottom) { 165 this.paddingBottom = paddingBottom; 166 } 167 168 172 public void setPaddingLeft(int paddingLeft) { 173 this.paddingLeft = paddingLeft; 174 } 175 176 180 public void setResample(boolean resample) { 181 this.resample = resample; 182 } 183 184 188 public void setInternalFontSize(int internalFontSize) { 189 this.internalFontSize = internalFontSize; 190 } 191 192 public void afterPropertiesSet() { 193 if (resample) { 194 scale = Math.round(internalFontSize / size); 195 size *= scale; 196 paddingTop *= scale; 197 paddingRight *= scale; 198 paddingBottom *= scale; 199 paddingLeft *= scale; 200 lineSpacing *= scale; 201 if (maxWidth != null) { 202 maxWidth = new Integer (maxWidth.intValue() * scale); 203 } 204 } 205 attributes.put(TextAttribute.FONT, font.deriveFont(size)); 206 attributes.put(TextAttribute.FOREGROUND, color); 207 } 208 209 public void generate(String text, int maxWidth, String color, OutputStream os) 210 throws IOException { 211 212 if (this.maxWidth != null) { 213 maxWidth = this.maxWidth.intValue(); 214 } 215 else if (resample && maxWidth < Integer.MAX_VALUE) { 216 maxWidth *= scale; 217 } 218 Dimension size = getSize(text, maxWidth); 219 BufferedImage image = createImage(size); 220 drawText(text, maxWidth, color, image); 221 if (resample) { 222 int w = (int) (size.getWidth() / scale); 223 int h = (int) (size.getHeight() / scale); 224 Image scaledImage = image.getScaledInstance(w, h, Image.SCALE_SMOOTH); 225 image = new BufferedImage (w, h, BufferedImage.TYPE_INT_ARGB); 226 Graphics g = image.getGraphics(); 227 g.drawImage(scaledImage, 0, 0, w, h, null); 228 g.dispose(); 229 } 230 231 ImageIO.write(image, "png", os); 232 image.flush(); 233 } 234 235 protected Dimension getSize(String text, float maxWidth) { 236 return layout(text, maxWidth, null, createImage(new Dimension (1, 1)), false); 237 } 238 239 protected void drawText(String text, float maxWidth, String color, 240 BufferedImage image) { 241 242 layout(text, maxWidth, color, image, true); 243 } 244 245 protected Dimension layout(String text, float maxWidth, String color, 246 BufferedImage image, boolean draw) { 247 248 FlatMap attrs = attributes; 249 if (draw && color != null) { 250 attrs = new FlatMap(attributes); 251 attrs.put(TextAttribute.FOREGROUND, ColorUtils.parseColor(color)); 252 } 253 AttributedString as = new AttributedString (text, attrs); 254 Graphics2D graphics = createGraphics(image); 255 FontRenderContext fc = graphics.getFontRenderContext(); 256 AttributedCharacterIterator it = as.getIterator(); 257 LineBreakMeasurer measurer = new LineBreakMeasurer (it, fc); 258 int y = paddingTop; 259 int maxX = 0; 260 while (measurer.getPosition() < it.getEndIndex()) { 261 TextLayout layout; 262 int nextBreak = text.indexOf('\n', measurer.getPosition() + 1); 263 if (nextBreak != -1) { 264 layout = measurer.nextLayout(maxWidth, nextBreak, false); 265 } 266 else { 267 layout = measurer.nextLayout(maxWidth); 268 } 269 y += layout.getAscent(); 270 if (draw) { 271 layout.draw(graphics, paddingLeft, y); 272 } 273 y += layout.getDescent(); 274 maxX = Math.max(maxX, paddingLeft + (int) layout.getVisibleAdvance() + paddingRight); 275 y += layout.getLeading(); 276 if (measurer.getPosition() < it.getEndIndex()) { 277 y += lineSpacing; 278 } 279 } 280 y += paddingBottom; 281 graphics.dispose(); 282 return new Dimension (maxX, y); 283 } 284 285 protected Graphics2D createGraphics(BufferedImage image) { 286 Graphics2D graphics = image.createGraphics(); 287 graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, antiAlias 288 ? RenderingHints.VALUE_ANTIALIAS_ON 289 : RenderingHints.VALUE_ANTIALIAS_OFF); 290 291 graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, antiAlias 292 ? RenderingHints.VALUE_TEXT_ANTIALIAS_ON 293 : RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); 294 295 graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, antiAlias 296 ? RenderingHints.VALUE_FRACTIONALMETRICS_ON 297 : RenderingHints.VALUE_FRACTIONALMETRICS_OFF); 298 299 return graphics; 300 } 301 302 protected BufferedImage createImage(Dimension size) { 303 return new BufferedImage ((int) size.getWidth(), (int) size.getHeight(), 304 BufferedImage.TYPE_INT_ARGB); 305 } 306 307 } 308 | Popular Tags |