Either PSP or Java has a broken gif codec :S

I’ve got here 2 gifs, identical in every way, except the bitmask color is at index 0 in image B, and index 12 in image A.

Image B loads fine, Image A appears to load fine.
However, when I apply a rotation tranform to it during drawing, I get an ugly opaque band across the top few rows of the image ???
The color of the band is dependant on the color at palette entry 0 :S

And yes, I am absolutely positive it is not my code :wink:
here are the 2 images

Image a =

Image b =

and the results of rotating the 2 images (using the same code) :-


import java.awt.*;
import java.awt.image.*;
import java.awt.geom.*;
import javax.imageio.*;
import javax.swing.*;
public class GifTest extends JFrame
{
   BufferedImage a,b;
   public GifTest()
   {
      setDefaultCloseOperation(EXIT_ON_CLOSE);
      try
      {
         a = ImageIO.read(getClass().getResource("broken.gif"));
         b = ImageIO.read(getClass().getResource("fixed.gif"));
      }
      catch(Exception e){}
   }

   public void paint(Graphics g)
   {
      Graphics2D g2d = (Graphics2D)g;

      AffineTransform af = AffineTransform.getRotateInstance(Math.PI/4, 50,50);
      g2d.setTransform(af);
      g2d.drawImage(a,50,50,null);

      AffineTransform af2 = AffineTransform.getRotateInstance(Math.PI/4, 150,50);
      g2d.setTransform(af2);
      g2d.drawImage(b,150,50,null);
   }

   public static void main(String [] args)
   {
      GifTest gf = new GifTest();
      gf.setBounds(50,50,300,300);
      gf.show();
   }
}

Very strange effect! :o

I’ve tried with PSP and you’re right, probably it’s a Java problem (I’ve always used the first color as transparent).

Probably with 256 colors Java will give different results…

I’m now using rotation in my new game using PNG images and no problem with color 0 as transparent.

I’ve tried using PNG images (4 bit) with 13th color as transparent, all is OK…

Maybe it’s really a problem with GIF codec.
:-/

[quote]I’ve got here 2 gifs, identical in every way, except the bitmask color is at index 0 in image B, and index 12 in image A.

Image B loads fine, Image A appears to load fine.
However, when I apply a rotation tranform to it during drawing, I get an ugly opaque band across the top few rows of the image ???
The color of the band is dependant on the color at palette entry 0 :S

And yes, I am absolutely positive it is not my code :wink:
here are the 2 images
[/quote]
Hi Abuse,

That looks like a bug to me, but I’m not sure whether it a Java 2D problem or an IIO bug. Either way, it’s something for our team to look at… So if you could submit a bug report (with your source code and images included), we’ll be sure to check it out.

Thanks!
Chris

done.

I believe its a bug with ImageIO, cos if I load the same images with toolkit.createImage/MediaTracker, the problem goes away.

Which kinda suprised me actually, I would have thought both would have used the same underlying codec -
the AWT utility classes must be in a real mess :o

btw, are we going to see a mass-deprecation in 1.5, finally saying goodbye to all the old ways of creating/loading/managing and rendering of images?

The AWT image loading and the ImageIO loading are still very separate at this time, as far as I know.

[quote]done.

I believe its a bug with ImageIO, cos if I load the same images with toolkit.createImage/MediaTracker, the problem goes away.

Which kinda suprised me actually, I would have thought both would have used the same underlying codec -
the AWT utility classes must be in a real mess :o

btw, are we going to see a mass-deprecation in 1.5, finally saying goodbye to all the old ways of creating/loading/managing and rendering of images?
[/quote]
Probably no deprecation in 1.5, but we’ve been trying to steer people away from those APIs for a while now. IIO is definitely the preferred method for loading images, and we’re doing everything we can to make it behave/perform as well as the old 1.1-era Toolkit image APIs.

Chris

Chris, is there any chance in 1.5 that ImageIO will return “Managed” images? Where they’re automatically grabbing VRAM if/when appropriate?

[quote]Chris, is there any chance in 1.5 that ImageIO will return “Managed” images? Where they’re automatically grabbing VRAM if/when appropriate?
[/quote]
What an excellent question… :slight_smile: The answer is an emphatic “yes”. We just completed that work a couple weeks ago, so that all BufferedImages (even those returned by ImageIO) can now be considered “managed images”. Of course, it’s still best (as always) to use GraphicsConfig.createCompatibleImage() so that we pick the most optimal format for your device. But at least now you don’t have to go through trickery to get your IIO images “managed”, as we take care of that for you under the hood.

I hope this makes things easier for you guys…

Chris

OH YES!

Yeah, Chris, that helps. Up on the Wiki is a tip on how to create a managed image from and ImageIO loaded image. Essentially, as I am SURE You know, we end up redrawing the image we just loaded!

I appreciate the reply.

um…so… we are still going to have to copy the image into an ‘optimal’ managed image?

