- 起因
因项目需要,要求在JPG图片中添加自定义属性信息,在网上找了很久,发现大多数是读取ESIF信息,键值信息都是固定死的,不符合需求,后面找到了com.adobe.xmp类库,也没找到关于XMP数据修改写入生成图片的,不过最后在该处获得了灵感并借鉴了部分代码:https://stackoverflow.com/questions/23253281/reading-jpg-files-xmp-metadata;实现思路:获取图片中的XMP元数据块,添加自定义属性信息,替换XMP数据,生成新的图片的,大功告成
- 引用
<dependency>
<groupId>com.adobe.xmp</groupId>
<artifactId>xmpcore</artifactId>
<version>6.1.10</version>
</dependency>
- 编写XMP添加组件类
import com.adobe.internal.xmp.XMPMeta;
import com.adobe.internal.xmp.XMPMetaFactory;
import com.adobe.internal.xmp.impl.XMPIteratorImpl;
import com.adobe.internal.xmp.properties.XMPPropertyInfo;
import java.io.*;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;
/**
* 图片读取添加XMP数据:
* 实现思路:获取图片中xmpmeta块信息,编辑替换
* @author lijiongquan
*/
public class XMPUtil {
private final byte[] OPEN_ARR = "<x:xmpmeta".getBytes();
private final byte[] CLOSE_ARR = "</x:xmpmeta>".getBytes();
private final String namespace = "http://www.xxxx.com.cn/xxxx/1.0/";
private final String xmpTag = "xxxx:";
private String orgPath ;
private String destPath;
private Map<String, String> xmpMap;
/**
* 添加图片XMP数据
* @param orgPath 图片路径
* @param destPath 生成图片路径
* @param xmpMap 添加数据集
*/
public void changeImgXMP(String orgPath, String destPath, Map<String, String> xmpMap){
this.orgPath = orgPath;
this.destPath = destPath;
this.xmpMap = xmpMap;
try{
setXMP();
}catch (Exception e){
e.printStackTrace();
}
}
private void setXMP()throws Exception{
File orgFile = new File(orgPath);
File destFile = new File(destPath);
if(destFile.exists()){
destFile.delete();
destFile.createNewFile();
}
FileInputStream in = new FileInputStream(orgFile);
ByteArrayOutputStream out = new ByteArrayOutputStream();
copy(in, out);
byte[] fileData = out.toByteArray();
int openIdx = indexOf(fileData, OPEN_ARR, 0);
if(openIdx>0){
int closeIdx = indexOf(fileData, CLOSE_ARR, openIdx + 1) + CLOSE_ARR.length;
byte[] beforeArr = Arrays.copyOfRange(fileData,0,openIdx);
byte[] afterArr = Arrays.copyOfRange(fileData,closeIdx+1,fileData.length);
byte[] xmpArr = Arrays.copyOfRange(fileData,openIdx,closeIdx);
XMPMeta xmpMeta = XMPMetaFactory.parseFromBuffer(xmpArr);
XMPMetaFactory.getSchemaRegistry().registerNamespace(namespace,xmpTag);
addXMPMeta(xmpMeta);
printXMPMeta(xmpMeta);
ByteArrayOutputStream xmpOut = new ByteArrayOutputStream();
XMPMetaFactory.serialize(xmpMeta, xmpOut);
byte[] xmpArrNew = xmpOut.toByteArray();
FileOutputStream outputStream = new FileOutputStream(destFile);
wirteByte(outputStream, beforeArr);
wirteByte(outputStream, xmpArrNew);
wirteByte(outputStream, afterArr);
outputStream.close();
}
}
private void wirteByte(OutputStream out, byte[] bytes) throws Exception{
out.write(bytes);
out.flush();
}
private void addXMPMeta(XMPMeta xmpMeta) throws Exception{
Iterator<String> iter = xmpMap.keySet().iterator();
while (iter.hasNext()){
String key = iter.next();
String value = xmpMap.get(key);
xmpMeta.setProperty(namespace,xmpTag+key,value);
}
}
private void printXMPMeta(XMPMeta xmpMeta) throws Exception{
XMPIteratorImpl xmpIterator = (XMPIteratorImpl)xmpMeta.iterator();
while (xmpIterator.hasNext()){
XMPPropertyInfo obj = (XMPPropertyInfo)xmpIterator.next();
System.out.println(obj.getNamespace()+"--"+obj.getPath()+"--"+obj.getValue());
}
}
private int indexOf(byte[] arr, byte[] sub, int start){
int subIdx = 0;
for(int x = start;x < arr.length;x++) {
if(arr[x] == sub[subIdx]){
if(subIdx == sub.length - 1){
return x - subIdx;
}
subIdx++;
} else{
subIdx = 0;
}
}
return -1;
}
private void copy(InputStream in, OutputStream out) throws Exception{
int len = -1;
byte[] buf = new byte[1024];
while((len = in.read(buf)) >= 0)
{
out.write(buf, 0, len);
}
in.close();
out.close();
}
}
- 调用
Map<String, String> xmpMap = new HashMap<>();
xmpMap.put("testKey","testValue");
xmpMap.put("testKey222","testValue22");
XMPUtil xmpUtil = new XMPUtil();
xmpUtil.changeImgXMP("F://4.jpg","F://6.jpg", xmpMap);