private final static byte[] app1 = new byte[] { (byte) 0xFF, (byte) 0xE1 };
private final static byte[] exifHeader = new byte[] { (byte) 0x45, (byte) 0x78, (byte) 0x69, (byte) 0x66, (byte) 0x00, (byte) 0x00 };
private final static byte[] tiffHeader = new byte[] { (byte) 0x49, (byte) 0x49, (byte) 0x2A, (byte) 0x00, (byte) 0x08, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
private final static byte[] orientationTag = new byte[] { (byte) 0x01, (byte) 0x12 };
private final static byte[] orientationTagDataType = new byte[] { (byte) 0x00, (byte) 0x03 };
private final static byte[] orientationTagLength = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01 };
private final static byte[] motorolaAlignType = new byte[] { (byte) 0x4D, (byte) 0x4D };
public static int detectExif(byte[] jpgFileBytes) {
boolean findExifOrTIFF = false;
int alignTypeI = 0;// 字节码的表示方式,Motorola 1为从高到低,intel 2从低到高
int orientationTagValue = -1;
int i = 0;
int searchEndIndex = 0;//搜索结束的字节索引(取自IFD0的entry截止位置)
for (; i < jpgFileBytes.length; i++) {
if (!findExifOrTIFF && jpgFileBytes[i] == app1[0] && jpgFileBytes[i + 1] == app1[1]) {
int headerOffset = i + 4;
byte[] header = Arrays.copyOfRange(jpgFileBytes, headerOffset, headerOffset + 6);//exif header
byte[] alignType;
int TIFF_Start = 0;
if (Arrays.equals(header, exifHeader)) {
TIFF_Start = headerOffset + 6;
alignType = Arrays.copyOfRange(jpgFileBytes, TIFF_Start, TIFF_Start + 2);
alignTypeI = Arrays.equals(alignType, motorolaAlignType) ? 1 : 2;
logger.info("Exif Header,format:" + alignTypeI);
searchEndIndex = getIFD0EndIndex(jpgFileBytes, TIFF_Start, alignTypeI);
findExifOrTIFF = true;
continue;
} else {
header = Arrays.copyOfRange(jpgFileBytes, headerOffset, headerOffset + 8);//tiff header
if (Arrays.equals(header, tiffHeader)) {
TIFF_Start = headerOffset + 8;
alignType = Arrays.copyOfRange(jpgFileBytes, TIFF_Start, TIFF_Start + 2);
alignTypeI = Arrays.equals(alignType, motorolaAlignType) ? 1 : 2;
logger.info("TIFF Header,format:" + alignTypeI);
searchEndIndex = getIFD0EndIndex(jpgFileBytes, TIFF_Start, alignTypeI);
findExifOrTIFF = true;
continue;
}
}
break;
}
if (findExifOrTIFF) {
if (i >= searchEndIndex) {
break;
} else if (jpgFileBytes[i] == orientationTag[0] && jpgFileBytes[i + 1] == orientationTag[1] && jpgFileBytes[i + 2] == orientationTagDataType[0] && jpgFileBytes[i + 3] == orientationTagDataType[1] && jpgFileBytes[i + 4] == orientationTagLength[0] && jpgFileBytes[i + 5] == orientationTagLength[1] && jpgFileBytes[i + 6] == orientationTagLength[2] && jpgFileBytes[i + 7] == orientationTagLength[3]) {
if (alignTypeI == 1) {
orientationTagValue = jpgFileBytes[i + 9];
break;
} else if (alignTypeI == 2) {
orientationTagValue = jpgFileBytes[i + 8];
break;
}
}
}
}
return orientationTagValue;
}
private static int getIFD0EndIndex(byte[] jpgFileBytes, int TIFF_Start, int alignTypeI) {
byte[] IFD0_OFFSET_VALUE = Arrays.copyOfRange(jpgFileBytes, TIFF_Start + 4, TIFF_Start + 8);
if(alignTypeI==2) {
ArrayUtils.reverse(IFD0_OFFSET_VALUE);
}
int offSet = Integer.parseInt(byte2HexStr(IFD0_OFFSET_VALUE), 16);
byte[] IFD0_ENTRY_NUM_ARR = Arrays.copyOfRange(jpgFileBytes,TIFF_Start+offSet,TIFF_Start+offSet+2);
if(alignTypeI==2) {
ArrayUtils.reverse(IFD0_ENTRY_NUM_ARR);
}
int IFD0_ENTRY_NUM = Integer.parseInt(byte2HexStr(IFD0_ENTRY_NUM_ARR), 16);//entry的数目
int searchEndIndex = TIFF_Start+offSet+2 + IFD0_ENTRY_NUM * 12;//每个entry 12个字节
return searchEndIndex;
}
纯java实现检测exif/jiff规范jpeg(jpg)orientation旋转方向
这段代码主要解析JPEG文件中的Exif信息,寻找TIFF头和Exif头,确定Motorola或Intel字节序,并查找方向标签(Orientation Tag),返回其值。通过对JPEG文件字节的遍历,找到APP1段,然后检查是否包含Exif或TIFF头,进一步获取IFD0的结束索引,最后读取方向标签的值。
摘要由CSDN通过智能技术生成