Bug 823

Summary: AWTTextureIO does not properly interpret a BufferedImage created with BufferedImage.getSubImage()
Product: [JogAmp] Jogl Reporter: Bill Kuker <bkuker>
Component: awtAssignee: Sven Gothel <sgothel>
Status: UNCONFIRMED ---    
Severity: normal    
Priority: ---    
Version: 2   
Hardware: All   
OS: all   
Type: --- SCM Refs:
Workaround: ---
Attachments: Test Program for bug

Description Bill Kuker 2013-09-02 03:56:58 CEST
java.awt.image.BufferedImage has a function which returns a BufferedImage which is a subimage of the original with dimensions w*h at offset x,y:

    public BufferedImage getSubimage(int x int y, int w, int h)

Rather than creating a copy of the pixel data this function plays games with the returned images Raster and Sample model. AWTTextureIO is not correctly taking into account all of the offsets in the data reported by the buffered image, and therefore any Texture created from a BufferedImage created with a call to

    someImage.getSubimage( x, y, w, h)

looks instead as if it were created from a BufferedImage created with a call to

    someImage.getSubimage( 0, 0, w, h)

instead

JDK 6's GIF writer seems to have the same bug, see http://bugs.sun.com/view_bug.do?bug_id=6795544 for a description of what I think is a very similar bug.

I have confirmed that this problem can be worked around with a function that creates a copy of the sub-image by allocating a new BufferedImage of the correct size, and then copying the pixels into it:

The code 

        tex = AWTTextureIO.newTexture(GLProfile.getDefault(), i.getSubimage(x,y,w,h), false); 

displays incorrectly for x !=0, y != 0 but the code 

        tex = AWTTextureIO.newTexture(GLProfile.getDefault(), workaround(i.getSubimage(x,y,w,h)), false); 

works as expected, given the function 

        private static BufferedImage workaround(BufferedImage i) { 
                BufferedImage d2 = new BufferedImage(i.getWidth(), i.getHeight(), i.getType()); 
                d2.getGraphics().drawImage(i, 0, 0, null); 
                return d2; 
        }

I will look into preparing a very short example program.
Comment 1 Bill Kuker 2013-09-02 05:08:58 CEST
Created attachment 501 [details]
Test Program for bug

This is a simple test program that should reproduce the problem.

A 256x256 texture is loaded, a 128x128 subimage is extracted at offset 128, 128 and used as a texture, once directly and once using the workaround in the ticket.

You should see TWO green squares, but see one red and one green, the green being a product of the workaround, the red being the texture in error.
Comment 2 Bill Kuker 2013-09-02 05:10:38 CEST
Just as a note, I was going crazy trying to reproduce this and discovered that the problem occurs when the image is a JPEG, but not when it is a PNG.
Comment 3 Bill Kuker 2013-09-02 14:22:31 CEST
In AWTTextureIO there is a function, createFromCustom(...), which re-writes the image to a new BufferedImage exactly as the workaround above does. I think that it hits this code for PNG with alpha, but perhaps not for JPEG, explaining the difference between the two image types.

(In reply to comment #2)
> Just as a note, I was going crazy trying to reproduce this and discovered
> that the problem occurs when the image is a JPEG, but not when it is a PNG.
Comment 4 Sven Gothel 2013-09-29 21:28:47 CEST
(In reply to comment #3)
> In AWTTextureIO there is a function, createFromCustom(...), which re-writes
> the image to a new BufferedImage exactly as the workaround above does. I
> think that it hits this code for PNG with alpha, but perhaps not for JPEG,
> explaining the difference between the two image types.
> 
> (In reply to comment #2)
> > Just as a note, I was going crazy trying to reproduce this and discovered
> > that the problem occurs when the image is a JPEG, but not when it is a PNG.

Bill, can you provide a patch ?

Please also note, we consider using our own PNG and JPEG decoder code
as the default - hence it is used by our TextureIO class.
Both are more efficient and expose better performance. The JPEG decoder
is even more compliant.