JPEG是网络中使用非常频繁的一种图片,本身是一种有损压缩格式,本文并不对其压缩和编码进行研究,只是对JPEG的文件存储格式进行浅析,然后说明在C#中实现对其存储数据的解析。
JPEG是按段存储的,在真正的图像数据之前会有多个段用来存储图片的信息,在SOS(Start of Scan)段之后之后开始扫面压缩的图像数据,最后遇到EOI(End of Image)段停止。
除SOI(Start of Image)段和EOI段外,JPEG的每个段都是由两部分组成:标记码(Tag)和段内数据:其中,标记码的长度为2个字节,第一个字节(高位字节)为0xFF,通常标志一个段的开始,第二个字节是该段的标志字节,用来标明该段的身份,对于不同的段,该字节的值是不同的;在标记码之后就是段内数据,段内数据的前两个字节用来定义该段的长度(注意,该长度不包括Tag的两个字节)。
注意:对于JPEG格式的图片,可以再段与段之间填充多个值为0xFF的字节,在进行图片解析时,这些字节是被忽略的。
对于JPEG来说,其真正的图像数据是位于SOS(start of Scan)段和EOI段之间的,所以对读取的图片字节流进行拆分时,可以从EOI段开始,获取SOS之前(包括SOS)各段的数据,获取的方法是首先定位标志位,然后再标志位后获取长度,然后按照长度读取出该段,然后继续寻找下一个段的标志位(此处必须注意的是在两个段之间可能会填充不定长个值为0xFF的字节),直到得到SOS段。在SOS段后便是图片的压缩数据,直接进行扫描,直到扫描到EOI段的Tag。
相关代码如下,在下面的代码中,首先通过file的方法或者filestream将图片作为字节流读入,然后进行处理:
代码中并没有把每个段切出来,只是在for循环中对如果定位每个段给出了方案,直到得到SOS段
之后,在下一个for循环中扫描数据直到扫描到EOI段 停止
int eoi= 0;
int sos = 0;
//找到jpeg图片sos段的结尾
for (int i = 2; i < allGetBytes.Length; i++)
{
if (allGetBytes.ElementAt(i) == 255 & allGetBytes.ElementAt(i + 1) == 218)
{
sos = i + 1;
break;
}
if (allGetBytes.ElementAt(i) == 255 && allGetBytes.ElementAt(i + 1) == 255)
{
continue;
}
if (allGetBytes.ElementAt(i) == 255 && allGetBytes.ElementAt(i + 1) != 255)
{
int count = 0;
count += allGetBytes.ElementAt(i + 2);
count = count * 16 * 16 + allGetBytes.ElementAt(i + 3);
i += (count + 1);
continue;
}
}
//在sos段后遍历搜索EOI结束段
for (int i = sos; i < allGetBytes.Length; i++)
{
if (allGetBytes.ElementAt(i) == 255 && allGetBytes.ElementAt(i + 1) == 217)
{
eoi = i+1;
break;
}
}
最后来就说一下在