很多人知道利用.png的字符串结尾可以判断前端传入的图片是否为png格式,但是这只是潜意识的判断!那么如何利用png读写的特殊内容来深意识地判断图片格式呢?最近在做东西的时候遇到了点问题,在加载图片的时候,加载失败,后缀都是jpg格式,但换个图片就可以了,为此,怀疑图片格式有问题,遂拖到UE里面查看 它的16进制,果然,两个图片的文件头根本就不一样,这不是欺负人嘛,害我白白浪费了半天的时间,差点要重新编译内核。

然后到网上找了一些资料,查看不同格式图片的文件头是怎样的。下面是不同图片的文件头标志:

图片的格式很多,一个图片文件的后缀名并不能说明这个图片的真正格式什么,那么如何获取图片的格式呢?我想到了几个简单但有效的方法,那就是读取图片文件的文件头标识。我们知道各种格式的图片的文件头标识识不同的,因此我们可以通过判断文件头的标识来识别图片格式。
     我对各种格式的图片文件头标识进行了分析,不仅查找资料,也用十六进制编辑器察看过图片的文件头,以下是我收集、分析的结果,供大家参考。

1.JPEG/JPG
- 文件头标识 (2 bytes): $ff, $d8 (SOI) (JPEG 文件标识)
- 文件结束标识 (2 bytes): $ff, $d9 (EOI)

2.TGA
- 未压缩的前5字节   00 00 02 00 00
- RLE压缩的前5字节   00 00 10 00 00

3.PNG
- 文件头标识 (8 bytes)   89 50 4E 47 0D 0A 1A 0A

4.GIF
- 文件头标识 (6 bytes)   47 49 46 38 39(37) 61
                        G  I  F  8  9 (7)  a

5.BMP
- 文件头标识 (2 bytes)   42 4D
                        B   M

6.PCX
- 文件头标识 (1 bytes)   0A

7.TIFF
- 文件头标识 (2 bytes)   4D 4D 或 49 49

8.ICO
- 文件头标识 (8 bytes)   00 00 01 00 01 00 20 20

9.CUR
- 文件头标识 (8 bytes)   00 00 02 00 01 00 20 20

10.IFF
- 文件头标识 (4 bytes)   46 4F 52 4D
                        F  O  R  M

11.ANI
- 文件头标识 (4 bytes)   52 49 46 46
                        R  I  F  F

 import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException; /**
* 图片转成十六进制
*/
public class img{
public static void main(String[] args) throws Exception {
try{
FileInputStream fis = new FileInputStream("png1.png");
java.io.ByteArrayOutputStream bos=new java.io.ByteArrayOutputStream();
byte[] buff=new byte[1024];
int len=0;
while((len=fis.read(buff))!=-1){
bos.write(buff,0,len);
}
//得到图片的字节数组
byte[] result=bos.toByteArray();
System.out.println("++++"+byte2HexStr(result));
//字节数组转成十六进制
String str=byte2HexStr(result);
}catch(IOException e){
} }
/*
* 实现字节数组向十六进制的转换方法一
*/
public static String byte2HexStr(byte[] b) {
String hs="";
String stmp="";
for (int n=0;n<9;n++) {
stmp=(Integer.toHexString(b[n] & 0XFF));
if (stmp.length()==1) hs=hs+"0"+stmp;
else hs=hs+stmp;
}
return hs.toUpperCase();
}
}

  根据这些文件头标识的收集,我可以写一个识别图像格式的模块了。但是在写这个模块之前可以对收集到的文件头标识进行优化,使得程序中字符串比对次数尽量的少。
1.JPEG我们知需要比对文件头的$ff, $d8这两个字符,而不用读取最后的两个结束标识了。
2.TGA,ICO,CUR只需比对第三个与第五个字符即可。
3.PNG比对[89][50]这两个字符。
4.GIF比对[47][49][46]与第五个字符。

废话不多说了,利用内存流来判断文件的格式,其实判断文件的前几个字节就可以简单的判断这个文件是什么类型的文件,例如

jpg文件 是 FFD8 (从低位到高位就要反过来 D8FF 下面都是一样)

BMP文件 是 424D ---4D42

其他的我就不一一列举了,想知道跟多文件类型分别是用什么字符作为文件的开头的话,下载个C32asm或者UE等这类16进制编辑器就可以看到了。

