Image resizing

U

Uli Kunkel

I have to downsize an image (about 10 times) and rotate it.
I heard that Image.getScaledInstance() is not very god to use for this.
Original image scale is 320x240.
For now I'm using Graphics2D and drawImage(). This is the relevant part
of the code:

----------------
Image image = new ImageIcon(buffer).getImage();

BufferedImage bim = new BufferedImage(240, 320, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D)(bim.createGraphics());
g2d.translate(0, 320); //counterclockwise
g2d.rotate(- Math.PI/2);
g2d.drawImage(image, 0, 0, 320, 240, picturelabel);
----------------

The photo is rotated ok, but the resizing part gives a very low quality
photo.I read that for multiple downsizing (> 2) it is best to do it with
multiple passes.
I tried using the code from:
http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html

but I end up with a entirely black photo.I must be doing something wrong.

Any suggestions would be appreciated.
 
J

John B. Matthews

Uli Kunkel said:
I have to downsize an image (about 10 times) and rotate it.
I heard that Image.getScaledInstance() is not very god to use for this.
Original image scale is 320x240.
For now I'm using Graphics2D and drawImage(). This is the relevant part
of the code:

----------------
Image image = new ImageIcon(buffer).getImage();

BufferedImage bim = new BufferedImage(240, 320, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D)(bim.createGraphics());
g2d.translate(0, 320); //counterclockwise
g2d.rotate(- Math.PI/2);
g2d.drawImage(image, 0, 0, 320, 240, picturelabel);
----------------

The photo is rotated ok, but the resizing part gives a very low quality
photo.I read that for multiple downsizing (> 2) it is best to do it with
multiple passes.
[...]

You might also experiment with AffineTransformOp and RenderingHints:

<sscce>
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

/** @author John B. Matthews */
public class TransformImage extends JPanel {

BufferedImage scaled;

public TransformImage() {
BufferedImage image = getImage("image.jpg");
AffineTransform scaleTransform = new AffineTransform();
int w = image.getWidth();
int h = image.getHeight();
// last-in-first-applied: rotate, scale, shear
// scaleTransform.shear(0.0, 0.0);
scaleTransform.scale(0.1, 0.1);
scaleTransform.rotate(-Math.PI / 2, w / 2, h / 2);
AffineTransformOp scaleOp = new AffineTransformOp(
scaleTransform, AffineTransformOp.TYPE_BILINEAR);
scaled = scaleOp.filter(image, null);
setPreferredSize(new Dimension(
scaled.getWidth(), scaled.getHeight()));
}

private BufferedImage getImage(String name) {
BufferedImage image = null;
try {
image = ImageIO.read(new File(name));
} catch (IOException ioe) {
ioe.printStackTrace(System.err);
}
return image;
}

public void paintComponent(Graphics g) {
final Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.drawImage(scaled, 0, 0, null);
}

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new TransformImage());
f.pack();
f.setVisible(true);
}
});
}
}
</sscce>
 
D

Daniel Pitts

Uli said:
I have to downsize an image (about 10 times) and rotate it.
I heard that Image.getScaledInstance() is not very god to use for this.
Original image scale is 320x240.
For now I'm using Graphics2D and drawImage(). This is the relevant part
of the code:

----------------
Image image = new ImageIcon(buffer).getImage();

BufferedImage bim = new BufferedImage(240, 320,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D)(bim.createGraphics());
g2d.translate(0, 320); //counterclockwise
g2d.rotate(- Math.PI/2);
g2d.drawImage(image, 0, 0, 320, 240, picturelabel);
----------------

The photo is rotated ok, but the resizing part gives a very low quality
photo.I read that for multiple downsizing (> 2) it is best to do it with
multiple passes.
I tried using the code from:
http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html


but I end up with a entirely black photo.I must be doing something wrong.

Any suggestions would be appreciated.
What type of object is "buffer"? Why use ImageIcon to get the image?
Where did you hear that getScaledInstance is bad for resizing?

You might be better off using a different drawImage overload, as well as
using g2d.setRenderingHints to specify the kind of image scaling you
want done.
 
U

