import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
//如果没有使用lombok,请删除注解,执行实现构造方法和getter,setter
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Watermark implements Serializable {
private String color = "#c7d4df";//"#e4ebf0";
private Integer width = 200;
private Integer height = 200;
private String order;//顺序
private String oa;
private String username;
private String telSuffix;//手机尾号
private Integer fontSize = 20;
private String fontFamily="microsoft-yahei";
private Integer lineGap = 20;//水印图片中每行字符串的间隔
private Float alpha=1.0f;//透明度
}
//生成背景透明的水印图片
import java.awt.*;
import java.awt.image.BufferedImage;
public class FontImage {
public static boolean isEmpty(String str) {
return (str == null || str.length() == 0);
}
public static BufferedImage buildWatermarkImage(Watermark watermark) {
String oa = watermark.getOa();
String username = watermark.getUsername();
String telSuffix = watermark.getTelSuffix();
telSuffix = isEmpty(telSuffix) ? "" : telSuffix;//为null的话,置为空串
String longerString = oa.length() > username.length() ? oa : username;
if (longerString.length() < telSuffix.length()) {
longerString = telSuffix;
}
int defaultSize = watermark.getFontSize();
Font font = new Font(watermark.getFontFamily(), Font.PLAIN, defaultSize);
BufferedImage image = new BufferedImage(watermark.getWidth(), watermark.getHeight(), BufferedImage.TYPE_INT_ARGB);
// background transparent start
Graphics2D g = image.createGraphics();
image = g.getDeviceConfiguration().createCompatibleImage(watermark.getWidth(), watermark.getHeight(), Transparency.TRANSLUCENT);//Transparency.TRANSLUCENT
g.dispose();
// background transparent end
g = image.createGraphics();
Color color = new Color(Integer.parseInt(watermark.getColor().substring(1), 16));
g.setColor(new Color(color.getRed(),color.getGreen() ,color.getBlue() , new Float(255*watermark.getAlpha()).intValue()));
g.setFont(font);// Set pen font
int stringWidth = g.getFontMetrics(font).stringWidth(longerString);
int size = defaultSize;
//自动根据水印大小调节字体大小
while (stringWidth > watermark.getWidth() && size >= 10) {
size -= 1;
font = new Font(watermark.getFontFamily(), Font.PLAIN, size);
g.setFont(font);// Set pen font
stringWidth = g.getFontMetrics(font).stringWidth(longerString);
}
g.shear(0.1, -0.6);// set the tilt
// Set font smoothing
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int y = watermark.getHeight() / 3 * 2;
String order = watermark.getOrder();
order = isEmpty(order) ? "out" : order;
int lineGap = watermark.getLineGap();
//顺序:o=oa,u=username,t=telsuffix
for (int i = 0; i < order.length(); i++) {
String chars = "";
switch (order.charAt(i)) {
case 'o':
chars += oa;
break;
case 'u':
chars += username;
break;
case 't':
chars += telSuffix;
break;
}
//align center
int iStringWidth = g.getFontMetrics(font).stringWidth(chars);
int x = watermark.getWidth() / 2 - iStringWidth / 2 - 10;
g.drawString(chars, x, y);// draw a string
y = y + (lineGap>0?lineGap:font.getSize());
chars = "";
}
g.dispose();// Release the brush
return image;
}
}
//处理前端请求(这里省略Service,将逻辑放到controller)
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
@Controller
public class WatermarkController{
/**
* @param oa oa账户,以此获得账户名和手机尾号
* @param w 水印宽度
* @param h 水印高度
* @param hexColor 十六进制颜色
* @param order 顺序,用oa,username, tel首字母(o,u,t)排列(可重复)
* @param response
*/
@RequestMapping(value = "/wk_image", method = RequestMethod.GET, produces = MediaType.IMAGE_PNG_VALUE)
public void image(String oa, String w, String h, String hexColor,String fontSize ,String fontFamily,String lineGap,String alpha, String order, HttpServletResponse response) {
if (FontImage.isEmpty(oa)) {
//自行处理异常
}
{
//TODO 可以考虑将图像文件放到缓存里面,每次根据oa,从缓存里面获取
}
try (ServletOutputStream outputStream = response.getOutputStream()) {//这样写可以自动关闭流
Watermark watermark = new Watermark();
watermark.setOa(oa);
watermark.setTelSuffix("测试账户名");//只要4位尾号,或者是加密的11位
watermark.setUsername("1234");
if (!FontImage.isEmpty(w) && w.matches("\\d+")) {
watermark.setWidth(Integer.parseInt(w));
}
if (!FontImage.isEmpty(h) && h.matches("\\d+")) {
watermark.setHeight(Integer.parseInt(h));
}
if (!FontImage.isEmpty(fontSize) && fontSize.matches("\\d+")) {
watermark.setFontSize(Integer.parseInt(fontSize));
}
if (!FontImage.isEmpty(lineGap) && lineGap.matches("\\d+")) {
watermark.setLineGap(Integer.parseInt(lineGap));
}
if (!FontImage.isEmpty(alpha) && alpha.matches("\\d+(\\.\\d*)?")) {
watermark.setAlpha(Math.min(Float.parseFloat(alpha), 1.0f));
}
if (!FontImage.isEmpty(hexColor)) {
watermark.setColor("#"+hexColor);
}
if (!FontImage.isEmpty(order)) {
watermark.setOrder(order);
}
if (!FontImage.isEmpty(fontFamily)) {
watermark.setFontFamily(fontFamily);
}
BufferedImage bufferedImage = FontImage.buildWatermarkImage(watermark);
ImageIO.write(bufferedImage, "png", outputStream);
} catch (Exception e) {
e.printStackTrace();
}
}
}
效果图: