View Javadoc
1   package net.sourceforge.jsh3modtool.gui.imagetable;
2   
3   import javax.swing.*;
4   
5   import java.awt.*;
6   import java.awt.geom.*;
7   import java.awt.image.BufferedImage;
8   
9   /***
10   * A JComponent that displays images.
11   * 
12   * The component creates a backbuffer from the incoming imagedata, if
13   * it is possible the backbuffer is created as an accelerated <code>Image</code>.
14   * 
15   * @author redsolo
16   */
17  public class ImagePanel extends JComponent
18  {    
19      /*** The back buffer image (this is drawn by the AWT) */
20      private Image backBufferImage;
21      private int imageWidth;
22      private int imageHeight;
23      
24  
25      /*** The image rotation in degrees */
26      private int             imageRotation;
27  
28      /*** The image position and dimension in the JPanel */
29      private final Rectangle     imagePosition; 
30  
31      /*** Message that is displayed if there is no image. */
32      private String messageIfNoAvailableImage;
33      /*** The size of the message in pixels */
34      private int  messageWidth;
35      /*** Original font that is copied when resizing the actual font that renders the text. */
36      private final Font originalFont;
37      /*** Buffered font that is used if the message hasnt changed. */
38      private Font bufferedFont;
39      /*** If the buffered font should reset. A reset will recalculate the font. */
40      private boolean redoBufferedFont = false;
41  
42      /***
43       * Creates a panel that can display an image.
44       */
45      protected ImagePanel()
46      {
47      	super();
48          setBackground( Color.black );
49          imagePosition = new Rectangle();
50          originalFont = (Font) UIManager.get("Label.font");
51          
52          setMessage( "No image" );
53      }
54  
55  
56      /***
57       * Resets the AffineTransform, ie scales and translates.
58       * @return an AffineTransform; null if there is no image.
59       */
60      protected AffineTransform redoTransform()
61      {
62          return redoTransform( getWidth(), getHeight() );
63      }
64  
65      /***
66       * Resets the AffineTransform, ie scales and translates.
67       * 
68       * @param componentWidth the width of the component that the imagepanel can use
69       * @param componentHeight the height of the component that the imagepanel can use
70       * @return an AffineTransform; null if there is no image.
71       */
72      protected AffineTransform redoTransform( final int componentWidth, final int componentHeight )
73      {
74          AffineTransform affineTransform = null;//new AffineTransform();
75          if ( backBufferImage != null )
76          {
77              affineTransform = new AffineTransform();
78  
79              final int outputImageWidth =  ( imageRotation % 180 == 0 ? imageWidth : imageHeight );
80              final int outputImageHeight = ( imageRotation % 180 == 0 ? imageHeight : imageWidth );
81  
82              final double heightScale = (double)  componentHeight / outputImageHeight;
83              final double widthScale = (double)   componentWidth  / outputImageWidth;
84  
85              final double scale = ( heightScale > widthScale ? widthScale : heightScale );
86              
87              final AffineTransform scaleTransform = AffineTransform.getScaleInstance( scale, scale );
88  
89              final AffineTransform rotateTransform = AffineTransform.getRotateInstance( Math.toRadians( imageRotation ) );
90  
91              double transX = 0, transY = 0;
92              switch ( imageRotation )
93              {
94                  case 90:
95                      transX = (scale * outputImageWidth) - (scale * outputImageWidth - componentWidth)/2;
96                      transY = -(scale * outputImageHeight - componentHeight)/2;
97                      break;
98                  case 180:
99                      transX = scale * outputImageWidth - (scale * outputImageWidth - componentWidth)/2;
100                     transY = scale * outputImageHeight -(scale * outputImageHeight - componentHeight)/2;
101                     break;
102                 case 270:
103                     transX =  -(scale * outputImageWidth - componentWidth)/2;
104                     transY =scale * outputImageHeight-(scale * outputImageHeight - componentHeight)/2;
105                     break;
106                 default:
107                     transX = - (scale * outputImageWidth - componentWidth)/2;
108                     transY = -(scale * outputImageHeight - componentHeight)/2;
109                     break;
110             }
111 
112             // Calculate position of image on the panel
113             imagePosition.x = -(int)(scale * outputImageWidth - componentWidth)/2;
114             imagePosition.y = -(int)(scale * outputImageHeight - componentHeight)/2;
115             imagePosition.width = (int)(scale*outputImageWidth);
116             imagePosition.height = (int)(scale*outputImageHeight);
117 
118             final AffineTransform translateTransform = AffineTransform.getTranslateInstance( transX , transY  );
119 
120             affineTransform.setToIdentity();
121             affineTransform.concatenate( translateTransform );
122             affineTransform.concatenate( rotateTransform );
123             affineTransform.concatenate( scaleTransform );
124         }
125         
126         return affineTransform;
127     }
128 
129     /*** {@inheritDoc} */
130     public void paintComponent (final Graphics graphics)
131     {
132     	final Graphics2D graphics2D = (Graphics2D) graphics;        
133         
134         // Draw your own background since someone f**ked upped.
135     	final Color buffColor = graphics2D.getColor();
136         graphics.setColor( getBackground() );
137         final Shape shape = new Rectangle(0,0, getWidth(), getHeight() );        
138         graphics2D.fill( shape );
139         graphics.setColor( buffColor );
140 
141         if (backBufferImage == null)
142         {            
143             if ( redoBufferedFont )
144             {
145                 createBufferedFont( graphics2D );
146             }
147             graphics2D.setFont(bufferedFont);
148             graphics2D.setColor(Color.gray);
149             graphics2D.drawString(messageIfNoAvailableImage, (getWidth()-messageWidth)/ 2, getHeight() / 2);
150         }
151         else
152         {
153             graphics2D.drawImage( backBufferImage, redoTransform(), null );
154         }
155     }
156     
157     /***
158      * Set the buffered image for this image.
159      * @param newImage the new buffered image.
160      */
161     public void setBufferedImage( final BufferedImage newImage )
162     {
163         if ( newImage != backBufferImage )
164         {
165             backBufferImage = newImage;
166             if ( backBufferImage == null )
167             {
168                 imageWidth = -1;
169                 imageHeight = -1;
170             }
171             else
172             {
173                 imageWidth = backBufferImage.getWidth(null);
174                 imageHeight = backBufferImage.getHeight( null );
175             }
176         }
177     }
178     
179     /***
180      * Redo the buffered font object to fit the new message.
181      * @param graphics the graphics object to get <code>FontMetrics</code> from.
182      */
183     private void createBufferedFont(final Graphics graphics)
184     {
185         bufferedFont = new Font( originalFont.getFontName(), originalFont.getStyle(), originalFont.getSize() );
186         messageWidth = graphics.getFontMetrics(bufferedFont).stringWidth(messageIfNoAvailableImage);
187 
188         while ( ( messageWidth > getWidth() ) && ( bufferedFont.getSize() > 2 ) )
189         {
190             bufferedFont = new Font( originalFont.getFontName(), originalFont.getStyle(), bufferedFont.getSize() - 2 );
191             messageWidth = graphics.getFontMetrics(bufferedFont).stringWidth(messageIfNoAvailableImage);
192         }
193         
194         redoBufferedFont = false;
195     }
196 
197     /***
198      * Sets the message if there is no image for this panel
199      * @param msg the message
200      */
201     public final void setMessage( final String msg )
202     {
203         //if ( ! ObjectUtils.equals( msg, messageIfNoAvailableImage ) )
204         {
205             redoBufferedFont = true;
206             messageIfNoAvailableImage = msg;
207             messageWidth = -1;
208         }
209     }
210     
211     /***
212      * Returns the image width.
213      * @return the image width; -1 if there is no image.
214      */
215     public int getImageWidth()
216     {
217         return imageWidth;
218     }
219 
220     /***
221      * Returns the image height.
222      * @return the image height; -1 if there is no image.
223      */
224     public int getImageHeight()
225     {
226         return imageHeight;
227     }
228     
229     /***
230      * Sets the image rotation.
231      * @param i the new rotation.
232      */
233     protected void setImageRotation(final int rotation)
234     {
235         imageRotation = rotation;
236     }
237     
238     /***
239      * Returns true if the panel has an image or not.
240      * @return true if the panel has an image or not; false otherwise.
241      */
242     public boolean hasImage()
243     {
244         return backBufferImage != null;
245     }
246 
247     /***
248      * Returns the image position in the component.
249      * @return the image position in the component. 
250      */
251     protected Rectangle getImagePosition()
252     {
253         return imagePosition;
254     }
255 
256     /***
257      * Returns the image rotation.
258      * @return the image rotation (in degrees).
259      */
260     public int getImageRotation()
261     {
262         return imageRotation;
263     }
264 }