|
Description
|
java version "1.4.0-beta3"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-beta3-b84)
Java HotSpot(TM) Client VM (build 1.4.0-beta3-b84, mixed mode)
I used to apply a LookupOp, created with a ByteLookupTable, to filter USHORT
pixels into BYTE ones for display. It works flawlessly in 1.3.0 and 1.3.1 but
not in 1.4b3.
My guess is this may be an issue with scanline stride passed to the underlying
MediaLib subroutine from the Java2D implementation, related to BUG #4192198.
That bug, which troubled AffineTransformOp, was fixed in 1.4b3, though I suspect
the fix might somehow be affecting LookupOp now.
Here's some sample code to illustrate the problem:
import java.awt.image.*;
class TestLookupOp
{
public static void main(String args[])
{
int width = 16;
WritableRaster srcRaster, dstRaster;
// Source: single-band USHORT Raster
srcRaster = Raster.createInterleavedRaster(DataBuffer.TYPE_USHORT,
width, width, 1, null);
// Set pixel values equal to their X coord
for (int i = 0; i < width; i++)
for (int j = 0; j < width; j++)
srcRaster.setSample(i, j, 0, i);
// Create lookup table and LookupOp which invert the pixel values
byte[] table = new byte[width];
for (int i = 0; i < width; i++) table[i] = (byte)(width - 1 - i);
ByteLookupTable blut = new ByteLookupTable(0, table);
LookupOp op = new LookupOp(blut, null);
// Destination: single-band BYTE Raster
dstRaster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
width, width, 1, null);
// Set pixel values to zero
for (int i = 0; i < width; i++)
for (int j = 0; j < width; j++)
dstRaster.setSample(i, j, 0, 0);
// Filter
op.filter(srcRaster, dstRaster);
// Dump the value of pixels along the last scanline
for (int i = 0; i < width; i++) {
System.out.print("X = " + i);
System.out.print(" src pixel: " +
srcRaster.getSample(i, width - 1, 0));
System.out.print(" dst pixel: " +
dstRaster.getSample(i, width - 1, 0));
System.out.println(" table[src pixel]: " +
table[srcRaster.getSample(i, width - 1, 0)]);
}
}
}
The output when runned in 1.3:
X = 0 src pixel: 0 dst pixel: 15 table[src pixel]: 15
X = 1 src pixel: 1 dst pixel: 14 table[src pixel]: 14
X = 2 src pixel: 2 dst pixel: 13 table[src pixel]: 13
X = 3 src pixel: 3 dst pixel: 12 table[src pixel]: 12
X = 4 src pixel: 4 dst pixel: 11 table[src pixel]: 11
X = 5 src pixel: 5 dst pixel: 10 table[src pixel]: 10
X = 6 src pixel: 6 dst pixel: 9 table[src pixel]: 9
X = 7 src pixel: 7 dst pixel: 8 table[src pixel]: 8
X = 8 src pixel: 8 dst pixel: 7 table[src pixel]: 7
X = 9 src pixel: 9 dst pixel: 6 table[src pixel]: 6
X = 10 src pixel: 10 dst pixel: 5 table[src pixel]: 5
X = 11 src pixel: 11 dst pixel: 4 table[src pixel]: 4
X = 12 src pixel: 12 dst pixel: 3 table[src pixel]: 3
X = 13 src pixel: 13 dst pixel: 2 table[src pixel]: 2
X = 14 src pixel: 14 dst pixel: 1 table[src pixel]: 1
X = 15 src pixel: 15 dst pixel: 0 table[src pixel]: 0
and in 1.4b3:
X = 0 src pixel: 0 dst pixel: 15 table[src pixel]: 15
X = 1 src pixel: 1 dst pixel: 15 table[src pixel]: 14
X = 2 src pixel: 2 dst pixel: 15 table[src pixel]: 13
X = 3 src pixel: 3 dst pixel: 6 table[src pixel]: 12
X = 4 src pixel: 4 dst pixel: 15 table[src pixel]: 11
X = 5 src pixel: 5 dst pixel: 15 table[src pixel]: 10
X = 6 src pixel: 6 dst pixel: 15 table[src pixel]: 9
X = 7 src pixel: 7 dst pixel: 14 table[src pixel]: 8
X = 8 src pixel: 8 dst pixel: 0 table[src pixel]: 7
X = 9 src pixel: 9 dst pixel: 0 table[src pixel]: 6
X = 10 src pixel: 10 dst pixel: 0 table[src pixel]: 5
X = 11 src pixel: 11 dst pixel: 0 table[src pixel]: 4
X = 12 src pixel: 12 dst pixel: 15 table[src pixel]: 3
X = 13 src pixel: 13 dst pixel: 233 table[src pixel]: 2
X = 14 src pixel: 14 dst pixel: 0 table[src pixel]: 1
X = 15 src pixel: 15 dst pixel: 15 table[src pixel]: 0
Release Regression From : 1.3.1_01a
The above release value was the last known release where this
bug was knwon to work. Since then there has been a regression.
Release Regression From : 1.3.1_01a
The above release value was the last known release where this
bug was knwon to work. Since then there has been a regression.
(Review ID: 136847)
======================================================================
|
|
Evaluation
|
This bug was indeed unmasked by the fix for 4192198, as the submitter suspected.
The problem was in lookupByteRaster() when the source is TYPE_SHORT and the
destination is TYPE_BYTE. We would loop through the raster, looking up values
using the source short values as indices, and then storing the resulting byte
values in the destination raster. The bug was that at the end of every
scanline we would increment the "y" pointer using the mlib_image stride value
(which is in bytes) rather than the RasterS_t scanlineStride value (which is
in pixels). Therefore, we were effectively skipping two rows at a time,
eventually reaching beyond the allocated memory and returning garbage values.
The fix is to increment the pointers in pixel units. (It appears that this
bug is also present in the lookupByteBI() method as well, so a similar fix
should be applied there too.)
xxxxx@xxxxx 2003-08-14
|
|
Comments
|
Submitted On 10-DEC-2001
jccwei
It appears to me a trivial bug that Sun should have it fixed
in formal release of 1.4. If not so, or you can't wait,
here's a trick that might work.
Similar to the workaround for 4192198 or a related one, it
is possible to cheat Java2D into doing the right thing.
Start with a Raster whose scanline stride is twice of its
width (hence twice the array size.) Fill in the pixel data
observing the doubled scanline stride. Create a second
Raster using the same DataBuffer from the first one, which
is like a different view to the same pixel data, only with
scanline stride = width. Now apply LookupOp on the second
Raster and it may give you the correct result. This appears
to work for filtering a single-band USHORT Raster into a
single-band BYTE Raster using LookupOp.
PLEASE NOTE: JDK6 is formerly known as Project Mustang
|