Skip to main content

Forcing caching of rendered image

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]
rhwentworth
Offline
Joined: 2004-07-02

How can I force a JAI image rendering pipeline to cache the rendered output for efficiency?

I am writing an application that will ultimately mosaic together large TIFF images, providing a GUI that allows the user to adjust the relative positioning of the constituent images. My current dilemma is this: The application works fine with small images but with large images things get extraordinarily slow, even though the images rendered at the GUI level have been scaled down using SubsampleAverage to be modestly sized thumbnails.

I would think that JAI might be smart enough to cache the results of the Subsampling operation, but each time I use Graphics2D.drawRenderedImage() to draw the RenderedOp representing the thumbnail image, it takes a long time.

For one image (866MB, scaled to rendered size 300x169) successive calls to drawRenderedImage() took 325, 204, 90, 91 and 77 sec.
For another image (624MB, scaled to rendered size 257x273) successive calls to drawRenderedImage() took 210, 103, 26, 41 and 37 sec.
Heap size is 1GB.

Maybe some caching is happening since the first invocation is the longest. But these results still seem unreasonably slow after the first rendering. Any idea what I'm doing wrong, or what I can do to force efficient rendering after the first one?

The relevant code looks more or less as follows.

// one-time setup

FileSeekableStream stream;
stream = new FileSeekableStream(file);
RenderedImage rawImage;
rawImage = JAI.create("stream", stream);

int scalePower = 6;
double scaleFactor = 1.0d / (1L << scalePower);
ParameterBlock pb = new ParameterBlock();
pb.addSource(rawImage);
pb.add(scaleFactor); // x scale
pb.add(scaleFactor); // y scale
pb.add(0.0F); // The x translation
pb.add(0.0F); // The y translation
RenderedOp imageAtScale;
imageAtScale = JAI.create("SubsampleAverage", pb);

// invoked repeatedly

protected void paintComponent(Graphics graphics) {
        Graphics2D g = (Graphics2D)graphics.create();
        g.drawRenderedImage(imageAtScale, new AffineTransform());
}

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
rgd
Offline
Joined: 2005-08-23

A 1GB heap is very small if you're dealing with an 866MB image!

JAI should be caching things... but by default everything shares one
cache, so the results are probably being flushed out before they can be
reused. What is the tile size of the output 300x169 image? If it's
made up of more than one tile, probably the first one gets cached but
then shoved out during computation of the second.

What you want to do in this case is to create a private tile cache and
attach it to the subsample operator.

I don't recall the detailed syntax offhand but look up TileCache or its
subclasses, create one of an appropriate size, then use the
RenderingHints mechanism to attach that to your operator as the tile
cache. Don't set the overall cache (via the JAI object)... you want
this only for the subsample op. There should be examples if you search
the archives.

You may need to do more cache tuning, but this should help immensely.
For example, IIRC the default cache size is horribly small. You can
increase that, search the archives for examples. But you still want a
private cache for the subsample op.

Good luck...

-Bob

On 11/1/11 3:17 PM, forums@java.net wrote:
> How can a force a JAI image rendering pipeline to cache the rendered output
> for efficiency?
>
> I am writing an application that will ultimately mosaic together large TIFF
> images, providing a GUI that allows the user to adjust the relative
> positioning of the constituent images. My current dilemma is this: The
> application works fine with small images but with large images things get
> extraordinarily slow, even though the images rendered at the GUI level have
> been scaled down using SubsampleAverage to be modestly sized thumbnails.
>
> I would think that JAI might be smart enough to cache the results of the
> Subsampling operation, but each time I use
> Graphics2D.drawRenderedImage() to
> draw the RenderedOp representing the thumbnail image, it takes a long time.
>
> For one image (866MB, scaled to rendered size 300x169) successive calls to
> drawRenderedImage() took 325, 204, 90, 91 and 77 sec.
> For another image (624MB, scaled to rendered size 257x273) successive calls
> to drawRenderedImage() took 210, 103, 26, 41 and 37 sec.
> Heap size is 1GB.
>
> Maybe some caching is happening since the first invocation is the longest.
> But these results still seem unreasonably slow after the first
> rendering. Any
> idea what I'm doing wrong, or what I can do to force efficient rendering
> after the first one?
>
> The relevant code looks more or less as follows.
>
> // one-time setup FileSeekableStream stream; stream = new
> FileSeekableStream(file); RenderedImage rawImage; rawImage =
> JAI.create("stream", stream); int scalePower = 6; double scaleFactor =
> 1.0d /
> (1L << scalePower); ParameterBlock pb = new ParameterBlock();
> pb.addSource(rawImage); pb.add(scaleFactor); // x scale
> pb.add(scaleFactor);
> // y scale pb.add(0.0F); // The x translation pb.add(0.0F); // The y
> translation RenderedOp imageAtScale; imageAtScale =
> JAI.create("SubsampleAverage", pb); // invoked repeatedly protected void
> paintComponent(Graphics graphics) { Graphics2D g =
> (Graphics2D)graphics.create(); g.drawRenderedImage(imageAtScale, new
> AffineTransform()); }
>
>
>

rhwentworth
Offline
Joined: 2004-07-02

New question: What is the preferred way of manually buffering the output or an intermediate state in a rendering chain?

Some new information is that the behavior I described, where successive renderings take way longer than one would expect, happens in a context where two images are being rendered in alternation. When only one image is present and it is rendered numerous times, renderings after the first are, as one would hope, very fast (ie. 3-40 ms).

So, I'm guessing that in rendering one image, data is pushed into the cache that forces the final rendered version of the other image out of the cache, necessitating its recalculation. JAI doesn't seem to be smart enough to know that information late in the rendering chain is more valuable than information early in the rendering chain, and so when the cache fills up it throws away the end result in favor of retaining raw image data tiles.

I'm guessing there is no way to gain enough control over JAI's cache to coax it into prioritizing what I'd like it to prioritize?

Lacking that, I'll be looking for a way of manually capturing a rendered copy to fully rendered image. Is there a preferred way of doing this?

Note that I'll also be looking for a way of manually capturing the state at an intermediate point in the rendering chain. Is there a preferred way of doing that?

Thanks.

rgd
Offline
Joined: 2005-08-23

See my previous reply: use a private tile cache for the ops you want at
a higher priority. If it's big enough to hold the entire image, you
shouldn't have an issue, and you can let the upstream ops thrash over
the default cache all they want.

-Bob

On 11/1/11 4:17 PM, forums@java.net wrote:
> New question: What is the preferred way of manually buffering the output or
> an intermediate state in a rendering chain?
>
> Some new information is that the behavior I described, where successive
> renderings take way longer than one would expect, happens in a context
> where
> two images are being rendered in alternation. When only one image is
> present and it is rendered numerous times, renderings after the first
> are, as
> one would hope, very fast (ie. 3-40 ms).
>
> So, I'm guessing that in rendering one image, data is pushed into the cache
> that forces the final rendered version of the other image out of the cache,
> necessitating its recalculation. JAI doesn't seem to be smart enough to
> know
> that information late in the rendering chain is more valuable than
> information early in the rendering chain, and so when the cache fills up it
> throws away the end result in favor of retaining raw image data tiles.
>
> I'm guessing there is no way to gain enough control over JAI's cache to
> coax
> it into prioritizing what I'd like it to prioritize?
>
> Lacking that, I'll be looking for a way of manually capturing a rendered
> copy
> to fully rendered image. Is there a preferred way of doing this?
>
> Note that I'll also be looking for a way of manually capturing the state at
> an intermediate point in the rendering chain. Is there a preferred way of
> doing that?
>
> Thanks.
>
>
>
>