前言
最近工作中有个需求是获取上传的图片的位置信息,并添加位置和时间水印。因为之前也没做过,所以找了很多网上的各种文章,杂七杂八的都有,比较乱,国庆假期正好有时间,写了这篇整理文章,可能写的不好请谅解.
技术使用
本文使用Springboot来做演示项目,因为比较方便和快速,下面我把需要使用到的pom信息贴到代码块中
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<dependency>
<groupId>com.drewnoakes</groupId>
<artifactId>metadata-extractor</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
- thymeleaf :用来展示页面和上传图片
- fastjson:解析Json数据格式
- metadata-extractor :主要用来获取图片中的EXIF信息
- commons-fileupload:可忽略,用来把file转换成MultipartFile的依赖
搭建演示Demo
我们需要在templeates中创建2个页面进行显示和上传图片: upload.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>Upload a file for</h1>
<form method="POST" action="/upload" enctype="multipart/form-data">
<input type="file" name="file" /><br/><br/>
<input type="submit" value="Submit" />
</form>
</body>
</html>
展示结果页面 result.html:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>Extracted Content:</h1>
<h2>><span th:text="${text}"></span></h2>
<p>From the image:</p>
<img th:src="'/' + ${file.getName()}"/>
</body>
</html>
处理图片
在开始处理图片之前,我们得准备一张手机拍摄的原图,记住一定得是原图,否则使用drew是获取不到图片的EXIF信息的,如图则为原图(我是直接用手机插PC直接拖的图片):
ExifUtil:
public class ExifUitl {
/**
* 得到图片的exif属性
*/
public static String[] readExif(File file) throws ImageProcessingException, IOException {
String[] array = new String[3];
ImageMetadataReader.readMetadata(file)
.getDirectories().forEach(v ->
v.getTags().forEach(t -> {
System.out.println(t.getTagName() + " : " + t.getDescription());
switch (t.getTagName()) {
// 伟度
case "GPS Latitude":
array[0] = pointToLatlong(t.getDescription());
break;
// 经度
case "GPS Longitude":
array[1] = pointToLatlong(t.getDescription());
break;
// 拍摄时间
case "Date/Time Original":
array[2] = t.getDescription();
default:
break;
}
})
);
return array;
}
/**
* 经纬度格式 转换
*/
public static String pointToLatlong (String point ) {
Double du = Double.parseDouble(point.substring(0, point.indexOf("°")).trim());
Double fen = Double.parseDouble(point.substring(point.indexOf("°")+1, point.indexOf("'")).trim());
Double miao = Double.parseDouble(point.substring(point.indexOf("'")+1, point.indexOf("\"")).trim());
Double duStr = du + fen / 60 + miao / 60 / 60 ;
return duStr.toString();
}
}
controller:
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public RedirectView singleFileUpload(MultipartRequest file, RedirectAttributes redirectAttributes) throws IOException, ImageProcessingException {
MultipartFile mfile = file.getFile("file");
File convFile = convert(mfile);
// 获取图片中得exif信息
String[] test = ExifUitl.readExif(convFile);
for (String one:test) {
System.out.println(one);
}
return new RedirectView("result");
}
@RequestMapping("/result")
public String result() {
return "result";
}
// 转换成file格式
public static File convert(MultipartFile file) throws IOException {
File convFile = new File(file.getOriginalFilename());
convFile.createNewFile();
FileOutputStream fos = new FileOutputStream(convFile);
fos.write(file.getBytes());
fos.close();
return convFile;
}
如何改变文本的样式
然后我们上传图片,页面500是因为没指定File文件,上传完后看看控制台已经打印了图片的EXIF信息,我们主要获取3个key就行了,如果这个地方显示NullPointException则是你的图片问题
3个Key信息,经纬度已经通过工具类转换,上面已经提供好了.
下面我们就把获取到的三个key通过水印的方式添加到图片中,现在需要用到一个水印的工具类,如代码块:
public class ImageFileUtil {
/**
* 图片添加水印
*
* @param srcImgPath
* 需要添加水印的图片的路径
* @param outImgPath
* 添加水印后图片输出路径
* @param markContentColor
* 水印文字的颜色
* @param waterMarkContent
* 水印的文字
*/
public File mark(File file, String srcImgPath, String outImgPath, Color markContentColor, String date, String waterMarkContent) {
Graphics2D g = null;
try {
Color color = new Color(133,123,85);
// 读取原图片信息
//File srcImgFile = new File(srcImgPath);
Image srcImg = ImageIO.read(file);
int srcImgWidth = srcImg.getWidth(null);
int srcImgHeight = srcImg.getHeight(null);
// 加水印
BufferedImage bufImg = new BufferedImage(srcImgWidth, srcImgHeight, BufferedImage.TYPE_INT_RGB);
g = bufImg.createGraphics();
g.drawImage(srcImg, 0, 0, srcImgWidth, srcImgHeight, null);
// 设置水印的颜色
g.setColor(markContentColor);
Font font = new Font("微软雅黑", Font.PLAIN, 77);
g.setFont(font);
//设置地址水印的位置坐标
int x = srcImgWidth - getWatermarkLength(waterMarkContent, g) - 12;
int y = srcImgHeight - 12;
g.drawString(waterMarkContent, x, y);
//设置时间水印的位置坐标
int xx = srcImgWidth -1* getWatermarkLength(date, g);
int yy = srcImgHeight - 99;
g.drawString(date, xx, yy);//画出水印
// 输出图片到本地
FileOutputStream outImgStream = new FileOutputStream(outImgPath);
ImageIO.write(bufImg, "jpg", outImgStream);
outImgStream.flush();
outImgStream.close();
// 输出图片到file中
File outputfile = new File(file.getName());
ImageIO.write(bufImg, "png", outputfile);
return outputfile;
} catch (Exception e) {
e.printStackTrace();
}finally {
if(g!=null){
// 释放图形资源
g.dispose();
}
}
return null;
}
/**
* 获取水印文字总长度
*
* @param waterMarkContent
* 水印的文字
* @param g
* @return 水印文字总长度
*/
public int getWatermarkLength(String waterMarkContent, Graphics2D g) {
return g.getFontMetrics(g.getFont()).charsWidth(waterMarkContent.toCharArray(), 0, waterMarkContent.length());
}
}
通过这个工具类我们就能生成水印图片,还有控制层需要添加的测试代码,为之前/upload接口
File file1 = new ImageFileUtil().mark(convFile,null,"D:/work/codestory-master/exitdemo/src/main/resources/static/"+mfile.getOriginalFilename(),color,test[2],"测试--后续替换成地址");
System.out.print("file1:");
System.out.println(file1);
redirectAttributes.addFlashAttribute("text","测试");
redirectAttributes.addFlashAttribute("file", file1);
下面我们来上传图片实测:
效果基本上实现,水印现在我们已经添加成功了,现在还需要做的就是根据GPS的经纬度得到位置信息文本,然后添加到水印中
结尾
本文的演示代码仅供参考,实际项目中使用变动应该也不大,也算是我在几十篇文章之中吸取的精华,如果对你有丁点儿的帮助的话,点个赞可好,有问题欢迎留言、私信!!