Graphic2D generating image with automatic text positioning - java

How can I auto-position text inside an image when generating one? For example, I have this method to generate my .png image:
public static void generatePNG(String message){
try {
int width = 400, height = 400;
// TYPE_INT_ARGB specifies the image format: 8-bit RGBA packed
// into integer pixels
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D ig2 = bi.createGraphics();
Font font = new Font("TimesRoman", Font.BOLD, 15);
ig2.setFont(font);
FontMetrics fontMetrics = ig2.getFontMetrics();
int stringWidth = fontMetrics.stringWidth(message);
int stringHeight = fontMetrics.getAscent();
ig2.setPaint(Color.black);
ig2.drawString(message, (width - stringWidth) / 2, height / 2 + stringHeight / 4);
ImageIO.write(bi, "PNG", new File("myimg.png"));
} catch (IOException ie) {
ie.printStackTrace();
}
}
But this centers text in my img, which was ok for testing, but now I want to add multiple lines to image and to start from top to bottom. The message I build with StringBuilder that I parse in my method is separated in new lines by System.lineSeparator() I also don't know how is it with width and height as my width must remain the same, while height can change as much as it wants, but how can I know how much will it need just by the message?

I assume that this is an example of an XY-problem. If your goal is to generate an image, with a certain text, automatically adjusted for some font and line breaks, then you could do this on your own. You could use FontMetrics and its methods to compute the proper size of the image, and the proper locations that are then drawn with drawString calls.
But this is complicated. And it's far, far, far more complicated than it looks at the first glance. I'm not even talking about النص العربي (arabic text), but even about the seemingly most trivial elements of fonts.
The most simple solution therefore is probably to rely on the hundreds of thousands of lines of time-tested code that have already been written by experts in this field, in order to solve this problem.
Which means:
Just drop the text into a JTextArea, and then create an image from that.
The following is an MCVE that shows how this could be achieved.
The core is the createTextImage method, which allows you to create an image from the text, with a certain font and colors. Optionally, you may specify the width of the image, and leave the daunting task of doing the line breaks to the JTextArea.
You may notice the "HTML" checkbox at the top. When it is enabled, the input is passed to a createHtmlImage method, so that you can even enter something like
<html>
This is <u>underlined</u> <br>
or in <i>italics</i>
</html>
to obtain an image of the rendered HTML output.
The full code is here:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.image.BufferedImage;
import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
public class GenerateTextImage {
public static void main(String[] args) {
String text = "This is a text" + "\n"
+ "with one line that is muuuuuuuuuuuuuuuuch longer than the others" + "\n"
+ "and some empty lines" + "\n"
+ "\n"
+ "\n"
+ "as a test.";
SwingUtilities.invokeLater(() -> createAndShowGui(text));
}
private static void createAndShowGui(String initialText) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().setLayout(new BorderLayout());
JPanel controlPanel = new JPanel();
JCheckBox htmlCheckBox = new JCheckBox("HTML", false);
controlPanel.add(htmlCheckBox);
f.getContentPane().add(controlPanel, BorderLayout.NORTH);
JPanel mainPanel = new JPanel(new GridLayout(1, 2));
f.getContentPane().add(mainPanel, BorderLayout.CENTER);
JTextArea inputTextArea = new JTextArea();
JScrollPane sp0 = new JScrollPane(inputTextArea);
sp0.setBorder(BorderFactory.createTitledBorder("Input:"));
mainPanel.add(sp0);
ImagePanel imagePanel = new ImagePanel();
JScrollPane sp1 = new JScrollPane(imagePanel);
sp1.setBorder(BorderFactory.createTitledBorder("Image:"));
mainPanel.add(sp1);
Runnable updateImage = () -> {
if (!htmlCheckBox.isSelected()) {
String text = inputTextArea.getText();
BufferedImage image = createTextImage(text);
imagePanel.setImage(image);
} else {
String text = inputTextArea.getText();
BufferedImage image = createHtmlImage(text);
imagePanel.setImage(image);
}
};
inputTextArea.getDocument().addDocumentListener(new DocumentListener() {
public void changedUpdate(DocumentEvent e) {
updateImage();
}
public void insertUpdate(DocumentEvent e) {
updateImage();
}
public void removeUpdate(DocumentEvent e) {
updateImage();
}
private void updateImage() {
updateImage.run();
}
});
htmlCheckBox.addChangeListener(e -> {
updateImage.run();
});
inputTextArea.setText(initialText);
f.setSize(1200, 600);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static BufferedImage createTextImage(String text) {
return createTextImage(text, -1, new Font("TimesRoman", Font.BOLD, 15), Color.BLACK, Color.WHITE);
}
/**
* Creates an image with the given text, using the given font and foreground- and background color.<br>
* <br>
* If the given width is not positive, then the width of the image will be computed
* to show the longest line that appears in the text. If the given width is positive,
* then the lines of the given text will be wrapped (at word boundaries) if possible,
* so that the whole text can be displayed.
*
* #param text The text
* #param width The image width
* #param font The font
* #param foreground The foreground color
* #param background The background color
* #return The image
*/
private static BufferedImage createTextImage(String text, int width, Font font, Color foreground, Color background) {
JTextArea textArea = new JTextArea(text);
textArea.setFont(font);
textArea.setForeground(foreground);
textArea.setBackground(background);
if (width > 0)
{
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
textArea.setSize(new Dimension(width, Short.MAX_VALUE));
}
Dimension size = textArea.getPreferredSize();
int w = Math.max(1, size.width);
if (width > 0)
{
w = width;
}
int h = Math.max(1, size.height);
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = image.createGraphics();
SwingUtilities.paintComponent(g, textArea, new JPanel(), 0, 0, w, h);
g.dispose();
return image;
}
private static BufferedImage createHtmlImage(String text) {
return createHtmlImage(text, new Font("TimesRoman", Font.BOLD, 15), Color.BLACK, Color.WHITE);
}
/**
* Creates an image with the given HTML string, using the given font and foreground- and background color.<br>
*
* #param html The HTML string
* #param font The font
* #param foreground The foreground color
* #param background The background color
* #return The image
*/
private static BufferedImage createHtmlImage(String html, Font font, Color foreground, Color background) {
JLabel label = new JLabel(html);
label.setOpaque(true);
label.setFont(font);
label.setForeground(foreground);
label.setBackground(background);
Dimension size = label.getPreferredSize();
int w = Math.max(1, size.width);
int h = Math.max(1, size.height);
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = image.createGraphics();
SwingUtilities.paintComponent(g, label, new JPanel(), 0, 0, w, h);
g.dispose();
return image;
}
static class ImagePanel extends JPanel {
private static final long serialVersionUID = 1L;
private BufferedImage image;
public void setImage(BufferedImage image) {
this.image = image;
repaint();
}
#Override
public Dimension getPreferredSize() {
if (image == null || super.isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(image.getWidth(), image.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (image != null) {
g.drawImage(image, 0, 0, null);
}
}
}
}
Edit: A small addendum for one of the comments. It centers the text horizontally, using the snippet from https://stackoverflow.com/a/3213361/3182664 . Note that this is not tested thoroughly. At some point, questions, comments and edits boil down to "Write some code for me". I'm a freelancer. You can hire me.
private static BufferedImage createTextImage(String text, int width, Font font, Color foreground, Color background) {
JTextPane textPane = new JTextPane();
textPane.setText(text);
// See https://stackoverflow.com/a/3213361/3182664
StyledDocument doc = textPane.getStyledDocument();
SimpleAttributeSet center = new SimpleAttributeSet();
StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER);
doc.setParagraphAttributes(0, doc.getLength(), center, false);
textPane.setFont(font);
textPane.setForeground(foreground);
textPane.setBackground(background);
if (width > 0)
{
//textPane.setLineWrap(true);
//textPane.setWrapStyleWord(true);
textPane.setSize(new Dimension(width, Short.MAX_VALUE));
}
Dimension size = textPane.getPreferredSize();
int w = Math.max(1, size.width);
if (width > 0)
{
w = width;
}
int h = Math.max(1, size.height);
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = image.createGraphics();
SwingUtilities.paintComponent(g, textPane, new JPanel(), 0, 0, w, h);
g.dispose();
return image;
}

Related

Image is not drawing on top left of panel

When i load image ,it do not load at upper left (if the image is large to be fit on window size).This is because i diminish its size as shown in code. Although i am giving its coordinate value 0,0 it is not drawing at that position.
import javax.swing.*;
import javax.imageio.ImageIO;
import java.io.*;
import java.awt.*;
import java.awt.image.BufferedImage;
public class photo extends JFrame
{
Dimension screenwidth=getToolkit().getScreenSize();
int mx=(int)screenwidth.getWidth();
int my=(int)screenwidth.getHeight();
BufferedImage picture1;
JLabel label3;
int neww;
int newh;
public photo() {
JFrame f = new JFrame("Image Editor v1.0");
f.setLayout(null);
try{
File file=new File("e:\\8.jpg");
picture1=ImageIO.read(file);
}catch(Exception e)
{
}
JPanel panel2 = new JPanel();
panel2.setLayout(null);
panel2.setBounds(101,20,mx-100,my-20);
f.add(panel2);
label3 = new JLabel("");
label3.setBounds(110,30,mx-110,my-30);
panel2.add(label3);
f.setExtendedState(Frame.MAXIMIZED_BOTH);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BufferedImage bi = null;
if(picture1.getWidth()>mx-110 ||picture1.getHeight()>my-30 )
{
neww= (int) Math.round(picture1.getWidth() * 0.25);
newh = (int) Math.round(picture1.getHeight() *0.25);
}
else
{
neww=picture1.getWidth();
newh=picture1.getHeight();
}
bi = new BufferedImage(neww,newh,BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) bi.createGraphics();
g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY));
g2d.drawImage(picture1,0,0,neww,newh,0,0,picture1.getWidth(),picture1.getHeight(), null);
label3.setIcon(new ImageIcon(bi));
}
public static void main(String[] args)
{
new photo();
}
}
You could add g2d.translate(0, 0); between g2d.addRenderingHints and g2d.drawImage and try it.
EDIT
So if you want the image to be at 101 px and 20 px, you should label3.setBounds(0,0,neww,newh); after label3.setIcon(new ImageIcon(bi)); instead of the current. I think this shall work as I have just tested.

