Tiff Textures

Another failrly simple question I hope…

I’m trying to texture a shape with a a pretty large tiff file (60mb+ uncompressed). Unfortunatly, it will not load using the TextureLoader class as I get an out of memory exception. I can however, load it using Java Advanced Imaging into a RenderedImage, but when I try and convert it to a BufferedImage make it a texture I get the out of memory exception again.

I’ve tried quite a few different ways of loading it and converting it but none of them have worked and I’m running out of ideas.

Here’s the code I’m using at the moment:

RenderedImage image = JAI.create(“fileload”, “c:\map.tif”);
RenderedImageAdapter ria = new RenderedImageAdapter (image);
BufferedImage bi = ria.getAsBufferedImage();

tl = new TextureLoader();
a.setTexture((Texture2D)tl.loadTexture(
bi,
“RGB”,
false,
Texture.BASE_LEVEL,
Texture.BASE_LEVEL_LINEAR,
Texture.WRAP));

I was wondering if anyone had tried this or had any advice. Any help would be greatly appreciated…

Maybe its trying to load it into VM memory. Have you tried increasing the heap and/or stack size with:

java -Xmx128m -Xms128m

or something?

Kev

Yeah, i’m using:

-Xms128m
-Xmx256m

Still seems to crash though

Well, I’ve got a little further. Now I can load into a BufferedImage, but can’t load that into the texture. This is what I have now:

System.out.println (“Reading file”);
BufferedImage bi = ImageIO.read(imgFile);

System.out.println (“Creating image component”);
ImageComponent2D ic = new ImageComponent2D (ImageComponent.FORMAT_RGB, bi.getWidth(), bi.getHeight(), bi);

System.out.println(“Setting image”);
tx.setImage(0, ic);

It gets to creating hte image component, says “THIS IS BAD, CONVERTING TEXTURE DYNAMICALLY”, then "java.lang.OutOfMemoryError
Exception in thread “main” ".

[quote]Yeah, i’m using:

-Xms128m
-Xmx256m

Still seems to crash though
[/quote]
If you’re getting an out of memory exception with those values - try increasing them substantially. That’s one huge image you are loading.

Will.

Thanks for the help!

I’ve managed to load the image. It turned out that at 50% scale it was still good enough quality and would fit in memory.

I’ve got another problem though, and thats the amount of time that it takes to make it a texture. Its usually somewhere around 4-5mins, which is too long really.

But it only takes something like 30-60secs for ImageIO to load the image, most of the rest seems to be taken up by converting the BufferedImage into a DirectBufferedImage. If I could read straight into a DirectBufferedImage it would save lots of time.

I’ve been playing with JAI, but can’t seem to get it to work (the texture comes out in a creamy colour instead of a map). I was wondering if anyone had been able to do it or had any advice…

This is what I’ve have so far:


BufferedImage dbi = null;
File imgFile = new File ("c:\\map.tif");

ImageInputStream stream = ImageIO.createImageInputStream(imgFile);
                                  Iterator iter = ImageIO.getImageReaders(stream);
                                  if (iter.hasNext())  
                                  {
                                    ImageReader reader = (ImageReader)iter.next();
                                    
                                    reader.setInput(stream, true, true);
                                    int iw = reader.getWidth(0);
                                    int ih = reader.getHeight(0);
                                    dbi = DirectBufferedImage.make(iw, ih, DirectBufferedImage.DIRECT_RGB);
                                    
                                    dbi = reader.read(0);
                                    stream.close();
                                    reader.dispose();
                                  }
                                  else
                                    stream.close();

This just comes out creamy. I think I’m missing a few bits and pieces, but I’m not sure what…

Hi,

[quote] dbi = DirectBufferedImage.make(iw, ih, DirectBufferedImage.DIRECT_RGB);

  dbi = reader.read(0);

[/quote]
Don’t you overwrite just-created DirectBufferedImage with return value of reader.read(…)?

Well, in case of big images this is not so easy but possible to read them DIRECTLY into DirectBufferedImage (only if you don’t need to resample etc.)

Also be aware of hardware texture size limitation - it is often 1024x1024, 2048x2048 or 4096x4096 pixels limit.

Yuri

Thanks for the reply!

