Java2D quality issues

Java2D quality issues

hello,

I’m making deep use of java2d (I simply love it) for the creation of animated desktop video graphics and video titling.

During the development of my applications I have discovered a bug in drawImage() http://developer.java.sun.com/developer/bugParade/bugs/4916948.html that causes incorrect results when drawing images with a translation-only AffineTransform. I also found a workaround for the problem, but I still hope that SUN fixes it asap.

Now I’m facing a pair of issues of which can deeply impact the graphical output quality of any java2d program. Consider that we’re drawing with the best rendering hints: interpolation, anti-aliasing etc.

  1. drawImage() bilinear interpolation gives ugly results on ARGB images.

consider the 2x2 bitmap pixels :

        X0
        00

where X is completely transparent (let’s say a transparent RED -> 0x00FF0000) and 0 is opaque (let’s say an opaque WHITE -> 0xFFFFFFFF).

The pixel bilinear interpolation takes the color of the X pixel into consideration. That’s completely wrong because the pixel is transparent. When drawing the bitmap at 0.5,0.5 over a clean graphics (0x00000000) the pixel interpolator of java2d gives ugly red artifacts.

  1. draw() renders low-quality shapes.

An example: the on-screen quality a simple basicStroke’d text is far from being perfect with font sizes smaller than 30-40 points. Anyone can figure out this by simply comparing the results of java2d with a vector graphics package like CorelDraw.

And the question is: will the situation change in jdk1.5 ?

Cheers,

Michele Puccini - ClassX Development (mik@classx.it)

  1. This is the correct way of doing bilinear interpolation. The fix is of course to not have contrasting colors in the transparent areas.

Isn’t there a renderinghint that causes alpha to be treated in a special way?

Cas :slight_smile:

[quote]1) This is the correct way of doing bilinear interpolation. The fix is of course to not have contrasting colors in the transparent areas.
[/quote]
Are you certain about that?

I would have expected that the interpolation of the colour data needs to account for the alpha data at the same time.
e.g.:


float L = 0.5; // Linear blend half way between the pixels
Cout = C1 * (L) + C2 *(1-L); // no alpha accounted for
float  F1 = L*(A1/(A1+A2)); // account for alpha 
Cbetter = C1 * F1 + C2 * (1-F1); // no spill of transparent colours

I didn’t test the above method. Am I making sense?

Well, I posted a little test image:

Looking at the image it clearly appears how java2d takes the tint of the red transparent pixels into account. That’s a wrong behaviour this causes ugly artifacts when drawing transformed-bilerped transparent images.

Comments ?

How does the new MacOSX java imlementation handle this ? I know that they redirect java2d calls on Quartz.

Cheers,

Mik

I don’t know what the official spec for j2d is, but for OpenGL this is normal filtering behaviour. The colours are interpolated as normal, then the alpha in interpolated separatly and applied to the new colour. If you want the behaviour seen in PSP then you just need to duplicate the colours around the edge.

BTW, i’m pretty sure that PSP doesn’t do bilinear filtering on its rotations, but it does do anti-aliasing which would give smoother edges like you’re seeing.

I reproduced your test images in both paint shop pro 8 and in java2d. But I got a pink edge in both psp as in java2d. How did you create your psp image?

This is what I did:

  1. I programmed an image with the specified source image and source alpha. A wrote the image to disk using my tga saver. It’s easier than finding out how to create the image in psp :slight_smile:
  2. loaded the tga in psp.
  3. loaded mask from image alpha
  4. added white layer behind loaded image.
  5. rotated layer with loaded image a couple of degrees.
    The result is a black square with a pink edge around it.

I took a quick look at the rendering hints, but found no way of removing the bleed without turning off filtering. I can be wrong though, I’m no java2d expert.

It is however possible in opengl. Here you use “glAlphaFunc(GL_EQUAL, 1)” (disclaimer: not tested, and can be wrong :-/ ). This will remove any color bleed along with half of the opaque pixels bordering with transparent pixels. This will also give a hard edge, and will not look antialiased :frowning:

The solution is to not have a contrasting color at the bordering transparent pixels. It’s even easy to write a routine that fixes the problem:


// use 8 neighbors, not 4
for each pixel in image {
 if (pixel.alpha is transparent) and (a neighboring pixel is opaque) {
  pixel.colorRGB = average color of neighboring opaque pixels
  }
}

I’m not 100% certain that the rotation will be done with quartz, but if you can point me to you test code I’ll run it on my Mac and let you know the results.

Hi swpalmer,

here’s an executable jar (very raw src included).

http://www.classx.it/public/bilerp_test.jar

Give it a run. Should work on MacOSX java …

The test shows a pair of test graphics. The one at left is bilerped and you can notice those ugly red pixels around.

Cheers,

Mik

[quote]I reproduced your test images in both paint shop pro 8 and in java2d. But I got a pink edge in both psp as in java2d. How did you create your psp image?
[/quote]

  1. Just donwload the java2d-rendered TGA pic from http://www.classx.it/public/txt.tga

  2. load it in PSP

  3. do a “selection/load from alpha channel”

  4. hit CTRL-C, create a new white image and hit CTRL-E

  5. Rotate the selection with the deformation tool.

And… yes, your pseudo-code looks correct. Now it’s all up to the SUN Java2D team !!

Cheers,

Mik

You are NOT using a transparent image in PSP!!! You are using a selection, which is a vector based shape. So you are comparing apples and oranges :slight_smile:

…and the pseudocode was ment for you :wink:

Sorry tom, but I think you’re wrong.

The outline you see is not a vector, but the edges of the non-transparent pixels. PSP doesn’t mistake.

Cheers,

Mik

[quote]Hi swpalmer,

here’s an executable jar (very raw src included).

http://www.classx.it/public/bilerp_test.jar

Give it a run. Should work on MacOSX java …
[/quote]
I tried, but the download kept timing out before it got started :frowning:

Gosh! Should work right now. It’s only 6kb so I suppose it shouldn’t take that much… ;D

Works fine with no ugly fringes. (Mac OS X 10.3)

http://www.vaxxine.com/canaan/java2d.png

time for a bug report then :wink:

Just another pic. This one compares Windows and MacOSX results.

Bilinear Interpolation Puzzle:
http://swjscmail1.java.sun.com/cgi-bin/wa?A2=ind0110&L=java2d-interest&F=&S=&P=5800

Image scaling often loses transparency:
http://developer.java.sun.com/developer/bugParade/bugs/4475230.html

The fix is to use a BufferedImage of type TYPE_INT_ARGB_PRE.

Many thanks TOM.

Hiroshi Sato also pointed out that ARGB_PRE is somewhat tricky.

http://swjscmail1.java.sun.com/cgi-bin/wa?A2=ind0110&L=java2d-interest&D=0&P=6112

An improvement is required from SUN.

I’ll try to apply the trick to my src and I’ll let you know.

In any case, I’ve posted a bug report about this problem.

Cheers,

Mik