Radio Button Group With Big Circles Java

For an Application in Java Swing (developed in netbeans), we need to create big circle exatcly like radio buttons, which means we have a group of circles that whenever the user clicks on one, it changes to a filled circle. The user can choose only 1 circle.
The working mechansim is exactly similar to radiobutton group only we need to have bigger circles. Any idea how we can do this?
Use JRadioButtons
But give them no text (if this is a requirement, .... it may not be your requirement, I don't know).
Instead give them two ImageIcons, 1 for unselected which is an empty circle, and use setIcon(Icon icon) to do this.
And the other for selected that is an image of a filled circle, and use setSelectedIcon(Icon icon) to do this.
You can create your own images easily by drawing on a BufferedImage.
For example, the code below creates:
..... ......
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import javax.swing.*;
#SuppressWarnings("serial")
public class CircleIconEg extends JPanel {
public static final String[] PLAYER_NAMES = {"John", "Bill", "Frank", "Andy"};
private static final int BI_WIDTH = 40;
private ButtonGroup btnGrp = new ButtonGroup();
private static Icon emptyIcon;
private static Icon selectedIcon;
// create our Circle ImageIcons
static {
// first the empty circle
BufferedImage img = new BufferedImage(BI_WIDTH, BI_WIDTH, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setStroke(new BasicStroke(4f));
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int x = 4;
int y = x;
int width = BI_WIDTH - 2 * x;
int height = width;
g2.setColor(Color.black);
g2.drawOval(x, y, width, height);
g2.dispose();
emptyIcon = new ImageIcon(img);
// next the filled circle
img = new BufferedImage(BI_WIDTH, BI_WIDTH, BufferedImage.TYPE_INT_ARGB);
g2 = img.createGraphics();
g2.setStroke(new BasicStroke(4f));
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.red);
g2.fillOval(x, y, width, height);
g2.setColor(Color.black);
g2.drawOval(x, y, width, height);
g2.dispose();
selectedIcon = new ImageIcon(img);
}
public CircleIconEg() {
setLayout(new GridLayout(0, 1, 0, 4));
for (String playerName : PLAYER_NAMES) {
JRadioButton radioBtn = createRadioButton(playerName);
btnGrp.add(radioBtn);;
add(radioBtn);
}
}
private JRadioButton createRadioButton(String playerName) {
JRadioButton rBtn = new JRadioButton(playerName, emptyIcon);
rBtn.setSelectedIcon(selectedIcon);
return rBtn;
}
private static void createAndShowGui() {
CircleIconEg mainPanel = new CircleIconEg();
JFrame frame = new JFrame("CircleIconEg");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Developing an image editor in java

I'm attempting to develop an image editor in Java. Part of my Java image implementation of the image editor is to load an image and draw some shapes in addition to performing rotation, scaling, etc.
I'm using JLabel to load images but is there a way to draw and apply transformation on an image using JLabel? All of the examples I've found online used JPanel.
You really need to look at Java2D turorial. You should draw images on Graphics2D and also rotate and scale images on Graphics2D.
Don't use JLabel, because
J-* Components are heavy (although JLabel is light-weighted). You can add an icon to a JLabel, but generally, they are used in stable cases, which won't be changed
frequently and arbitrarily. Painting on a J-* component brings
too many changes on it.
If you add a great number of components, it will also reduce performance.
(Each component would paint itself in a separate Graphics object which belongs to
it and its container will paint them all and the layout also matters.)
Another drawback is it is sometimes very difficult even impossible to
do some manipulations on a component or on a couple of components together. For example, what if you want to add two pictures and group them? You need 2 JLabels, 1 JPanel (maybe). Then what if you want to draw a line across these two images and group them again?
Below are the basic steps:
override paint or paintComponent method of a component;
cast Graphics instance to Graphics2D;
set some rendering attributes of Graphics2D;
set transform (rotation, scale, etc.) of Graphics2D;
draw image on Graphics2D
A large variety of classes are used, such as Graphics2D, AffineTransform, RenderingHints, BufferedImage, Shape, etc. and even more methods. I can't describe everything here. Just read the Java2D tutorial. It gives you an overview of the APIs and tells you how to do these things.
I'm using JLabel to load images but is there away to draw and apply
transformation on an image using JLabel?
Not sure exactly what you mean.
But you can simply get the icon of the JLabel (which is the image being displayed) do what needs to be done on the icon which we converted to BufferedImage and than reapply the icon via setIcon(..).
Here is a short example hope it helps:
JLabel with icon/BufferedImage before rotating -45 degrees:
JLabel after icon was got, rotated and re applied via setIcon(...):
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import javax.swing.AbstractAction;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Test {
private static JLabel imageLabel;
private static JFrame frame;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel panel = new JPanel();
imageLabel = new JLabel(new ImageIcon(createImage()));//set image of JLabel
panel.add(imageLabel);
frame.add(panel);
frame.pack();
frame.setVisible(true);
startImageChangeTimer();//creates a timer which will rotate image after 5 seconds
}
private void startImageChangeTimer() {
Timer timer = new Timer(5000, new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
//get JLabel Icon and convert to BufferedImage
BufferedImage img = getBufferedImageOfIcon(imageLabel.getIcon(), imageLabel.getWidth(), imageLabel.getHeight());
//rotate the image
img = createTransformedImage(img, -45);
//change the labels image
imageLabel.setIcon(new ImageIcon(img));
frame.pack();//resize frame accrodingly
}
});
timer.setRepeats(false);
timer.start();
}
});
}
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;
}
public static BufferedImage getBufferedImageOfIcon(Icon icon, int imgW, int imgH) {
BufferedImage img = new BufferedImage(imgW, imgH, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = (Graphics2D) img.getGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
icon.paintIcon(null, g2d, 0, 0);
g2d.dispose();
return img;
}
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;
}
}
Update:
I do tend to agree with #shuangwhywhy. Draw image to JPanel via paintComponent(Graphics g) thus you can simply resize the image and set it to the JPanel image (via getters and setters)and than call repaint() to show the changes.
Here is Simple Image Editor
/*Arpana*/
CPanel displayPanel;
JButton sharpenButton, blurringButton, edButton, resetButton;
public ConvolveApp()
super();
Container container = getContentPane();
displayPanel = new CPanel();
container.add(displayPanel);
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(2, 2));
panel
.setBorder(new TitledBorder(
"Click a Button to Perform the Associated Operation and Reset..."));
sharpenButton = new JButton("Sharpen");
sharpenButton.addActionListener(new ButtonListener());
blurringButton = new JButton("Blur");
blurringButton.addActionListener(new ButtonListener());
edButton = new JButton("Edge Detect");
edButton.addActionListener(new ButtonListener());
resetButton = new JButton("Reset");
resetButton.addActionListener(new ButtonListener());
panel.add(sharpenButton);
panel.add(blurringButton);
panel.add(edButton);
panel.add(resetButton);
container.add(BorderLayout.SOUTH, panel);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
setSize(displayPanel.getWidth(), displayPanel.getHeight() + 10);
setVisible(true);
public static void main(String arg[]) {
new ConvolveApp();
class ButtonListener implements ActionListener
public void actionPerformed(ActionEvent e)
JButton button = (JButton) e.getSource();
if (button.equals(sharpenButton))
displayPanel.sharpen();
displayPanel.repaint();
else if (button.equals(blurringButton))
displayPanel.blur();
displayPanel.repaint();
else if (button.equals(edButton))
displayPanel.edgeDetect();
displayPanel.repaint();
else if (button.equals(resetButton))
displayPanel.reset();
displayPanel.repaint();
class CPanel extends JLabel
Image displayImage;
BufferedImage biSrc;
BufferedImage biDest;
BufferedImage bi;
Graphics2D big;
CPanel()
setBackground(Color.black);
loadImage();
setSize(displayImage.getWidth(this), displayImage.getWidth(this));
createBufferedImages();
bi = biSrc;
public void loadImage()
displayImage = Toolkit.getDefaultToolkit().getImage("Arpana.jpg");
MediaTracker mt = new MediaTracker(this);
mt.addImage(displayImage, 1);
try
mt.waitForAll();
if (displayImage.getWidth(this) == -1)
System.out.println("No jpg file");
System.exit(0);
public void createBufferedImages()
biSrc = new BufferedImage(displayImage.getWidth(this), displayImage
.getHeight(this), BufferedImage.TYPE_INT_RGB);
big = biSrc.createGraphics();
big.drawImage(displayImage, 0, 0, this);
biDest = new BufferedImage(displayImage.getWidth(this), displayImage
.getHeight(this), BufferedImage.TYPE_INT_RGB);
public void sharpen()
float data[] = { -1.0f, -1.0f, -1.0f, -1.0f, 9.0f, -1.0f, -1.0f, -1.0f,
-1.0f };
Kernel kernel = new Kernel(3, 3, data);
ConvolveOp convolve = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP,
null);
convolve.filter(biSrc, biDest);
bi = biDest;
public void blur()
float data[] = { 0.0625f, 0.125f, 0.0625f, 0.125f, 0.25f, 0.125f,
0.0625f, 0.125f, 0.0625f };
Kernel kernel = new Kernel(3, 3, data);
ConvolveOp convolve = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP,
null);
convolve.filter(biSrc, biDest);
bi = biDest;
public void edgeDetect()
float data[] = { 1.0f, 0.0f, -1.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.0f,
-1.0f };
Kernel kernel = new Kernel(3, 3, data);
ConvolveOp convolve = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP,
null);
convolve.filter(biSrc, biDest);
public void reset()
big.setColor(Color.black);
big.clearRect(0, 0, bi.getWidth(this), bi.getHeight(this));
big.drawImage(displayImage, 0, 0, this);
bi = biSrc;
public void update(Graphics g)
g.clearRect(0, 0, getWidth(), getHeight());
paintComponent(g);
I have only heard of people using JLabels to accomplish this. I recommend displaying the BufferedImage as the background of the JLabel. When the user applies an edit to the image, edit the image (If you don't already have a library for manipulating images, I strongly recommend imgscalr) and reapply it as the background of the JLabel (if it doesn't automatically update).
/* Arpana*/
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.TitledBorder;
public class ConvolveApp extends JFrame {
CPanel displayPanel;
JButton sharpenButton, blurringButton, edButton, resetButton;
public ConvolveApp() {
super();
Container container = getContentPane();
displayPanel = new CPanel();
container.add(displayPanel);
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(2, 2));
panel
.setBorder(new TitledBorder(
"Click a Button to Perform the Associated Operation and Reset..."));
sharpenButton = new JButton("Sharpen");
sharpenButton.addActionListener(new ButtonListener());
blurringButton = new JButton("Blur");
blurringButton.addActionListener(new ButtonListener());
edButton = new JButton("Edge Detect");
edButton.addActionListener(new ButtonListener());
resetButton = new JButton("Reset");
resetButton.addActionListener(new ButtonListener());
panel.add(sharpenButton);
panel.add(blurringButton);
panel.add(edButton);
panel.add(resetButton);
container.add(BorderLayout.SOUTH, panel);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
setSize(displayPanel.getWidth(), displayPanel.getHeight() + 10);
setVisible(true);
}
public static void main(String arg[]) {
new ConvolveApp();
}
class ButtonListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
JButton button = (JButton) e.getSource();
if (button.equals(sharpenButton)) {
displayPanel.sharpen();
displayPanel.repaint();
} else if (button.equals(blurringButton)) {
displayPanel.blur();
displayPanel.repaint();
} else if (button.equals(edButton)) {
displayPanel.edgeDetect();
displayPanel.repaint();
} else if (button.equals(resetButton)) {
displayPanel.reset();
displayPanel.repaint();
}
}
}
}
class CPanel extends JLabel {
Image displayImage;
BufferedImage biSrc;
BufferedImage biDest; // Destination image is mandetory.
BufferedImage bi; // Only an additional reference.
Graphics2D big;
CPanel() {
setBackground(Color.black);
loadImage();
setSize(displayImage.getWidth(this), displayImage.getWidth(this));
createBufferedImages();
bi = biSrc;
}
public void loadImage() {
displayImage = Toolkit.getDefaultToolkit().getImage("Arpana.jpg");
MediaTracker mt = new MediaTracker(this);
mt.addImage(displayImage, 1);
try {
mt.waitForAll();
} catch (Exception e) {
System.out.println("Exception while loading.");
}
if (displayImage.getWidth(this) == -1) {
System.out.println("No jpg file");
System.exit(0);
}
}
public void createBufferedImages() {
biSrc = new BufferedImage(displayImage.getWidth(this), displayImage
.getHeight(this), BufferedImage.TYPE_INT_RGB);
big = biSrc.createGraphics();
big.drawImage(displayImage, 0, 0, this);
biDest = new BufferedImage(displayImage.getWidth(this), displayImage
.getHeight(this), BufferedImage.TYPE_INT_RGB);
}
public void sharpen() {
float data[] = { -1.0f, -1.0f, -1.0f, -1.0f, 9.0f, -1.0f, -1.0f, -1.0f,
-1.0f };
Kernel kernel = new Kernel(3, 3, data);
ConvolveOp convolve = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP,
null);
convolve.filter(biSrc, biDest);
bi = biDest;
}
public void blur() {
float data[] = { 0.0625f, 0.125f, 0.0625f, 0.125f, 0.25f, 0.125f,
0.0625f, 0.125f, 0.0625f };
Kernel kernel = new Kernel(3, 3, data);
ConvolveOp convolve = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP,
null);
convolve.filter(biSrc, biDest);
bi = biDest;
}
public void edgeDetect() {
float data[] = { 1.0f, 0.0f, -1.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.0f,
-1.0f };
Kernel kernel = new Kernel(3, 3, data);
ConvolveOp convolve = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP,
null);
convolve.filter(biSrc, biDest);
bi = biDest;
}
public void reset() {
big.setColor(Color.black);
big.clearRect(0, 0, bi.getWidth(this), bi.getHeight(this));
big.drawImage(displayImage, 0, 0, this);
bi = biSrc;
}
public void update(Graphics g) {
g.clearRect(0, 0, getWidth(), getHeight());
paintComponent(g);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g;
g2D.drawImage(bi, 0, 0, this);
}
}

