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;
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
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
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
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 }