问题
I looked at java.awt.Graphics documentation, stackoverflow, could not find a solution. I have in input two things, an image file and the multi line text (paragraph). I need to write the multi line text on the image file and then save it as a new image. Wondering if I am missing something really simple here. I am open to using any good third party libraries as well.
final BufferedImage image = ImageIO.read(new File("c:/anil/Lenna.png"));
Graphics g = image.getGraphics();
g.setFont(g.getFont().deriveFont(30f));
g.drawString("Hello world", 100, 100);
g.dispose();
Above code writes just a single line on the image.
回答1:
if you want to draw several lines you have to do it explicitly...
so first step is to 'detect' lines
String str = ... //some text with line breaks;
String [] lines = str.spilt("\n"); //breaking the lines into an array
second step is to draw all lines
Graphics g = image.getGraphics();
g.setFont(g.getFont().deriveFont(30f));
int lineHeight = g.getFontMetrics().getHeight();
//here comes the iteration over all lines
for(int lineCount = 0; lineCount < lines.length; lineCount ++){ //lines from above
int xPos = 100;
int yPos = 100 + lineCount * lineHeight;
String line = lines[lineCount];
g.drawString(line, xpos, yPos);
}
g.dispose();
回答2:
JLabel accepts simple html to format text. Then you can paint it on your image:
JLabel l=new JLabel("<html>line1<br>line2");
l.setSize(l.getPrefferedSize());
g.translate(10,10); // fixed location
l.paint(g);
edit: complete example
public class OP_32110247 extends JPanel {
private final JLabel l = new JLabel();
private final BufferedImage image;
public OP_32110247(String imgfile, String txt) throws IOException {
image = ImageIO.read(new URL(imgfile));
l.setText(txt);
l.setFont(getFont().deriveFont(Font.BOLD,30f));
l.setSize(l.getPreferredSize());
l.setForeground(Color.GREEN);
Dimension d = new Dimension(image.getWidth(), image.getHeight());
setPreferredSize(d);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Dimension d = getSize();
g.drawImage(image, 0, 0, null);
//place text in center of image
g.translate((d.width-l.getWidth())/2, (d.height-l.getHeight())/2);
l.paint(g);
}
public static void main(String[] args) throws IOException {
String txt = "<html>line1<br>line2";
String image = "http://kysoft.pl/proj/java/j+c.png";
JFrame f = new JFrame();
f.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
f.setContentPane(new OP_32110247(image,txt));
f.pack();
f.setVisible(true);
}
}
回答3:
The best solution is to extend JLabel and override paintComponent. Create the Label with the image required. After calling super.paintComponent draw your text, each line positioning below another using the font metrics. Something like below:
class ImageWithTextLabel extends JLabel {
List<String> lines = new ArrayList<>();
Point textPosition = new Point(0,0);
private Font textFont;
private ImageWithTextLabel(Icon image) {
super(image);
}
public void addText(String text) {
lines.add(text);
}
public void setTextPosition(Point textPosition) {
this.textPosition = textPosition;
}
@Override protected void paintComponent(Graphics g) {
super.paintComponent(g);
int from = textPosition.y ;
g.setFont(textFont);
for (String line : lines) {
g.drawString(line, textPosition.x, from);
from += g.getFontMetrics().getHeight();
}
}
public void setTextFont(Font font) {
textFont = font;
}
}
回答4:
see Drawing Multiple Lines of Text(Oracle Java Tutorials) and complete code use LineBreakMeasurer:
int width = 400;
int height = 500;
BufferedImage bufferedImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = bufferedImage.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setColor(Color.MAGENTA);
Hashtable<TextAttribute,Object> map = new Hashtable<TextAttribute,Object>();
map.put(TextAttribute.FAMILY, "微软雅黑");
map.put(TextAttribute.SIZE,new Float(18.0));
AttributedString vanGogh = new AttributedString(
"Many people 中国 believe that Vincent van Gogh painted his best works " +
"during the two-year period he spent in Provence. Here is where he " +
"painted The Starry Night--which some consider to be his greatest " +
"work of all. However, as his artistic brilliance reached new " +
"heights in Provence, his physical and mental health plummeted. ",
map);
AttributedCharacterIterator paragraph = vanGogh.getIterator();
int paragraphStart = paragraph.getBeginIndex();
int paragraphEnd = paragraph.getEndIndex();
FontRenderContext frc = g2d.getFontRenderContext();
LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(paragraph, frc);
float breakWidth = 250f;
float drawPosY = 20;
float drawPosx = 0f;
lineMeasurer.setPosition(paragraphStart);
while(lineMeasurer.getPosition()< paragraphEnd ){
TextLayout layout = lineMeasurer.nextLayout(breakWidth);
drawPosx = layout.isLeftToRight()?0:breakWidth-layout.getAdvance();
drawPosY += layout.getAscent();
layout.draw(g2d,drawPosx,drawPosY);
drawPosY += layout.getDescent() + layout.getLeading();
}
g2d.dispose();
File file = new File("myimage.png");
ImageIO.write(bufferedImage,"png",file);
file = new File("myimage.jpg");
ImageIO.write(bufferedImage,"jpg",file);
来源:https://stackoverflow.com/questions/32110247/write-multi-line-text-on-an-image-using-java