001 /* 002 * ImageLoader 003 * 004 * Copyright (c) 2000, 2001, 2002, 2003 Marco Schmidt. 005 * All rights reserved. 006 */ 007 008 package net.sourceforge.jiu.codecs; 009 010 import java.io.File; 011 import java.io.FilenameFilter; 012 import java.io.IOException; 013 import java.util.Vector; 014 import net.sourceforge.jiu.codecs.InvalidFileStructureException; 015 import net.sourceforge.jiu.codecs.InvalidImageIndexException; 016 import net.sourceforge.jiu.codecs.WrongFileFormatException; 017 import net.sourceforge.jiu.codecs.BMPCodec; 018 import net.sourceforge.jiu.codecs.IFFCodec; 019 import net.sourceforge.jiu.codecs.PCDCodec; 020 import net.sourceforge.jiu.codecs.PNGCodec; 021 import net.sourceforge.jiu.codecs.PNMCodec; 022 import net.sourceforge.jiu.codecs.PSDCodec; 023 import net.sourceforge.jiu.codecs.RASCodec; 024 import net.sourceforge.jiu.codecs.tiff.TIFFCodec; 025 import net.sourceforge.jiu.data.PixelImage; 026 import net.sourceforge.jiu.ops.MissingParameterException; 027 import net.sourceforge.jiu.ops.OperationFailedException; 028 029 /** 030 * A convenience class with static methods to load images from files using JIU codecs. 031 * The load methods of this class try to load an image with all codecs registered with this class. 032 * This includes almost every codec that resides in the <code>net.sourceforge.jiu.codecs</code> package. 033 * You can register additional codecs with {@link #registerCodecClass} or remove the usage 034 * of codecs with {@link #removeCodecClass}. 035 * <p> 036 * A Codec that cannot safely identify a file to be in the format that it supports must not be used with ImageLoader. 037 * The failure to identify typically comes from the lack of magic byte sequences defined for the format. 038 * In order to load such a file, use the codec manually. 039 * Example: {@link PalmCodec}. 040 * <p> 041 * In order to load an image via {@link java.awt.Toolkit} (JPEG, PNG or GIF), use 042 * {@link net.sourceforge.jiu.gui.awt.ToolkitLoader}. 043 * It combines the loading features of java.awt.Toolkit and JIU's ImageLoader. 044 * <h3>Usage example</h3> 045 * <pre> 046 * PixelImage image = null; 047 * try 048 * { 049 * image = ImageLoader.load("image.tif"); 050 * } 051 * catch (Exception e) 052 * { 053 * // handle exception 054 * } 055 * </pre> 056 * @author Marco Schmidt 057 */ 058 public class ImageLoader 059 { 060 // all elements of class String 061 private static Vector fileExtensions; 062 private static Vector imageCodecClasses; 063 064 static 065 { 066 imageCodecClasses = new Vector(); 067 registerCodecClass(new BMPCodec()); 068 registerCodecClass(new IFFCodec()); 069 registerCodecClass(new PCDCodec()); 070 registerCodecClass(new PNGCodec()); 071 registerCodecClass(new PNMCodec()); 072 registerCodecClass(new PSDCodec()); 073 registerCodecClass(new RASCodec()); 074 registerCodecClass(new TIFFCodec()); 075 } 076 077 private ImageLoader() 078 { 079 } 080 081 /** 082 * Creates an instance of one of the codec classes known to ImageLoader. 083 * @param index 0-based index of codec number, maximum value is {@link #getNumCodecs}<code> - 1</code> 084 * @return new codec object or <code>null</code> if no object could be instantiated 085 */ 086 public static ImageCodec createCodec(int index) 087 { 088 ImageCodec result = null; 089 if (index >= 0 && index < getNumCodecs()) 090 { 091 Class c = (Class)imageCodecClasses.elementAt(index); 092 try 093 { 094 Object obj = c.newInstance(); 095 if (obj != null && obj instanceof ImageCodec) 096 { 097 result = (ImageCodec)obj; 098 } 099 } 100 catch (IllegalAccessException iae) 101 { 102 // ignore 103 } 104 catch (InstantiationException ie) 105 { 106 // ignore 107 } 108 } 109 return result; 110 } 111 112 /** 113 * Returns a filename filter ({@link java.io.FilenameFilter}) that accepts files 114 * with name extensions typical for the image file formats known to ImageLoader. 115 * The filter could then be used in an file dialog like {@link java.awt.FileDialog}. 116 * <p> 117 * Note that this filter does not include file formats supported by the AWT 118 * {@link java.awt.Toolkit} (GIF and JPEG, also PNG since Java 1.3). 119 * @return filter for image file names 120 */ 121 public static FilenameFilter createFilenameFilter() 122 { 123 return new FilenameFilter() 124 { 125 public boolean accept(File dir, String name) 126 { 127 if (name == null) 128 { 129 return false; 130 } 131 if (fileExtensions == null) 132 { 133 updateFileExtensions(); 134 } 135 name = name.toLowerCase(); 136 int index = 0; 137 while (index < fileExtensions.size()) 138 { 139 String ext = (String)fileExtensions.elementAt(index++); 140 if (name.endsWith(ext)) 141 { 142 return true; 143 } 144 } 145 return false; 146 } 147 }; 148 } 149 150 /** 151 * Returns the number of codec classes currently known to ImageLoader. 152 * This number can be changed by registering additional codecs 153 * ({@link #registerCodecClass}) 154 * or by removing codec classes ({@link #removeCodecClass}). 155 * @return number of known codec classes 156 */ 157 public static int getNumCodecs() 158 { 159 return imageCodecClasses.size(); 160 } 161 162 /** 163 * Attempts to load an image from a file. 164 * @param file the file from which an image is to be loaded 165 * @return the image on success or <code>null</code> on failure 166 */ 167 public static PixelImage load(File file) throws 168 IOException, 169 InvalidFileStructureException, 170 InvalidImageIndexException, 171 UnsupportedTypeException 172 { 173 return load(file, null); 174 } 175 176 /** 177 * Attempts to load an image from a file, notifying the 178 * argument progress listeners. 179 * @param file the file to load an image from 180 * @param listeners a Vector of ProgressListener objects to be notified 181 * @return an instance of a class implementing {@link PixelImage} 182 */ 183 public static PixelImage load(File file, Vector listeners) throws 184 IOException, 185 InvalidFileStructureException, 186 InvalidImageIndexException, 187 UnsupportedTypeException 188 { 189 for (int i = 0; i < getNumCodecs(); i++) 190 { 191 PixelImage result = null; 192 try 193 { 194 ImageCodec codec = createCodec(i); 195 codec.setFile(file, CodecMode.LOAD); 196 codec.addProgressListeners(listeners); 197 codec.process(); 198 result = codec.getImage(); 199 if (result != null) 200 { 201 return result; 202 } 203 } 204 catch (MissingParameterException mpe) 205 { 206 // ignore 207 } 208 catch (WrongFileFormatException wffe) 209 { 210 // ignore 211 } 212 catch (IOException ioe) 213 { 214 // ignore 215 } 216 catch (OperationFailedException ofe) 217 { 218 // ignore 219 //System.out.println("codec: " + ofe); 220 } 221 } 222 return null; 223 } 224 225 /** 226 * Load an image from a file given by its name. 227 * Simply calls load(fileName, null). 228 * @param fileName name of the file from which an image is to be loaded 229 * @return the loaded image on success, null on failure 230 */ 231 public static PixelImage load(String fileName) throws 232 IOException, 233 InvalidFileStructureException, 234 InvalidImageIndexException, 235 UnsupportedTypeException 236 { 237 return load(fileName, null); 238 } 239 240 /** 241 * Attempts to load an image from the file with the given name, 242 * using the given list of progress listeners. 243 * @param fileName name of the file from which an image is to be loaded 244 * @param listeners a list of objects implementing ProgressListener 245 * @return the loaded image 246 */ 247 public static PixelImage load(String fileName, Vector listeners) throws 248 IOException, 249 InvalidFileStructureException, 250 InvalidImageIndexException, 251 UnsupportedTypeException 252 { 253 return load(new File(fileName), listeners); 254 } 255 256 /** 257 * Registers a codec class with ImageLoader. 258 * The argument is an instance of the class to be registered. 259 * Note that the codec class must have an empty constructor. 260 * <p> 261 * Example: let's say you have written a new codec called ACMEImageCodec. 262 * Your codec supports loading images. 263 * Then you could register it like that: 264 * <pre> 265 * ImageLoader.registerCodecClass(new ACMEImageCodec()); 266 * </pre> 267 * <p> 268 * @param codec an instance of the codec class to be registered 269 */ 270 public static void registerCodecClass(ImageCodec codec) 271 { 272 if (codec == null) 273 { 274 return; 275 } 276 if (imageCodecClasses.contains(codec.getClass())) 277 { 278 return; 279 } 280 if (!codec.isLoadingSupported()) 281 { 282 throw new IllegalArgumentException("Codec does not support loading."); 283 } 284 imageCodecClasses.addElement(codec.getClass()); 285 updateFileExtensions(); 286 } 287 288 /** 289 * Removes all codec classes from the internal list of codec classes. 290 * After a call to this method, ImageLoader will not load anything unless 291 * new codecs get registered. 292 */ 293 public static void removeAllCodecClasses() 294 { 295 imageCodecClasses = new Vector(); 296 updateFileExtensions(); 297 } 298 299 /** 300 * Removes a codec class from the internal list of codec classes. 301 * @param codec an instance of the codec class to be removed 302 */ 303 public static void removeCodecClass(ImageCodec codec) 304 { 305 if (codec == null) 306 { 307 return; 308 } 309 int index = imageCodecClasses.indexOf(codec.getClass()); 310 if (index != -1) 311 { 312 imageCodecClasses.remove(index); 313 updateFileExtensions(); 314 } 315 else 316 { 317 throw new IllegalArgumentException("The argument codec's class " + 318 "could not be found in the internal list of codec classes."); 319 } 320 } 321 322 private static void updateFileExtensions() 323 { 324 fileExtensions = new Vector(); 325 int index = 0; 326 while (index < getNumCodecs()) 327 { 328 try 329 { 330 ImageCodec codec = createCodec(index++); 331 String[] extArray = codec.getFileExtensions(); 332 if (extArray != null && extArray.length > 0) 333 { 334 for (int i = 0; i < extArray.length; i++) 335 { 336 fileExtensions.addElement(extArray[i].toLowerCase()); 337 } 338 } 339 } 340 catch (Exception e) 341 { 342 } 343 } 344 } 345 }