Android开发——JPEG码流分析

项目中使用Android解析JPEG码流,在此记录一下思路,一切以下方的实例分析图片数据信息编写。

目录

JPEG图片格式

1.SOI(0xFFD8):图片开始段

2.APP0(0xFFE0)

3.APPn(0xFFEn)可选

4.DQT(0xFFDB):量化表段

5.SOF0(0xFFC0):帧开始段

6.DHT(0xFFC4):Huffman表段

7.DRI可选

8.SOS(0xFFDA):扫描开始段

9.压缩图像数据

10.EOI(0xFFD9):图像结束段

实例分析:

具体部分代码如下:


JPEG图片格式

1.SOI(0xFFD8):图片开始段

名称字节数
段标识1FF
段类型1D8

2.APP0(0xFFE0)

名称字节数说明
段标识1FF
段类型1E0
段长度200 10
标识符54A 46 49 46 00“JFIF0”
主版本号101
次版本号101
密度单位1010表示无单位;1表示点数/英寸;2表示点数/厘米
X方向像素密度200 78水平方向像素密度
Y方向像素密度200 78竖直方向像素密度
缩略图水平像素数目100
缩略图垂直像素数目100
缩略图RGB位图3×n,n=缩略图像素总数=缩略图X像素×缩略图Y像素;缩略图X像素和缩略图Y像素的值都大于0,才有该值

3.APPn(0xFFEn)可选

名称字节数说明
应用程序保留标记n20xFFE1~0xFFFn=1~15,记录地点、时间等信息
数据段长度2

4.DQT(0xFFDB):量化表段

名称字节数说明
段标识1FFJPEG文件一般有2个DQT段,Y值(亮度)1个, C值(色度)1个。
段类型1DB一个DQT段可以包含多个QT, 每个都有自己的信息字节
段长度200 43
量化表信息100量化表信息:0-3位;QT号:4-7位(0=8bit;否则=16bit)
量化表内容6408 06 ...n = 64 × QT精度的字节数,即64×1

5.SOF0(0xFFC0):帧开始段

名称字节数说明
段标识1FF
段类型1C0
段长度200 11= 8+组件数量×3
精度108
图片高度200 14
图片宽度200 14
组件数量1031=灰度图,3=YCbcr或YIQ彩色图,4=CMYK彩色图
//Y颜色分量
组件ID1011=Y,2=Cb,3=Cr,4=I,5=Q
采样系数1220~3位:垂直采样系数,4~7位:水平采样系数
量化表号100
//Cb颜色分量
组件ID102
采样系数111
量化表号101
//Cr颜色分量Y采样是逐点采样,CbCr都是隔点采样,这就是标准的YUV422的数据。
组件ID103
采样系数111
量化表号101

6.DHT(0xFFC4):Huffman表段

名称字节数说明
段标识1FF
段类型1C4
段长度200 1F
HT信息1000~3位:HT号;4位:HT类型(0=DC表,1=AC表);5~7位:必须=0
HT位表16...16个数的和≤256
HT值表n...n=位表16个数的和
HT位表:00 01 05 01 01 01 01 01 01 00 00 00 00 00 00 00
HT值表:00 01 02 03 04 05 06 07 08 09 0A 0B
数量
00
0100
0501 02 03 04 05
0106
0107
0108
0109
010A
010B
00
00
00
00
00
00
00

注:此处有四个DHT表,只举一个例子。

7.DRI可选

8.SOS(0xFFDA):扫描开始段

名称字节数说明
段标识1FF
段类型1DA
段长度200 0C
扫描组件数量103
//组件1
0111=Y,2=Cb,3=Cr,4=I,5=Q
001Huffman表号0~3位:AC表号,4~7位:DC表号
//组件2
021
111
//组件3
031
111
300 3F 00意义不明确,忽略

9.压缩图像数据

10.EOI(0xFFD9):图像结束段

实例分析:

使用UltraEdit软件将图片转为16进制形式(随便截取了一张图片,20像素×20像素)

具体部分代码如下:

由于硬件传输至APP中是有包头,包头数据信息等一大堆乱七八糟的东西的,而且我做的这个项目,硬件端协议(如上图所示,SOI后边就是JPEG的格式了)对我来说不太明确的(但是还好我是硬件出身的,是懂硬件怎么传输的),一步一步摸索过来。比如说整个包长度4185字节,包头数据信息89字节,剩下的其实是4096,也就是说硬件每次传输4K字节,算一下就知道了(我真是个大SB),然后数据(FF D8 ...)我还不知道怎么处理,后来才有了前边的JPEG数据结构分析。

还有一个事就是,我以为图片解码是要我自己编程解码,后来是试试看的想法,也是懂了JPEG格式,将数据流写入文件,然后将文件变成JPEG格式,我觉得就可以显示图片了。后来去对应路径去验证,确实可以,只能说手机性能过剩,可能是硬解码牛逼。

//获取数据流
inputStream = socket.getInputStream();
len = inputStream.read(dwMagicCode);//这个是将数据流读取数据到数组,我这个写法是把dwMagicCode读满
while (true) {
    if (new String(dwMagicCode).equals("ZAKJ")) {//包头识别
       len = inputStream.read(wSizeArray);
       wSize = Integer.parseInt(ConvertDataToInt(wSizeArray, 0), 16);//包长度
       Log.d("TReqReceive+wSize", String.valueOf(wSize));

       len = inputStream.read(wCmdIdArray);
       wCmdId = Integer.parseInt(ConvertDataToInt(wCmdIdArray, 0), 16);//命令

       buffer = new byte[wSize - 12];
       len = inputStream.read(buffer);
       if(wCmdId == enNetCmd.CMD_PostSnapFileData){//命令码3024
          PictureData = new byte[wSize - 89];
          FileName = new String(buffer, 25, 6);//文件名称
          System.arraycopy(buffer, 77, PictureData, 0, wSize - 89);
          File newfile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/ftp" +"/"+FileName+".JPG");//根据文件名称及路径,创建文件
          try {
                if (!newfile.exists()){
                     newfile.createNewFile();
                 }
                 FileOutputStream fos = new FileOutputStream(Environment.getExternalStorageDirectory().getAbsolutePath() + "/ftp" +"/"+FileName+".JPG",true);
                 fos.write(PictureData);//数据流输出
                 fos.close();
           } catch (FileNotFoundException e) {
                  e.printStackTrace();
           } catch (IOException e) {
                  e.printStackTrace();
           }
        }
    }
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chinalihuanyu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值