概 述
很多网站的图片为了版权考虑都加有水印,尤其是那些图片类网站。自己正好最近和图片打交道比较多,因此就探索了一番基于 Spring Boot
这把利器来实现从 图片上传 → 图片加水印 的一把梭操作!
搭建Spring Boot基础工程
过程不再赘述了,这里给出 pom中的关键依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
</dependencies>
编写文件上传服务
主要就是编写 ImageUploadService
服务
@Service
public class ImageUploadService {
/**
* 功能:上传图片
* @param file 文件
* @param uploadPath 服务器上上传文件的路径
* @param physicalUploadPath 服务器上上传文件的物理路径
* @return 上传文件的 URL相对地址
*/
public String uploadImage(MultipartFile file, String uploadPath, String physicalUploadPath ) {
String filePath = physicalUploadPath + file.getOriginalFilename();
try {
File targetFile=new File(filePath);
FileUtils.writeByteArrayToFile(targetFile, file.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
return uploadPath + "/" + file.getOriginalFilename();
}
}
编写图片加水印服务
编写 ImageWatermarkService
服务
加图片水印
里面就一个主要的 watermarkAdd
方法,代码后面写有详细解释
@Service
public class ImageWatermarkService {
/**
* imgFile 图像文件
* imageFileName 图像文件名
* uploadPath 服务器上上传文件的相对路径
* realUploadPath 服务器上上传文件的物理路径
*/
public String watermarkAdd(File imgFile, String imageFileName, String uploadPath, String realUploadPath ) {
String imgWithWatermarkFileName = "watermark_" + imageFileName;
OutputStream os = null;
try {
// 源图片
Image image = ImageIO.read(imgFile);
int width = image.getWidth(null);
int height = image.getHeight(null);
BufferedImage bufferedImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB); // ①
// 得到画笔对象
Graphics2D g = bufferedImage.createGraphics(); // ②
g.drawImage(image, 0, 0, width,height,null); // ③
String logoPath = realUploadPath + "/" + Const.LOGO_FILE_NAME; // 水印图片地址
File logo = new File(logoPath); // 读取水印图片
Image imageLogo = ImageIO.read(logo);
int markWidth = imageLogo.getWidth(null); // 水印图片的宽度和高度
int markHeight = imageLogo.getHeight(null);
g.setComposite( AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, Const.ALPHA) ); // 设置水印透明度
g.rotate(Math.toRadians(-10), bufferedImage.getWidth()/2, bufferedImage.getHeight()/2); // 设置水印图片的旋转度
//添加单个水印
double x2 = width * 0.9 - markWidth;
double y2 = height * 0.9 - markHeight;
g.drawImage(imageLogo, new Double(x2).intValue(), new Double(y2).intValue(), null); // ④
/* // 循环添加多个水印logo
double count = 1.5;
while ( x < width*count ) { // 循环添加多个水印logo
y = -height / 2;
while( y < height*count ) {
g.drawImage(imageLogo, x, y, null); // ④
y += markHeight + yInterval;
}
x += markWidth + xInterval;
}*/
g.dispose();
os = new FileOutputStream(realUploadPath + "/" + imgWithWatermarkFileName);
JPEGImageEncoder en = JPEGCodec.createJPEGEncoder(os); // ⑤
en.encode(bufferedImage); // ⑥
} catch (Exception e) {
e.printStackTrace();
} finally {
if(os!=null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return uploadPath + "/" + imgWithWatermarkFileName;
}
}
代码思路解释如下:
可以对照代码中的标示数字和下面的解释进行理解:
- ① 创建缓存图片
- ② 创建绘图工具
- ③ 将原图绘制到缓存图片
- ④ 将水印 logo绘制到缓存图片
- ⑤ 创建图像编码工具类
- ⑥ 编码缓存图像生成目标图片
可见思路清晰易懂!
加文字水印
里面就一个主要的 markImage
方法,代码后面写有详细解释
/**
* 给图片添加水印文字
*
* @param text 水印文字
* @param srcImgPath 源图片路径
* @param targetPath 目标图片路径
*/
public String markImage(String text, String srcImgPath, String targetPath, String uploadPath) {
return markImage(text, srcImgPath, targetPath, uploadPath,null);
}
/**
* 给图片添加水印文字、可设置水印文字的旋转角度
*
* @param text
* @param srcImgPath
* @param targetPath
* @param degree
*/
public String markImage(String text, String srcImgPath, String targetPath, String uploadPath, Integer degree) {
targetPath = targetPath+"watermark.jpg";
OutputStream os = null;
try {
// 0、图片类型
String type = srcImgPath.substring(srcImgPath.indexOf(".") + 1, srcImgPath.length());
// 1、源图片
Image srcImg = ImageIO.read(new File(srcImgPath));
int imgWidth = srcImg.getWidth(null);
int imgHeight = srcImg.getHeight(null);
BufferedImage buffImg = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);
// 2、得到画笔对象
Graphics2D g = buffImg.createGraphics();
// 3、设置对线段的锯齿状边缘处理
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(srcImg.getScaledInstance(imgWidth, imgHeight, Image.SCALE_SMOOTH), 0, 0, null);
// 4、设置水印旋转
if (null != degree) {
g.rotate(Math.toRadians(degree), (double) buffImg.getWidth() / 2, (double) buffImg.getHeight() / 2);
}
// 5、设置水印文字颜色
g.setColor(Const.color);
// 6、设置水印文字Font
g.setFont(Const.font);
// 7、设置水印文字透明度
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, Const.ALPHA));
// 8、第一参数->设置的内容,后面两个参数->文字在图片上的坐标位置(x,y)
int positionWidth = 50;
int positionHeight = imgHeight-30;
g.drawString(text,positionWidth, positionHeight);
// 9、释放资源
g.dispose();
// 10、生成图片
os = new FileOutputStream(targetPath);
// ImageIO.write(buffImg, "JPG", os);
ImageIO.write(buffImg, type.toUpperCase(), os);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != os){
os.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return uploadPath + "/" +"watermark.jpg";
}
编写图片上传/处理控制器
我们在该控制器代码中将上述的 图片上传服务 和 图片加水印服务 给用起来:
package com.example.controller;
import com.example.po.ImageInfo;
import com.example.service.ImageUploadService;
import com.example.service.ImageWatermarkService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
@RestController
public class WatermarkController {
@Autowired
private ImageUploadService imageUploadService;
@Autowired
private ImageWatermarkService watermarkService;
@RequestMapping(value = "/watermarktest", method = RequestMethod.POST)
public ImageInfo watermarkTest( @RequestParam("file") MultipartFile image ) {
ImageInfo imgInfo = new ImageInfo();
String uploadPath = "static/images/"; // 服务器上上传文件的相对路径
String physicalUploadPath = getClass().getClassLoader().getResource(uploadPath).getPath(); // 服务器上上传文件的物理路径
String imageURL = imageUploadService.uploadImage( image, uploadPath, physicalUploadPath );
File imageFile = new File(physicalUploadPath + image.getOriginalFilename() );
String watermarkAddImageURL = watermarkService.watermarkAdd(imageFile, image.getOriginalFilename(), uploadPath, physicalUploadPath);
imgInfo.setImageURL(imageURL);
imgInfo.setWatermarkAddImageURL(watermarkAddImageURL);
return imgInfo;
}
@RequestMapping(value = "/watermarktesttest", method = RequestMethod.POST)
public ImageInfo watermarkTestTest( @RequestParam("file") MultipartFile image, @RequestParam("text") String text) {
ImageInfo imgInfo = new ImageInfo();
String uploadPath = "static/images/"; // 服务器上上传文件的相对路径
String physicalUploadPath = getClass().getClassLoader().getResource(uploadPath).getPath(); // 服务器上上传文件的物理路径
String imageURL = imageUploadService.uploadImage( image, uploadPath, physicalUploadPath );
System.out.println("给图片添加水印文字开始...");
// 给图片添加水印文字
String watermarkAddImageURL = watermarkService.markImage(text, physicalUploadPath + image.getOriginalFilename(), physicalUploadPath,uploadPath);
System.out.println("给图片添加水印文字结束...");
imgInfo.setImageURL(imageURL);
imgInfo.setWatermarkAddImageURL(watermarkAddImageURL);
return imgInfo;
}
}
Const配置类
public class Const {
public static final String LOGO_FILE_NAME ="66.jpg";
// 水印透明度
public static final float ALPHA = 0.8f;
// 水印横向位置
public static int positionWidth = 100;
// 水印纵向位置
public static int positionHeight = 300;
// 水印文字字体
public static final Font font = new Font("宋体", Font.BOLD, 100);
// 水印文字颜色
public static final Color color = Color.black;
}
实际实验与效果展示
之后我们再去项目的资源目录下查看上传的原图 和 加完水印后图片即可。大家自己去试试。