@如何给图片添加文字水印??????
思路:将文字生成一张图片,再将该图片作为水印覆盖到源文件
网上:关于直接添加文字水印的方法,试了很多种无论怎么调试,都会因为文字的长度导致水印排版异常,只适合添加固定长度的文字水印,并不适合拓展延伸。
代码直接粘贴如下:
//可能引用的包
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
//代码
/**
* 生成背景透明的文字水印,文字位于透明区域正中央,可设置旋转角度
* @param word 水印文字
* @param color 颜色
* @param path 文字转水印后的文件地址
* @param degree 水印文字旋转角度
* @param alpha 水印不透明度0f-1.0f
*/
public static String createWordImage(String word, String path, Color color, Double degree, float alpha) throws IOException {
File outFile = new File(path);
Font font = new Font("微软雅黑", Font.PLAIN, 350);
//设置一个分辨率高的画布,分辨率低了,生成水印覆盖到源文件上时会出现锯齿状,无法通过设置去除锯齿边缘。
int width = 2550; //画布宽
int height = 690; //画布高
//1,创建画布 生成像素 2550*690 像素高一点避免出现生成的图会有锯齿状
BufferedImage buffImg = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
/**2,得到画笔对象*/
Graphics2D g2d = buffImg.createGraphics();
// ---------- 增加下面的代码使得背景透明 -----------------
buffImg = g2d.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
g2d.dispose();
g2d = buffImg.createGraphics();
// ---------- 背景透明代码结束 -----------------
// 设置对线段的锯齿状边缘处理 这里设置作用不大,只有画布分辨率高,才能解决锯齿状
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
// 设置水印旋转
if (null != degree) {
//注意rotate函数参数theta,为弧度制,故需用Math.toRadians转换一下 以矩形区域中央为圆心旋转
g2d.rotate(Math.toRadians(degree), (double) buffImg.getWidth() / 2, (double) buffImg.getHeight() / 2);
}
// 设置颜色
g2d.setColor(color);
// 设置 Font
g2d.setFont(font);
//设置透明度:1.0f为透明度 ,值从0-1.0,依次变得不透明
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
//获取真实宽度
float realWidth = getRealFontWidth(word);
float fontSize = font.getSize();
//计算绘图偏移x、y,使得使得水印文字在图片中居中 这里需要理解x、y坐标是基于Graphics2D.rotate过后的坐标系
float x = 0.5f * width - 0.5f * fontSize * realWidth;
float y = 0.5f * height + 0.5f * fontSize;
//取绘制的字串宽度、高度中间点进行偏移,使得文字在图片坐标中居中
g2d.drawString(word, x, y);
//释放资源
g2d.dispose();
if (outFile != null) {
//输出png图片到指定目录
ImageIO.write(buffImg, "png", outFile);
}
//返回数据流
ByteArrayOutputStream out = new ByteArrayOutputStream();
boolean flag = ImageIO.write(buffImg, "png", out);
if (flag) {
return path;
}
return null;
}
/**
* 获取真实字符串宽度,ascii字符占用0.5,中文字符占用1.0
*/
private static float getRealFontWidth(String text) {
int len = text.length();
float width = 0f;
for (int i = 0; i < len; i++) {
if (text.charAt(i) < 256) {
width += 0.5f;
} else {
width += 1.0f;
}
}
return width;
}
//加水印过程
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
String source = "C:\\Users\\Administrator\\Desktop\\11111.jpg"; //要加水印的源文件图片
String imageType = "png"; //图片类型jpg,jpeg,png,gif
String imageName = System.currentTimeMillis() + "IMG_603222" + "." + imageType; //生成的图片名称
String output = "D:\\photo\\" + imageName + imageType; //保存地址
String word = "文字水印"; //文字长度暂无限制,可根据实际情况自行测试调整
String newicon = "D:\\photo\\newlogo.png"; //组合生成后的logo图路劲
Integer degree = null; //水印旋转角度-45,null表示不旋转
//生成文字水印
String logo = createWordImage(text, output + System.currentTimeMillis() + ".png", Color.BLACK, null, 0.1f);
//加水印
String url = markImageByMoreLogo(logo, newicon, new File(source), output, degree);
System.out.println("加水印后文件地址:" + url);
}
/**
* @Description : 平铺水印,根据水印设置的不同方式展示效果
* @param: [
* logo:原水印文件地址
* , newicon:覆盖水印后的地址
* , source:要加水印的源文件
* , output:图片存储地址
* , outArtwork:输出地址
* , imageName:图片名称
* , imageType:图片类型
* , degree:水印旋转角度,null表示不旋转
* , logoNum:水印的设置展示方式,目前有5种样式效果
* ]
*/
public static String markImageByMoreLogo(String logo, String newicon, File source, String output, Integer degree) {
try {
if (!source.isFile()) {
return source + " 不是一个图片文件!";
}
//将源图片读到内存中
Image img = ImageIO.read(source);
//图片宽
int width = img.getWidth(null);
//图片高
int height = img.getHeight(null);
//调整水印宽度
ImageWaterMarkUtil.resizeImage(logo, newicon, (int) (width / 3.5));
//将logo读到内存中
File ficon = new File(newicon);
//将icon加载到内存中
Image ic = ImageIO.read(ficon);
//icon高度
int icheight = ic.getHeight(null);
//icon宽度
int icwidth = ic.getWidth(null);
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
//创建一个指定 BufferedImage 的 Graphics2D 对象
Graphics2D g = bi.createGraphics();
//水印宽度 水印宽度 = 2(图片宽度)/(3logoNum + 1)
int temp2 = icwidth;
//水印间隔 水印宽度/2
// int space2 = icwidth / 2;
//默认两张水印图片的 间隔高度 是水印的高度的2倍
int temp = 2 * icheight;
//水印高个数
int space = height / 3 / icheight;
//初始化图片位置
int x = 0;
int y = icheight;
//设置对线段的锯齿状边缘处理
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
//呈现一个图像,在绘制前进行从图像空间到用户空间的转换
g.drawImage(img.getScaledInstance(width, height, Image.SCALE_SMOOTH), 0, 0, null);
//透明度,最小值为0,最大值为1
float clarity;
for (int i = 0; i < space; i++) {
//水印图象的地址 水印一般为gif或者png的,这样可设置透明度
ImageIcon imgIcon = new ImageIcon(newicon);
//得到Image对象。
Image con = imgIcon.getImage();
//透明度,最小值为0,最大值为1
clarity = 1f;
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, clarity));
//表示水印图片的坐标位置(x,y)
//g.drawImage(con, 300, 220, null);
x = icwidth / 2;
if (null != degree) {
//设置水印旋转
g.rotate(Math.toRadians(degree), (double) x + icwidth / 2, (double) y + icheight / 2);
}
//给图片横向加水印
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, clarity));
//表示水印图片的坐标位置(x,y)
g.drawImage(con, x, y, null);
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
if (null != degree) {
//设置水印旋转
g.rotate(Math.toRadians(-degree), (double) x + icwidth / 2, (double) y + icheight / 2);
}
x += 3 * temp2 / 2;
y += (icheight + temp);
//给图片纵向加水印
g.drawImage(con, x, y, null);
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
}
g.dispose();
//保存原图
try {
// 输出 文件 到指定的地址
FileOutputStream out = new FileOutputStream(output);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bi);
param.setQuality(1, true);
encoder.encode(bi, param);
out.close();
} catch (Exception e) {
e.printStackTrace();
}
ficon.delete();
} catch (Exception e) {
e.printStackTrace();
}
return output;
}
/**
* 修改logo的像素
* @param srcPath 源图片地址
* @param desPath 修改大小后图片地址
* @param scaleSize 图片的修改比例,目标宽度
*/
public static void resizeImage(String srcPath, String desPath, int scaleSize) throws IOException {
File srcFile = new File(srcPath);
Image srcImg = ImageIO.read(srcFile);
BufferedImage bi = null;
try {
bi = ImageIO.read(srcFile);
} catch (Exception e) {
e.printStackTrace();
}
float width = bi.getWidth(); // 像素
float height = bi.getHeight(); // 像素
float scale = width / scaleSize;
BufferedImage buffImg = null;
buffImg = new BufferedImage(scaleSize, (int) (height / scale),
BufferedImage.TYPE_INT_RGB);
//保持Png图片的透明背景属性
Graphics2D g = buffImg.createGraphics();
buffImg = g.getDeviceConfiguration().createCompatibleImage(scaleSize, (int) (height / scale), Transparency.TRANSLUCENT);
g = buffImg.createGraphics();
//使用TYPE_INT_RGB修改的图片会变色
buffImg.getGraphics().drawImage(
srcImg.getScaledInstance(scaleSize, (int) (height / scale), Image.SCALE_SMOOTH), 0,
0, null);
//压缩保存
//boolean ff=ImageIO.write(buffImg, "PNG", new File(desPath));
// 输出 文件 到指定的地址
FileOutputStream out = new FileOutputStream(desPath);
try {
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(buffImg);
param.setQuality(1, true);
encoder.encode(buffImg, param);
out.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
out.close();
}
}
// 给图片加文字水印,结束。
//给视频加水印的方式建议先用文字生成图片。