How to convert multi-line text to image using Java [closed] - java

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();
}
}
}

Related

How to cut the pic to circle through java graphics 2d? And I expect the result is similar to object-fit: cover in css

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();
}
}
}

Getting High Resolution Image from JPanel

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

Convert text content to 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;
}
}

Java rotated image turns all black?

I am making a basic java application and trying to rotate an image. I wrote the following quick method
private Image rotate(double degs){
ImageIcon img = new ImageIcon("src/inc/img/char_male.png");
Image temp = new BufferedImage(img.getIconWidth(), img.getIconHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = (Graphics2D) temp.getGraphics();
g2.rotate(Math.toRadians(degs));
g2.drawImage(img.getImage(), 0, 0, Color.WHITE, null);
System.out.println("Rotating "+degs);
g2.dispose();
return temp;
}
The problem is when I run this and repaint the GUI, the image turns pure black. Am I doing something wrong with the BufferedImage creation? I am changing the GUI in the repaint using a JLabel,
label.setIcon(new ImageIcon(rotate(90)));
You need to rotate and translate at the same time so that the center of rotation is the center of the image. The AffineTransform rotate method has an overload for this as does the Graphics2D rotate method. For e.g., what if you try,...
private Image rotate(double degs){
ImageIcon img = new ImageIcon("src/inc/img/char_male.png"); // why an ImageIcon???
Image temp = new BufferedImage(img.getIconWidth(), img.getIconHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = (Graphics2D) temp.getGraphics();
g2.rotate(Math.toRadians(degs), img.getIconWidth()/2, img.getIconHeight()/2); // changed
g2.drawImage(img.getImage(), 0, 0, Color.WHITE, null);
System.out.println("Rotating "+degs);
g2.dispose();
return temp;
}
Sorry, here's the corrected code:
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
public class ImageRotate {
private static final String IMAGE_PATH = "src/yr2011/images/guitar_3406632_n.jpg";
public static void main(String[] args) {
try {
BufferedImage image = ImageIO.read(new File(IMAGE_PATH));
ImageIcon icon = new ImageIcon(image);
JOptionPane.showMessageDialog(null, new JLabel(icon));
icon = new ImageIcon(rotate(image, 90));
JOptionPane.showMessageDialog(null, new JLabel(icon));
} catch (IOException e) {
e.printStackTrace();
}
}
private static Image rotate(Image image, double degs) {
int width = image.getWidth(null);
int height = image.getHeight(null);
BufferedImage temp = new BufferedImage(height, width, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = temp.createGraphics();
g2.rotate(Math.toRadians(degs), height / 2, height / 2);
g2.drawImage(image, 0, 0, Color.WHITE, null);
g2.dispose();
return temp;
}
}
I don't use Java, so that I can't tell if there's something wrong with your code, but a common error when doing image rotation is rotating out of the viewport. When you imagine the original image sitting at the coordinate origin, rotating it by 90 degrees moves the image below the x-axis (or left of the y-axis, depending on the direction). In both cases the rotated image leaves the viewport and you get an empty image. The solution is to shift the rotated image back to place.
I had the same probleme and I solved it in an other way:
My picture had a transparent background but I didn't know it because I look it always on white background. Anyway, I solved my problem when I use
BufferedImage temp = new BufferedImage(height, width, BufferedImage.TYPE_INT_ARGB);
instead of
BufferedImage temp = new BufferedImage(height, width, BufferedImage.TYPE_INT_RGB);
I think that graphics2d work with a black background if you don't precise transparent type.

Java awt font spacing options

Since the Brazilian government does not have a public API for postal codes, I am trying to reverse engineer the code that correios.com.br uses to generate the image below so I can generate my own images to train the OCR program.
I believe that I have already got almost everything right besides the text spacing and the colors:
I am not interested on the colors now, but the text spacing is really bothering me. For instance, have a look on the 'Ti' in 'Tijuca'. The two letters are really close together in the original image and I can't reproduce this feature. I have already tried to derive the font, setting values to TextAttribute.TRACKING and TextAttribute.KERNING, but it did not work.
Here follows my code:
import java.awt.Color;
import java.awt.font.TextAttribute;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Hashtable;
import javax.imageio.ImageIO;
public class CreateImage {
/**
* #param args
*/
public static void main(String[] args) {
int width = 570;
int height = 120;
boolean new_image = true;
BufferedImage img;
if (!new_image) {
try {
img = ImageIO.read(new File("original.jpg"));
} catch (IOException e) {
e.printStackTrace();
new_image = true;
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
}
} else {
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
}
Graphics2D g2d = img.createGraphics();
if (new_image) {
// white background
g2d.setPaint(Color.WHITE);
g2d.fillRect(0, 0, width, height);
g2d.setPaint(Color.BLACK);
} else {
g2d.setPaint(Color.RED);
}
Font myfont = new Font("SansSerif", Font.BOLD, 11);
/*
Hashtable<TextAttribute, Float> attributes = new Hashtable<TextAttribute, Float>();
attributes.put(TextAttribute.TRACKING, new Float(-0.01));
myfont = myfont.deriveFont(attributes);
*/
g2d.setFont(myfont);
g2d.drawString("Logradouro:", 5, 13);
g2d.drawString("Bairro:", 5, 33);
g2d.drawString("Localidade / UF:", 5, 53);
g2d.drawString("CEP:", 5, 73);
g2d.drawString("Avenida das Américas - de 3979 a 5151 - lado ímpar", 105, 13);
g2d.drawString("Barra da Tijuca", 105, 33);
g2d.drawString("Rio de Janeiro/RJ", 105, 53);
g2d.drawString("22631-004", 105, 73);
g2d.dispose();
File file = new File("clone.jpg");
try {
ImageIO.write(img, "jpg", file);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("clone.jpg file created.");
}
}
My question is: What are the other options to control how a string is spaced when it's drawn? Do you have any ideas on what the original code may be doing?
Thanks!
I can't really say how to do it properly in Swing, but what you are looking for is in typography called "kerning", so that attribute ought to do something similar.

Categories