針對短信/彩信業務需解析圖片元數據(尺寸、色深、格式驗證),本文實現基於文件頭解析的純 Java 方案,不依賴 ImageIO,適合輕量級場景。
GIF87a / GIF89a (偏移 0-5)2^( (flag & 0x07) + 1 )JFIF (偏移 6-9)0xFFC0 後:高度(2B)、寬度(2B)、精度(1B)、分量數(1B)…BM (偏移 0-1)2^bitsPNG (偏移 1-3)PicsModelpublic class PicsModel implements Serializable {
private String picsExtendName; // 格式
private int picsWidth, picsHeight;
private String picsColor; // 色深描述
private String picsSize; // 文件大小 KB/MB
// getter/setter 省略
}
readpicpublic class readpic {
public static void main(String[] args) {
PicsModel m = getFileAttributes("E:/test.jpg");
System.out.println("格式:" + m.getPicsExtendName());
System.out.println("寬:" + m.getPicsWidth() + " 高:" + m.getPicsHeight());
System.out.println("色深:" + m.getPicsColor() + " 大小:" + m.getPicsSize());
}
private static PicsModel getFileAttributes(String path) {
byte[] data = readFile(path);
PicsModel m = new PicsModel();
m.setPicsSize(formatSize(data.length));
String fmt = detectFormat(data);
m.setPicsExtendName(fmt);
switch (fmt) {
case "GIF": parseGIF(data, m); break;
case "JPG": parseJPG(data, m); break;
case "BMP": parseBMP(data, m); break;
case "PNG": parsePNG(data, m); break;
}
return m;
}
// 讀取文件字節數組
private static byte[] readFile(String path) throws IOException {
try (FileInputStream in = new FileInputStream(path)) {
byte[] buf = new byte[in.available()];
in.read(buf);
return buf;
}
}
// 格式檢測:按簽名匹配
private static String detectFormat(byte[] b) {
if (b[0]==71 && b[1]==73 && b[2]==70 && b[3]==56 && (b[4]==55||b[4]==57) && b[5]==97) return "GIF";
if (b[6]==74 && b[7]==70 && b[8]==73 && b[9]==70) return "JPG";
if (b[0]==66 && b[1]==77) return "BMP";
if (b[1]==80 && b[2]==78 && b[3]==71) return "PNG";
return "UNKNOWN";
}
// 通用小端序讀取(GIF/BMP/PNG)
private static int readLE(byte[] b, int offset, int len) {
int val = 0;
for (int i = len-1; i >= 0; i--) {
val = (val << 8) | (b[offset+i] & 0xFF);
}
return val;
}
// 大端序讀取(JPG/JFIF 段)
private static int readBE(byte[] b, int offset, int len) {
int val = 0;
for (int i = 0; i < len; i++) {
val = (val << 8) | (b[offset+i] & 0xFF);
}
return val;
}
private static void parseGIF(byte[] b, PicsModel m) {
m.setPicsWidth(readLE(b, 6, 2));
m.setPicsHeight(readLE(b, 8, 2));
int flag = b[10] & 0xFF;
m.setPicsColor(formatColor(1 << ((flag & 0x07) + 1)));
}
private static void parseJPG(byte[] b, PicsModel m) {
// 簡化:嘗試兩種常見偏移
int w1 = readBE(b, 166, 2), h1 = readBE(b, 164, 2), c1 = (b[167] & 0xFF) * 8;
if (w1>0 && h1>0 && c1<=24) { m.setPicsWidth(w1); m.setPicsHeight(h1); m.setPicsColor(formatColor(1<= 1048576) return (colors/1048576) + "M";
if (colors >= 1024) return (colors/1024) + "K";
return String.valueOf(colors);
}
private static String formatSize(long bytes) {
if (bytes >= 1024) return (bytes/1024 + 1) + "K";
return bytes + "B";
}
}





0xFFC0 SOF 標記,動態定位尺寸,避免固定偏移失效。RandomAccessFile 僅讀取頭部,避免全量載入內存。ImageIO 或 metadata-extractor 庫,標準、健壯、支持更多格式(EXIF、ICC Profile 等)。