Search code examples
javaawtbufferedimagegraphics2djavax.imageio

Java Graphics2D drawString is "blacking out" the source image


Java 8 and Mac OS (High Sierra) here. I have the following class TextOverlayer that reads an image off the file system and needs to overlay some red text onto the image, and then save that "overlayed" image as a different file on the file system:

public class TextOverlayer implements ImageObserver {

  public static void main(String[] args) throws IOException {

      // Instantiate a TextOverlayer and read a source/input image from disk
      TextOverlayer textOverlayer = new TextOverlayer();
      BufferedImage bufferedImage = ImageIO.read(Paths.get("/User/myuser/pix/sourceImage.jpg").toFile());

      // Lay some text over the image at specific coordinates
      BufferedImage drawn = textOverlayer.drawText(bufferedImage, "Some text");

      // Write the overlayed image to disk
      File outputfile = new File("/User/myuser/pix/targetImage.jpg");
      ImageIO.write(drawn, "jpg", outputfile);

  }

  private BufferedImage drawText(BufferedImage old, String text) {

      int w = old.getWidth() / 3;
      int h = old.getHeight() / 3;
      BufferedImage img = new BufferedImage(
              w, h, BufferedImage.TYPE_INT_ARGB);
      Graphics2D g2d = img.createGraphics();
      g2d.drawImage(old, 0, 0, w, h, this);
      g2d.setPaint(Color.red);
      g2d.setFont(new Font("Serif", Font.BOLD, 20));
      FontMetrics fm = g2d.getFontMetrics();
      int x = img.getWidth() - fm.stringWidth(text) - 5;
      int y = fm.getHeight();
      g2d.drawString(text, x, y);
      g2d.dispose();

      return img;

  }

  @Override
  public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
      return false;
  }

}

When this runs, no errors are thrown and the targetImage.jpg is successfully written to disk, except its just an image of a small black box. I would have expected targetImage.jpg to be the exact same as sourceImage.jpg, just with some extra text added to it at the desired coordinates (within the image).

Any ideas where I'm going awry?


Solution

  • You don't need the ImageObserver and you likely can't write an image with an alpha channel to a JPEG file with the included writers.

    This works:

    public class TextOverlayer {
    
        public static void main(String[] args) throws IOException {
    
            // Instantiate a TextOverlayer and read a source/input image from disk
            TextOverlayer textOverlayer = new TextOverlayer();
            BufferedImage bufferedImage = ImageIO.read(Paths.get("/User/myuser/pix/sourceImage.jpg").toFile());
    
            // Lay some text over the image at specific coordinates
            BufferedImage drawn = textOverlayer.drawText(bufferedImage, "Some text");
    
            // Write the overlayed image to disk
            File outputfile = new File("/User/myuser/pix/targetImage.jpg");
            boolean result = ImageIO.write(drawn, "jpg", outputfile);
            if (!result) {
                System.out.println("FAILED");
            }
        }
    
        private BufferedImage drawText(BufferedImage old, String text) {
    
            int w = old.getWidth();
            int h = old.getHeight();
            BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
            Graphics2D g2d = img.createGraphics();
            g2d.drawImage(old, 0, 0, w, h, null);
            g2d.setPaint(Color.red);
            g2d.setFont(new Font("Serif", Font.BOLD, 20));
            FontMetrics fm = g2d.getFontMetrics();
            int x = img.getWidth() - fm.stringWidth(text) - 5;
            int y = fm.getHeight();
            g2d.drawString(text, x, y);
            g2d.dispose();
    
            return img;
    
        }
    }