Skip to main content

Efficiently displaying lots of BufferedImages

Please note these java.net forums are being decommissioned and use the new and improved forums at https://community.oracle.com/community/java.
3 replies [Last post]
jahuudi
Offline
Joined: 2009-11-24

Hi,
i am working on an application for OCR Postcorrection.
For every word the engine detected, i get the coordinates and process a BufferedImage subimage of the scanned file ( a tif image).
Right now every word is a JPanel container that has a DisplayJAI object for displaying the BufferedImage.
When a document has lots of words, displaying this huge amount of images takes quite a while, which can be annoying for the user browsing the document.

I am wondering if there is any faster or more efficient method of doing this.
As i am really no expert in the specifics of java images, i would appreciate any kind of input.

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
fabriziogiudici
Offline
Joined: 2006-01-04

On 03/10/2011 09:42 AM, forums@java.net wrote:
> Hi,
>
> i am working on an application for OCR Postcorrection.
>
> For every word the engine detected, i get the coordinates and process a
> BufferedImage subimage of the scanned file ( a tif image).
>
> Right now every word is a JPanel container that has a DisplayJAI
> object for
> displaying the BufferedImage.
>
> When a document has lots of words, displaying this huge amount of images
> takes quite a while, which can be annoying for the user browsing the
> document.
>
The faster way to render an image, where you don't need any longer
tiling, is to copy the bits to an image created with
createCompatibleImage() (if you google about it, you should find it).
These images are optimized to be used by the graphic hardware, thus are
rendered faster. Of course, this has an overhead (creation of the
compatible image, which is fast, and copying the bits on it). It gives
you an advantage if the image to be rendered is used for some time; also
if it should be scaled.

jahuudi
Offline
Joined: 2009-11-24

Hi,
thanks for your tip. i tried to create the Images using the method you suggested.
I came up with the test application i posted below. The problem i have encountered is
that it works for some .tif files, but for others i get an ArrayIndexoutofBounds Exception
while trying to set the data of the new image. It seems that the old and new data models have exactly the same values, so i can't quite pinpoint the reason.

<code>
import java.awt.FlowLayout;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.awt.image.renderable.ParameterBlock;
import java.io.IOException;

import javax.media.jai.JAI;
import javax.media.jai.RenderedOp;
import javax.swing.JFrame;

import com.sun.media.jai.codec.FileSeekableStream;
import com.sun.media.jai.widget.DisplayJAI;

public class TiffTest extends JFrame {

private static final long serialVersionUID = 1L;

private RenderedOp rop;
private GraphicsConfiguration graphicsConfiguration;

public TiffTest() {

super();
this.setLayout(new FlowLayout());

// String inputFilename = "bsb00004431_00017.tif";
String inputFilename = "bsb00001305_00004.tif";
// String inputFilename = "bsb00001830_00063.tif";

FileSeekableStream image = null;
try {
image = new FileSeekableStream(inputFilename);
} catch (IOException e) {
e.printStackTrace();
System.exit(0);
}

ParameterBlock pb = new ParameterBlock();
pb.add(image);
rop = JAI.create("tiff", pb);
graphicsConfiguration = GraphicsEnvironment
.getLocalGraphicsEnvironment().getDefaultScreenDevice()
.getDefaultConfiguration();

DisplayJAI panel3 = new DisplayJAI(getImage(100,150,100,100));
this.add(panel3);

}

public BufferedImage getImage(int x, int y, int w, int h) {
Raster r = rop.getData();
BufferedImage bim = graphicsConfiguration.createCompatibleImage(w,h);
Raster subr = r.createChild(x, y, w, h, 0, 0, null);

bim.setData(subr);
return bim;
}

public static void main(String[] args) {

TiffTest jtc = new TiffTest();

jtc.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jtc.setVisible(true);
jtc.pack();
}
}
</code>

rgd
Offline
Joined: 2005-08-23

I don't know why the first two don't work. But if the images are tiled,
the method of calling rop.getData() is extraordinarily inefficient.
That method requires creating the entire image as a single raster, which
means reading the whole thing and untiling it. Far better would be to
use rop.getData(Rectangle) which will do the subsetting early, most
likely reading only the tiles that are needed to satisfy the request.
If you're extracting a small area from a large image, that could make a
big difference.

-Bob

On 3/16/11 8:06 AM, forums@java.net wrote:
> Hi,
>
> thanks for your tip. i tried to create the Images using the method you
> suggested.
>
> I came up with the test application i posted below. The problem i have
> encountered is
>
> that it works for some .tif files, but for others i get an
> ArrayIndexoutofBounds Exception
>
> while trying to set the data of the new image. It seems that the old and
> new
> data models have exactly the same values, so i can't quite pinpoint the
> reason.
>
> The last of the image files works, the other two don't. Right now i have no
> idea why.
>
> http://www.cip.ifi.lmu.de/~voblt/bsb00001305_00004.tif
>
> http://www.cip.ifi.lmu.de/~voblt/bsb00001830_00063.tif
>
> http://www.cip.ifi.lmu.de/~voblt/bsb00004431_00017.tif
>
>

>
> import java.awt.FlowLayout;
> import java.awt.GraphicsConfiguration;
> import java.awt.GraphicsEnvironment;
> import java.awt.image.BufferedImage;
> import java.awt.image.Raster;
> import java.awt.image.renderable.ParameterBlock;
> import java.io.IOException;
> import javax.media.jai.JAI;
> import javax.media.jai.RenderedOp;
> import javax.swing.JFrame;
> import com.sun.media.jai.codec.FileSeekableStream;
> import com.sun.media.jai.widget.DisplayJAI;
> public class TiffTest extends JFrame {
>      private static final long serialVersionUID = 1L;
>      private RenderedOp rop;
>      private GraphicsConfiguration graphicsConfiguration;
>      public TiffTest() {
>
>          super();
>          this.setLayout(new FlowLayout());
> //        String inputFilename = "bsb00004431_00017.tif";
>          String inputFilename = "bsb00001305_00004.tif";
> //        String inputFilename = "bsb00001830_00063.tif";
>          FileSeekableStream image = null;
>          try {
>              image = new FileSeekableStream(inputFilename);
>          } catch (IOException e) {
>              e.printStackTrace();
>              System.exit(0);
>          }
>
>          ParameterBlock pb = new ParameterBlock();
>          pb.add(image);
>          rop = JAI.create("tiff", pb);
>          graphicsConfiguration = GraphicsEnvironment
>
> .getLocalGraphicsEnvironment().getDefaultScreenDevice()
>                  .getDefaultConfiguration();
>
>          DisplayJAI panel3 = new DisplayJAI(getImage(100,150,100,100));
>          this.add(panel3);
>      }
>
>      public BufferedImage getImage(int x, int y, int w, int h) {
>          Raster r = rop.getData();
>          BufferedImage bim =
> graphicsConfiguration.createCompatibleImage(w,h);
>          Raster subr = r.createChild(x, y, w, h, 0, 0, null);
>
>          bim.setData(subr);
>          return bim;
>      }
>      public static void main(String[] args) {
>
>          TiffTest jtc = new TiffTest();
>          jtc.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
>          jtc.setVisible(true);
>          jtc.pack();
>      }
> }
>
>

>
>