1 23 24 package org.infoglue.deliver.util.graphics; 25 26 import java.awt.Color ; 27 import java.awt.Font ; 28 import java.awt.Graphics2D ; 29 import java.awt.RenderingHints ; 30 import java.awt.font.FontRenderContext ; 31 import java.awt.font.LineBreakMeasurer ; 32 import java.awt.font.TextAttribute ; 33 import java.awt.font.TextLayout ; 34 import java.awt.geom.Point2D ; 35 import java.awt.image.BufferedImage ; 36 import java.io.File ; 37 import java.io.IOException ; 38 import java.io.InputStream ; 39 import java.lang.reflect.Method ; 40 import java.net.URL ; 41 import java.net.URLConnection ; 42 import java.text.AttributedCharacterIterator ; 43 import java.text.AttributedString ; 44 import java.util.HashMap ; 45 import java.util.Iterator ; 46 import java.util.Map ; 47 48 import javax.imageio.ImageIO ; 49 50 import org.apache.log4j.Logger; 51 import org.infoglue.cms.util.CmsPropertyHandler; 52 53 59 public class AdvancedImageRenderer 60 { 61 private static final long serialVersionUID = -1377395059993980530L; 62 63 private final static Logger logger = Logger.getLogger( AdvancedImageRenderer.class.getName() ); 64 65 private int imageType = BufferedImage.TYPE_4BYTE_ABGR; 67 68 private static BufferedImage templateImage = null; 71 72 private BufferedImage renderedImage = null; 74 75 private String fontName = "Dialog"; 77 78 private int fontStyle = Font.PLAIN; 80 81 private int fontSize = 18; 83 84 private Font font = null; 86 87 private Color fgColor = new Color ( 0, 0, 0, 255 ); 90 private Color bgColor = new Color ( 255, 255, 255, 255 ); 93 private int renderWidth = 200; 95 96 private int align = 0; 99 private int padTop = 4; 101 102 private int padBottom = 4; 104 105 private int padLeft = 4; 107 108 private int padRight = 4; 110 111 private int maxRows = 20; 113 114 private String imageFormatName = "png"; 116 117 private int trimEdges = 0; 119 120 private String backgroundImageUrl = null; 122 123 private BufferedImage backgroundImage = null; 125 126 private int tileBackgroundImage = 0; 128 129 130 private static Map renderHints = null; 131 132 private static Map methodMap = null; 134 135 private static Map defaultConfigMap = new HashMap (); 137 138 143 public AdvancedImageRenderer() 144 { 145 if ( methodMap == null ) 147 { 148 methodMap = new HashMap (); 149 Method [] methods = this.getClass().getDeclaredMethods(); 150 String name = null; 151 for ( int i = 0; i < methods.length; i++ ) 152 { 153 name = methods[ i ].getName().toLowerCase(); 154 if ( name.startsWith( "set" ) && methods[ i ].getParameterTypes().length == 1 ) 155 { 156 name = name.substring( "set".length() ); 157 methodMap.put( name , methods[ i ] ); 158 String propVal = CmsPropertyHandler.getProperty( "rendertext." + name ); 160 if ( propVal != null && propVal.trim().length() > 0 ) 161 { 162 defaultConfigMap.put( name, propVal.toLowerCase() ); 164 } 165 } 166 } 167 logger.debug( defaultConfigMap ); 168 } 169 if ( renderHints == null ) 170 { 171 renderHints = new HashMap (); 172 renderHints.put( RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY ); 173 renderHints.put( RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY ); 174 renderHints.put( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON ); 175 renderHints.put( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON ); 176 renderHints.put( RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY ); 177 renderHints.put( RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE ); 178 } 179 } 180 181 186 public boolean writeImage( File file ) 187 { 188 boolean success = false; 189 try 190 { 191 success = ImageIO.write( this.renderedImage, this.imageFormatName , file ); 192 } 193 catch ( Exception e ) 194 { 195 logger.error( "Couldn't write Image file : " + file, e ); 196 } 197 return success; 198 } 199 200 205 public BufferedImage renderImage( CharSequence text, Map renderAttributes ) 206 { 207 AttributedString attributedString = new AttributedString ( text.toString() ); 208 return this.renderImage( attributedString, renderAttributes ); 209 } 210 211 217 public BufferedImage renderImage( AttributedString attributedString, Map renderAttributes ) 218 { 219 Map tempMap = new HashMap ( defaultConfigMap ); 221 if ( renderAttributes != null ) 222 { 223 tempMap.putAll( renderAttributes ); 224 } 225 renderAttributes = tempMap; 226 if ( renderAttributes != null && renderAttributes.size() > 0 ) 227 { 228 Iterator keyIter = renderAttributes.entrySet().iterator(); 229 while ( keyIter.hasNext() ) 230 { 231 Map.Entry entry = (Map.Entry )keyIter.next(); 232 String key = entry.getKey().toString().trim().toLowerCase(); 233 if ( hasAttribute( key ) && entry.getValue() != null ) 234 { 235 setAttribute( key, entry.getValue().toString() ); 236 } 237 } 238 } 239 if ( templateImage == null ) 241 { 242 templateImage = new BufferedImage ( 8, 8, imageType ); 243 } 244 245 font = new Font ( fontName, fontStyle, fontSize ); 246 247 249 float wrappingWidth = renderWidth - ( padLeft + padRight ); 250 251 if ( wrappingWidth < 0 ) 252 { 253 throw new IllegalArgumentException ( "The renderwidth (" + renderWidth + ") is lesser than the total padding (" 254 + ( padLeft + padRight ) + "), modify your settings."); 255 } 256 257 Graphics2D g2d = templateImage.createGraphics(); 258 g2d.setRenderingHints( renderHints ); 259 260 attributedString.addAttribute( TextAttribute.FONT, font ); 261 attributedString.addAttribute( TextAttribute.FOREGROUND, fgColor ); 262 263 FontRenderContext context = g2d.getFontRenderContext(); 264 265 AttributedCharacterIterator iterator = attributedString.getIterator(); 266 LineBreakMeasurer measurer = new LineBreakMeasurer ( iterator, context ); 267 268 TextLayout layout = null; 269 double renderHeight = padTop + padBottom; 271 int numRows = 0; 272 while ( measurer.getPosition() < iterator.getEndIndex() ) 273 { 274 if ( ( layout = measurer.nextLayout( wrappingWidth ) ) == null || ( numRows >= maxRows ) ) 275 { 276 break; 277 } 278 numRows++; 279 renderHeight += layout.getAscent() + layout.getDescent() + layout.getLeading(); 280 } 281 282 renderedImage = new BufferedImage ( renderWidth, (int)( renderHeight + 0.5 ), templateImage.getType() ); 283 Graphics2D img2d = renderedImage.createGraphics(); 284 img2d.setRenderingHints( renderHints ); 285 286 img2d.setColor( fgColor ); 287 288 checkAndSetBackground(); 289 290 Point2D.Float pen = new Point2D.Float ( padLeft, padTop ); 291 292 context = img2d.getFontRenderContext(); 293 iterator = attributedString.getIterator(); 294 measurer = new LineBreakMeasurer ( iterator, context ); 295 numRows = 0; 296 while ( measurer.getPosition() < iterator.getEndIndex() ) 297 { 298 if ( ( layout = measurer.nextLayout( wrappingWidth ) ) == null || ( numRows >= maxRows ) ) 299 { 300 break; 301 } 302 numRows++; 303 pen.y += layout.getAscent(); 304 305 float dx = 0.0f; 306 if ( align == 1 || !layout.isLeftToRight() ) { 308 dx = ( wrappingWidth - layout.getVisibleAdvance() ); 309 } 310 else if ( align == 2 ) { 312 dx = ( wrappingWidth - layout.getVisibleAdvance() ) / 2; 313 } 314 315 layout.draw( img2d, pen.x + dx, pen.y ); 316 pen.y += layout.getDescent() + layout.getLeading(); 317 } 318 319 renderedImage = horizontalTrim(); 321 322 return renderedImage; 323 } 324 325 328 private void checkAndSetBackground() 329 { 330 Graphics2D img2d = renderedImage.createGraphics(); 331 img2d.setBackground( bgColor ); 332 img2d.clearRect( 0, 0, renderedImage.getWidth(), renderedImage.getHeight() ); 333 334 if ( backgroundImageUrl != null ) 335 { 336 try 337 { 338 if ( backgroundImage == null ) 339 { 340 URLConnection connection = new URL ( backgroundImageUrl ).openConnection(); 341 InputStream is = connection.getInputStream(); 345 backgroundImage = ImageIO.read( is ); 346 is.close(); 347 } 348 349 if ( tileBackgroundImage == 1 && backgroundImage.getWidth() < renderedImage.getWidth() ) { 351 int xnum = (int)( renderedImage.getWidth() / backgroundImage.getWidth() + 0.5 ) + 1; 352 while ( xnum-- >= 0 ) 353 { 354 img2d.drawImage( backgroundImage, backgroundImage.getWidth() * xnum, 0, null ); 355 } 356 } 357 if ( tileBackgroundImage == 2 && backgroundImage.getHeight() < renderedImage.getHeight() ) { 359 int ynum = (int)( renderedImage.getHeight() / backgroundImage.getHeight() + 0.5 ) + 1; 360 while ( ynum-- >= 0 ) 361 { 362 img2d.drawImage( backgroundImage, 0, backgroundImage.getHeight() * ynum, null ); 363 } 364 } 365 if ( tileBackgroundImage == 3 && backgroundImage.getHeight() < renderedImage.getHeight() ) { 367 int ynum = (int)( renderedImage.getHeight() / backgroundImage.getHeight() + 0.5 ) + 1; 368 while ( ynum-- >= 0 ) 369 { 370 int xnum = (int)( renderedImage.getWidth() / backgroundImage.getWidth() + 0.5 ) + 1; 371 while ( xnum-- >= 0 ) 372 { 373 img2d.drawImage( backgroundImage, backgroundImage.getWidth() * xnum, backgroundImage.getHeight() * ynum, null ); 374 } 375 } 376 } 377 378 if ( tileBackgroundImage == 0 ) 379 { 380 img2d.drawImage( backgroundImage, 0, 0, null ); 381 } 382 } 383 catch ( IOException ioe ) 384 { 385 logger.error( "Error in reading backgoundImageUrl: " + backgroundImageUrl, ioe ); 386 } 387 } 388 } 389 390 394 private BufferedImage horizontalTrim() 395 { 396 if ( trimEdges == 0 ) 397 { 398 return renderedImage; 399 } 400 401 int imgHeight = renderedImage.getHeight(); 402 int imgWidth = renderedImage.getWidth(); 403 404 int bgRGB = bgColor.getRGB(); 406 int w = 0; 408 int leftPos = 0, rightPos = 0; 409 410 if ( this.trimEdges == 1 || this.trimEdges == 3 ) 411 { 412 loop: for ( w = 0; w < imgWidth; w++ ) 413 { 414 int imgRGB = 0; 415 for ( int y = 0; y < imgHeight; y++ ) 416 { 417 imgRGB = renderedImage.getRGB( w, y ); 418 if ( imgRGB != bgRGB ) 419 { 420 break loop; 421 } 422 } 423 } 424 425 leftPos = ( w > 0 ) ? w - 1 : 0; 426 leftPos -= padLeft; 427 leftPos = ( leftPos <= 0 ) ? 0 : leftPos; 429 } 430 431 if ( this.trimEdges == 2 || this.trimEdges == 3 ) 433 { 434 loop: for ( w = ( imgWidth - 1 ); w >= 0; w-- ) 435 { 436 int imgRGB = 0; 437 for ( int y = 0; y < imgHeight; y++ ) 438 { 439 imgRGB = renderedImage.getRGB( w, y ); 440 if ( imgRGB != bgRGB ) 441 { 442 break loop; 443 } 444 } 445 } 446 rightPos = w + 1; 447 rightPos += padRight; 448 rightPos = ( rightPos > imgWidth ) ? imgWidth - 1 : rightPos; 450 } 451 else 452 { 453 rightPos = imgWidth - 1; 454 } 455 return renderedImage.getSubimage( leftPos, 0, rightPos - leftPos, imgHeight - 1 ); 456 } 457 458 464 public boolean hasAttribute( CharSequence attributeName ) 465 { 466 return methodMap.containsKey( attributeName.toString().toLowerCase() ); 467 } 468 469 477 public void setAttribute( CharSequence attribute, CharSequence value ) 478 { 479 logger.debug("set attribute: " + attribute + " = " + value ); 480 Method method = (Method )methodMap.get( attribute ); 481 if ( method != null ) 482 { 483 try 484 { 485 Class [] params = method.getParameterTypes(); 486 Class param = params[ 0 ]; 487 if ( param.isPrimitive() ) 488 { 489 if ( param.getName().equals( "int" ) ) 490 { 491 method.invoke( this, new Object [] 492 { new Integer (Integer.parseInt( value.toString() )) } ); 493 } 494 else if ( param.getName().equals( "float" ) ) 495 { 496 method.invoke( this, new Object [] 497 { new Float (Float.parseFloat( value.toString() )) } ); 498 } 499 else if ( param.getName().equals( "double" ) ) 500 { 501 method.invoke( this, new Object [] 502 { new Double (Double.parseDouble( value.toString() )) } ); 503 } 504 else if ( param.getName().equals( "boolean" ) ) 505 { 506 method.invoke( this, new Object [] 507 { new Boolean (Boolean.getBoolean( value.toString() )) } ); 508 } 509 } 510 else if ( param.equals( String .class ) ) 511 { 512 method.invoke( this, new Object [] 513 { value.toString() } ); 514 } 515 else if ( param.equals( Color .class ) ) 516 { 517 method.invoke( this, new Object [] 518 { ColorHelper.getColor( value.toString() ) } ); 519 } 520 521 } 522 catch ( Exception e ) 523 { 524 logger.warn( "Error in setting properties: " + attribute + " = " + value, e ); 525 } 526 } 527 else 528 { 529 logger.warn( "No attribut, named: " + attribute + " found, value =" + value ); 530 } 531 } 532 533 536 public void setAlign( int align ) 537 { 538 this.align = align; 539 } 540 541 544 public void setBackgroundImage( BufferedImage backgroundImage ) 545 { 546 this.backgroundImage = backgroundImage; 547 } 548 549 552 public void setBackgroundImageURL( String backgroundImageUrl ) 553 { 554 this.backgroundImageUrl = backgroundImageUrl; 555 } 556 557 560 public void setBgColor( Color bgColor ) 561 { 562 this.bgColor = bgColor; 563 } 564 565 568 public void setFgColor( Color fgColor ) 569 { 570 this.fgColor = fgColor; 571 } 572 573 576 public void setFontName( String fontName ) 577 { 578 this.fontName = fontName; 579 } 580 581 584 public void setFontSize( int fontSize ) 585 { 586 this.fontSize = fontSize; 587 } 588 589 592 public void setFontStyle( int fontStyle ) 593 { 594 this.fontStyle = fontStyle; 595 } 596 597 600 public void setImageType( int imageType ) 601 { 602 this.imageType = imageType; 603 } 604 605 608 public void setPadBottom( int padBottom ) 609 { 610 this.padBottom = padBottom; 611 } 612 613 616 public void setPadLeft( int padLeft ) 617 { 618 this.padLeft = padLeft; 619 } 620 621 624 public void setPadRight( int padRight ) 625 { 626 this.padRight = padRight; 627 } 628 629 633 public void setPad( int pad ) 634 { 635 this.padRight = pad; 636 this.padLeft = pad; 637 this.padTop = pad; 638 this.padBottom = pad; 639 } 640 641 644 public void setPadTop( int padTop ) 645 { 646 this.padTop = padTop; 647 } 648 649 652 public void setRenderHints( Map renderHints ) 653 { 654 this.renderHints = renderHints; 655 } 656 657 660 public void setRenderWidth( int renderWidth ) 661 { 662 this.renderWidth = renderWidth; 663 } 664 665 668 public void setTemplateImage( BufferedImage templateImage ) 669 { 670 this.templateImage = templateImage; 671 } 672 673 676 public void setTileBackgroundImage( int tileBackgroundImage ) 677 { 678 this.tileBackgroundImage = tileBackgroundImage; 679 } 680 681 684 public void setBackgroundImageUrl( String backgroundImageUrl ) 685 { 686 this.backgroundImageUrl = backgroundImageUrl; 687 } 688 689 692 public void setMaxRows( int maxRows ) 693 { 694 this.maxRows = maxRows; 695 } 696 697 700 public void setTrimEdges( int trimEdges ) 701 { 702 this.trimEdges = trimEdges; 703 } 704 705 708 public void setImageFormatName( String imageFormatName ) 709 { 710 this.imageFormatName = imageFormatName; 711 } 712 713 717 public String getImageFormatName() 718 { 719 return this.imageFormatName; 720 } 721 } 722 | Popular Tags |