Stretch a JLabel text

Is there a way to make a JLabel's text stretch to 100% height? I need the text to update when the component's size changes as well.
I saw some solution that could work; It involved calculating and setting the font size so it appears the right height. I would have also have to add listeners for when the height changed to make it respond and I do not know exactly where I should do that.
I am hoping for a better solution with layout managers, but couldn't find anything.
Any ideas?
In the approach shown below, the desired text is imaged using TextLayout using a suitably large Font size and scaled to fill the component. There's a related example here.
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JLabel;
/** #see https://stackoverflow.com/questions/8281886 */
public class LayoutTest extends JLabel {
private static final int SIZE = 256;
private BufferedImage image;
private LayoutTest(String string) {
super(string);
image = createImage(super.getText());
}
#Override
public void setText(String text) {
super.setText(text);
image = createImage(super.getText());
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(image.getWidth() / 2, image.getHeight() / 2);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
}
private BufferedImage createImage(String label) {
Font font = new Font(Font.SERIF, Font.PLAIN, SIZE);
FontRenderContext frc = new FontRenderContext(null, true, true);
TextLayout layout = new TextLayout(label, font, frc);
Rectangle r = layout.getPixelBounds(null, 0, 0);
System.out.println(r);
BufferedImage bi = new BufferedImage(
r.width + 1, r.height + 1, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) bi.getGraphics();
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(getBackground());
g2d.fillRect(0, 0, bi.getWidth(), bi.getHeight());
g2d.setColor(getForeground());
layout.draw(g2d, 0, -r.y);
g2d.dispose();
return bi;
}
private static void display() {
JFrame f = new JFrame("LayoutTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new LayoutTest("Sample"));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
display();
}
});
}
}

