001 package com.croftsoft.core.animation.icon; 002 003 import java.awt.*; 004 import java.awt.image.*; 005 import java.net.URL; 006 import javax.swing.*; 007 008 import com.croftsoft.core.awt.image.NullVolatileImage; 009 import com.croftsoft.core.lang.NullArgumentException; 010 011 /********************************************************************* 012 * When contents lost, reloads the VolatileImage from the ClassLoader. 013 * 014 * <p> 015 * This class only works with opaque (non-transparent) images. 016 * </p> 017 * 018 * <p> 019 * Example code: 020 * </p> 021 * <pre> 022 * Icon heroIcon = new ResourceImageIcon ( 023 * HERO_IMAGE_FILENAME, 024 * getClass ( ).getClassLoader ( ), 025 * new Dimension ( 026 * ( int ) scalingRatio * HERO_IMAGE_WIDTH, 027 * ( int ) scalingRatio * HERO_IMAGE_HEIGHT ), 028 * animatedComponent ); 029 * </pre> 030 * 031 * @see 032 * VolatileImage 033 * 034 * @version 035 * 2003-02-18 036 * @since 037 * 2003-02-18 038 * @author 039 * <a href="https://www.croftsoft.com/">David Wallace Croft</a> 040 *********************************************************************/ 041 042 public final class ResourceImageIcon 043 implements Icon 044 ////////////////////////////////////////////////////////////////////// 045 ////////////////////////////////////////////////////////////////////// 046 { 047 048 private final String imageFilename; 049 050 private final ClassLoader classLoader; 051 052 // 053 054 private VolatileImage volatileImage; 055 056 private boolean scaleImage; 057 058 private int width; 059 060 private int height; 061 062 private boolean resized; 063 064 ////////////////////////////////////////////////////////////////////// 065 ////////////////////////////////////////////////////////////////////// 066 067 /********************************************************************* 068 * Main constructor. 069 * 070 * @param imageFilename 071 * 072 * The image path and filename, usually pulled from a JAR. 073 * 074 * @param classLoader 075 * 076 * The ClassLoader to use to load the image as a resource file. 077 * 078 * @param scaleDimension 079 * 080 * If not null, used to pre-scale the VolatileImage. 081 * 082 * @param component 083 * 084 * If not null, prepareVolatileImage() is called during construction. 085 *********************************************************************/ 086 public ResourceImageIcon ( 087 String imageFilename, 088 ClassLoader classLoader, 089 Dimension scaleDimension, 090 Component component ) 091 ////////////////////////////////////////////////////////////////////// 092 { 093 NullArgumentException.check ( this.imageFilename = imageFilename ); 094 095 NullArgumentException.check ( this.classLoader = classLoader ); 096 097 if ( scaleDimension != null ) 098 { 099 setSize ( scaleDimension ); 100 } 101 102 if ( component == null ) 103 { 104 volatileImage = NullVolatileImage.INSTANCE; 105 } 106 else 107 { 108 prepareVolatileImage ( component ); 109 } 110 } 111 112 public ResourceImageIcon ( String imageFilename ) 113 ////////////////////////////////////////////////////////////////////// 114 { 115 this ( 116 imageFilename, 117 ResourceImageIcon.class.getClassLoader ( ), 118 ( Dimension ) null, 119 ( Component ) null ); 120 } 121 122 ////////////////////////////////////////////////////////////////////// 123 ////////////////////////////////////////////////////////////////////// 124 125 public int getIconWidth ( ) { return width; } 126 127 public int getIconHeight ( ) { return height; } 128 129 ////////////////////////////////////////////////////////////////////// 130 ////////////////////////////////////////////////////////////////////// 131 132 /********************************************************************* 133 * If VolatileImage contents are lost, calls prepareVolatileImage(). 134 *********************************************************************/ 135 public void paintIcon ( 136 Component component, 137 Graphics graphics, 138 int x, 139 int y ) 140 ////////////////////////////////////////////////////////////////////// 141 { 142 if ( resized 143 || volatileImage.contentsLost ( ) ) 144 { 145 prepareVolatileImage ( component ); 146 } 147 148 graphics.drawImage ( volatileImage, x, y, component ); 149 } 150 151 ////////////////////////////////////////////////////////////////////// 152 ////////////////////////////////////////////////////////////////////// 153 154 /********************************************************************* 155 * Loads the VolatileImage. 156 * 157 * <p> 158 * Call this method to load the image after construction but before 159 * the first call to paint(). This is useful if you cannot perform 160 * this operation when the main constructor is called because the 161 * Component is not ready at the time and you do not want to wait 162 * until the first paint() because the load may stall animation. 163 * </p> 164 * 165 * <p> 166 * Example code: 167 * </p> 168 * 169 * <pre> 170 * ResourceImageIcon heroIcon = new ResourceImageIcon ( 171 * HERO_IMAGE_FILENAME, 172 * getClass ( ).getClassLoader ( ), 173 * ( Dimension ) null, // no scaling 174 * ( Component ) null ); 175 * 176 * [...wait until Component is ready...] 177 * 178 * heroIcon.prepareVolatileImage ( animatedComponent ); 179 * </pre> 180 *********************************************************************/ 181 public void prepareVolatileImage ( Component component ) 182 ////////////////////////////////////////////////////////////////////// 183 { 184 URL imageURL 185 = classLoader.getResource ( imageFilename ); 186 187 ImageIcon imageIcon = new ImageIcon ( imageURL ); 188 189 Image imageIconImage = imageIcon.getImage ( ); 190 191 if ( !scaleImage ) 192 { 193 width = imageIcon.getIconWidth ( ); 194 195 height = imageIcon.getIconHeight ( ); 196 } 197 198 if ( volatileImage != null ) 199 { 200 volatileImage.flush ( ); 201 } 202 203 volatileImage = component.createVolatileImage ( width, height ); 204 205 Graphics2D graphics = volatileImage.createGraphics ( ); 206 207 if ( scaleImage ) 208 { 209 graphics.drawImage ( 210 imageIconImage, 0, 0, width, height, null ); 211 } 212 else 213 { 214 graphics.drawImage ( imageIconImage, 0, 0, null ); 215 } 216 217 imageIconImage.flush ( ); 218 219 graphics.dispose ( ); 220 } 221 222 public void setWidth ( int width ) 223 ////////////////////////////////////////////////////////////////////// 224 { 225 if ( width < 1 ) 226 { 227 throw new IllegalArgumentException ( "width < 1: " + width ); 228 } 229 230 scaleImage = true; 231 232 resized = true; 233 234 this.width = width; 235 } 236 237 public void setHeight ( int height ) 238 ////////////////////////////////////////////////////////////////////// 239 { 240 if ( height < 1 ) 241 { 242 throw new IllegalArgumentException ( "height < 1: " + height ); 243 } 244 245 scaleImage = true; 246 247 resized = true; 248 249 this.height = height; 250 } 251 252 public void setSize ( Dimension size ) 253 ////////////////////////////////////////////////////////////////////// 254 { 255 setWidth ( size.width ); 256 257 setHeight ( size.height ); 258 } 259 260 ////////////////////////////////////////////////////////////////////// 261 ////////////////////////////////////////////////////////////////////// 262 }