Saturday, March 17, 2012

Diagonal Watermarks with Java

I just had the pleasure of needing to add some watermarks to some images from one of our applications, and I soon realized that Java2D is not my specialty. So I went on to search for some code on how to add watermarks with Java and I found plenty, but I couldn't find anything on how to rotate the text in order to produce those diagonal watermarks that you see on most word processors.

So I finally started to understand a bit more about transforms and how they add up to each other and then devise a plan of how to actually accomplish the task.

So for those of you who might be struggling with the same issue, I am posting up my code. Please feel free to comment or improve on it.


import java.io.*;
import java.awt.*;
import java.awt.image.*;
import javax.imageio.*;
import javax.swing.ImageIcon;

import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;

public class CreateWatermark {
public static void main(String[] args) {
CreateWatermark cw = new CreateWatermark();
cw.create(args[0]);
}

public void create(String filename) {
try {
File file = new File(filename);
if (!file.exists()) {
System.out.println("Can't find file " + filename);
return;
}

// We want to draw our watermark diagonally rotated across the center from
//bottom to top like Word processors do
String watermark = "Licensed for Evaluation Purpose Only";
ImageIcon photo = new ImageIcon(filename);

BufferedImage bufferedImage = new BufferedImage(photo.getIconWidth(),
photo.getIconHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D)bufferedImage.getGraphics();
g2d.drawImage(photo.getImage(), 0, 0, null);

//Create an alpha composite of 50%
AlphaComposite alpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f);
g2d.setComposite(alpha);

g2d.setColor(Color.white);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

Font f1 = new Font("Arial", Font.BOLD, 24);
g2d.setFont(f1);

FontMetrics fontMetrics = g2d.getFontMetrics();
Rectangle2D rect = fontMetrics.getStringBounds(watermark, g2d);

// Move our origin to the center
g2d.translate(photo.getIconWidth() / 2.0f, photo.getIconHeight() / 2.0f);

// Create a rotation transform to rotate the text based on the diagonal
// angle of the picture aspect ratio
AffineTransform at2 = new AffineTransform();
double opad = photo.getIconHeight() / (double)photo.getIconWidth();
double angle = Math.toDegrees(Math.atan(opad));
double idegrees = -1 * angle;
double theta = (2 * Math.PI * idegrees) / 360;
at2.rotate(theta);
g2d.transform(at2);

//Now reposition our coordinates based on size (same as we would normally
//do to center on straight line but based on starting at center
float x1 = (int)rect.getWidth() / 2.0f *-1;
float y1 = (int)rect.getHeight() / 2.0f;
g2d.translate(x1, y1);

//finally let's draw the string
g2d.drawString(watermark, 0.0f, 0.0f);

//Free graphic resources
g2d.dispose();

//Write the image as a jpg
FileOutputStream fos = new FileOutputStream(new File("myfile.jpg"));
OutputStream out = new BufferedOutputStream(fos);
ImageIO.write(bufferedImage, "jpg", out);
out.flush();
out.close();
}
catch (IOException ioe) {
ioe.printStackTrace();
}
}
}