1

I've got a method that's supposed to add some text to screenshots. The screenshot is fed into this method as a File object like this:

private void modifyScreenshot(File file) throws Exception {

    String textToAdd = "Something something";

    BufferedImage image = ImageIO.read(file);

    Graphics g = image.getGraphics();

At this point, adding the text via g.drawString is easy to do. However, I want the text to not cover any of the actual screenshot, but be in a white area "above" the screenshot.

What I mean is, at this point, this is what the Graphics object looks like when it gets saved to file:

enter image description here

However, I want it to look like this instead, with the "Some text some text" being the string I specify in the code.

enter image description here

So, how would I be able to add white rectangle above the image where the text can be written?

EDIT: Note, this is not simply adding a string to an image. This involves "enlarging" the canvas to have white space for the string, so that the string is not over the actual image.

Andrio
  • 1,852
  • 2
  • 25
  • 54
  • have you tried composing your text and image into a new image (and its graphics object)? – BeyelerStudios Jun 11 '15 at 15:57
  • related http://stackoverflow.com/questions/2658554/using-graphics2d-to-overlay-text-on-a-bufferedimage-and-return-a-bufferedimage/2658663#2658663 – Madhawa Priyashantha Jun 11 '15 at 15:58
  • I wouldn't consider this as a duplicate of the linked question. Here, there should be a title added (this means that, e.g. the target image has to be made larger (how much? See my answer...)). I'd vote for reopen (if I couldn't reopen it just so...) – Marco13 Jun 17 '15 at 22:21

2 Answers2

3

Here's the rough idea:

BufferedImage image = ImageIO.read(file);
int whiteSpaceHeight = 20;
BufferedImage result = new BufferedImage(image.getWidth(),
      image.getHeight()+whiteSpaceHeight, image.getType());
Graphics graphics = result.getGraphics();
graphics.drawImage(image, 0, whiteSpaceHeight, null);
graphics.drawString(textToAdd, 0, whiteSpaceHeight/2);
Tagir Valeev
  • 97,161
  • 19
  • 222
  • 334
1

(Edit: Answer was rewritten - see history for details)

The task that is indicated in the example image may in fact be a bit tricky: Namely, having multi-line text. But one simple solution here is to use a JLabel and a CellRendererPane for rendering the text, because it also supports HTML. So for a title like

String title = 
    "<html><font size=4>This <font color=#FF0000><b>Text</b></font><br>" +
    "with line breaks<br>" +
    "will be the title</font></html>");

with line breaks and colors and a dedicated font size, one can obtain the appropriate image:

Titled image

Here is an example showing how this may be achieved:

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.imageio.ImageIO;
import javax.swing.CellRendererPane;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

public class TitleAdder
{
    public static void main(String[] args)
    {
        addTitle("yS2aQ.png", "output.png", 
            "<html><font size=4>This <font color=#FF0000><b>Text</b></font><br>" +
            "with line breaks<br>" +
            "will be the title</font></html>");
    }

    private static void addTitle(
        String inputFileName, String outputFileName, String title)
    {
        try (InputStream in = new FileInputStream(inputFileName);
             OutputStream out = new FileOutputStream(outputFileName))
        {
            BufferedImage sourceImage = ImageIO.read(in);
            BufferedImage targetImage = 
                addTitle(sourceImage, title);
            ImageIO.write(targetImage, "png", out);

            // Show the image, for testing
            show(targetImage);
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    private static BufferedImage addTitle(
        BufferedImage sourceImage, String title)
    {
        JLabel label = new JLabel(title);
        label.setBackground(Color.WHITE);
        label.setForeground(Color.BLACK);
        label.setOpaque(true);
        int titleHeight = label.getPreferredSize().height;
        int height = sourceImage.getHeight() + titleHeight;
        BufferedImage targetImage = new BufferedImage(
            sourceImage.getWidth(), height, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = targetImage.createGraphics();
        SwingUtilities.paintComponent(g, label, new CellRendererPane(), 
            0, 0, sourceImage.getWidth(), titleHeight);
        g.drawImage(sourceImage, 0, titleHeight, null);
        g.dispose();

        return targetImage;
    }

    private static void show(final BufferedImage image)
    {
        SwingUtilities.invokeLater(new Runnable()
        {

            @Override
            public void run()
            {
                JFrame f = new JFrame();
                f.getContentPane().add(new JLabel(new ImageIcon(image)));
                f.pack();
                f.setLocationRelativeTo(null);
                f.setVisible(true);
            }
        });
    }
}
Marco13
  • 53,703
  • 9
  • 80
  • 159