上一篇介紹了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();
}