Uli Kunkel

Daniel said:
What type of object is "buffer"? Why use ImageIcon to get the image?
Where did you hear that getScaledInstance is bad for resizing?

You might be better off using a different drawImage overload, as well as
using g2d.setRenderingHints to specify the kind of image scaling you
want done.

buffer is a byte array of a jpg photo.I used ImageIcon because I saw it
in a couple of places with some hint that it was better but I really
don't know why.
I heard that getScaledInstance is not so good in a couple of places.One
of them is:
http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html

It says that it is not good when I downsize more than 2 times.
I tried a few different interpolation renderinghints with no luck.

Anyway for now I tried getScaledInstance() and it returns a much better
photo than drawImage().
I suppose I'm doing something wrong with the drawImage()...
 
U

Uli Kunkel

John said:
Uli Kunkel said:
I have to downsize an image (about 10 times) and rotate it.
I heard that Image.getScaledInstance() is not very god to use for this.
Original image scale is 320x240.
For now I'm using Graphics2D and drawImage(). This is the relevant part
of the code:

----------------
Image image = new ImageIcon(buffer).getImage();

BufferedImage bim = new BufferedImage(240, 320, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D)(bim.createGraphics());
g2d.translate(0, 320); //counterclockwise
g2d.rotate(- Math.PI/2);
g2d.drawImage(image, 0, 0, 320, 240, picturelabel);
----------------

The photo is rotated ok, but the resizing part gives a very low quality
photo.I read that for multiple downsizing (> 2) it is best to do it with
multiple passes.
[...]

You might also experiment with AffineTransformOp and RenderingHints:

<sscce>
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

/** @author John B. Matthews */
public class TransformImage extends JPanel {

BufferedImage scaled;

public TransformImage() {
BufferedImage image = getImage("image.jpg");
AffineTransform scaleTransform = new AffineTransform();
int w = image.getWidth();
int h = image.getHeight();
// last-in-first-applied: rotate, scale, shear
// scaleTransform.shear(0.0, 0.0);
scaleTransform.scale(0.1, 0.1);
scaleTransform.rotate(-Math.PI / 2, w / 2, h / 2);
AffineTransformOp scaleOp = new AffineTransformOp(
scaleTransform, AffineTransformOp.TYPE_BILINEAR);
scaled = scaleOp.filter(image, null);
setPreferredSize(new Dimension(
scaled.getWidth(), scaled.getHeight()));
}

private BufferedImage getImage(String name) {
BufferedImage image = null;
try {
image = ImageIO.read(new File(name));
} catch (IOException ioe) {
ioe.printStackTrace(System.err);
}
return image;
}

public void paintComponent(Graphics g) {
final Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.drawImage(scaled, 0, 0, null);
}

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new TransformImage());
f.pack();
f.setVisible(true);
}
});
}
}
</sscce>

Thank you very much for the code.
I finally tried it out and it works very fast. But the problem is that
when I scale more than 5 times than the quality is not so good.
I tried changeing AffineTransformOp to TYPE_BICUBIC and to
TYPE_NEAREST_NEIGHBOR but it's the same.
Maybe I should try to scale by 2 in a couple of iterations...
 
A

Andrew Thompson

John said:
Thank you very much for the code.
I finally tried it out and it works very fast. But the problem is that
when I scale more than 5 times than the quality is not so good.

I am willing to bet that reducing a 320x240
image to 64x48 (or less) is never going to
make it prettier. ;-)
 
U

Uli Kunkel

Andrew said:
I am willing to bet that reducing a 320x240
image to 64x48 (or less) is never going to
make it prettier. ;-)

I'm reducing something like 3456x2592, 1600x1200 or something in between
to a 320x240.
Maybe I should have the original photo taken in 640x480.I'll give it a try..
 
U

Uli Kunkel

bugbear said:
Uli said:
If the result is truly the same (binary identical)
you have a bug, since that parameter WILL make a difference

BugBear

Sorry, I thought the quality is the same.
But I compared only by viewing.
If anyone knows about some software that checks photo quality I'd like
to try it.
 
U

Uli Kunkel