Java - Draw text in the center of an image

I need to write text in the center of an image. The text to write is not always the same.
The code I'm using is here:
// Here I first draw the image
g.drawImage(img, 22, 15, 280, 225, null);
// I get the text
String text = photoText.getText();
// Set the text color to black
g.setColor(Color.black);
// I draw the string
g.drawString(text, 79.5F, 220.0F);
The problem is that the text isn't at the center of the image, what can I do?
I only need to draw the text at the horizontal center.
Using a JLabel is less work, but FontMetrics, shown here, will let you manage the geometry directly.
One possible solution: draw the image in a JPanel, being sure to set the panel's preferredsize as the size of the image, have the JPanel use a GridBagLayout, and place the text in a JLabel that is added to the JPanel, without GridBagConstraints. This is one way to center the JLabel in the JPanel.
The easy way is to use a JLabel with an Icon and Text. Then set the horizontal/vertical text position to CENTER and the text is painted in the center of the image.
From your code it looks like you are trying to paint the text near the bottom of the image. In this case you can use the JLabel with an Icon as a container. Then you can set the layout to something like a BoxLayout and add another label with the text.
No custom painting is required for either approach.
import java.awt.*;
import javax.swing.*;
import javax.swing.text.*;
public class LabelImageText extends JPanel
{
public LabelImageText()
{
JLabel label1 = new JLabel( new ColorIcon(Color.ORANGE, 100, 100) );
label1.setText( "Easy Way" );
label1.setHorizontalTextPosition(JLabel.CENTER);
label1.setVerticalTextPosition(JLabel.CENTER);
add( label1 );
//
JLabel label2 = new JLabel( new ColorIcon(Color.YELLOW, 200, 150) );
label2.setLayout( new BoxLayout(label2, BoxLayout.Y_AXIS) );
add( label2 );
JLabel text = new JLabel( "More Control" );
text.setAlignmentX(JLabel.CENTER_ALIGNMENT);
label2.add( Box.createVerticalGlue() );
label2.add( text );
label2.add( Box.createVerticalStrut(10) );
//
JLabel label3 = new JLabel( new ColorIcon(Color.GREEN, 200, 150) );
add( label3 );
JLabel text3 = new JLabel();
text3.setText("<html><center>Text<br>over<br>Image<center></html>");
text3.setLocation(20, 20);
text3.setSize(text3.getPreferredSize());
label3.add( text3 );
//
JLabel label4 = new JLabel( new ColorIcon(Color.CYAN, 200, 150) );
add( label4 );
JTextPane textPane = new JTextPane();
textPane.setText("Add some text that will wrap at your preferred width");
textPane.setEditable( false );
textPane.setOpaque(false);
SimpleAttributeSet center = new SimpleAttributeSet();
StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER);
StyledDocument doc = textPane.getStyledDocument();
doc.setParagraphAttributes(0, doc.getLength(), center, false);
textPane.setBounds(20, 20, 75, 100);
label4.add( textPane );
}
public static class ColorIcon implements Icon
{
private Color color;
private int width;
private int height;
public ColorIcon(Color color, int width, int height)
{
this.color = color;
this.width = width;
this.height = height;
}
public int getIconWidth()
{
return width;
}
public int getIconHeight()
{
return height;
}
public void paintIcon(Component c, Graphics g, int x, int y)
{
g.setColor(color);
g.fillRect(x, y, width, height);
}
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("LabelImageText");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new LabelImageText() );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
I mean I have to write a text in the center of the image and then save the image
You can use Screen Image to create an image of any component. This assumes you are displaying the image and text on a GUI.
Or, if you are talking about just reading in an image adding text to the image and then saving the image, then you will need to create a BufferedImage and draw the image on it and then draw the text on it. You will need to use the FontMetrics class as mentioned by Trashgod. My suggestion won't help.
I used TextLayout to get the text properly centered:
Here's how to create the image and save it as a file:
int imgWidth = 250;
int imgHeight = 250;
var img = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g = img.createGraphics();
var backgroundColor = new Color(0, 150, 100);
g.setPaint(backgroundColor);
g.fillRect(0, 0, imgWidth, imgHeight);
var font = new Font("Arial", Font.PLAIN, 80);
g.setFont(font);
g.setPaint(Color.WHITE);
String text = "0";
var textLayout = new TextLayout(text, g.getFont(), g.getFontRenderContext());
double textHeight = textLayout.getBounds().getHeight();
double textWidth = textLayout.getBounds().getWidth();
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
// Draw the text in the center of the image
g.drawString(text, imgWidth / 2 - (int) textWidth / 2,
imgHeight / 2 + (int) textHeight / 2);
String imgFormat = "png";
ImageIO.write(img, imgFormat, new File("/home/me/new_image." + imgFormat));

Categories

Resources