First seen in 2D's nightly build on 2003-09-15. Caused by the fix
4886732: AffineTransformOp does not work properly for some of the rendering hints
(changes in awt_ImagingLib.c, http://javaweb.sfbay/jcg/1.5.0-tiger/2D/4886732).
This is kind of obscure bug, so let me start with a brief introduction
of how we interface with medialib code (at least, as I understand
Suppose we filter a SRC image to a DST with transform.
The longest chain of conversions may be:
SRC -1-> SRC_ARGB
DST -2-> DST_ARGB
SRC_ARGB -3-> DST_ARGB
DST_ARGB -4-> DST
where 1,2,3 are conversions happening in awt_ImagingLib.c
(namely, expand/set*default methods), and 3 is the transformation
itself (for example, mlib_ImageAffine_s32_1ch_nn).
Note that whether 1,2,4 happen or not depends on the format of the
source and destination images.
So, prior to the fix for 4886732, 1,2 and 4 were broken because
they used to deal with the data on byte-by-byte basis, thus screwing
up the byte order.
Interestingly, it worked if the number of conversions was even: the
bytes will be switched twice: once converting the source image, and
once - converting the results to the destination.
But for some combinations of image formats only source, or
only destination conversion is needed, so those cases were not
Andrew's fix for 4886732 addressed almost all of the cases except
one, when conversion 4 was required for IntegerComponentRaster-based
One of the cases would be transforming a 25-bit image to almost any
destination. For example 25-bit to BGR
25-bit -1-> ARGB // good, covered by previous fix
ARGB -2-> ARGB
ARGB -3-> BGR // bytes swapped during conversion in setPackedICRdefault
So, my fix plugs this hole by fixing the setPackedICRdefault method.
(awt_ImagingLib.c line 3179).
While at it, I've removed a lot of duplicated code, by making
set/expandPacked* call corresponding set/expandPacked*default
method, with 'supportsAlpha' set to FALSE, as that was the only
difference that I could find between the default and non-default methods.
(Correction: it was pointed out that they were indeed different in
their initial state, but when fixed, they'd appear to be the exactly
Note that the 'non-default' method are not even used in the current
code: they're called from store/expandRasterArray, which are never
After fixing this bug I extended Andrew's testcase to render (both
using drawImage and AffineTransformOp.filter) from
any to almost any of the default image formats (plus a couple of
custom ones), and found that we still have problems in cases with
For example, rendering transformed USHORT_4444_ARGB to almost any
format results in garbage, on any platform, on 1.5 and 1.4.2. But
this happens only if AffineTransformOp is used directly instead of
just calling drawImage with transform set.
The reason for this is a bug in one of the storeImageArray method,
which never converts the image back to the destination format from
expanded ARGB, but just mem-copies it instead (see
The drawImage escapes this bug by always executing
AffineTransformOp.filter(src, 'new ARGB image') - see
DrawImage.renderImageXform(), thus avoiding conversion 3, and then
using our sw loops to convert ARBG to dest.
As I see it, there are two ways to fix this:
- fix medialib conversion
- fix AffineTransformOp to behave the same way the code in
renderImageXform does (that is, avoid the buggy code)
The ideal solution would be to do both, but I really didn't want to
spend time working on this medialib code since it's likely that
it'll become obsolete with Jim's new transformation code.
In any case, we should try to make our drawImage and
AffineTransformOp.filter stuff consistent, probably by introducing
some helper code in the latter.