John said:
Uli Kunkel said:
I have to downsize an image (about 10 times) and rotate it.
I heard that Image.getScaledInstance() is not very god to use for this.
Original image scale is 320x240.
For now I'm using Graphics2D and drawImage(). This is the relevant part
of the code:

----------------
Image image = new ImageIcon(buffer).getImage();

BufferedImage bim = new BufferedImage(240, 320, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D)(bim.createGraphics());
g2d.translate(0, 320); //counterclockwise
g2d.rotate(- Math.PI/2);
g2d.drawImage(image, 0, 0, 320, 240, picturelabel);
----------------

The photo is rotated ok, but the resizing part gives a very low quality
photo.I read that for multiple downsizing (> 2) it is best to do it with
multiple passes.
[...]

You might also experiment with AffineTransformOp and RenderingHints:

<sscce>
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

/** @author John B. Matthews */
public class TransformImage extends JPanel {

BufferedImage scaled;

public TransformImage() {
BufferedImage image = getImage("image.jpg");
AffineTransform scaleTransform = new AffineTransform();
int w = image.getWidth();
int h = image.getHeight();
// last-in-first-applied: rotate, scale, shear
// scaleTransform.shear(0.0, 0.0);
scaleTransform.scale(0.1, 0.1);
scaleTransform.rotate(-Math.PI / 2, w / 2, h / 2);
AffineTransformOp scaleOp = new AffineTransformOp(
scaleTransform, AffineTransformOp.TYPE_BILINEAR);
scaled = scaleOp.filter(image, null);
setPreferredSize(new Dimension(
scaled.getWidth(), scaled.getHeight()));
}

private BufferedImage getImage(String name) {
BufferedImage image = null;
try {
image = ImageIO.read(new File(name));
} catch (IOException ioe) {
ioe.printStackTrace(System.err);
}
return image;
}

public void paintComponent(Graphics g) {
final Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.drawImage(scaled, 0, 0, null);
}

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new TransformImage());
f.pack();
f.setVisible(true);
}
});
}
}
</sscce>

What if I have an Image variable and don't load the image from disk.
How do I create BufferedImage from it?
Do I have to use Graphics2D to load it to the BufferedImage and than use it?
 
J

John B. Matthews

Uli Kunkel said:
John said:
Uli Kunkel said:
I have to downsize an image (about 10 times) and rotate it.
I heard that Image.getScaledInstance() is not very god to use for this.
Original image scale is 320x240.
For now I'm using Graphics2D and drawImage(). This is the relevant part
of the code:

----------------
Image image = new ImageIcon(buffer).getImage();

BufferedImage bim = new BufferedImage(240, 320,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D)(bim.createGraphics());
g2d.translate(0, 320); //counterclockwise
g2d.rotate(- Math.PI/2);
g2d.drawImage(image, 0, 0, 320, 240, picturelabel);
----------------

The photo is rotated ok, but the resizing part gives a very low quality
photo. I read that for multiple downsizing (> 2) it is best to do it with
multiple passes.
[...]

You might also experiment with AffineTransformOp and RenderingHints:
[...]
What if I have an Image variable and don't load the image from disk.
How do I create BufferedImage from it? Do I have to use Graphics2D to
load it to the BufferedImage and than use it?

If your Image is an instanceof BufferedImage, you're all set. If not,
you'll have to refer to the docs of whatever concrete class extends the
abstract Image class. In either case, the Graphics class's drawImage
methods that take an Image parameter are available to you.
 
U

Uli Kunkel

John said:
Uli Kunkel said:
John said:
I have to downsize an image (about 10 times) and rotate it.
I heard that Image.getScaledInstance() is not very god to use for this.
Original image scale is 320x240.
For now I'm using Graphics2D and drawImage(). This is the relevant part
of the code:

----------------
Image image = new ImageIcon(buffer).getImage();

BufferedImage bim = new BufferedImage(240, 320,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D)(bim.createGraphics());
g2d.translate(0, 320); //counterclockwise
g2d.rotate(- Math.PI/2);
g2d.drawImage(image, 0, 0, 320, 240, picturelabel);
----------------

