title: Faster performance with TIFF rendering in Java with JAI
body: <p>I have been working on software that analyzes microscopy data, which is stored as a multilayer tiff file. After looking through StackOverflow and through the JAI documentation, I hobbled together some code to store the tiff stack and render it correctly.</p>
  
  <p>However, it suffers from some pretty bad performance. I had hoped for some faster performance after reading posts such as this:
  <a href="https://stackoverflow.com/questions/1494457/anyone-have-any-luck-writing-a-very-fast-tiff-viewer-editor-in-java">Anyone have any luck writing a very fast tiff viewer/editor in Java?</a></p>
  
  <p>Unfortunately, it's not nearly as good as I would have hoped for. I do not have much experience working with external image libraries, or with Java's Graphics capabilities for that matter, so I'm not sure how I would improve this.</p>
  
  <p>For some context, here is a video of the 'stuttering' I experience while traversing through the tiff stack:
  <a href="http://www.youtube.com/watch?v=WiR4o6TsqyM&amp;feature=channel_video_title" rel="nofollow noreferrer">http://www.youtube.com/watch?v=WiR4o6TsqyM&amp;feature=channel_video_title</a></p>
  
  <p>Note how the frames stutter occasionally as the slider is dragged. </p>
  
  <p>I improved performance when the image is zoomed in by removing smoothing when scaling, but it still isn't as fast I would have liked.</p>
  
  <p>My code is below:</p>
  
  <pre><code>/** Converts the RenderedImage into a BufferedImage, which is more flexible
   * @param img   The original RenderedImage
   * @return  The new BufferedImage
   */
  public BufferedImage convertRenderedImage(RenderedImage img) {
      if (img instanceof BufferedImage) {
          return (BufferedImage)img;  
      }   
      ColorModel cm = img.getColorModel();
      int width = img.getWidth();
      int height = img.getHeight();
      WritableRaster raster = cm.createCompatibleWritableRaster(width, height);
      boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
      Hashtable&lt;String, Object&gt; properties = new Hashtable&lt;String, Object&gt;();
      String[] keys = img.getPropertyNames();
      if (keys!=null) {
          for (int i = 0; i &lt; keys.length; i++) {
              properties.put(keys[i], img.getProperty(keys[i]));
          }
      }
      BufferedImage result = new BufferedImage(cm, raster, isAlphaPremultiplied, properties);
      img.copyData(raster);
      return result;
  }
  
  /** Draws everything on top of the scaled image
   * @param scale The current scale value
   */
  private void setScaledImage(double scale) 
  {
      //Optimizes the image type for drawing onto the screen
      GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
      GraphicsDevice device = env.getDefaultScreenDevice();
      GraphicsConfiguration config = device.getDefaultConfiguration();
  
      int w = (int)(scale*currImage.getWidth());
      int h = (int)(scale*currImage.getHeight());
      scaled = config.createCompatibleImage(w, h, BufferedImage.TYPE_INT_RGB);
      Graphics2D g2 = scaled.createGraphics();
      g2.drawImage(currImage, 0, 0, w, h, null);
      g2.dispose();
  }
  </code></pre>
  
  <p>I've loaded the multilayer tiff into an imageDecoder with JAI, and to display the correct layer when the slider is dragged, I use the following code:</p>
  
  <pre><code>try {
      currImage = convertRenderedImage(imageStack.decodeAsRenderedImage(currentLayerSlider.getValue()-1));
      setScaledImage (scaleSlider.getValue()/100.0);
      curves.changeFrame(currentLayerSlider.getValue());
      drawImageOverlay ();} 
  catch (IOException e) {
      e.printStackTrace();
      currImage = null;}
  </code></pre>
  
  <p>Basically, whenever the slider is dragged, I extract a rendered image from the imageStack, convert it to a BufferedImage (so that it can be used with an ImageIcon), scale it, and set it as the displayed image. I think the slow part is converting it to the buffered image, and scaling it. Is there any way to do this faster?</p>
  
  <p>Does anyone have any suggestions for how to improve things, or insight from similar experiences?</p>
  
  <p>Any help would be much appreciated.</p>