Java实现添加文字水印&图片水印的方法详解
作者:全村最野的狗 时间:2023-01-28 08:11:39
为什么要给图片添加水印
为图片添加水印的主要作用是保护图片版权,防止图片被未经授权的人使用或传播。
通常情况下,图片水印会包含图片作者的名字、版权信息或公司商标等信息,这些信息可以帮助识别图片的所有者,并对未经授权的使用进行追究。
此外,图片水印还可以用于提醒人们图片的使用限制,例如是否需要授权、是否可以用于商业用途等。
除此之外,图片水印还可以用于增加图片的视觉吸引力或宣传性,例如可以在图片中添加品牌 logo 或宣传标语等。
总的来说,图片水印的主要作用是保护图片版权和提醒人们图片的使用限制,但也可以用于提升图片的视觉效果和宣传性。
绘制文字水印
为图片添加水印是一种常用的图片处理技术。在 Java 中可以使用 Graphics2D 类来绘制水印。
以下是一个简单的例子,展示了如何在图片的右下角添加一个水印:
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Watermark {
public static void main(String[] args) {
// 读取原图片
BufferedImage image = null;
try {
image = ImageIO.read(new File("original.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
// 获取图片的宽度和高度
int width = image.getWidth();
int height = image.getHeight();
// 创建一个图片缓存对象
BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 获取图片的画笔
Graphics2D g = newImage.createGraphics();
// 将原图片绘制到缓存图片上
g.drawImage(image, 0, 0, width, height, null);
// 设置水印的字体样式
g.setFont(new Font("微软雅黑", Font.BOLD, 20));
// 设置水印的颜色
g.setColor(Color.red);
// 设置水印的位置
g.drawString("Hello World!", width - 120, height - 10);
// 释放图形上下文使用的系统资源
g.dispose();
// 保存带水印的图片
try {
ImageIO.write(newImage, "jpg", new File("watermarked.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
动态计算字符串的宽度
如果你已经知道了字符串的大小(size)和内容(str),想要计算字符串的宽度,可以使用以下方法:
首先创建一个 Font 对象,使用该对象的 getStringBounds 方法计算字符串的宽度。
import java.awt.Font;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
public class StringWidth {
public static void main(String[] args) {
// 字符串内容
String str = "Hello World!";
// 字体大小
int size = 20;
// 创建字体对象
Font font = new Font("微软雅黑", Font.BOLD, size);
// 创建字体渲染上下文
FontRenderContext frc = new FontRenderContext(null, true, true);
// 计算字符串的宽度
Rectangle2D bounds = font.getStringBounds(str, frc);
// 输出字符串的宽度
System.out.println(bounds.getWidth());
}
}
在这段代码中,我们首先创建了一个 Font 对象,然后使用该对象的 getStringBounds 方法计算字符串的宽度。
注意,在调用 getStringBounds 方法时,需要传入一个 FontRenderContext 对象,该对象用于描述字体的渲染环境,可以影响字符串的显示效果。
最后,计算出的字符串宽度是一个 Rectangle2D 对象,你可以使用 getWidth 方法来获取实际的宽度值。
自适应文字水印位置
可以看到,我们添加的水印已经超出了图片的范围,导致显示不完全,出现这种结果的原因是因为我们默认字符的宽度为120px
.您可以通过上面介绍的动态计算字符宽度来让水印始终显示在图片上。
import java.awt.Color;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Watermark {
public static void main(String[] args) {
// 读取原图片
BufferedImage image = null;
try {
image = ImageIO.read(new File("original.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
// 获取图片的宽度和高度
int width = image.getWidth();
int height = image.getHeight();
// 创建一个图片缓存对象
BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 获取图片的画笔
Graphics2D g = newImage.createGraphics();
// 字符串内容
String str = "Hello World!";
// 字体大小
int size = 20;
// 创建字体对象
Font font = new Font("微软雅黑", Font.BOLD, size);
// 创建字体渲染上下文
FontRenderContext frc = new FontRenderContext(null, true, true);
// 计算字符串的宽度和高度
Rectangle2D bounds = font.getStringBounds(str, frc);
// 字符宽度
int strWidth = (int)bounds.getWidth();
// 字符高度
int strHeight = (int)bounds.getHeight();
// 将原图片绘制到缓存图片上
g.drawImage(image, 0, 0, width, height, null);
// 设置水印的字体样式
g.setFont(font);
// 设置水印的颜色
g.setColor(Color.red);
// 设置水印的位置
g.drawString("Hello World!", width - strWidth - 10, height - strHeight - 10);
// 释放图形上下文使用的系统资源
g.dispose();
// 保存带水印的图片
try {
ImageIO.write(newImage, "jpg", new File("watermarked.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
绘制图片水印
如果你想在 png 格式的图片上绘制透明的图片水印,可以使用以下方法:
首先读取原图片和水印图片,然后使用 Graphics2D 类的 drawImage 方法将水印图片绘制到原图片上,最后使用 setComposite 方法设置水印图片的 alpha 通道值来调整水印的透明度。
紫色部分为图片水印。
具体实现如下:
import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class TransparentWatermark {
public static void main(String[] args) {
// 读取原图片
BufferedImage image = null;
try {
image = ImageIO.read(new File("original.png"));
} catch (IOException e) {
e.printStackTrace();
}
// 获取图片的宽度和高度
int width = image.getWidth();
int height = image.getHeight();
// 创建一个图片缓存对象
BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 获取图片的画笔
Graphics2D g = newImage.createGraphics();
// 将原图片绘制到缓存图片上
g.drawImage(image, 0, 0, width, height, null);
// 读取水印图片
BufferedImage watermark = null;
try {
watermark = ImageIO.read(new File("watermark.png"));
} catch (IOException e) {
e.printStackTrace();
}
// 获取水印图片的宽度和高度
int wmWidth = watermark.getWidth();
int wmHeight = watermark.getHeight();
// 设置水印图片的透明度
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.5f));
// 绘制水印图片
g.drawImage(watermark, width - wmWidth - 10, height - wmHeight - 10, wmWidth, wmHeight, null);
// 释放图形上下文使用的系统资源
g.dispose();
// 保存带水印的图片
try {
ImageIO.write(newImage, "png", new File("watermarked.png"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
提升图片处理速度
目前我们添加文字水印和图片水印耗时都在 700ms - 2000ms
。
可以考虑以下几种方法来提升速度:
使用多线程:如果你需要批量添加文字水印,可以考虑使用多线程的方式来加速处理速度。例如,你可以将图片分成多份,每份使用一个线程处理,最后再将结果合并。
使用更快的图片处理库:如果你使用的是 Java 原生的图片处理工具(例如 java.awt 包),可以考虑使用更快的图片处理库,例如 OpenCV、Imaging、Thumbnails 等。这些库通常具有更快的处理速度,并且支持更多的图片格式和操作。
减少图片的质量:如果你的图片尺寸较大,可以考虑将图片的质量压缩到一个较低的水平,这样可以减少图片的体积,从而加快处理速度。
优化代码:如果你的代码有一些低效的地方,可以考虑优化代码,提升程序的执行效率。例如,可以避免使用过多的循环和分支语句,或者使用更快的算法等。
来源:https://juejin.cn/post/7196647843138404412