解析图片内隐含的信息并将其打印在图片上做水印
周五收到说要做一个给照片加水印的功能,大概就是说将一张含有坐标点的图片,将它的坐标点以及拍摄时间给打印在照片上,于是乎就在网上找了些相关文章,一开始不太顺利,图片根本解析不出来东西还报了一堆的错,开始还以为是代码的问题,就在那找啊找测啊测的,后来才发现是依赖的jar没导全,以及开发工具设置的一些问题。
其实这个功能分两步,
一、将图片(必须是带有位置信息的照片)里含有的信息解析出来:
package photo; import java.awt.Color; 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 javax.swing.ImageIcon; import com.drew.imaging.ImageMetadataReader; import com.drew.imaging.ImageProcessingException; import com.drew.metadata.Directory; import com.drew.metadata.Metadata; import com.drew.metadata.Tag; import com.sun.image.codec.jpeg.JPEGCodec; import com.sun.image.codec.jpeg.JPEGEncodeParam; import com.sun.image.codec.jpeg.JPEGImageEncoder; /** * java读取照片信息 */ public class SampleUsage { public static void main(String[] args) throws Exception, Exception { File file = new File("D:\\test\\aa.jpg"); printImageTags(file); } /** * 读取照片里面的信息 */ private static void printImageTags(File file) throws ImageProcessingException, Exception { Metadata metadata = ImageMetadataReader.readMetadata(file); for (Directory directory : metadata.getDirectories()) { for (Tag tag : directory.getTags()) { String tagName = tag.getTagName(); // 标签名 String desc = tag.getDescription(); // 标签信息 if (tagName.equals("Image Height")) { System.out.println("图片高度: " + desc); } else if (tagName.equals("Image Width")) { System.out.println("图片宽度: " + desc); } else if (tagName.equals("Date/Time Original")) { System.out.println("拍摄时间1: " + desc); }else if (tagName.equals("Date/Time Digitized")) { System.out.println("拍摄时间2: " + desc); } else if (tagName.equals("GPS Latitude")) { System.err.println("纬度 : " + desc); System.err.println("纬度(度分秒格式) : " + pointToLatlong(desc)); } else if (tagName.equals("GPS Longitude")) { System.err.println("经度: " + desc); System.err.println("经度(度分秒格式): " + pointToLatlong(desc)); } System.err.println("tagName: " + tagName+"----->desc"+desc); } } } /** * 经纬度格式 转换为 度分秒格式 ,如果需要的话可以调用该方法进行转换 * * @param point * 坐标点 * @return */ 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(); } }
运行结果就如下:
ps:需要注意得是查看一张图片是否含有位置信息,找到图片鼠标右键点击“属性”–>“详细信息” 如下:
二、就是将第一步解析到的信息拿到你想要的,并将它打印在照片上:
package photo; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.Image; import java.awt.image.BufferedImage; import java.io.FileOutputStream; import javax.swing.ImageIcon; import com.sun.image.codec.jpeg.JPEGCodec; import com.sun.image.codec.jpeg.JPEGEncodeParam; import com.sun.image.codec.jpeg.JPEGImageEncoder; public class ImageEdit { public static void main(String[] a) { ImageEdit.createStringMark("D:\\test\\photo\\IMG_954.jpg", "*****测试文字*****","D:\\test\\B.jpg"); } /** * @param filePath 源图片路径 * @param markContent 图片中添加内容 * @param outPath 输出图片路径 * 字体颜色等在函数内部实现的 */ //给jpg添加文字 public static boolean createStringMark(String filePath,String markContent,String outPath) { ImageIcon imgIcon=new ImageIcon(filePath); Image theImg =imgIcon.getImage(); int width=theImg.getWidth(null)==-1?200:theImg.getWidth(null); int height= theImg.getHeight(null)==-1?200:theImg.getHeight(null); System.out.println(width); System.out.println(height); System.out.println(theImg.toString()); BufferedImage bimage = new BufferedImage(width,height, BufferedImage.TYPE_INT_RGB); Graphics2D g=bimage.createGraphics(); Color mycolor = Color.red; g.setColor(mycolor); g.setBackground(Color.red); g.drawImage(theImg, 0, 0, null ); g.setFont(new Font("宋体",Font.PLAIN,80)); //字体、字型、字号 g.drawString(markContent,width/80,height-height/100); //画文字 g.dispose(); try { FileOutputStream out=new FileOutputStream(outPath); //先用一个特定的输出文件名 JPEGImageEncoder encoder =JPEGCodec.createJPEGEncoder(out); JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bimage); param.setQuality(100, true); // encoder.encode(bimage, param); out.close(); } catch(Exception e) { return false; } return true; } }
测试结果:
因为我的需求是将解析的信息加在照片的下方(关于字体、颜色、位置都可以设置),所以:
看起来是大功告成了呢,哈哈。再顺便排个雷,以下我再将用到的jjar包和eclipse设置告诉一下,话不多数上截图
这两个jar缺一不可的,jar包的话可以去
https://mvnrepository.com/artifact/com.drewnoakes/metadata-extractor/2.6.2
https://mvnrepository.com/artifact/com.adobe.xmp/xmpcore/5.1.2
里下载这两个,在文件类型里选择jar还是pom
如果eclipse(MyEclipse同理)在打印照片时,引入的
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
报错的话:
Access restriction: The type JPEGImageEncoder is not accessible due to restriction on required library C:\Java\jre1.6.0_07\lib\rt.jar
此时解决办法:
Eclipse默认把这些受访问限制的API设成了ERROR。只要把Windows-Preferences-Java-Complicer-Errors/Warnings里面的Deprecated and restricted API中的Forbidden references(access rules)选为Warning就可以编译通过。
最后的最后,将这两个合二为一,我需要的是拍摄时间以及经纬度,那么以下:
/** * @author yc * @date 2019年3月8日 */
package photo; import com.drew.imaging.ImageMetadataReader; import com.drew.imaging.ImageProcessingException; import com.drew.imaging.jpeg.JpegMetadataReader; import com.drew.metadata.Directory; import com.drew.metadata.Metadata; import com.drew.metadata.Tag; import com.sun.image.codec.jpeg.JPEGCodec; import com.sun.image.codec.jpeg.JPEGEncodeParam; import com.sun.image.codec.jpeg.JPEGImageEncoder; import java.awt.Color; 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 javax.swing.ImageIcon; public class ExifTester { public static void main(String[] args) throws ImageProcessingException, Exception { File file = new File("D:\\test\\photo\\IMG_954.jpg"); if(file.exists()){ String imageMsg = printImageTags(file); boolean result = ImageEdit.createStringMark(file.getPath(), imageMsg,"D:\\test\\B.jpg"); System.out.println("iamgeMsg:----->" + imageMsg+"打印到照片上:"+result); }else{ System.out.println("图片不存在或错误,请核实!"); } } /** * 读取照片里面的信息 */ private static String printImageTags(File jpegFile) throws ImageProcessingException, Exception { //File jpegFile = new File(filePath); Metadata metadata = JpegMetadataReader.readMetadata(jpegFile); String imageToString = ""; imagesEntity image = new imagesEntity(); for (Directory directory : metadata.getDirectories()) { for (Tag tag : directory.getTags()) { // System.out.print("name : " + tag.getTagName() + " -->"); // System.out.println("desc : " + tag.getDescription()); String tagName = tag.getTagName(); String desc = tag.getDescription(); if (tagName.equals("Image Height")) { System.out.println("图片高度: " + desc); } else if (tagName.equals("Image Width")) { System.out.println("图片宽度: " + desc); } else if (tagName.equals("Date/Time Original")) { image.setDateOriginal(desc); System.out.println("拍摄时间1: " + desc); } else if (tagName.equals("Date/Time Digitized")) { image.setDateDigitized(desc); System.out.println("拍摄时间2: " + desc); } else if (tagName.equals("GPS Latitude")) { System.err.println("纬度 : " + desc); image.setLatitude(pointToLatlong(desc)); System.err.println("纬度(度分秒格式) : " + pointToLatlong(desc)); } else if (tagName.equals("GPS Longitude")) { System.err.println("经度: " + desc); image.setLongitude(pointToLatlong(desc)); System.err.println("经度(度分秒格式): " + pointToLatlong(desc)); } } } imageToString = image.getLongitude() + "," + image.getLatitude() + " " + image.getDateOriginal(); System.err.println("照片内获取信息为" + imageToString); return imageToString; } /** * 经纬度格式 转换为 度分秒格式 ,如果需要的话可以调用该方法进行转换 * * @param point * 坐标点 * @return */ 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(); } /** * @param filePath 源图片路径 * @param markContent 图片中添加内容 * @param outPath 输出图片路径 * 字体颜色等在函数内部实现的 */ //给jpg添加文字 public static boolean createStringMark(String filePath,String markContent,String outPath) { ImageIcon imgIcon=new ImageIcon(filePath); Image theImg =imgIcon.getImage(); int width=theImg.getWidth(null)==-1?200:theImg.getWidth(null); int height= theImg.getHeight(null)==-1?200:theImg.getHeight(null); System.out.println(width); System.out.println(height); System.out.println(theImg.toString()); BufferedImage bimage = new BufferedImage(width,height, BufferedImage.TYPE_INT_RGB); Graphics2D g=bimage.createGraphics(); Color mycolor = Color.red; g.setColor(mycolor); g.setBackground(Color.red); g.drawImage(theImg, 0, 0, null ); g.setFont(new Font("宋体",Font.PLAIN,80)); //字体、字型、字号 g.drawString(markContent,width/80,height-height/100); //画文字位置 g.dispose(); try { FileOutputStream out=new FileOutputStream(outPath); //先用一个特定的输出文件名 JPEGImageEncoder encoder =JPEGCodec.createJPEGEncoder(out); JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bimage); param.setQuality(100, true); // encoder.encode(bimage, param); out.close(); } catch(Exception e) { return false; } return true; } }
信息实体:
/** * @author yc * @date 2019年3月8日 */ package photo; /** * @author yang.cheng * @date 2019年3月8日 */ public class imagesEntity { private String DateOriginal; private String DateDigitized; private String Latitude; private String Longitude; public String getDateOriginal() { return DateOriginal; } public void setDateOriginal(String dateOriginal) { DateOriginal = dateOriginal; } public String getDateDigitized() { return DateDigitized; } public void setDateDigitized(String dateDigitized) { DateDigitized = dateDigitized; } public String getLatitude() { return Latitude; } public void setLatitude(String latitude) { Latitude = latitude; } public String getLongitude() { return Longitude; } public void setLongitude(String longitude) { Longitude = longitude; } @Override public String toString() { return "imagesEntity [DateOriginal=" + DateOriginal + ", DateDigitized=" + DateDigitized + ", Latitude=" + Latitude + ", Longitude=" + Longitude + "]"; } }