Windows Phone 解析图片尺寸之jpg

  上一篇介绍了Windows Phone 解析图片尺寸之png,本篇介绍一下如何解析jpg图片的尺寸大小,由于jpg图片的格式相对于png要复杂很多,所以首先我们要先清楚的了解jpg图片的数据格式,jpg图片包括SOI和数据两个部分。
  SOI,Start of Image,图像开始,标记代码 2字节 固定值0xFFD8。
  数据部分分成很多数据段,数据段的一般结构如下。

段数据结构
名称 字节 说明
段标识 >= 1 多于一个的0xFF
段类型 1 类型编码(称作“标记码”)
段长度 2 包括段内容和段长度本身,不包括段标识和段类型
短内容 <= 65533  

  段类型有30种,但只有10种是必须被所有程序识别的,其它的类型都可以忽略。在这么多的段中,其中JPG图片的尺寸相关信息存储在SOF0(图像基本信息)段中。所以需要详细了解一下SOFO段的数据结构。

SOFO段结构
名称 字节 说明
段标识 1 0XFF
段类型 1 0XCO JFIF格式的为0XC2
段长度 2 其值=8+组件数量×3
样本精度 1 8 每个样本位数(大多数软件不支持12和16)
图片高的 2 采用Motorola格式,即:高位在前,低位在后
图片宽度 2 采用Motorola格式,即:高位在前,低位在后

  由于我们是为了解析JPG图片的宽度和高度信息,所以上表SOFO段结构只列出了到宽度为止结构信息,接下来还有其他一些图片的相关信息,这里就不再列出。
  根据上面对JPG图片格式的解析,我们可以分一下几步来解析JPG图片的尺寸信息。
  1.读取2个字节的SOI,即0xFFD8,根据这两个字节判断图片是否为JPG图片,如果不是,则退出解析过程。

View Code
        //读取2个字节的SOI,即0xFFD8
byte[] header = new byte[2];
stream.Read(header, 0, 2);
//判断是否为JPG,不是退出解析
if (!(header[0] == 0xFF &&
header[1] == 0xD8))
{
//不是JPG图片
return;
}

  2.接下来就需要解析图片的数据部分,由于数据部分是有很多不同的数据段构成,数据段拥有一些共同的特性,所以这里我们需要做一个循环来逐个遍历查找到SOFO数据段。

View Code
        //段类型
int type = -1;
int ff = -1;
//记录当前读取的位置
long ps = 0;
//逐个遍历所以段,查找SOFO段
do
{
do
{
//每个新段的开始标识为oxff,查找下一个新段
ff = stream.ReadByte();
if (ff < 0) //文件结束
{
return;
}
} while (ff != 0xff);

do
{
//段与段之间有一个或多个oxff间隔,跳过这些oxff之后的字节为段标识
type = stream.ReadByte();
} while (type == 0xff);

//记录当前位置
ps = stream.Position;
switch (type)
{
case 0x00:
case 0x01:
case 0xD0:
case 0xD1:
case 0xD2:
case 0xD3:
case 0xD4:
case 0xD5:
case 0xD6:
case 0xD7:
break;
case 0xc0: //SOF0段(图像基本信息)
case 0xc2: //JFIF格式的 SOF0段
{
//找到SOFO段,解析宽度和高度信息
getJpgSize(stream);
return;
}
default: //别的段都跳过
//获取段长度,直接跳过
ps = stream.ReadByte() * 256;
ps = stream.Position + ps + stream.ReadByte() - 2;
break;
}
if (ps + 1 >= stream.Length) //文件结束
{
return;
}
stream.Position = ps; //移动指针
} while (type != 0xda); // 扫描行开始

  3.找到SOFO数据段后,就可以解析图片的宽度和高度信息。

View Code
        /// <summary>
/// 解析JPG图片的尺寸
/// </summary>
/// <param name="stream"></param>
private void getJpgSize(Stream stream)
{
//跳过2个自己长度信息和1个字节的精度信息
stream.Seek(3, SeekOrigin.Current);

//高度 占2字节 低位高位互换
height_ = stream.ReadByte() * 256;
height_ += stream.ReadByte();
//宽度 占2字节 低位高位互换
width_ = stream.ReadByte() * 256;
width_ += stream.ReadByte();
}

 

posted @ 2012-03-22 22:51  宇之乐  阅读(1716)  评论(2编辑  收藏  举报