Can’t we just specify where we intend to render the image at load time?

i.e.

ImageIO.read(URL image, GraphicsConfiguration intendedDestination)

There is already a way to specify loading into an already existing image.

Look up ImageReadParam.setDestination(BufferedImage);

You will have to use a ImageReader directly, rather than the ImageIO.read() method.

I was going to use this in a project at work, but unfortunately there are some leaks in ImageIO that caused huge problems for me… I needed to stream video as JPEGs (JMF is so flakey and worked so poorly that it was unusable). ImageIO seems to make a lot temp files that it never gets rid of. (Why it is making temp files at all is another question. Maybe I needed a setUseCache(false)? ) There is also a memory leak that happens when reusing a reader the only work around has other problems.
I was forced to go back to AWT image loading… which is also buggy… failing to decode occasionally where ImageIO had no problems. Seems to be related to thinking it is done reading and yet the image isn’t ready… sigh…

Oh yeah, why isn’t there a ImageIO.read(ByteBuffer) method? I had to do hacks to wrap my buffer with an InputStream

I’m sorry, I wrote two completely separate thoughts in nearby sentences.

The first thought is:
BufferedImages are now all managed by default, so all you have to do is call ImageIO.read(). You can render the returned image immediately to any surface (other BufferedImages, the Swing backbuffer, the screen), and we’ll cache that image in hardware as appropriate (it’s “managed” under the hood, you don’t have to worry about anything). So no need to copy the image returned by IIO into another image.

The second thought is:
If you are creating an image yourself (say you want to do some custom rendering into it), and you will be rendering that image to a screen or backbuffer surface, it’s still best to call GraphicsConfig.createCompatibleImage(). That’s what we’ve been telling folks all along, and that remains unchanged.

Hopefully that clears up some confusion. We really need to finish up that elusive “Java 2D Images Explained” document, which should be a good reference. I know that the various image types and creation methods have been mysterious in the past. This new managed image work should clear things up a bit, because the answer is always simply “BufferedImage”. No matter how it was created, or what ColorModel it uses, we’ll try to accelerate it under the hood.

Chris

Yes, if you call setUseCache(false), we won’t create a temp file (in some cases, the temp file can help improve performance, but in your case you’ll be reading so many images that it’s best to disable the cache).

I think there may be one or two outstanding bugs related to “leaks” in JPEGImageReader reuse that were fixed for 1.5… Are you calling ImageReader.reset() between each reuse? That should ensure that the reader cleans up any resources used for the last image decoding.

Hmm… You might want to look at the new JAI/IIO Tools package, which includes a couple Image{In/Out}putStreams based on NIO:
http://java.sun.com/products/java-media/jai/forDevelopers/jai-imageio-1_0-rc-docs/com/sun/media/imageio/stream/package-summary.html

If this doesn’t suit your needs, or if you have any ideas about how NIO/IIO interaction could be made easier for developers, please submit an RFE.

Thanks,
Chris

[quote]Are you calling ImageReader.reset() between each reuse? That should ensure that the reader cleans up any resources used for the last image decoding.
[/quote]
That was the ‘workaround’… the problem is that the performance degrades way too much…
http://developer.java.sun.com/developer/bugParade/bugs/4867874.html
and the original problem:
http://developer.java.sun.com/developer/bugParade/bugs/4868479.html

[quote]Hmm… You might want to look at the new JAI/IIO Tools package, which includes a couple Image{In/Out}putStreams based on NIO:
http://java.sun.com/products/java-media/jai/forDevelopers/jai-imageio-1_0-rc-docs/com/sun/media/imageio/stream/package-summary.html
[/quote]
Thanks I wasn’t aware that NIO ImageIO streams were part of that package. I may be able to use that if the overall leaks/speed issues can be solved.

IMHO the JPEG decoder should be using SSE2 instructions on Intel (where available) since it will result in a drastic performance increase… It seems you are using a vanilla C JPEG decoder or something. The time spent decoding images for what I was doing was just WAY out there - I’m talking an order of magnitude slower than it should be. Intel makes a nice JPEG library that works well, and is free as far as I know. (It is what I am using on my encoding side in my video streaming application, since I needed native code to fetch the images from hardware anyway, I just fetch “JPEG” buffers.)

I just checked out that NIO stuff for ImageIO. I see that it will make an ImageInputStream from a ReadableByteChannel, but not a ByteBuffer. Looking at the various implementations of ReadableByteChannel, I don’t see one that works like a ByteArrayInputStream but on a ByteBuffer instead, so it won’t be that simple to make this work for my purposes.
There is a ByteArrayImageSource in AWT, but no ByteBufferImageSource for either AWT or ImageIO.
For AWT I can back my ByteBuffer with an array and coax AWT into reading my image. For ImageIO I have to jump through a couple extra hoops to do that. A more direct path to the ByteBuffer for ImageIO is what I want. (along with the memory leak fixed :slight_smile: )