i want to rotate an image and in next level i want to resize it plese
help me.
i create a class that extended from JPanel and override paintComponent() method
for drawing image.
public class NewJPanel extends javax.swing.JPanel {
/** Creates new form NewJPanel */
public NewJPanel() {
initComponents();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 20, 20, this);
}
Here is some code I use. You can modify it to fit your needs.
Resize Image:
/**
* Resizes the image
*
* #param filePath File path to the image to resize
* #param w Width of the image
* #param h Height of the image
* #return A resized image
*/
public ImageIcon resizeImage(String filePath, int w, int h) {
String data = filePath;
BufferedImage bsrc, bdest;
ImageIcon theIcon;
//scale the image
try {
if (dataSource == DataTypeEnum.file) {
bsrc = ImageIO.read(new File(data));
} else {
bsrc = ImageIO.read(new URL(filePath));
}
bdest = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g = bdest.createGraphics();
AffineTransform at = AffineTransform.getScaleInstance(
(double) w / bsrc.getWidth(), (double) h / bsrc.getHeight());
g.drawRenderedImage(bsrc, at);
//add the scaled image
theIcon = new ImageIcon(bdest);
return theIcon;
} catch (Exception e) {
Window.getLogger().warning("This image can not be resized. " +
"Please check the path and type of file.");
//restore the old background
return null;
}
}
Rotate Image:
NOTE: The angle is in radians
public static BufferedImage rotate(BufferedImage image, double angle) {
double sin = Math.abs(Math.sin(angle)),
cos = Math.abs(Math.cos(angle));
int w = image.getWidth(),
h = image.getHeight();
int neww = (int) Math.floor(w * cos + h * sin),
newh = (int) Math.floor(h * cos + w * sin);
GraphicsConfiguration gc = getDefaultConfiguration();
BufferedImage result =
gc.createCompatibleImage(neww, newh, Transparency.TRANSLUCENT);
Graphics2D g = result.createGraphics();
g.translate((neww - w) / 2, (newh - h) / 2);
g.rotate(angle, w / 2, h / 2);
g.drawRenderedImage(image, null);
g.dispose();
return result;
}
Without giving away a full solution
Graphics2D has rotate and scale functions.
Use the BufferedImage class
BufferedImage newImg = new BufferedImage(newWidth, newHeight, imageType);
newImg.createGraphics().drawImage(oldImg,0,0,newWidth, newHeight,0,0,oldWidth,oldHeight, null);
then just repaint using newImg instead of the old image, should work, I'm not near a compiler at the moment to test.
http://download.oracle.com/javase/1.4.2/docs/api/java/awt/Graphics.html#drawImage%28java.awt.Image,%20int,%20int,%20int,%20int,%20int,%20int,%20int,%20int,%20java.awt.image.ImageObserver%29
Related
I'm using latest JDK 7u45 for my development.When I create a simple servlet which used for generating verification code,I found out the image is rather blurred.The image looks just like this:
The image is of rather poor quality,and look really poor with my Macbook pro retina display.
The Code I'm using for creating the BufferedImage is rather simple:
public static BufferedImage getImage() {
BufferedImage image = new BufferedImage(IMAGE_WIDTH,IMAGE_HEIGHT,BufferedImage.TYPE_INT_RGB);
Graphics graphics = image.getGraphics();
drawRandomNumber((Graphics2D)graphics);
return image;
}
private static void drawRandomNumber(Graphics2D graphics) {
graphics.setColor(Color.RED);
graphics.setFont(new Font("Arial",Font.BOLD|Font.ITALIC,RANDOM_NUMBER_FONT_SIZE));
char lch = 'a',hch = 'z';
char lcach = 'A',hcach = 'Z';
int x = RANDOM_NUMBER_START_X;
for (int i = 0;i < RANDOM_NUMBER_NUM;i++) {
char ch = new Random().nextBoolean() ?
(char)(new Random().nextInt(hch - lch) + lch) :
(char)(new Random().nextInt(hcach - lcach) + lcach);
int degree = new Random().nextInt() % 30;
graphics.rotate(degree * Math.PI / 180,x,RANDOM_NUMBER_START_Y);
graphics.drawString(ch + "",x,RANDOM_NUMBER_START_Y);
graphics.rotate(-degree * Math.PI / 180,x,RANDOM_NUMBER_START_Y);
x += 60;
}
}
And the code that writes the image to the servlet:
ImageIO.write(image, "png", response.getOutputStream());
I just want to know If I want to create a high quality image which support HDPI display,what should I do?Is there any way to produce high quality image with java code?I tried many ways but they seem to help nothing.
private float xScaleFactor, yScaleFactor = ...;
private BufferedImage originalImage = ...;
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
int newW = (int)(originalImage.getWidth() * xScaleFactor);
int newH = (int)(originalImage.getHeight() * yScaleFactor);
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(originalImage, 0, 0, newW, newH, null);
}
I am just wondering how to rotate a rectangle image with paintComponent() method of JLabel component and set its new width and height correctly?
I tried to rotate (see attached image) and the image scale becomes bigger but the JLabel scale keeps the same what makes image be out of JLabel bounds or something :S So my question is how to set image new width and height to component dynamically in a more optimal way?
+1 to MadProgrammers comment and link.
Using the method from link (edited slightly to omit use of GraphicsConfiguration, drawRenderImage(..) and changed variable names):
//https://stackoverflow.com/questions/4156518/rotate-an-image-in-java
public static BufferedImage createTransformedImage(BufferedImage image, double angle) {
double sin = Math.abs(Math.sin(angle));
double cos = Math.abs(Math.cos(angle));
int originalWidth = image.getWidth();
int originalHeight = image.getHeight();
int newWidth = (int) Math.floor(originalWidth * cos + originalHeight * sin);
int newHeight = (int) Math.floor(originalHeight * cos + originalWidth * sin);
BufferedImage rotatedBI = new BufferedImage(newWidth, newHeight, BufferedImage.TRANSLUCENT);
Graphics2D g2d = rotatedBI.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.translate((newWidth - originalWidth) / 2, (newHeight - originalHeight) / 2);
g2d.rotate(angle, originalWidth / 2, originalHeight / 2);
g2d.drawImage(image, 0, 0, null);
g2d.dispose();
return rotatedBI;
}
Here is an example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class RotateImage {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new MyRotatableImage(createImage(), -45));
frame.pack();
frame.setVisible(true);
}
});
}
public static BufferedImage createImage() {
BufferedImage img = new BufferedImage(100, 50, BufferedImage.TRANSLUCENT);
Graphics2D g2d = img.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, img.getWidth(), img.getHeight());
g2d.setColor(Color.BLACK);
g2d.setFont(new Font("Calibri", Font.BOLD, 20));
FontMetrics fm = g2d.getFontMetrics();
String text = "Hello world";
int textWidth = fm.stringWidth(text);
g2d.drawString(text, (img.getWidth() / 2) - textWidth / 2, img.getHeight() / 2);
g2d.dispose();
return img;
}
}
class MyRotatableImage extends JPanel {
private BufferedImage transformedImage;
public MyRotatableImage(BufferedImage img, int angle) {
transformedImage = createTransformedImage(img, angle);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.drawImage(transformedImage, 0, 0, null);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(transformedImage.getWidth(), transformedImage.getHeight());
}
//https://stackoverflow.com/questions/4156518/rotate-an-image-in-java
public static BufferedImage createTransformedImage(BufferedImage image, double angle) {
double sin = Math.abs(Math.sin(angle));
double cos = Math.abs(Math.cos(angle));
int originalWidth = image.getWidth();
int originalHeight = image.getHeight();
int newWidth = (int) Math.floor(originalWidth * cos + originalHeight * sin);
int newHeight = (int) Math.floor(originalHeight * cos + originalWidth * sin);
BufferedImage rotatedBI = new BufferedImage(newWidth, newHeight, BufferedImage.TRANSLUCENT);
Graphics2D g2d = rotatedBI.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.translate((newWidth - originalWidth) / 2, (newHeight - originalHeight) / 2);
g2d.rotate(angle, originalWidth / 2, originalHeight / 2);
g2d.drawImage(image, 0, 0, null);
g2d.dispose();
return rotatedBI;
}
}
Reference:
Rotate an image in java
OK, so you want the JLabel to keep its dimensions and resize the image instead.
You're probably already using an affine transform anyways, so you can use some trigonometry and min/max to find the AABB of the rotated image. Scale appropriately (I assume you're already using affine transforms to do the rotation)
Edit:
AABB = Axis Aligned Bounding Box, its sides correspond to the min/max x,y coords of the rotated image. Just a more concise way of saying things.
OK I tried the sample David Kroukamp showed me. Thanks, David, you pointed me to right direction. I think it is a really good snippet to lean back on.
public static BufferedImage rotateImage(Image image, int angle)
{
double sin = Math.abs(Math.sin(angle));
double cos = Math.abs(Math.cos(angle));
int originalWidth = image.getWidth(null);
int originalHeight = image.getHeight(null);
int newWidth = (int) Math.floor(originalWidth * cos + originalHeight * sin);
int newHeight = (int) Math.floor(originalHeight * cos + originalWidth * sin);
BufferedImage rotatedBI = new BufferedImage(newWidth, newHeight, BufferedImage.TRANSLUCENT);
Graphics2D g2d = rotatedBI.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.translate((newWidth - originalWidth) / 2, (newHeight - originalHeight) / 2);
g2d.rotate(angle, originalWidth / 2, originalHeight / 2);
g2d.drawImage(image, 0, 0, null);
g2d.dispose();
return rotatedBI;
}
David Kroukamp's result image preview
I tested the snippet and the result image + its component's scale were really dynamic changed.
But the result component width I've got has been always a little bit wider than it's inner image was :S
For example here is my version of an image rotated in 45 degrees angle
... As I could find (on blue background) its width is not totally fit to surround white image ... Actually I was looking for some kind of standard Java Image Processing rotate solution but I couldn't find it :( so I had to dig deeper to the problem and at least figure out how to solve the 'wider effect' and avoid create new BufferedImage object every re-paint...
OK, as a reault of my research, I tried to write some kind of my rotate code adaptation. Here it is :
>tested
public static void rotateImage(Graphics g, Image image,int tilt,JComponent component)
{
// create the transform, note that the transformations happen
// in reversed order (so check them backwards)
AffineTransform at = new AffineTransform();
//5. modify component scale ...
double sin = Math.abs(Math.sin(Math.toRadians(tilt)));
double cos = Math.abs(Math.cos(Math.toRadians(tilt)));
int w=image.getWidth(null);
int h=image.getHeight(null);
int newW=(int) Math.floor(w * cos + h * sin);
int newH=(int) Math.floor(h * cos + w * sin);
component.setSize(newW, newH);
int width=component.getWidth();
int height=component.getHeight();
// 4. translate it to the center of the component
at.translate(width / 2, height / 2);
// 3. do the actual rotation
at.rotate(Math.toRadians(tilt));
// 2. just a scale because this image is big
// at.scale(1, 1);
// 1. translate the object so that you rotate it around the
// center (easier :))
at.translate(-image.getWidth(null)/2, -image.getHeight(null)/2);
// draw the image
((Graphics2D) g).drawImage(image, at, null);
}
... so the result image rotated on -30 degrees tilt looks like this
I dearly hope the tip saves ones day :)
Thank you all for help
I am trying to rotate an instance of a BufferImage named pic when I try this it resizes and skews and crops the image, any advice to get it to work properly
public void rotate(double rads){
AffineTransform tx = new AffineTransform();
tx.rotate(rads,pic.getWidth()/2,pic.getHeight()/2);
AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
pic = op.filter(pic, null);
}
When I have it rotate 90˚ it works fine so I'm wondering if the problem is that it is the shape of the image?
For use with AffineTransform, you can square an image using something like this:
private BufferedImage getImage(String name) {
BufferedImage image;
try {
image = ImageIO.read(new File(name));
} catch (IOException ioe) {
return errorImage;
}
int w = image.getWidth();
int h = image.getHeight();
int max = Math.max(w, h);
max = (int) Math.sqrt(2 * max * max);
BufferedImage square = new BufferedImage(
max, max, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = square.createGraphics();
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.drawImage(image, (max - w) / 2, (max - h) / 2, null);
g2d.dispose();
return square;
}
I have snippet of code that I am using for the purpose of resizing an image to a curtain size (I want to change the resolution to something like 200 dpi). Basically the reason I need it is because I want to display the image that the user have picked (somewhat large) and then if the user approves I want to display the same image in a different place but using a smaller resolution. Unfortunately, if I give it a large image nothing appears on the screen. Also, if I change
imageLabel.setIcon(newIcon);
to
imageLabel.setIcon(icon);
I get the image to display but not in the correct resolution that's how I know that I have a problem inside this snipper of code and not somewhere else.
Image img = icon.getImage();
BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
BufferedImage bi = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.createGraphics();
boolean myBool = g.drawImage(img, 0, 0, 100, 100, null);
System.out.println(myBool);
ImageIcon newIcon = new ImageIcon(bi);
imageLabel.setIcon(newIcon);
submitText.setText(currentImagePath);
imageThirdPanel.add(imageLabel);
You don't really have to care about the details of scaling images. The Image class has already a method getScaledInstance(int width, int height, int hints) designed for this purpose.
Java documentation says:
Creates a scaled version of this image. A new Image object is returned
which will render the image at the specified width and height by
default. The new Image object may be loaded asynchronously even if the
original source image has already been loaded completely. If either
the width or height is a negative number then a value is substituted
to maintain the aspect ratio of the original image dimensions.
And you can use it like this:
// Scale Down the original image fast
Image scaledImage = imageToScale.getScaledInstance(newWidth, newHighth, Image.SCALE_FAST);
// Repaint this component
repaint();
Check this for a complete example.
Here is my solution:
private BufferedImage resizeImage(BufferedImage originalImage, int width, int height, int type) throws IOException {
BufferedImage resizedImage = new BufferedImage(width, height, type);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(originalImage, 0, 0, width, height, null);
g.dispose();
return resizedImage;
}
Try this CODE to resize image :
public static Image scaleImage(Image original, int newWidth, int newHeight) {
//do nothing if new and old resolutions are same
if (original.getWidth() == newWidth && original.getHeight() == newHeight) {
return original;
}
int[] rawInput = new int[original.getHeight() * original.getWidth()];
original.getRGB(rawInput, 0, original.getWidth(), 0, 0, original.getWidth(), original.getHeight());
int[] rawOutput = new int[newWidth * newHeight];
// YD compensates for the x loop by subtracting the width back out
int YD = (original.getHeight() / newHeight) * original.getWidth() - original.getWidth();
int YR = original.getHeight() % newHeight;
int XD = original.getWidth() / newWidth;
int XR = original.getWidth() % newWidth;
int outOffset = 0;
int inOffset = 0;
for (int y = newHeight, YE = 0; y > 0; y--) {
for (int x = newWidth, XE = 0; x > 0; x--) {
rawOutput[outOffset++] = rawInput[inOffset];
inOffset += XD;
XE += XR;
if (XE >= newWidth) {
XE -= newWidth;
inOffset++;
}
}
inOffset += YD;
YE += YR;
if (YE >= newHeight) {
YE -= newHeight;
inOffset += original.getWidth();
}
}
return Image.createRGBImage(rawOutput, newWidth, newHeight, false);
}
Another example is given here :
2D-Graphics/LoadImageandscaleit.htm">http://www.java2s.com/Tutorial/Java/0261_2D-Graphics/LoadImageandscaleit.htm
http://www.java2s.com/Code/JavaAPI/java.awt/ImagegetScaledInstanceintwidthintheightinthints.htm
I need to perform java image crop and resize without an X server.
I tried several methods.
the first method below works, but outputs a fairly ugly resized image (probably using nearest neighbor algorithm for the resize:
static BufferedImage createResizedCopy(Image originalImage, int scaledWidth, int scaledHeight, boolean preserveAlpha)
{
int imageType = preserveAlpha ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage scaledBI = new BufferedImage(scaledWidth, scaledHeight, imageType);
Graphics2D g = scaledBI.createGraphics();
if (preserveAlpha)
{
g.setComposite(AlphaComposite.Src);
}
g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null);
g.dispose();
return scaledBI;
}
So I decided to use bicubic resize, which gives better results:
public static BufferedImage createResizedCopy(BufferedImage source, int destWidth, int destHeight, Object interpolation)
{
if (source == null) throw new NullPointerException("source image is NULL!");
if (destWidth <= 0 && destHeight <= 0) throw new IllegalArgumentException("destination width & height are both <=0!");
int sourceWidth = source.getWidth();
int sourceHeight = source.getHeight();
double xScale = ((double) destWidth) / (double) sourceWidth;
double yScale = ((double) destHeight) / (double) sourceHeight;
if (destWidth <= 0)
{
xScale = yScale;
destWidth = (int) Math.rint(xScale * sourceWidth);
}
if (destHeight <= 0)
{
yScale = xScale;
destHeight = (int) Math.rint(yScale * sourceHeight);
}
GraphicsConfiguration gc = getDefaultConfiguration();
BufferedImage result = gc.createCompatibleImage(destWidth, destHeight, source.getColorModel().getTransparency());
Graphics2D g2d = null;
try
{
g2d = result.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, interpolation);
AffineTransform at = AffineTransform.getScaleInstance(xScale, yScale);
g2d.drawRenderedImage(source, at);
}
finally
{
if (g2d != null) g2d.dispose();
}
return result;
}
public static GraphicsConfiguration getDefaultConfiguration()
{
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
return gd.getDefaultConfiguration();
}
This worked fine until I tried to put it on the server, and at this point I bumped into java.awt.HeadlessException.
my attempts to play with java.awt.headless=true failed.
So, here is the question:
How do I resize and crop and image in Java without an X server, using a bicubic interpolation algorithm?
Answer:
Using the code from Bozho comment, I created this function which does the trick (interpolation should be RenderingHints.VALUE_INTERPOLATION_*).
public static BufferedImage createResizedCopy(BufferedImage source, int destWidth, int destHeight, Object interpolation)
{
BufferedImage bicubic = new BufferedImage(destWidth, destHeight, source.getType());
Graphics2D bg = bicubic.createGraphics();
bg.setRenderingHint(RenderingHints.KEY_INTERPOLATION, interpolation);
float sx = (float)destWidth / source.getWidth();
float sy = (float)destHeight / source.getHeight();
bg.scale(sx, sy);
bg.drawImage(source, 0, 0, null);
bg.dispose();
return bicubic;
}
Check this code. Also check if Image.getScaledInstance(..) (with "smooth" scaling) doesn't solve the problem. And finally, take a look at the java-image-scaling-library.