[quote] Well, in case of big images this is not so easy but possible to read them DIRECTLY into DirectBufferedImage (only if you don’t need to resample etc.)
[/quote]
this is really what I’m aiming to do, I don’t need to do anything with the image except texture my terrain shape with it as fast as possible. If you have any code to do this it would be very much appreciated!

It seems most of the time is spent drawing the Bufferedimage onto the DirectBufferedImage when it is converted, so I’ve been trying to find different ways to convert it (like using ByteArrayOutputStream) but no success… are there any other ways of doing this?

Hi,

I can not send you the code - it is quite application specific and to make an example from it I have to factor it out from a big application, but I will give you some pointers:

[description for big JPEG files]

You can go for low-level image i/o using javax.imageio - use ImageInputStream and ImageReader to read from it.

You can create ImageReadParam that can contain your destination buffered image, which you construct manually using your own byte array, color model etc.

After you read image using reader.read(0, param) and use byte array as source for pixels of DirectBufferedImage, so it at the end shares pixel data with regular BufferedImage used for reading. This way you save the pixel storage.

Yuri

Cheers!

I think I understand. It should be something like this?:

ImageInputStream stream = ImageIO.createImageInputStream(imgFile);
                                  Iterator iter = ImageIO.getImageReaders(stream);
                                  if (iter.hasNext())  
                                  {
                                    ImageReader reader = (ImageReader)iter.next();
                                    
                                                                       
                                    reader.setInput(stream, true, true);
                                  
                                    
                            
                                    ImageReadParam param = new ImageReadParam();
                                    dbi = DirectBufferedImage.getDirectImageRGB(reader.getWidth(0), reader.getHeight(0));
                                    param.setDestination(dbi);
                                    reader.read(0, param);

But I get a java.lang.IllegalArgumentException: sourceBands.length != destinationBands.length at the reader.read(0, param); line.

Hi,

You can not use DirectBufferedImage as destination because of its specifics.

Create byte[], ColorModel, Raster, SampleModel etc. and BufferedImage based on it. Then use it as Destination and after reading create DirectBufferedImage with dimensions and byte[] used at the beginning.

Yuri

Many thanks for your help Yuri!! Sorry I’m being a little slow getting this :-/

I’ve managed to create the BufferedImage and read it. As I understand it, the byte[] created to make the BufferedImage will be populated when the file is read. This can then be used to create the DirectBufferedImage without the need for copying the data?

I’ve tried this:

ImageInputStream stream = ImageIO.createImageInputStream(imgFile);
                                  Iterator iter = ImageIO.getImageReaders(stream);
                                  if (iter.hasNext())  
                                  {
                                    ImageReader reader = (ImageReader)iter.next();
reader.setInput(stream, true, true);

//Generates a 16 color model
ColorModel colorModel = generateColorModel();

byte[] b = new byte [reader.getWidth(0) * reader.getHeight(0) * 3];

DataBuffer dbuf = new DataBufferByte(b, reader.getWidth(0)* reader.getHeight(0), 0);

int numBanks = dbuf.getNumBanks();

int bitMasks[] = new int[]{(byte)0xf};
                                            SampleModel sampleModel = new SinglePixelPackedSampleModel(
                                                DataBuffer.TYPE_BYTE, reader.getWidth(0), reader.getHeight(0), bitMasks);

WritableRaster raster = Raster.createWritableRaster(sampleModel, dbuf, null);

BufferedImage tmpbi = new BufferedImage(colorModel, raster, false, null);
                                            
                                            ImageReadParam param = new ImageReadParam();
                                            param.setDestination(tmpbi);
                                                  reader.read(0, param);
                                                  DirectBufferedImage dbi = DirectBufferedImage.getDirectImageRGB(tmpbi.getWidth(), tmpbi.getHeight(), b);

tx = (Texture2D)TextureLoader.tf.constructTexture(dbi, "RGB", false, Texture.BASE_LEVEL, Texture.BASE_LEVEL_LINEAR,
                                  Texture.CLAMP_TO_EDGE, true, TextureLoader.SCALE_DRAW_BEST);

This doesn’t produce any exceptions and loads really fast, but the shape comes out all black. I’ve tried getting the raster out of the BufferedImage and reading the byte array from that, but that just produced the same result.

Could you point me in the right direction again? I’m not sure what I’m doing wrong…