import java.io.FileInputStream;
import java.io.IOException;
public class CheckPNGByCRC32 {
static final int CHUNKTYPECODE_BYTE_LENGTH = 4;
static int CHUNKDATA_BYTE_LENGTH = 0;
static final int FILE_HEADER_BYTE_LENGTH = 8;
static final int CRC_BYTE_LENGTH = 4;
/**
* byte数组转换成16进制字符串
*
* @param src
* @return
*/
public static String bytesToHexString(byte[] src) {
StringBuilder stringBuilder = new StringBuilder();
if (src == null || src.length <= 0) {
return null;
}
for (int i = 0; i < src.length; i++) {
int v = src[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
/**
* 根据文件流读取图片文件真实类型 // [-119, 80, 78, 71, 13, 10, 26, 10//文件头标识
*
* @param is
* @return
*/
public static String getTypeByStream(FileInputStream is) {
byte[] b = new byte[FILE_HEADER_BYTE_LENGTH];
b = readInfoByLocation(FILE_HEADER_BYTE_LENGTH, is);
String type = bytesToHexString(b).toUpperCase();
if (type.contains("FFD8FF")) {
return "jpg";
} else if (type.contains("89504E47")) {
return "png";
} else if (type.contains("47494638")) {
return "gif";
} else if (type.contains("49492A00")) {
return "tif";
} else if (type.contains("424D")) {
return "bmp";
}
return type;
}
public static byte[] readInfoByLocation(int length, FileInputStream is) {
byte[] b = new byte[length];
try {
is.read(b, 0, length);
} catch (IOException e) {
e.printStackTrace();
}
return b;
}
/**
* 解析IHDR数据块
*
* @param is
* @return
*/
public static String getIHDRInfo(FileInputStream is) {
String fileType = "";// 文件标示
int IHDRLength = 0;// IHDR字节长度
String result = "";// 判断文件中CRC的值与根据数据块计算后的CRC是否相等,监测当前数据块是否被修改
byte[] b = new byte[CHUNKTYPECODE_BYTE_LENGTH];
b = readInfoByLocation(b.length, is);
// 0, 0, 0, 13, //IHDR长度
IHDRLength = Integer.parseInt(bytesToHexString(b), 16);
System.out.println("chunk data length:" + IHDRLength);
byte[] ihdrData = new byte[IHDRLength + CHUNKTYPECODE_BYTE_LENGTH];
try {
is.read(ihdrData);
} catch (IOException e1) {
e1.printStackTrace();
}
// IHDR标示,16进制转换成ascII码再转成string为IHDR
// 73, 72, 68, 82, //I H D R
for (int i = 0; i < 4; i++) {
fileType += String.valueOf(backchar(ihdrData[i]));
}
// IEND文件结束
System.out.println("Data block identification:" + fileType);
// 0, 0, 3, 78,//宽
byte[] picWidthByte = { ihdrData[4], ihdrData[5], ihdrData[6], ihdrData[7] };
int picWidth = Integer.parseInt(bytesToHexString(picWidthByte), 16);
System.out.println("picture width:" + picWidth);
// 0, 0, 4, 127, //高
byte[] picHeightByte = { ihdrData[8], ihdrData[9], ihdrData[10], ihdrData[11] };
int picHeight = Integer.parseInt(bytesToHexString(picHeightByte), 16);
System.out.println("picture heigh:" + picHeight);
// 8, 色深 2的8次方=256 ,256真彩色
System.out.println("Color depth:" + new java.math.BigInteger("2").pow(ihdrData[12]));
// 4
System.out.println("Color type:" + ihdrData[13]);
// 00 PNG Spec规定此处总为0(非0值为将来使用更好的压缩方法预留),表示使压缩方法(LZ77派生算法)
String compressionMethod = String.valueOf(ihdrData[14]);
// 00 同上
String compressionMethod1 = String.valueOf(ihdrData[15]);
// 00 非隔行扫描
String nonInterlacedScanning = String.valueOf(ihdrData[16]);
// 读取文件中CRC值
byte[] crcInFileByte = new byte[CRC_BYTE_LENGTH];
crcInFileByte = readInfoByLocation(b.length, is);
String crcInFileString = bytesToHexString(crcInFileByte).toUpperCase();
System.out.println("crc in file:" + crcInFileString);
// 根据数据计算CRC
String calcCrcByData = CrcTest.getCrc(ihdrData).toUpperCase();
System.out.println("calculate by data :" + calcCrcByData);
if (crcInFileString.equals(calcCrcByData)) {
result = fileType + "CRC right, not modify";
} else {
result = fileType + "CRC wrong,modified";
}
return result;
}
public static void readFile(FileInputStream is) {
boolean isContinue=true;
do{
String result = "";// 判断文件中CRC的值与根据数据块计算后的CRC是否相等,监测当前数据块是否被修改
String dataType = "";
byte[] b = new byte[CHUNKTYPECODE_BYTE_LENGTH];
b = readInfoByLocation(b.length, is);
// 0, 0, 0, 13, //IHDR长度
int dataLength = Integer.parseInt(bytesToHexString(b), 16);
System.out.println("chunk data length:" + dataLength);
byte[] ihdrData = new byte[dataLength + CHUNKTYPECODE_BYTE_LENGTH];
try {
is.read(ihdrData);
} catch (IOException e1) {
e1.printStackTrace();
}
for (int i = 0; i < 4; i++) {
dataType += String.valueOf(backchar(ihdrData[i]));
}
System.out.println("Data block identification:" + dataType);
if(dataType.equals("IEND")){
isContinue=false;
}
// 读取文件中CRC值
byte[] crcInFileByte = new byte[CRC_BYTE_LENGTH];
crcInFileByte = readInfoByLocation(b.length, is);
String crcInFileString = bytesToHexString(crcInFileByte).toUpperCase();
System.out.println("crc in file:" + crcInFileString);
// 根据数据计算CRC
String calcCrcByData = CrcTest.getCrc(ihdrData).toUpperCase();
System.out.println("calculate by data :" + calcCrcByData);
if (crcInFileString.equals(calcCrcByData)) {
result = dataType + " CRC right, not modify";
} else {
result = dataType + " CRC wrong,modified";
}
System.out.println(result);
System.out.println(" ***** ");
}while(isContinue);
}
/**
* 字符转ASC
*
* @param st
* @return
*/
public static int getAsc(String st) {
byte[] gc = st.getBytes();
int ascNum = (int) gc[0];
return ascNum;
}
/**
* ASC转字符
*
* @param backnum
* @return
*/
public static char backchar(int backnum) {
char strChar = (char) backnum;
return strChar;
}
public static String convertHexToString(String hex) {
StringBuilder sb = new StringBuilder();
StringBuilder temp = new StringBuilder();
// 49204c6f7665204a617661 split into two characters 49, 20, 4c...
for (int i = 0; i < hex.length() - 1; i += 2) {
// grab the hex in pairs
String output = hex.substring(i, (i + 2));
// convert hex to decimal
int decimal = Integer.parseInt(output, 16);
// convert the decimal to character
sb.append((char) decimal);
temp.append(decimal);
}
return sb.toString();
}
public static byte[] hexStringToBytes(String hexString) {
if (hexString == null || hexString.equals("")) {
return null;
}
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
return d;
}
private static byte charToByte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}
/*
* JPEG (jpg),文件头:FFD8FF PNG (png),文件头:89504E47 GIF (gif),文件头:47494638 TIFF
* (tif),文件头:49492A00 Windows Bitmap (bmp),文件头:424D
*/
public static void main(String[] args) throws Exception {
String src = "D:\\maizi2.png";
FileInputStream is = new FileInputStream(src);
String type = getTypeByStream(is);
System.out.println("file type:" + type);
System.out.println(" ***** ");
String IHDR = getIHDRInfo(is);
System.out.println("IHDR:" + IHDR);
System.out.println(" ***** ");
readFile(is);
}
}