The photo is rotated ok, but the resizing part gives a very low quality
photo. I read that for multiple downsizing (> 2) it is best to do it with
multiple passes.
[...]

You might also experiment with AffineTransformOp and RenderingHints:
[...]
What if I have an Image variable and don't load the image from disk.
How do I create BufferedImage from it? Do I have to use Graphics2D to
load it to the BufferedImage and than use it?

If your Image is an instanceof BufferedImage, you're all set. If not,
you'll have to refer to the docs of whatever concrete class extends the
abstract Image class. In either case, the Graphics class's drawImage
methods that take an Image parameter are available to you.

Now I'm converting an Image to BufferedImage successfully but I have
another problem.
I display the photo on a JLabel and save it to a file. The displayed
photo is ok but the photo saved on a file has some red shades like it is
missing some "layers".
Anyway here is the code:
-------------------------------------
BufferedImage scaled;
//Transforms the Image to BufferedImage
BufferedImage bim = bufferImage(image);

AffineTransform scaleTransform = new AffineTransform();
int w = bim.getWidth();
int h = bim.getHeight();
scaleTransform.rotate(-Math.PI / 2, w / 2, h / 2);
AffineTransformOp scaleOp = new AffineTransformOp(
scaleTransform, AffineTransformOp.TYPE_BICUBIC);

scaled = scaleOp.filter(bim, null);
setPreferredSize(new Dimension(
scaled.getWidth(), scaled.getHeight()));
final Graphics2D g2d = (Graphics2D)(scaled.createGraphics());
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.drawImage(scaled, 0, 0, null);

icon = new ImageIcon(scaled);
ImageIO.write(scaled, "jpg", new File("C:\\output_photo1.jpg"));
 
J

John B. Matthews

[...]
I display the photo on a JLabel and save it to a file.

I assume "it" refers to the rotated photo, not the JLabel.
The displayed photo is ok but the photo saved on a file has some red
shades like it is missing some "layers". [...]

Any ideas what is wrong?

Sadly, no. Using this jpg:

<http://en.wikipedia.org/wiki/Image:Mona_Lisa.jpg>

I get normal results for png, but not for jpg.

ImageIO.write(scaled, "png", new File("temp.png"));
ImageIO.write(scaled, "jpg", new File("temp.jpg"));

<http://sites.google.com/site/trashgod/rotated>

Interestingly, NetBeans opens the jpg just fine, but gimp and the usual
utilities don't like it. Eliminating the alpha channel helps, but the
BufferedImage returned by filter() is still problematic.
 
J

John B. Matthews

"John B. Matthews said:
[...]
I display the photo on a JLabel and save it to a file.

I assume "it" refers to the rotated photo, not the JLabel.
The displayed photo is ok but the photo saved on a file has some red
shades like it is missing some "layers". [...]

Any ideas what is wrong?

Sadly, no. Using this jpg:

<http://en.wikipedia.org/wiki/Image:Mona_Lisa.jpg>

I get normal results for png, but not for jpg.

ImageIO.write(scaled, "png", new File("temp.png"));
ImageIO.write(scaled, "jpg", new File("temp.jpg"));

<http://sites.google.com/site/trashgod/rotated>

Interestingly, NetBeans opens the jpg just fine, but gimp and the usual
utilities don't like it. Eliminating the alpha channel helps, but the
BufferedImage returned by filter() is still problematic.

Curiously, using BufferedImage.TYPE_INT_RGB and
AffineTransformOp.TYPE_NEAREST_NEIGHBOR works fine.
 
U

Uli Kunkel

John said:
John B. Matthews said:
[...]
I display the photo on a JLabel and save it to a file.
I assume "it" refers to the rotated photo, not the JLabel.
The displayed photo is ok but the photo saved on a file has some red
shades like it is missing some "layers". [...]

Any ideas what is wrong?
Sadly, no. Using this jpg:

<http://en.wikipedia.org/wiki/Image:Mona_Lisa.jpg>

I get normal results for png, but not for jpg.

ImageIO.write(scaled, "png", new File("temp.png"));
ImageIO.write(scaled, "jpg", new File("temp.jpg"));

