摘要:时间年月日星期五说明本文部分内容均来自慕课网。慕课网教学源码无学习源码第一章课程简介引言通过一个项目案例的讲解,如何在应用中实现图片水印的添加。
时间:2017年07月21日星期五
说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com
教学源码:无
学习源码:https://github.com/zccodere/s...
通过一个项目案例的讲解,如何在JavaWeb应用中实现图片水印的添加。
1-2 课程内容课程内容
</>复制代码
1.Java图片水印实现思路
2.课程项目案例介绍
框架
实现方式
结果演示
3.课程案例详解
实现图片添加单个文字水印
实现图片添加单个图片水印
实现图片添加多个文字水印
实现图片添加多个图片水印
实现多图片批量添加水印
4.课程总结
1-3 课程目标
目标
第二章:实现原理 2-1 实现思路</>复制代码
1.了解Java图片水印实现思路
2.掌握文字水印和图片水印的思路
3.掌握多图片批量水印的实现
实现思路
2-2 实用工具类</>复制代码
1.创建缓存图片对象
2.创建Java绘图工具对象
3.使用绘图工具对象将原图绘制到缓存图片对象
4.使用绘图工具将水印(文字/图片)绘制到缓存图片对象
5.创建图像编码工具类
6.使用图片编码工具类,输出缓存图像到目标图片文件
实用工具类
</>复制代码
1.BufferedImage:图片缓存类
2.Graphics2D:对平面2D图片进行操作
3.JPEGImageEncoder:对图片文件进行编码处理并输出到磁盘文件中
第三章:案例介绍
3-1 案例演示
项目案例
</>复制代码
基于Strutus2框架的JavaWeb应用程序,允许一次上传多个图片,应用默认为上传图片添加水印,并将原图与添加水印图片对比展示。
说明
</>复制代码
个人学习时,均使用SpringBoot框架相关技术
结果演示
默认首页
点击浏览并选中图片
点击上传,结果如下
第四章:添加单个文字水印 4-1 搭建项目创建名为watermark的maven项目POM文件如下
</>复制代码
4.0.0
com.myimooc
watermark
0.0.1-SNAPSHOT
jar
watermark
http://maven.apache.org
org.springframework.boot
spring-boot-starter-parent
1.5.1.RELEASE
UTF-8
UTF-8
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-freemarker
commons-io
commons-io
2.5
net.coobird
thumbnailator
0.4.8
org.apache.maven.plugins
maven-compiler-plugin
1.8
1.8
编写配置类和启动类,完成后项目结构如下
4-2 编写页面代码演示:
4-3 编写控制器类</>复制代码
上传文件
图片上传
请上传图片
代码演示:
</>复制代码
package com.myimooc.watermark.controller;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import com.myimooc.watermark.domain.PicInfo;
import com.myimooc.watermark.service.MarkService;
import com.myimooc.watermark.service.UploadService;
/**
* WatermarkController 控制类
*
* @author ZhangCheng on 2017-07-21
*
*/
@Controller
public class WatermarkController {
private static Logger logger = LoggerFactory.getLogger(WatermarkController.class);
@Autowired
private UploadService uploadService;
@Autowired
private MarkService markService;
/***
* 单图片上传
*
* @param image
* @param request
* @return
*/
@PostMapping("/watermark")
public ModelAndView watermark(MultipartFile image, HttpServletRequest request) {
ModelAndView mav = new ModelAndView("/watermark");
PicInfo picInfo = new PicInfo();
String uploadPath = "static/images/";
String realUploadPath = getClass().getClassLoader().getResource(uploadPath).getPath();
logger.info("上传相对目录:{}", uploadPath);
logger.info("上传绝对目录:{}", uploadPath);
String imageURL = uploadService.uploadImage(image, uploadPath, realUploadPath);
File imageFile = new File(realUploadPath + image.getOriginalFilename());
String logoImageURL = markService.watermake(imageFile, image.getOriginalFilename(), uploadPath, realUploadPath);
picInfo.setImageURL(imageURL);
picInfo.setLogoImageURL(logoImageURL);
mav.addObject("picInfo", picInfo);
return mav;
}
/**
* 图片批量上传
*
* @param image
* @param request
* @return
*/
@PostMapping("/morewatermark")
public ModelAndView morewatermark(List image, HttpServletRequest request) {
ModelAndView mav = new ModelAndView("/morewatermark");
String uploadPath = "static/images/";
String realUploadPath = getClass().getClassLoader().getResource(uploadPath).getPath();
logger.info("上传相对目录:{}", uploadPath);
logger.info("上传绝对目录:{}", realUploadPath);
if (image != null && image.size() > 0) {
List picInfoList = new ArrayList();
for (MultipartFile imageFileTemp : image) {
if(imageFileTemp == null || imageFileTemp.getSize() < 1){
continue;
}
PicInfo picInfo = new PicInfo();
String imageURL = uploadService.uploadImage(imageFileTemp, uploadPath, realUploadPath);
File imageFile = new File(realUploadPath + imageFileTemp.getOriginalFilename());
String logoImageURL = markService.watermake(imageFile, imageFileTemp.getOriginalFilename(), uploadPath,
realUploadPath);
picInfo.setImageURL(imageURL);
picInfo.setLogoImageURL(logoImageURL);
picInfoList.add(picInfo);
}
mav.addObject("picInfoList", picInfoList);
}
return mav;
}
}
4-4 编写水印接口
代码演示:
</>复制代码
package com.myimooc.watermark.service;
import java.awt.Color;
import java.awt.Font;
import java.io.File;
/**
* 图片水印服务类
* @author ZhangCheng on 2017-07-21
*
*/
public interface MarkService {
/** 水印文字内容 */
public static final String MARK_TEXT = "妙手空空";
/** 水印文字类型 */
public static final String FONT_NAME = "微软雅黑";
/** 水印文字样式 */
public static final int FONT_STYLE = Font.BOLD;
/** 水印文字大小 */
public static final int FONT_SIZE= 120;// 单位:像素
/** 水印文字颜色 */
public static final Color FONT_COLOR= Color.BLACK;
/** 水印文字位置X轴 */
public static final int X = 10;
/** 水印文字位置Y轴 */
public static final int Y = 10;
/** 水印文字透明度*/
public static final float ALPHA = 0.3F;
/** 水印图片*/
public static final String LOGO = "logo.png";
/**
* 功能:将传入的图片添加水印并保存到服务器中
* @param file
* @param uploadPath
* @param realUploadPath
* @return 添加水印后图片的URL相对地址
*/
String watermake(File imageFile,String imageFileName,String uploadPath,String realUploadPath);
}
4-5 添加单个文字水印
代码演示
</>复制代码
package com.myimooc.watermark.service;
import java.awt.AlphaComposite;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.imageio.ImageIO;
import org.springframework.stereotype.Service;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
/**
* 图片水印服务类,添加文字水印
* @author ZhangCheng on 2017-07-21
*
*/
//@Service
@SuppressWarnings("unused")
public class TextMarkServiceImpl implements MarkService {
@Override
public String watermake(File imageFile,String imageFileName, String uploadPath, String realUploadPath) {
String logoFileName = "logo_" + imageFileName;
OutputStream os = null;
try {
Image image = ImageIO.read(imageFile);
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);
// 设置水印文字字体信息
g.setFont(new Font(FONT_NAME,FONT_STYLE,FONT_SIZE));
// 设置水印文字颜色
g.setColor(FONT_COLOR);
int markWidth = FONT_SIZE * getTextLength(MARK_TEXT);
int markHeight = FONT_SIZE;
// 水印的高度和宽度之差
int widthDiff = width - markWidth;
int heightDiff = height - markHeight;
int x = X;
int y = Y;
// 判断设置的值是否大于图片大小
if(x > widthDiff){
x = widthDiff;
}
if(y > heightDiff){
y =heightDiff;
}
// 设置水印文字透明度
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, ALPHA));
// 添加水印
g.drawString(MARK_TEXT, x, y + FONT_SIZE);
g.dispose();
os = new FileOutputStream(realUploadPath + "/" + logoFileName);
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 + "/" + logoFileName;
}
/**
* 功能:获取文本长度。汉字为1:1,英文和数字为2:1
*/
private int getTextLength(String text){
int length = text.length();
for(int i = 0 ; i < text.length(); i++){
String s = String.valueOf(text.charAt(i));
if(s.getBytes().length > 1){
length++;
}
}
length = length % 2 == 0 ? length / 2 : length / 2 + 1;
return length;
}
}
第五章:添加单个图片水印
5-1 图片水印添加
代码演示:
</>复制代码
package com.myimooc.watermark.service;
import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.imageio.ImageIO;
import org.springframework.stereotype.Service;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
/**
* 图片水印服务类,添加图片水印
* @author ZhangCheng on 2017-07-22
*
*/
//@Service
@SuppressWarnings("unused")
public class ImageMarkServiceImpl implements MarkService {
@Override
public String watermake(File imageFile, String imageFileName, String uploadPath, String realUploadPath) {
String logoFileName = "logo_" + imageFileName;
OutputStream os = null;
// 图片地址
String logoPath = realUploadPath + "/" + LOGO;
try {
Image image = ImageIO.read(imageFile);
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);
// 读取Logo图片
File logo = new File(logoPath);
Image imageLogo = ImageIO.read(logo);
// 获取Logo图片的宽度和高度
int markWidth = imageLogo.getWidth(null);
int markHeight = imageLogo.getHeight(null);
// 原图和Logo图片的高度和宽度之差
int widthDiff = width - markWidth;
int heightDiff = height - markHeight;
int x = X;
int y = Y;
// 判断设置的值是否大于图片大小
if(x > widthDiff){
x = widthDiff;
}
if(y > heightDiff){
y =heightDiff;
}
// 设置水印透明度
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, ALPHA));
// 添加水印
g.drawImage(imageLogo, x, y, null);
g.dispose();
os = new FileOutputStream(realUploadPath + "/" + logoFileName);
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 + "/" + logoFileName;
}
}
第六章:添加多个文字水印
6-1 添加多个文字水印
代码演示:
</>复制代码
package com.myimooc.watermark.service;
import java.awt.AlphaComposite;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.imageio.ImageIO;
import org.springframework.stereotype.Service;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
/**
* 图片水印服务类,添加多个文字水印
* @author ZhangCheng on 2017-07-22
*
*/
//@Service
@SuppressWarnings("unused")
public class MoreTextMarkServiceImpl implements MarkService {
@Override
public String watermake(File imageFile, String imageFileName, String uploadPath, String realUploadPath) {
String logoFileName = "logo_" + imageFileName;
OutputStream os = null;
try {
Image image = ImageIO.read(imageFile);
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);
// 设置水印文字字体信息
g.setFont(new Font(FONT_NAME,FONT_STYLE,FONT_SIZE));
// 设置水印文字颜色
g.setColor(FONT_COLOR);
int markWidth = FONT_SIZE * getTextLength(MARK_TEXT);
int markHeight = FONT_SIZE;
// 设置水印透明度
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, ALPHA));
// 旋转图片
g.rotate(Math.toRadians(30), bufferedImage.getWidth()/2, bufferedImage.getHeight()/2);
int x = -width / 2;
int y = -height / 2;
int xmove = 200;// 水印之间的间隔
int ymove = 200;// 水印之间的间隔
// 循环添加
while (x < width * 1.5){
y = -height / 2;
while(y < height * 1.5){
g.drawString(MARK_TEXT, x, y);
y += markHeight + ymove;
}
x += markWidth + xmove;
}
g.dispose();
os = new FileOutputStream(realUploadPath + "/" + logoFileName);
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 + "/" + logoFileName;
}
/**
* 功能:获取文本长度。汉字为1:1,英文和数字为2:1
*/
private int getTextLength(String text){
int length = text.length();
for(int i = 0 ; i < text.length(); i++){
String s = String.valueOf(text.charAt(i));
if(s.getBytes().length > 1){
length++;
}
}
length = length % 2 == 0 ? length / 2 : length / 2 + 1;
return length;
}
}
第七章:添加多个图片水印
7-1 添加多个图片水印
代码演示:
</>复制代码
package com.myimooc.watermark.service;
import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.imageio.ImageIO;
import org.springframework.stereotype.Service;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
/**
* 图片水印服务类,添加多个图片水印
* @author ZhangCheng on 2017-07-22
*
*/
@Service
public class MoreImageMarkServiceImpl implements MarkService {
@Override
public String watermake(File imageFile, String imageFileName, String uploadPath, String realUploadPath) {
String logoFileName = "logo_" + imageFileName;
OutputStream os = null;
try {
Image image = ImageIO.read(imageFile);
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 + "/" + LOGO;
// 读取Logo图片
File logo = new File(logoPath);
Image imageLogo = ImageIO.read(logo);
// Logo图片的宽度和高度
int markWidth = imageLogo.getWidth(null);
int markHeight = imageLogo.getHeight(null);
// 设置水印透明度
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, ALPHA));
// 旋转图片
g.rotate(Math.toRadians(30), bufferedImage.getWidth()/2, bufferedImage.getHeight()/2);
int x = -width / 2;
int y = -height / 2;
int xmove = 200;// 水印之间的间隔
int ymove = 200;// 水印之间的间隔
// 循环添加
while (x < width * 1.5){
y = -height / 2;
while(y < height * 1.5){
// 添加水印
g.drawImage(imageLogo, x, y, null);
y += markHeight + ymove;
}
x += markWidth + xmove;
}
g.dispose();
os = new FileOutputStream(realUploadPath + "/" + logoFileName);
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 + "/" + logoFileName;
}
}
第八章:批量添加图片水印
8-1 批量添加图片水印
代码演示
1.编写moreupload.html
</>复制代码
上传文件
图片批量上传
请上传图片
2.修改WatermarkController类
</>复制代码
package com.myimooc.watermark.controller;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import com.myimooc.watermark.domain.PicInfo;
import com.myimooc.watermark.service.MarkService;
import com.myimooc.watermark.service.UploadService;
/**
* WatermarkController 控制类
*
* @author ZhangCheng on 2017-07-21
*
*/
@Controller
public class WatermarkController {
private static Logger logger = LoggerFactory.getLogger(WatermarkController.class);
@Autowired
private UploadService uploadService;
@Autowired
private MarkService markService;
/***
* 单图片上传
*
* @param image
* @param request
* @return
*/
@PostMapping("/watermark")
public ModelAndView watermark(MultipartFile image, HttpServletRequest request) {
ModelAndView mav = new ModelAndView("/watermark");
PicInfo picInfo = new PicInfo();
String uploadPath = "static/images/";
String realUploadPath = getClass().getClassLoader().getResource(uploadPath).getPath();
logger.info("上传相对目录:{}", uploadPath);
logger.info("上传绝对目录:{}", uploadPath);
String imageURL = uploadService.uploadImage(image, uploadPath, realUploadPath);
File imageFile = new File(realUploadPath + image.getOriginalFilename());
String logoImageURL = markService.watermake(imageFile, image.getOriginalFilename(), uploadPath, realUploadPath);
picInfo.setImageURL(imageURL);
picInfo.setLogoImageURL(logoImageURL);
mav.addObject("picInfo", picInfo);
return mav;
}
/**
* 图片批量上传
*
* @param image
* @param request
* @return
*/
@PostMapping("/morewatermark")
public ModelAndView morewatermark(List image, HttpServletRequest request) {
ModelAndView mav = new ModelAndView("/morewatermark");
String uploadPath = "static/images/";
String realUploadPath = getClass().getClassLoader().getResource(uploadPath).getPath();
logger.info("上传相对目录:{}", uploadPath);
logger.info("上传绝对目录:{}", realUploadPath);
if (image != null && image.size() > 0) {
List picInfoList = new ArrayList();
for (MultipartFile imageFileTemp : image) {
if(imageFileTemp == null || imageFileTemp.getSize() < 1){
continue;
}
PicInfo picInfo = new PicInfo();
String imageURL = uploadService.uploadImage(imageFileTemp, uploadPath, realUploadPath);
File imageFile = new File(realUploadPath + imageFileTemp.getOriginalFilename());
String logoImageURL = markService.watermake(imageFile, imageFileTemp.getOriginalFilename(), uploadPath,
realUploadPath);
picInfo.setImageURL(imageURL);
picInfo.setLogoImageURL(logoImageURL);
picInfoList.add(picInfo);
}
mav.addObject("picInfoList", picInfoList);
}
return mav;
}
}
3.编写morewatermark.html
</>复制代码
处理结果
操作结果
[#list picInfoList as item]
[/#list]
返回
4.效果展示
访问图片批量上传页
选择文件
点击上传图片,结果如下
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/67449.html
时间:2017年07月09日星期日说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com教学源码:无学习源码:https://github.com/zccodere/s... 第一章:概述 1-1 课程概述 主要内容 验证码历史 课程内容 不同方案对比 设计与实现 总结 1-2 验证码历史 验证码历史 无验证码:垃圾骚扰 Luis von Ahn:Captcha 不断...
摘要:时间年月日星期六说明本文部分内容均来自慕课网。可以更加专注于业务逻辑开发,缩短项目开发周期,提高项目开发速度。 时间:2017年07月15日星期六说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com教学源码:无学习源码:https://github.com/zccodere/s... 第一章:课程介绍 1-1 课程介绍 在用户进行信息概略浏览的时候,提供缩...
摘要:时间年月日星期五说明本文部分内容均来自慕课网。线性堆叠式二维码示意图矩阵式二维码在一个矩形空间通过黑白像素在矩阵中的不同分布进行编码。 时间:2017年06月23日星期五说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com教学示例源码:无个人学习源码:https://github.com/zccodere/s... 第一章:二维码的概念 1-1 二维码概述...
摘要:时间年月日星期一说明本文部分内容均来自慕课网。多用于网络加密。散列函数函数或消息摘要函数主要作用散列函数用来验证数据的完整性。 时间:2017年4月10日星期一说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com教学示例源码:https://github.com/zccodere/s...个人学习源码:https://github.com/zccodere...
阅读 1895·2021-11-11 16:55
阅读 2689·2021-08-27 13:11
阅读 3710·2019-08-30 15:53
阅读 2375·2019-08-30 15:44
阅读 1498·2019-08-30 11:20
阅读 1120·2019-08-30 10:55
阅读 1003·2019-08-29 18:40
阅读 3202·2019-08-29 16:13