Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4684046
Votes 7
Synopsis Using CropImageFilter on PNG images fails
Category java:classes_2d
Reported Against 1.4
Release Fixed 1.5(tiger-b31)
State 10-Fix Delivered, bug
Priority: 4-Low
Related Bugs
Submit Date 13-MAY-2002
Description




When you use CropImageFilter to crop an image that was produced from a PNG image, from time to time the following exception is thrown in the ImageFetcher thread:

java.io.IOException: Stream closed

	at java.io.BufferedInputStream.ensureOpen(BufferedInputStream.java:120)

	at java.io.BufferedInputStream.read(BufferedInputStream.java:199)

	at sun.awt.image.PNGImageDecoder.produceImage(PNGImageDecoder.java:244)

	at sun.awt.image.InputStreamImageSource.doFetch(InputStreamImageSource.java:257)

	at sun.awt.image.ImageFetcher.fetchloop(ImageFetcher.java:214)

	at sun.awt.image.ImageFetcher.run(ImageFetcher.java:182)

I suspect there's a thread issue going on, because this isn't 100% repeatable and seems to vary wildly from run to run. However, I'm developing a Windows XP look and feel implementation which does a lot of image loading and cropping, and this happens often enough to cause my LAF to fail to work about 7 times in 10.

I can consistently reproduce this with the following code which loads 6 images and crops each one 1000 times:

package org.dubh.plaf.xp;

import java.awt.*;
import javax.swing.*;
import java.net.*;
import java.awt.image.*;

public class CropPNGBug
{
  private final static String[] pngImages = new String[]
  {
    "image/olive/button.png",
    "image/olive/button-enabled.png",
    "image/olive/button-enabled-armed.png",
    "image/olive/button-enabled-default.png",
    "image/olive/button-enabled-down.png",
    "image/olive/caption-active.png"
  };

  public static void main( String[] args )
  {
    Image[] images = new Image[ pngImages.length ];
    for ( int i=0; i < pngImages.length; i++ )
    {
      URL u = CropPNGBug.class.getResource( pngImages[i] );
      images[i] = new ImageIcon( u ).getImage();
    }

    // Now crop them all
    for ( int i=0; i < images.length; i++ )
    {
      for ( int j=0; j < 1000; j++ )
      {
        CropImageFilter cif = new CropImageFilter( 0, 0, 5, 5 );
        ImageIcon icon = new ImageIcon( createImage(
          new FilteredImageSource( images[i].getSource(), cif ) ) );
      }
    }
  }

  private static Image createImage( ImageProducer ip )
  {
    return Toolkit.getDefaultToolkit().createImage( ip );
  }
}

(you'll need to replace the array of image references with valid paths). Email me if you need the original images.
(Review ID: 146404) 
======================================================================
Work Around




None, it's extremely erratic and non-predictable. I'm going to try using the Sixlegs PNG library instead of Sun's, since the exception is coming from the PNGImageDecoder, ultimately.
======================================================================
Evaluation




 The reason of the problem is that the PNGImageDecoder does not check
 the decoder status (is it aborted or not) inside the produceImage().
 If system is busy (e.g., running large number of decoders)
 decoding may be performing for relatively long period of time and
 corresponding image consumer may be disposed (aborting associated
 decoder and closing associated BufferedInputStream) before decoding
 is finished.
 As a result aborted decoder may try to read data from closed stream
 and fail.

 The solution is to hide exceptions was thrown by aborted decoder.


======================================================================
Comments
  
  Include a link with my name & email   

Submitted On 17-MAY-2002
cairn
Eventually worked round this by using a BufferedImage and 
avoiding using CropImageFilter:

// Workaround nasty crop filter bugs.
BufferedImage i = new BufferedImage( 
      icon.getIconWidth(), icon.getIconHeight(), 
BufferedImage.TYPE_INT_ARGB 
    );
icon.paintIcon( null, i.createGraphics(), 0, 0 );

return image.getSubimage( x, y, width, height );




PLEASE NOTE: JDK6 is formerly known as Project Mustang