Write multi line text on an image using Java

风流意气都作罢 提交于 2019-12-20 07:17:13

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!