tags:

views:

161

answers:

1

I am trying to use JAI to perform a rotate task on an image. I can get this working no problem. However, there is severe loss of midtones in the image. The image can be rotated in photoshop without this lack of contrast.

Please see the following 3 images stacked next to each other here, to see what I mean;

http://imgur.com/SYPhZ.jpg

The top image is the original, the middle is rotated in photoshop to prove that it can be done, and the bottom is from the result of my code.

To see the actual images, please see here;

Before rotate: http://imgur.com/eiAOO.jpg After rotate : http://imgur.com/TTUKS.jpg

You can see the issue most clearly if you load the images in two different tabs, and flick between them.

In terms of code, I load the image as follows;

  public void testIt() throws Exception {

    File source = new File("c:\\STRIP.jpg");
    FileInputStream fis = new FileInputStream(source);
    BufferedImage sourceImage = ImageIO.read(fis);
    fis.close();

    BufferedImage rotatedImage = doRotate(sourceImage, 15);
    FileOutputStream output = new FileOutputStream("c:\\STRIP_ROTATED.jpg");
    ImageIO.write(rotatedImage, "JPEG", output);

}

and then here is the rotate function;

 public BufferedImage doRotate(BufferedImage input, int angle) {
    int width = input.getWidth();
    int height = input.getHeight();


    double radians = Math.toRadians(angle / 10.0);

    // Rotate about the input image's centre
    AffineTransform rotate = AffineTransform.getRotateInstance(radians, width / 2.0, height / 2.0);

    Shape rect = new Rectangle(width, height);

    // Work out how big the rotated image would be..
    Rectangle bounds = rotate.createTransformedShape(rect).getBounds();

    // Shift the rotated image into the centre of the new bounds
    rotate.preConcatenate(
            AffineTransform.getTranslateInstance((bounds.width - width) / 2.0, (bounds.height - height) / 2.0));

    BufferedImage output = new BufferedImage(bounds.width, bounds.height, input.getType());
    Graphics2D g2d = (Graphics2D) output.getGraphics();

    // Fill the background with white
    g2d.setColor(Color.WHITE);
    g2d.fill(new Rectangle(width, height));

    RenderingHints hints = new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
    hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    g2d.setRenderingHints(hints);
    g2d.drawImage(input, rotate, null);

    return output;
}
+1  A: 

This is apparently a bug in JAI that has existed for a while:

The earliest mention that I was able to find of this issue appears here. That original article points to an old jai-core issue here. Having read that resolution, it appears that there is a root bug that is still open and described here.

Whether or not all of that detective work is relevant to your application, it may be possible to construct a color space that is more tolerant than the default that JAI is using for your test code.

In the absolute worst case, you could write the pixel traversal yourself to create a rotated image. That isn't the optimal solution but I mention it for completeness if you absolutely need a solution to this problem today.

Bob Cross