(Java 6) Thumbnails in JFileChooser - Performance steigern?

Status
Nicht offen für weitere Antworten.

Taste

Bekanntes Mitglied
Hallo,

ich verwende einen FileChooser, und in diesem eine Thumbnaildarstellung für jpeg, png usw.

Hierzu verwende ich bislang folgende Implementierung:

Spezialisierter FileChooser
Code:
public class ImageFileChooser extends JFileChooser
{
   private static final Dimension MAX_IMAGE_SIZE_DEFAULT = new Dimension(40, 40);
   private static final long      serialVersionUID       = 1L;
   private final Dimension        maxImageSize;

   public ImageFileChooser(File startDirectory, Dimension maxImageSize)
   {
      super(startDirectory);
      this.maxImageSize = maxImageSize;
   }

public Icon getIcon(File f)
   {
      if (f.isFile())
      {
         GUITools.showAutoWaitCursor(this);
         try
         {
            Icon aux = new ImageIcon(f.getAbsolutePath());
            int w = aux.getIconWidth();
            int h = aux.getIconHeight();

            if (w > 0 && h > 0)
            {
               if (w <= maxImageSize.width && h <= maxImageSize.width)
                  return aux;

               ImageTool tool = new ImageTool(f);
               double heightToWidth = ((double) h) / ((double) w);

               while (w > maxImageSize.width || h > maxImageSize.height)
               {
                 // ...Bildgrößen werden angepasst...               }
               }

               tool.scale(w, h);
               return new ImageIcon(tool.getImage());
            }
         }
         catch (Exception e)
         {
            // return super...
         }
      }
      return super.getIcon(f);
   }
}

Image-Berechnung
Code:
public class ImageTool
{
   private final Image        sourceImage;
   private Image               transformedImage      = null;
   private static JComponent   mediaTrackerComponent = new JComponent();
   private static MediaTracker mediaTracker          = new MediaTracker(
                                                           mediaTrackerComponent);
   private static int          nextMediaTrackerId    = 0;

   public ImageTool(File file) throws IOException
   {
      //this(Toolkit.getDefaultToolkit().createImage(file.getAbsolutePath()));
      String mimeType = getMIMEType(file);

      if (mimeType != null && mimeType.toUpperCase().startsWith("IMAGE"))
      {
         sourceImage = Toolkit.getDefaultToolkit().createImage(
               file.getAbsolutePath());
      }
      else
      {
         throw new RuntimeException("File is not an image");
      }
   }

public void scale(Integer width, Integer height)
   {
      Validate.isTrue(
            width != null || height != null,
            "either width, height or both must be specified");
      Validate.isTrue(
            width == null ? true : width.intValue() > 0,
            "width must be positive");
      Validate.isTrue(
            height == null ? true : height.intValue() > 0,
            "height must be positive");

      // we have to wait for the source image to be loaeded completely
      // before the transformation can be done
      this.waitForImageLoaded();
      
      if ((width != null) && (this.getSourceWidth() <= width.intValue()))
      {
         width = new Integer(this.getSourceWidth());
      }
      
      if (height == null)
      {
         double scaleFactor = (double) width.intValue()
               / (double) this.getSourceWidth();
         height = new Integer((int) (this.getSourceHeight() * scaleFactor));
      }
      else if (width == null)
      {         
         double scaleFactor = (double) height.intValue()
               / (double) this.getSourceHeight();
         width = new Integer((int) (this.getSourceWidth() * scaleFactor));
      }
      
      ImageFilter scaleFilter = new ReplicateScaleFilter(width.intValue(),
            height.intValue());
      ImageProducer imageProducer = new FilteredImageSource(
            this.sourceImage.getSource(), scaleFilter);
      this.transformedImage = Toolkit.getDefaultToolkit().createImage(
            imageProducer);
   }

   public void waitForImageLoaded()
   {
      waitForImage(this.sourceImage);
   }

   /**
    * Wait until the specified image is loaded.
    */
   private synchronized static void waitForImage(Image image)
   {
      Validate.notNull(image);
      int id = getNextMediaTrackerId();
      mediaTracker.addImage(image, id);
      try
      {
         try
         {
            mediaTracker.waitForID(id);
         }
         catch (InterruptedException exc)
         {
            throw new RuntimeException("interrupted while waiting for image",
                  exc);
         }

         if (mediaTracker.isErrorID(id))
         {
            throw new RuntimeException("error while loading image");
         }
      }
      finally
      {
         mediaTracker.removeImage(image);
      }
   }

   private synchronized static int getNextMediaTrackerId()
   {
      return nextMediaTrackerId++;
   }

   public static String getMIMEType(File file)
   {
      if (!file.exists())
         throw new IllegalArgumentException("File does not exit!");
      if (file.isDirectory())
         return "directory";
      try
      {
         return file.toURI().toURL().openConnection().getContentType();
      }
      catch (IOException e)
      {
         throw new IllegalArgumentException(e.getMessage());
      }
   }

// ...einige Getter und Setter...

}

Ich habe nun das Problem, dass das ganze furchtbar inperformant ist unter Java 1.4.2. Um ein Verzeichnis mit etwa 100 jpegs mit einer Größe zwischen 2kb und 1000kb zu öffnen benötigt das ganze auf einem potenten Rechner etwa 30 Sekunden.

Was kann ich ändern, um die Geschwindigkeit zu erhöhen? Seht ihr große Optimierungsmöglichkeiten?

Ich habe hier
http://java.sun.com/developer/technicalArticles/javase/6_desktop_features_2/
(etwa in der Mitte) etwas über enorm gestiegene Bildverarbeitungsperformance unter Java 6 gelesen.
Kann ich davon provitieren? Gibt es einen anderen Weg?

Gruß, Taste
 
Hat sich ersteinmal erledigt. Dankeschön für Eure Mühe soweit.

Mir ist unter anderem aufgefallen, dass dank des Observer-Patterns die getIcon()-Methode meines FileChoosers bis zu acht mal je File aufgerufen wird. Daher habe die erzeugten Icons in einer LRUMap gespeichert. Dies beschleunigt schon ein wenig 🙂

Ansonsten setze ich jetzt einfach mal auf Java 6.

Gruß
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben