FULL PRODUCT VERSION : jdk1.7.0_45.zip sources. Runtime used when bag occures: java version "1.7.0_45" Java(TM) SE Runtime Environment (build 1.7.0_45-b18) Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode) ADDITIONAL OS VERSION INFORMATION : Windows 7 professional, SP1 EXTRA RELEVANT SYSTEM CONFIGURATION : doesnt' matter any hard or soft specifications, pure logical bug due to lack of debugging depth A DESCRIPTION OF THE PROBLEM : When trying to read some BufferedImage from arbitrarily rectangle from image through using javax.imageio.ImageReader with setting ImageReadParam source read rectangle only 1st call is always sucessfull, all other subsequent ones return invalid colored BufferedImage or even throw EOFException. This bug only occures on BMP rasters reading. JPG and PNG works correctly, GIF format was not tested. ImageReader instance (for BMP) is get by call to javax.imageio.ImageIO.getImageReadersBySuffix( "BMP" ).getNext(). The problem cause is due to logical bug when in subsequent calls source stream is not positioned to the 1st byte after BMP header as expected by class code logic. To solve this bug, you can insert follow code line just before comment line at source file line #780 (in BMPImageReader.java) ... iis.seek( bitmapOffset ); //++ BUG fix (insert before source line #780) // There should only be one tile (line #780). switch(imageType) { case VERSION_2_1_BIT: // no compression read1Bit(bdata); break; ... STEPS TO FOLLOW TO REPRODUCE THE PROBLEM : 1. Get ImageReader for BMP raster format using some image stream 2. Set rectangle for ImageReadParam (param) 3. Use param to read part of image at least twice time EXPECTED VERSUS ACTUAL BEHAVIOR : EXPECTED - Each read returns requested rectangle from image. So it works for all valid image types except BMP. ACTUAL - 1st read returns requested image rectangle as BufferedImage. All subsequent reads returns some strange image or even throw EOFException. It depends on color model of input image. 32 bit BMP usually throw EOFException on 2nd read and follow ones. ERROR MESSAGES/STACK TRACES THAT OCCUR : java.io.EOFException at javax.imageio.stream.ImageInputStreamImpl.readFully(ImageInputStreamImpl.java:353) at javax.imageio.stream.ImageInputStreamImpl.readFully(ImageInputStreamImpl.java:405) at com.sun.imageio.plugins.bmp.BMPImageReader.read32Bit(BMPImageReader.java:1345) at com.sun.imageio.plugins.bmp.BMPImageReader.read(BMPImageReader.java:851) at ru.ts.tests.TestImageRectangleRead.main(TestImageRectangleRead.java:67) REPRODUCIBILITY : This bug can be reproduced always. ---------- BEGIN SOURCE ---------- package tests; import javax.imageio.ImageIO; import javax.imageio.ImageReadParam; import javax.imageio.stream.FileImageInputStream; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.util.Iterator; public class TestImageRectangleRead { public static void main( String[] args ) { System.out.println( "+++ TEST rectangle sub-image API +++" ); if ( args.length == 0 ) System.out.println( "Expected file paths not found" ); javax.imageio.ImageReader reader; for ( String path : args ) { System.out.println( "Processing file \"" + path + "\"" ); try { File file = new File( path ); FileImageInputStream iis = new FileImageInputStream( file ); int pntIndex = path.lastIndexOf( '.' ); if ( pntIndex < 0 || pntIndex >= path.length() ) { System.err.println( "Input path doesn't have known extension, skipping" ); continue; } String ext = path.substring( pntIndex + 1 ); System.out.println( "Extension is \"" + ext + "\"" ); // Find corresponding reader Iterator iter = ImageIO.getImageReadersBySuffix( ext ); reader = null; if ( iter.hasNext() ) reader = (javax.imageio.ImageReader) iter.next(); else { System.err.println( "Reader for \""+ext +"\" not found by call to ImageIO.getImageReadersBySuffix( \"" + ext + "\" ), skipping" ); continue; } reader.setInput( iis ); ImageReadParam param = reader.getDefaultReadParam(); int w = reader.getWidth( 0 ); int h = reader.getHeight( 0 ); System.out.println( "Image successfully opened, w=" + w + ", h=" + h ); // read UL corner System.out.println( "Read UL corner and write it to disk" ); Rectangle ulRect = new Rectangle( 0, 0, w/2, h/2); param.setSourceRegion( ulRect ); BufferedImage bi = reader.read( 0, param ); final String ulpath = "C:/temp/ULCorner." + ext; if ( ImageIO.write( bi, ext, new File( ulpath ) ) ) System.out.println( "New UL file successfully stored: \"" + ulpath + "\"" ); else System.err.println( "No no appropriate writer was found, file not created" ); // read LR corner System.out.println( "Read LR corner and write it to disk" ); Rectangle lrRect = new Rectangle( w/2, h/2, w/2, h/2 ); param.setSourceRegion( lrRect ); bi = reader.read( 0, param ); final String lrpath = "C:/temp/LRCorner." + ext; if ( ImageIO.write( bi, ext, new File( lrpath ) ) ) System.out.println( "New LR file successfully stored: \"" + lrpath + "\"" ); else System.err.println( "No no appropriate writer was found, file not created" ); } catch ( Exception e ) { e.printStackTrace(); } } } } ---------- END SOURCE ---------- CUSTOMER SUBMITTED WORKAROUND : Creates MyBMPImageReader.java as copy of BMPImageReader.java and fix bug by insertion new code line before original source line 780 (sources of SDK version 1.45) iis.seek( bitmapOffset ); //++ BUG fix, insert before line #780 Use in any way this new class except of reader returned by call to ImageIO.getImageReadersBySuffix( "BMP" )
|