<http://sites.google.com/site/trashgod/rotated>

Interestingly, NetBeans opens the jpg just fine, but gimp and the usual
utilities don't like it. Eliminating the alpha channel helps, but the
BufferedImage returned by filter() is still problematic.

Curiously, using BufferedImage.TYPE_INT_RGB and
AffineTransformOp.TYPE_NEAREST_NEIGHBOR works fine.

Does anyone know what gives better quality/performance AffineTransform
scaling and rotating or getScaledInstance() of the Image class?
 
U

Uli Kunkel

John said:
Uli Kunkel said:
I have to downsize an image (about 10 times) and rotate it.
I heard that Image.getScaledInstance() is not very god to use for this.
Original image scale is 320x240.
For now I'm using Graphics2D and drawImage(). This is the relevant part
of the code:

----------------
Image image = new ImageIcon(buffer).getImage();

BufferedImage bim = new BufferedImage(240, 320, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D)(bim.createGraphics());
g2d.translate(0, 320); //counterclockwise
g2d.rotate(- Math.PI/2);
g2d.drawImage(image, 0, 0, 320, 240, picturelabel);
----------------

The photo is rotated ok, but the resizing part gives a very low quality
photo.I read that for multiple downsizing (> 2) it is best to do it with
multiple passes.
[...]

You might also experiment with AffineTransformOp and RenderingHints:

<sscce>
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

/** @author John B. Matthews */
public class TransformImage extends JPanel {

BufferedImage scaled;

public TransformImage() {
BufferedImage image = getImage("image.jpg");
AffineTransform scaleTransform = new AffineTransform();
int w = image.getWidth();
int h = image.getHeight();
// last-in-first-applied: rotate, scale, shear
// scaleTransform.shear(0.0, 0.0);
scaleTransform.scale(0.1, 0.1);
scaleTransform.rotate(-Math.PI / 2, w / 2, h / 2);
AffineTransformOp scaleOp = new AffineTransformOp(
scaleTransform, AffineTransformOp.TYPE_BILINEAR);
scaled = scaleOp.filter(image, null);
setPreferredSize(new Dimension(
scaled.getWidth(), scaled.getHeight()));
}

private BufferedImage getImage(String name) {
BufferedImage image = null;
try {
image = ImageIO.read(new File(name));
} catch (IOException ioe) {
ioe.printStackTrace(System.err);
}
return image;
}

public void paintComponent(Graphics g) {
final Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.drawImage(scaled, 0, 0, null);
}

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new TransformImage());
f.pack();
f.setVisible(true);
}
});
}
}
</sscce>

I now see that I have a resolution problem with this.
I rotate a 640x480 photo and I get 560x560 resolution.
It's interesting that a photo is not displayed as a square it is
displayed in a 480x640 ratio.
Probably the problem is in the other 2 arguments of:

scaleTransform.rotate(-Math.PI / 2, w / 2, h / 2);

Any ideas?
 
U

Uli Kunkel

Uli said:
John said:
Uli Kunkel said:
I have to downsize an image (about 10 times) and rotate it.
I heard that Image.getScaledInstance() is not very god to use for this.
Original image scale is 320x240.
For now I'm using Graphics2D and drawImage(). This is the relevant
part of the code:

----------------
Image image = new ImageIcon(buffer).getImage();

BufferedImage bim = new BufferedImage(240, 320,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D)(bim.createGraphics());
g2d.translate(0, 320); //counterclockwise
g2d.rotate(- Math.PI/2);
g2d.drawImage(image, 0, 0, 320, 240, picturelabel);
----------------

The photo is rotated ok, but the resizing part gives a very low
quality photo.I read that for multiple downsizing (> 2) it is best to
do it with multiple passes.
[...]

You might also experiment with AffineTransformOp and RenderingHints:

<sscce>
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

