Suppose I have a JPanel Called panel, and already with a paintComponent, I drew some shapes like rectangles. I can get a buffered image out of my panel like:
int w = panel.getWidth();
int h = panel.getHeight();
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g = bi.createGraphics();
panel.paint(g);
ImageIO.write(bi1, "png", new File("test.png"));
How can I get a High Resolution image out of my panel? (the current output image is just based on the resolution of my JPanel in my monitor)
I tried AffineTransform, but it doesn't do what I need.
Note that I already drew everything in my panel, and do not want to change my drawing in my paintComponent method.
I am really searching for a practical way, and appreciate any help.
There are two possible ways you might achieve this, you could physically resize the component or you could apply an AffineTransform to the Graphics context, there are problems with both...
So, starting with this screen...
The background image is quite large to start with and has been scaled down (roughly) to fit within the current component, this is important for what's about to come...
I then resized it by 4 (this should, roughly, get you to around 300dpi)
Dimension original = tp.getSize();
System.out.println("Original = " + original);
int width = tp.getWidth() * 4;
int height = tp.getHeight() * 4;
System.out.println("Target = " + width + "x" + height);
tp.setSize(width, height);
tp.doLayout();
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
tp.print(g2d);
g2d.dispose();
tp.setSize(original);
tp.doLayout();
try {
ImageIO.write(img, "png", new File("Test.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
Which resulted in...
Well, okay, the background image looks cool, but the text is off...
Okay, so instead, we could use an AffineTransform...
int width = tp.getWidth() * 4;
int height = tp.getHeight() * 4;
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g2d.setTransform(AffineTransform.getScaleInstance(4, 4));
tp.print(g2d);
g2d.dispose();
try {
ImageIO.write(img, "png", new File("Test.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
Which resulted in...
Okay, now the image looks crap and the text is okay...
And for reference, the test code...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class HiRes {
public static void main(String[] args) {
new HiRes();
}
public HiRes() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
final TestPane tp = new TestPane();
JButton print = new JButton("Print");
print.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Dimension original = tp.getSize();
System.out.println("Original = " + original);
int width = tp.getWidth() * 4;
int height = tp.getHeight() * 4;
System.out.println("Target = " + width + "x" + height);
tp.setSize(width, height);
tp.doLayout();
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
// g2d.setTransform(AffineTransform.getScaleInstance(4, 4));
tp.print(g2d);
g2d.dispose();
tp.setSize(original);
tp.doLayout();
try {
ImageIO.write(img, "png", new File("Test.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(tp);
frame.add(print, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage background;
public TestPane() {
setLayout(new GridBagLayout());
try {
background = ImageIO.read(new File("/some/image/some/where"));
} catch (IOException ex) {
ex.printStackTrace();
}
setLayout(new GridBagLayout());
JLabel label = new JLabel("This is a test");
label.setForeground(Color.WHITE);
label.setFont(label.getFont().deriveFont(24f));
add(label);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (background != null) {
Graphics2D g2d = (Graphics2D) g.create();
Image scaled = background;
if (getWidth() < getHeight()) {
scaled = background.getScaledInstance(getWidth(), -1, Image.SCALE_SMOOTH);
} else {
scaled = background.getScaledInstance(-1, getHeight(), Image.SCALE_SMOOTH);
}
int x = (getWidth() - scaled.getWidth(this)) / 2;
int y = (getHeight() - scaled.getHeight(this)) / 2;
g2d.drawImage(scaled, x, y, this);
g2d.dispose();
}
}
}
}
Use print instead of paint
Scale up your component and your image dimension, then scale your image back to target size
Use transform will make your image blurring, try to scale your image 8 times and you'll see the differences
Related
I want to cut the pic to circle by using java graphics 2d, but the result is unsatisfying. I would like the final pic come as similar as the "object-fit: cover" comes out in css.
This is the original pic
original pic
Below are my codes and the final result.
BufferedImage testImage = ImageIO.read(new File("/Users/huangruixiang/Desktop/test.png"));
BufferedImage formatAvatarImage = new BufferedImage(200, 200, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D graphics = formatAvatarImage.createGraphics();
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Ellipse2D.Double shape = new Ellipse2D.Double(0, 0, 200, 200);
graphics.setClip(shape);
graphics.drawImage(testImage, 0, 0, 200, 200, null);
graphics.dispose();
ImageIO.write(formatAvatarImage,"png",new File("/Users/huangruixiang/Desktop/circle.png"));
resule
And the effect I want is similar to this
Expected effect
Here you go.
You have to use a different drawImage method than the one you used.
Here's the complete runnable code.
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class CenterCutImage {
public static void main(String[] args) {
CenterCutImage cci = new CenterCutImage();
BufferedImage image = cci.readImage("/do3kO.png");
BufferedImage croppedImage = cci.createCenterCut(image, new Dimension(200, 200));
String path = "D:\\Eclipse\\Eclipse-2020-workspace\\com.ggl.testing3\\resources";
cci.writeImage(croppedImage, path, "circle.png");
}
public BufferedImage createCenterCut(BufferedImage inputImage, Dimension d) {
BufferedImage image = new BufferedImage(d.width, d.height, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g2d = (Graphics2D) image.getGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int x = (inputImage.getWidth() - d.width) / 2;
int y = (inputImage.getHeight() - d.height) / 2;
Ellipse2D.Double shape = new Ellipse2D.Double(0, 0, d.width, d.height);
g2d.setClip(shape);
g2d.drawImage(inputImage, 0, 0, d.width, d.height, x, y, x + d.width, y + d.height, null);
g2d.dispose();
return image;
}
public BufferedImage readImage(String filename) {
try {
return ImageIO.read(getClass().getResourceAsStream(filename));
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
public void writeImage(BufferedImage croppedImage, String path, String filename) {
try {
ImageIO.write(croppedImage, "png", new File(path + "/" + filename));
} catch (IOException e) {
e.printStackTrace();
}
}
}
In Java swing, is there any way to draw only the shape of an image, instead of the image itself? And if so, how can I do it?
I added a picture to show you what I mean:
.
My image would consist of a one-colored shape and a transparent background. My intention is to be able to change the images color.
ImageFilter is what you sought. GrayFilter could be used.
class ShapeFilter extends RGBImageFilter {
public RedBlueSwapFilter() {
// The filter's operation does not depend on the
// pixel's location, so IndexColorModels can be
// filtered directly.
canFilterIndexColorModel = true;
}
public int filterRGB(int x, int y, int rgb) {
return (rgb & 0x00_ff_ff_ff) == 0x00_ff_ff_ff // White
|| rgb & 0xff_00_00_00) == 0x00_00_00) // or transparent
? rgb : 0xff_ff_00_00; // Red opaque
}
}
Usage inside a Component (JComponent) with createImage:
Image img = ImageIO.readImage(...);
ImageFilter filter = new ShapeFilter();
ImageProducer producer = new FilteredImageSource(img.getSource(), filter);
Image img2 = createImage(producer);
You could generate a "mask" of the image
The great feature of this technique is that you can generate the mask in what ever color or opacity you want
import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.Transparency;
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;
import javax.swing.UIManager;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static GraphicsConfiguration getGraphicsConfiguration() {
return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
}
public static BufferedImage createCompatibleImage(int width, int height, int transparency) {
BufferedImage image = getGraphicsConfiguration().createCompatibleImage(width, height, transparency);
image.coerceData(true);
return image;
}
public static void applyQualityRenderingHints(Graphics2D g2d) {
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
}
public static BufferedImage generateMask(BufferedImage imgSource, Color color, float alpha) {
int imgWidth = imgSource.getWidth();
int imgHeight = imgSource.getHeight();
BufferedImage imgMask = createCompatibleImage(imgWidth, imgHeight, Transparency.TRANSLUCENT);
Graphics2D g2 = imgMask.createGraphics();
applyQualityRenderingHints(g2);
g2.drawImage(imgSource, 0, 0, null);
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, alpha));
g2.setColor(color);
g2.fillRect(0, 0, imgSource.getWidth(), imgSource.getHeight());
g2.dispose();
return imgMask;
}
public BufferedImage tint(BufferedImage master, BufferedImage tint) {
int imgWidth = master.getWidth();
int imgHeight = master.getHeight();
BufferedImage tinted = createCompatibleImage(imgWidth, imgHeight, Transparency.TRANSLUCENT);
Graphics2D g2 = tinted.createGraphics();
applyQualityRenderingHints(g2);
g2.drawImage(master, 0, 0, null);
g2.drawImage(tint, 0, 0, null);
g2.dispose();
return tinted;
}
public class TestPane extends JPanel {
private BufferedImage master;
private BufferedImage mask;
public TestPane() {
try {
master = ImageIO.read(new File(bring your own image));
mask = generateMask(master, Color.RED, 1.0f);
} catch (IOException exp) {
exp.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();
if (master != null && mask != null) {
size = new Dimension(master.getWidth() + mask.getWidth(), Math.max(master.getHeight(), mask.getHeight()));
}
return size;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int x = (getWidth() - (master.getWidth() + mask.getWidth())) / 2;
int y = (getHeight() - master.getHeight()) / 2;
g.drawImage(master, x, y, this);
x += mask.getWidth();
y = (getHeight() - mask.getHeight()) / 2;
g.drawImage(mask, x, y, this);
}
}
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I want to ask one question regarding my code which is how do I convert a multiple-line text into a single image using BufferReader. I am able to get the image of the text but all the lines of the text are coming as one single string in one line.
Enclosing my code. Please review my code and suggest me as soon as possible:
package mypack;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import javax.imageio.ImageIO;
public class ImageDemo {
public static void main(String[] args) throws IOException {
// reading the String object from a file to be converted to image
/*File file = new File("D:/Vivek.txt");
StringBuilder sb=new StringBuilder();
BufferedReader reader = new BufferedReader(new FileReader(file));
while(true)
{
String text=reader.readLine();
System.out.println(text);
if(text==null)
break;
sb.append(text).append(' ');
sb.append("\n");
}
String text1=sb.toString();
reader.close();*/
String text=new String(Files.readAllBytes(Paths.get("D:/Vivek.txt")), StandardCharsets.UTF_8);
System.out.println(text);
// Image file name
String fileName = "Image";
// create a File Object
File newFile = new File("D:/Vivek.jpg");
// create the font you wish to use
Font font = new Font("Tahoma", Font.PLAIN, 20);
// create the FontRenderContext object which helps us to measure the
// text
FontRenderContext frc = new FontRenderContext(null, true, true);
// get the height and width of the text
Rectangle2D bounds = font.getStringBounds(text, frc);
int w = (int) bounds.getWidth();
int h = (int) bounds.getHeight();
// create a BufferedImage object
BufferedImage image = new BufferedImage(w, h,
BufferedImage.TYPE_INT_RGB);
// calling createGraphics() to get the Graphics2D
Graphics2D g = image.createGraphics();
// set color and other parameters
g.setColor(Color.white);
g.fillRect(0, 0, w, h);
g.setColor(Color.BLACK);
g.setFont(font);
g.drawString(text, (float) bounds.getX(), (float) -bounds.getY());
// releasing resources
g.dispose();
RenderedImage rImage = (RenderedImage) image;
// creating the file
ImageIO.write(rImage, "jpeg", newFile);
//merging the two buffered images to get a new image with text along with logo.
//load the source images
BufferedImage img1=ImageIO.read(new File("D:/Vivek.jpg"));
BufferedImage img2=ImageIO.read(new File("D:/logo.jpg"));
BufferedImage joined=joinBufferedImage(img1, img2);
ImageIO.write(joined, "png", new File("D:/Joined.png"));
System.out.println("Success");
}
public static BufferedImage joinBufferedImage(BufferedImage img1,BufferedImage img2) {
//do some calculate first
int offset = 500;
int wid = img1.getWidth()+img2.getWidth()+offset;
int height = Math.max(img1.getHeight(),img2.getHeight())+offset;
//create a new buffer and draw two image into the new image
BufferedImage newImage = new BufferedImage(wid,height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = newImage.createGraphics();
Color oldColor = g2.getColor();
//fill background
g2.setPaint(Color.WHITE);
g2.fillRect(0, 0, wid, height);
//draw image
g2.setColor(oldColor);
g2.drawImage(img2, null, 0, 0);
g2.drawImage(img1, null, 170, 150);
g2.dispose();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
return newImage;
}
}
Hi here I am writing multiple lines on JPanel. And you can write code which create Image from JPanel.
package Stakeoverflow.swingFrame;
import java.awt.Color;
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 java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
public class MultiLineTextToImage{
public static void main(String[] args) {
String text = "Hello";
/*
Because font metrics is based on a graphics context, we need to create
a small, temporary image so we can ascertain the width and height
of the final image
*/
int width = 1000;
int height = 1000;
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
Font font = new Font("Arial", Font.PLAIN, 48);
g2d.setFont(font);
FontMetrics fm = g2d.getFontMetrics();
g2d.dispose();
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
g2d = img.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g2d.setFont(font);
//fm = g2d.getFontMetrics();
g2d.setColor(Color.BLACK);
File file = new File("C:\\Read.text");
BufferedReader br=null;
int nextLinePosition=100;
int fontSize = 48;
try {
br = new BufferedReader(new FileReader(file));
String line;
while ((line = br.readLine()) != null) {
g2d.drawString(line, 0, nextLinePosition);
nextLinePosition = nextLinePosition + fontSize;
}
br.close();
} catch (FileNotFoundException ex) {
Logger.getLogger(Testing.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Testing.class.getName()).log(Level.SEVERE, null, ex);
}
g2d.dispose();
try {
ImageIO.write(img, "png", new File("Text.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
im trying to make a method in java that will resize rotate and draw a image after given arguments.
It does not work tho. Idk how? Btw is it posible to do this with the normal Graphic class and not Graphic2D ? Thanks!
public void drawResizedAndRotatedImage(Image image, Graphics g, int x, int y, int sizeX, int sizeY, double degrees){
//Resize
BufferedImage im = new BufferedImage(sizeX, sizeY, BufferedImage.TYPE_4BYTE_ABGR);
#SuppressWarnings("unused")
Graphics g2 = (Graphics)im.getGraphics();
//Rotate
ImageIcon imageIcon = new ImageIcon(image);
BufferedImage bufferedImage = new BufferedImage(imageIcon.getIconWidth(), imageIcon.getIconHeight(), BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g2d = (Graphics2D)bufferedImage.getGraphics();
g2d.rotate(Math.toRadians(degrees), imageIcon.getIconWidth() / 2, imageIcon.getIconHeight() / 2);
//Draw
g.drawImage(image, x, y, sizeX, sizeY, null);
}
Okay, so you create a BufferedImage and grab it's Graphics context...
BufferedImage im = new BufferedImage(sizeX, sizeY, BufferedImage.TYPE_4BYTE_ABGR);
Graphics g2 = (Graphics)im.getGraphics();
And do nothing with it...
You then create a second BufferedImage, grab it's Graphics context, set it's rotational context and paint nothing to it...
BufferedImage bufferedImage = new BufferedImage(imageIcon.getIconWidth(), imageIcon.getIconHeight(), BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g2d = (Graphics2D)bufferedImage.getGraphics();
g2d.rotate(Math.toRadians(degrees), imageIcon.getIconWidth() / 2, imageIcon.getIconHeight() / 2);
You then paint the original image to the supplied Graphics context...
g.drawImage(image, x, y, sizeX, sizeY, null);
Having achieved nothing at all...
I think you need to start by taking a read through Transforming Shapes, Text, and Images to get some grounding on the basics...
Transformations are compounding, they also only effect whatever is painted to the Graphics context AFTER they have been applied.
The simplest approach would actually be to use a AffineTransform
double scaleWidth = (double)sizeX / (double)image.getWidth(this);
double scaleHeight = (double)sizeY / (double)image.getHeight(this);
BufferedImage img = new BufferedImage(sizeX, sizeY, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
AffineTransform at = new AffineTransform();
at.scale(scaleWidth, scaleHeight);
at.rotate(Math.toRadians(degrees), image.getWidth(this) / 2d, image.getHeight(this) / 2d);
g2d.setTransform(at);
g2d.drawImage(image, sizeX / 2, sizeY / 2, null);
g2d.dispose();
// And finally, the result...
g.drawImage(img, x, y, null);
For example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.AffineTransform;
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;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestImage {
public static void main(String[] args) {
new TestImage();
}
public TestImage() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage original;
public TestPane() {
try {
original = ImageIO.read(new File("Your image here"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public Image scaleAndRotate(Image image, int sizeX, int sizeY, double degrees) {
double scaleWidth = (double)sizeX / (double)image.getWidth(this);
double scaleHeight = (double)sizeY / (double)image.getHeight(this);
BufferedImage img = new BufferedImage(sizeX, sizeY, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
AffineTransform at = new AffineTransform();
at.scale(scaleWidth, scaleHeight);
at.rotate(Math.toRadians(degrees), image.getWidth(this) / 2d, image.getHeight(this) / 2d);
g2d.setTransform(at);
g2d.drawImage(image, sizeX / 2, sizeY / 2, null);
g2d.dispose();
return img;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int scaleWidth = getWidth() / 2;
int scaleHeight = getHeight() / 2;
Image img = scaleAndRotate(original, scaleWidth, scaleHeight, 45.0);
int x = (getWidth() - img.getWidth(this)) / 2;
int y = (getHeight()- img.getHeight(this)) / 2;
g2d.drawImage(img, x, y, this);
g2d.dispose();
}
}
}
You may also like to take a read through...
Java: maintaining aspect ratio of JPanel background image
Quality of Image after resize very low -- Java
For discussions about scaling algorithms and techniques
You should also know that the size of an image when it rotates also changes, have a look at (one of my favourite answers to refer to) Rotate an image in java for more details about how to calculate the resulting image size of a rotated image...
Is there out any Java library that allows converting text content to image files? I only know of ImageMagick (JMagick in this case) but I wouldn't like to install any external binaries (my app will be deployed as a .war file in a Tomcat server so I don't want any other dependencies more than Java).
For example, from the string "Hello", I would like to generate this simple image:
The Graphics 2D API should be capable of achieving what you need. It has some complex text handling capabilities as well.
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class TextToGraphics {
public static void main(String[] args) {
String text = "Hello";
/*
Because font metrics is based on a graphics context, we need to create
a small, temporary image so we can ascertain the width and height
of the final image
*/
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
Font font = new Font("Arial", Font.PLAIN, 48);
g2d.setFont(font);
FontMetrics fm = g2d.getFontMetrics();
int width = fm.stringWidth(text);
int height = fm.getHeight();
g2d.dispose();
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
g2d = img.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g2d.setFont(font);
fm = g2d.getFontMetrics();
g2d.setColor(Color.BLACK);
g2d.drawString(text, 0, fm.getAscent());
g2d.dispose();
try {
ImageIO.write(img, "png", new File("Text.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
Also check out Writing/Saving and Image
WARNING I used this to generate 90k PNG images only to find that they can be viewed in IE but not in Chrome Version 70.0.3538.77
The above code works just fine for me (I changed the text color to WHITE so I could see it in chrome)
I was using Chrome 70.0.3538.77 on Mac OS Mojave 10.14 using Java 10.0.2. The resulting image was 4778x2411 pixels ...
Updated...
On IE that is black on white but on Chrome that is black on black. Yet I set background to white.
So what you're telling me is, a transparent PNG is been displayed differently on different browsers, because the browsers use different default backgrounds ... why are you surprised by this?
The original solution, deliberately, used a transparent based image. This is evident by the use of BufferedImage.TYPE_INT_ARGB when creating the image, which is applying a Alpha (A) based RGB color model.
This is unexpected as there is g2d.setBackground(Color.white).
No, actually, it is entirely expected, if only you understood what setBackground actually does and how it should be used
From the JavaDocs
Sets the background color for the Graphics2D context. The background
color is used for clearing a region. When a Graphics2D is constructed
for a Component, the background color is inherited from the Component.
Setting the background color in the Graphics2D context only affects
the subsequent clearRect calls and not the background color of the
Component. To change the background of the Component, use appropriate
methods of the Component.
From the "sounds" of things, you want a non-transparent image, with a filled background color. So, once again, it's off to the JavaDocs and a little bit of reading would have lead you to BufferedImage.TYPE_INT_RGB, which removes the Alpha channel, but you'd still have to fill the background of the image.
For this, I'd use Graphics2D#setColor and Graphics2D#fillRect, only because it works.
So, you'd end up with a modified version of the above which might look something like...
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
g2d = img.createGraphics();
//...
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, img.getWidth(), img.getHeight());
g2d.setColor(Color.BLACK);
g2d.drawString(text, 0, fm.getAscent());
g2d.dispose();
try {
ImageIO.write(img, "png", new File("Text.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
If I change to "jpg" then I get orange/pink text on black background on both IE and Chrome
Well, this is related to a well known, and sadly, common issue/bug in ImageIO, which attempts to apply the alpha channel of transparent color models to the JPG, which doesn't support alpha channels.
See Issue using ImageIO.write jpg file: pink background for more details.
But the basic solution is to either use PNG, which supports alpha channels, or to use a non-transparent image.
So, the long and short of all this is. The problem is NOT with the original answer, nor is it with ImageIO, BufferedImage, Graphics, the AWT library, Chrome or IE, but with your lack of understanding of how these APIs (and the example) works.
Without any external libraries, do the following:
Measure the text size in pixels (see Measuring Text)
Create a java.awt.image.BufferedImage in the right size for the text
Acquire the graphics object for the BufferedImage using the createGraphics() method
Draw the text
Save the image using the javax ImageIO class
Edit - fixed the link
Consider the following snippet:
public static final HashMap<RenderingHints.Key, Object> RenderingProperties = new HashMap<>();
static{
RenderingProperties.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
RenderingProperties.put(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
RenderingProperties.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
}
public static BufferedImage textToImage(String Text, Font f, float Size){
//Derives font to new specified size, can be removed if not necessary.
f = f.deriveFont(Size);
FontRenderContext frc = new FontRenderContext(null, true, true);
//Calculate size of buffered image.
LineMetrics lm = f.getLineMetrics(Text, frc);
Rectangle2D r2d = f.getStringBounds(Text, frc);
BufferedImage img = new BufferedImage((int)Math.ceil(r2d.getWidth()), (int)Math.ceil(r2d.getHeight()), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.setRenderingHints(RenderingProperties);
g2d.setBackground(Color.WHITE);
g2d.setColor(Color.BLACK);
g2d.clearRect(0, 0, img.getWidth(), img.getHeight());
g2d.setFont(f);
g2d.drawString(Text, 0, lm.getAscent());
g2d.dispose();
return img;
}
Uses only the java Graphics API to create a image based on a font rendered onto a bufferedimage.
demo# For multi line texts #
Pass the file as argument to the program
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
public class TextToGraphics {
public static void main(String[] args){
System.out.println(args[0]);
File file = new File(args[0]);
try{
BufferedReader br = new BufferedReader(new FileReader(file));
StringBuilder sb = new StringBuilder();
String line;
while((line = br.readLine())!=null){
sb.append(line).append("\n");
}
convert(sb.toString(),args[0]+"_img");
System.out.println("Done.");
}
catch(FileNotFoundException e){
e.printStackTrace();
}
}
public static void convert(String text, String img_name) {
String[] text_array = text.split("[\n]");
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
Font font = new Font("Consolas", Font.BOLD, 12);
g2d.setFont(font);
FontMetrics fm = g2d.getFontMetrics();
int width = fm.stringWidth(getLongestLine(text_array));
int lines = getLineCount(text);
int height = fm.getHeight() * (lines + 4);
g2d.dispose();
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
g2d = img.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g2d.setFont(font);
fm = g2d.getFontMetrics();
g2d.setColor(Color.BLACK);
for (int i = 1; i <= lines; ++i) {
g2d.drawString(text_array[i - 1], 0, fm.getAscent() * i);
}
g2d.dispose();
try {
String img_path = System.getProperty("user.dir") + "/" + img_name + ".png";
ImageIO.write(img, "png", new File(img_path));
} catch (IOException ex) {
ex.printStackTrace();
}
}
public static int getLineCount(String text) {
return text.split("[\n]").length;
}
private static String getLongestLine(String[] arr) {
String max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (max.length() < arr[i].length()) {
max = arr[i];
}
}
return max;
}
}
Here is a simple Program to write Graphics contents to png format.
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.io.File;
import javax.imageio.ImageIO;
class ImageWriteEx extends JPanel{
public void paint(Graphics g){
Image img = createImageWithText();
g.drawImage(img, 20, 20, this);
}
private static BufferedImage createImageWithText(){
BufferedImage bufferedImage = new BufferedImage(200, 200, BufferedImage.TYPE_INT_RGB);
Graphics g = bufferedImage.getGraphics();
g.drawString("www.stackoverflow.com", 20, 20);
g.drawString("www.google.com", 20, 40);
g.drawString("www.facebook.com", 20, 60);
g.drawString("www.youtube.com", 20, 80);
g.drawString("www.oracle.com", 20, 1000);
return bufferedImage;
}
public static void main(String[] args){
try{
BufferedImage bi = createImageWithText();
File outputfile = new File("save.png");
ImageIO.write(bi, "png", outputfile);
} catch(Exception e){
e.printStackTrace();
}
JFrame frame = new JFrame();
frame.getContentPane().add(new ImageWriteEx());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300,300);
frame.setVisible(true);
}
}
In case someone wants TextImages with several lines. I made some and displayed them with
new ImageIcon(*here the image*)
in JOptionPane (without adding text). That fills the whole JOptionPane nicely. Here the code:
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
public class TextImage
{
public static BufferedImage make(String...textrows)
{
BufferedImage helperImg = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = helperImg.createGraphics();
Font font = *here some font*;
g2d.setFont(font);
FontMetrics fm = g2d.getFontMetrics();
String longestText = "";
for(String row: textrows)
{
if(row.length()>longestText.length())
{
longestText = row;
}
}
int width = fm.stringWidth(longestText);
int height = fm.getHeight()*textrows.length;
g2d.dispose();
BufferedImage finalImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
g2d = finalImg.createGraphics();
g2d.setColor(*here some Color*);
g2d.fillRect(0, 0, width, height);
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g2d.setFont(font);
fm = g2d.getFontMetrics();
g2d.setColor(Color.BLACK);
int y = fm.getAscent();
for(String row: textrows)
{
g2d.drawString(row, 0, y);
y += fm.getHeight();
}
g2d.dispose();
return finalImg;
}
}