java利用16进制来辨别png格式的图片的更多相关文章

  1. java中16进制转换10进制

    java中16进制转换10进制 public static void main(String[] args) { String str = "04e1"; String myStr ...

  2. java byte 16进制转换

    整型转16进制: int devIdInt = Integer.parseInt(devId);String devIdString = Integer.toHexString(devIdInt); ...

  3. Java Hex 16进制的 byte String 转换类

    package mobi.dzs.android.util; import java.util.Locale; /** * 16进制值与String/Byte之间的转换 * @author Jerry ...

  4. Java中将16进制字符串转换成汉字

    技术交流群:233513714 /** * 将16进制字符串转换成汉字 * @param str * @return */ public static String deUnicode(String ...

  5. java中 16进制字符串 与普通字符串 与 byte数组 之间的转化

    方法依赖commons-codec包  maven的引入方式如下 <dependency> <groupId>commons-codec</groupId> < ...

  6. Java中16进制与字符串之间的相互转换

    笔者前几日在开服过程中需要将字符串转化成为16进制的字符串,在网上找到了一些方法尝试之后,均发现存在一个问题-->字符串转为16进制后再转回来,英文正常,中文出现乱码 经过考虑决定通过以下方式进 ...

  7. Java 基础------16进制转2进制

    我们知道,数字8用二进制表示为:1000 用16进制表示为:8 那么我给你一个16进制的数字,0x7f,他的二进制是什么呢? 一个16进制的位数,用4位表示.比如,0x 7 f 其中: 7用4位二进制 ...

  8. LR编写Socket脚本方法1(XML/16进制报文data.ws格式)

    本文主要讲述了Socket协议脚本的基础知识和编写方法,让大家能够在短时间内快速掌握简单的Socket协议脚本的编写方法.1.socket协议介绍Socket协议有万能协议之称,很多系统底层都是用的s ...

  9. Java中byte与16进制字符串的互换原理

    我们都知道Java中的byte是由8个bit组成的,而16进制即16中状态,它是由4个bit来表示的,因为24=16.所以我们可以把一个byte转换成两个用16进制字符,即把高4位和低4位转换成相应的 ...

随机推荐

  1. python第十一天-----补:线程池

    低版本: #!/usr/bin/env python import threading import time import queue class TreadPool: ""&q ...

  2. wcf session开启

    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] pu ...

  3. 防止刷新/后退引起的重复提交问题的Java Token代码,非Struts

    贴子转自http://hi.baidu.com/bobylou,转之前并没有验证文章里的方法是不是有效,估计原作者把它放到blog之前应该做过测试了吧. Struts本身有一套完善的防止重复提交表单的 ...

  4. 使用 BeanCopier 复制对象

    Cglib是一款比较底层的操作java字节码的框架. BeanCopier是一个工具类,可以用于Bean对象内容的复制. 复制Bean对象内容的方法有很多,比如自己手动get set ,或者使用Pro ...

  5. nop 添加字段

    一.Libraries 1.core 层------------实体字段 2.data-Map----------映射到数据库 二.Admin 1.Models  --------admin界面模型  ...

  6. linux 管道命令 竖线 ‘ | ’

    管道符号,是unix功能强大的一个地方,符号是一条竖线:"|", 用法: command 1 | command 2 他的功能是把第一个命令command 1执行的结果作为comm ...

  7. 使用代码在windows-store中打开、搜索应用程序

    //Launcher.LaunchUriAsync(newUri("ms-windows-store:PDP?PFN=" + Package.Current.Id.FamilyNa ...

  8. LLVM 初探<一>

    一.安装LLVM LLVM是一个低级虚拟机,全称为Low Level Virtual Machine.LLVM也是一个新型的编译器框架,相关的介绍Wikipedia. 现在LLVM的版本已经有很多,根 ...

  9. redhat 6上nis配置

    redhat 6上nis有点改动.在这里记一下 新装系统以后,首先要 yum install ypserv 安装ypserv的包 然后是设置 # 设置nis服务器名字 ypdomainname cen ...

  10. 《The Book of CSS3》学习笔记

    一.浏览器前缀 E{ -moz-name : value; /* Firefox */ -ms-name : value; /* IE */ -o-name : value; /* Opera */ ...