/** @author John B. Matthews */
public class TransformImage extends JPanel {

BufferedImage scaled;

public TransformImage() {
BufferedImage image = getImage("image.jpg");
AffineTransform scaleTransform = new AffineTransform();
int w = image.getWidth();
int h = image.getHeight();
// last-in-first-applied: rotate, scale, shear
// scaleTransform.shear(0.0, 0.0);
scaleTransform.scale(0.1, 0.1);
scaleTransform.rotate(-Math.PI / 2, w / 2, h / 2);
AffineTransformOp scaleOp = new AffineTransformOp(
scaleTransform, AffineTransformOp.TYPE_BILINEAR);
scaled = scaleOp.filter(image, null);
setPreferredSize(new Dimension(
scaled.getWidth(), scaled.getHeight()));
}

private BufferedImage getImage(String name) {
BufferedImage image = null;
try {
image = ImageIO.read(new File(name));
} catch (IOException ioe) {
ioe.printStackTrace(System.err);
}
return image;
}

public void paintComponent(Graphics g) {
final Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.drawImage(scaled, 0, 0, null);
}

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new TransformImage());
f.pack();
f.setVisible(true);
}
});
}
}
</sscce>

I now see that I have a resolution problem with this.
I rotate a 640x480 photo and I get 560x560 resolution.
It's interesting that a photo is not displayed as a square it is
displayed in a 480x640 ratio.
Probably the problem is in the other 2 arguments of:

scaleTransform.rotate(-Math.PI / 2, w / 2, h / 2);

Any ideas?

I read about the rotation transformation and added:

scaleTransform.setToTranslation((480 - w)/2,(640 - h)/2);

so now its ok.
 
J

John B. Matthews

Uli Kunkel said:
John said:
John B. Matthews said:
[...]
I display the photo on a JLabel and save it to a file.
I assume "it" refers to the rotated photo, not the JLabel.

The displayed photo is ok but the photo saved on a file has some red
shades like it is missing some "layers".
[...]

Any ideas what is wrong?
Sadly, no. Using this jpg:

<http://en.wikipedia.org/wiki/Image:Mona_Lisa.jpg>

I get normal results for png, but not for jpg.

ImageIO.write(scaled, "png", new File("temp.png"));
ImageIO.write(scaled, "jpg", new File("temp.jpg"));

<http://sites.google.com/site/trashgod/rotated>

Interestingly, NetBeans opens the jpg just fine, but gimp and the usual
utilities don't like it. Eliminating the alpha channel helps, but the
BufferedImage returned by filter() is still problematic.

Curiously, using BufferedImage.TYPE_INT_RGB and
AffineTransformOp.TYPE_NEAREST_NEIGHBOR works fine.

Does anyone know what gives better quality/performance AffineTransform
scaling and rotating or getScaledInstance() of the Image class?

It's hard to imagine that latter isn't implemented in terms of the
former, but I see it's difficult to detect small perturbations in
quality.
 
J

John B. Matthews

Uli Kunkel said:
Uli said:
John said:
I have to downsize an image (about 10 times) and rotate it.
I heard that Image.getScaledInstance() is not very god to use for this.
Original image scale is 320x240.
For now I'm using Graphics2D and drawImage(). This is the relevant
part of the code:

----------------
Image image = new ImageIcon(buffer).getImage();

BufferedImage bim = new BufferedImage(240, 320,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D)(bim.createGraphics());
g2d.translate(0, 320); //counterclockwise
g2d.rotate(- Math.PI/2);
g2d.drawImage(image, 0, 0, 320, 240, picturelabel);
----------------

The photo is rotated ok, but the resizing part gives a very low
quality photo.I read that for multiple downsizing (> 2) it is best to
do it with multiple passes.
[...]
I now see that I have a resolution problem with this.
I rotate a 640x480 photo and I get 560x560 resolution.
It's interesting that a photo is not displayed as a square it is
displayed in a 480x640 ratio.
Probably the problem is in the other 2 arguments of:

scaleTransform.rotate(-Math.PI / 2, w / 2, h / 2);

Any ideas?

I read about the rotation transformation and added:

scaleTransform.setToTranslation((480 - w)/2,(640 - h)/2);

so now its ok.

Nice!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,586
Members
45,095
Latest member
SimplyleanKetoDiet

Latest Threads

Top