阿拉巴馬文翻譯語言翻譯公司
GIF數據緊縮
...
Initialize String Table; [.c.] = Empty; [.c.]k = First Character in CharStream; while ([.c.]k != EOF ) { if ( [.c.]k is in the StringTable) { [.c.] = [.c.]k; } else { add [.c.]k to the StringTable; Output the Index of [.c.] in the StringTable to the CodeStream; [.c.] = k; } [.c.]k = Next Character in CharStream; } Output the Index of [.c.] in the StringTable to the CodeStream; Output the Index of [.c.] in the StringTable to the CodeStream;
|
文件結尾部門
2.LZW算法和GIF數據壓縮
|
|
塊終結器 |
Block Terminator - 標識注釋塊竣事,固定值0 |
事實上,這類猜想法是很準確(有點欠好理解,細心想想吧)翻譯上面的解碼進程用偽代碼表示就像下面如許:
讀取第一個編碼到[code],這是一個根編碼,在編譯表中可以找到,把該編碼所對應的字符輸出到數據流,[old]=[code];讀取下一個編碼到[code],這就有兩種環境:在編譯表中有或沒有該編碼,華頓翻譯社們先來看第一種環境:先輸出當前編碼[code]所對應的字符(串)到數據流,然后把[old]所對應的字符(串)當成prefix [...],當前編碼[code]所對應的字符(串)的第一個字符當做k,組合起來當前字符串Current String就為[...]k,把[...]k添加到編譯表,讀下一個編碼;我們來看看在編譯表中找不到該編碼的情形,回憶一下編碼環境:如果數據流中有一個p[...]p[...]pq如許的字符串,p[...]在編譯表中而p[...]p不在,編譯器將輸出p[...]的索引而添加p[...]p到編譯表,下一個字符串p[...]p可以在編譯表中找到而p[...]pq不在編譯表,一樣將輸出p[...]p的索引值而添加p[...]pq到編譯表,如許看來,解碼器總比編碼器『慢一步』,當我們遇到p[...]p所對應的索引時,華頓翻譯社們不知到該索引對應的字符串(在解碼器的編譯表中還沒有該索引,事實上,這個索引將鄙人一步添加),這時候需要用猜想法:目前假定上面的p[...]所對應的索引值是#58,那麼上面的字符串經過編譯之后是#58#59,我們在解碼器中讀到#59時,編譯表的最大索引只有#58,#59所對應的字符串就等於#58所對應的字符串(也就是p[...])加上它的第一個字符(也就是p),也就是p[...]p。
好了,如今來看看解碼數據翻譯數據的解碼,其實就是數據編碼的逆向進程,要從已編譯的數據(編碼流)中找出編譯表,然后對比編譯表還原圖像的光柵數據翻譯
首先,照樣要初始化編譯表翻譯GIF文件的圖像數據的第一個字節存儲的就是LZW編碼的編碼巨細(一般等於圖像的位數),按照編碼巨細,初始化編譯表的根條目(從0到2的編碼大小次方),然后界說一個當前編碼Current Code,記作[code],界說一個Old Code,記作[old]。
看起來和調色板圖像的實現道理差不多,可是應該留意到的是,華頓翻譯社們這里的編譯表不是事前創建好的,而是憑據原始圖像數據動態創建的,解碼時還要從已編碼的數據中還原出本來的編譯表(GIF文件中是不攜帶編譯表信息的),為了更好理解編解碼道理,我們來看看具體的處置過程:
LZW緊縮的道理,就是先提取原始圖象數據中的分歧圖案,基於這些圖案建立一個編譯表,然后用編譯表中的圖案索引來替代原始光柵數據中的響應圖案,削減原始數據巨細。應用法式數據
利用法式自界說數據塊 - 一個或多個數據塊(Data Sub-Blocks)組成,保留運用程序本身定義的數據 |
Initialize String Table; [code] = First Code in the CodeStream; Output the String for [code] to the CharStream; [old] = [code]; [code] = Next Code in the CodeStream; while ([code] != EOF ) { if ( [code] is in the StringTable) { Output the String for [code] to the CharStream; // 輸出[code]所對應的字符串 [...] = translation for [old]; // [old]所對應的字符串 k = first character of translation for [code]; // [code]所對應的字符串的第一個字符 add [...]k to the StringTable; [old] = [code]; } else { [...] = translation for [old]; k = first character of [...]; Output [...]k to CharStream and add it to StringTable; [old] = [code]; } [code] = Next Code in the CodeStream; } 注釋塊
編碼器(Compressor)
圖形文本擴大(Plain Text Extension)
|
編碼長度
然后寫入圖像數據塊中翻譯
4.打包
前面講過,一個GIF的數據塊的巨細從0到255個字節,第一個字節是這個數據塊的巨細(字節數),這就需要將編譯編后的碼數據打包成一個或幾個大小不大於255個字節的數據包。
BYTE |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
|
1 |
...
文件終結 文本數據塊
0 |
b |
b |
b |
a |
a |
a |
a |
a |
1 |
d |
c |
c |
c |
c |
c |
b |
b |
2 |
e |
e |
e |
e |
d |
d |
d |
d |
3 |
g |
g |
f |
f |
f |
f |
f |
e |
4 |
h |
h |
h |
h |
h |
g |
g |
g |
|
... |
N |
|
|
|
|
|
|
|
|
下面是GIF文件的圖像數據結構:
...
...
解碼器(Decompressor)
如今來初始化編譯表:#0=a翻譯社#1=b,#2=c,#3=d.目前入手下手讀取第一個字符a,[.c.]a=a,可以在在編譯表中找到,修改[.c.]=a;不做任何事繼續讀取第二個字符b,[.c.]b=ab,在編譯表中不克不及找,那麼添加[.c.]b到編譯表:#4=ab,同時輸出[.c.](也就是a)的索引#0到編碼流,點竄[.c.]=b;讀下一個字符a,[.c.]a=ba,在編譯表中不克不及找到:添加編譯表#5=ba,輸出[.c.]的索引#1到編碼流,點竄[.c.]=a;讀下一個字符c,[.c.]c=ac,在編譯表中不克不及找到:添加編譯表#6=ac,輸出[.c.]的索引#0到編碼流,點竄[.c.]=c;讀下一個字符a,[.c.]c=ca,在編譯表中不能找到:添加編譯表#7=ca,輸出[.c.]的索引#2到編碼流,點竄[.c.]=a;讀下一個字符b,[.c.]b=ab,編譯表的#4=ab,點竄[.c.]=ab;讀取最后一個字符a,[.c.]a=aba,在編譯表中不克不及找到:添加編譯表#8=aba,輸出[.c.]的索引#4到編碼流,點竄[.c.]=a;好了,目前沒稀有據了,輸出[.c.]的值a的索引#0到編碼流,這樣最后的輸出了局就是:#0#1#0#2#4#0.來看一個具體的例子翻譯社我們有一個字母表a,b,c,d.有一個輸入的字符流abacaba。
...
這一部份只有一個值為0的字節,標識一個GIF文件竣事.
|
N+1 |
塊終結 |
Block Terminator - 標識注釋塊竣事,固定值0 |
http://dev.gameres.com/Program/Visual/Other/GIFDoc.htm
|
Comment Data - 一個或多個數據塊(Data Sub-Blocks)構成 |
文件終結器(Trailer)
BYTE |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
BIT |
1 |
擴展塊標識 |
Extension Introducer - 標識這是一個擴展塊,固定值0x21 |
2 |
圖形節制擴大標簽 |
Plain Text Label - 標識這是一個圖形文本擴大塊,固定值0x01 |
3 |
塊大小 |
Block Size - 塊大小,固定值12 |
4 |
文本框左側界位置 |
Text Glid Left Posotion - 像素值,文本框離邏輯屏幕的左側界距離 |
5 |
6 |
文本框上界限位置 |
Text Glid Top Posotion - 像素值,文本框離邏輯屏幕的上邊界距離 |
7 |
8 |
文本框高度 |
Text Glid Width -像素值 |
9 |
10 |
文本框高度 |
Text Glid Height - 像素值 |
11 |
12 |
字符單元格寬度 |
Character Cell Width - 像素值,單個單位格寬度 |
13 |
字符單位格高度 |
Character Cell Height- 像素值,單個單位格高度 |
14 |
文本前景色索引 |
Text Foreground Color Index - 前風景在全局色彩列表中的索引 |
15 |
文本靠山色索引 |
Text Blackground Color Index - 背景色在全局顏色列表中的索引 |
N |
|
BYTE |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
BIT |
1 |
擴大塊標識 |
Extension Introducer - 標識這是一個擴展塊,固定值0x21 |
2 |
圖形控制擴大標簽 |
Application Extension Label - 標識這是一個應用法式擴大塊,固定值0xFF |
3 |
塊巨細 |
Block Size - 塊大小,固定值11 |
4 |
應用法式標識符 |
Application Identifier - 用來判別利用程序自身的標識(8個持續ASCII字符) |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
運用法式鑒別碼 |
Application Authentication Code - 應用法式定義的特別標識碼(3個陸續ASCII字符) |
13 |
14 |
N |
這一部門是可選的(需要89a版本),用來繪制一個簡單的文本圖像,這一部分由用來繪制的純文本數據(7-bit ASCII字符)和控制繪制的參數等構成。圖形文本擴大的構成:
繪制文本借助於一個文本框(Text Grid)來界說界限,在文本框中划分多個單元格,每個字符占用一個單位,繪制時按從左到右、從上到下的挨次順次進行,直到最后一個字符或者占滿整個文本框(之后的字符將被疏忽,是以界說文本框的巨細時應當注重到是不是可以容納全部文本),繪制文本的色彩利用全局色彩列表,沒有則可使用一個已保存的前一個色彩列表翻譯別的,圖形文本擴展塊也屬於圖形塊(Graphic Rendering Block),可以在它前面界說圖形節制擴大對它的顯示情勢進一步修改。這里利用的LZW緊縮算法是從標準的LZW緊縮算法演化過來的,它們之間有如下的不同: [1]GIF文件定義了一個編碼大小(Clear Code),這個值等於2的『編碼長度』次方,在重新開始一個編譯表(編譯表溢出)時均須輸出該值,解碼器碰到該值時意味著要從新初始化一個編譯表; [2]在一個圖像的編碼數據竣事之前(也就是在塊終結器的前面),需要輸出一個Clear Code+1的值,解碼器在碰到該值時就意味著GIF文件的一個圖象數據流的竣事; [3]第一個可用到的編譯表索引值是Clear Code+2(從0到Clear Code-1是根索引,再上去兩個不成使用,新的索引從Clare Code+2最先添加); [4]GIF輸出的編碼流是不定長的,每個編碼的巨細從Code Size + 1位到12位,編碼的最大值就是4095(編譯表需要界說的索引數就是4096),當編碼所須的位數超過當前的位數時就把當前位數加1,這就需要在編碼或解碼時注意到編碼長度的改變。 3.編譯成字節序列 因為GIF輸出的編碼流是不定長的,這就需要把它們編譯成固定的8-bit長度的字符流,編譯遞次是從右往左翻譯下面是一個具編制子:編譯5位長度編碼到8位字符把光柵數據序列(數據流)緊縮成GIF文件的圖象數據(字符流)可以按下面的步調進行: 1.定義編碼長度 GIF圖像數據的第一個字節就是編碼長度(Code Size),這個值是指要施展闡發一個像素所需要的最小位數,平常就等於圖像的色深; 2.壓縮數據 經由過程LZW壓縮算法將圖像的光柵數據流壓縮成GIF的編碼數據流。 GIF文件的圖像數據利用了可變長度編碼的LZW緊縮算法(Variable-Length_Code LZW Compression),這是從LZW(Lempel Ziv Compression)緊縮算法演化過來的,經由過程緊縮原始數據的重復部門來到達削減文件巨細的目標。注釋擴展(Comment Extension)
這一部門是可選的(需要89a版本),可以用來紀錄圖形、版權、描寫等任何的非圖形和控制的純文本數據(7-bit ASCII字符),注釋擴展並不影響對圖像數據流的處理,解碼器完全可以疏忽它翻譯寄存位置可所以數據流的任何處所,最好不要妨礙節制和數據塊,推荐放在數據流的入手下手或結尾翻譯具體構成:
BYTE |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
BIT |
1 |
擴展塊標識 |
Extension Introducer - 標識這是一個擴展塊,固定值0x21 |
2 |
注釋塊標簽 |
Comment Label - 標識這是一個注釋塊,固定值0xFE |
|
BYTE |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
BIT |
1 |
|
Plain Text Data - 一個或多個數據塊(Data Sub-Blocks)構成,保留要在顯示的字符串。 |
這是供給給應用程序本身利用的(需要89a版本),利用程序可以在這里定義本身的標識、信息等,構成:
編碼數據,第一步,初始化一個編譯表,假定這個編譯表的大小是12位的,也就是最多有4096個單元,別的假定華頓翻譯社們有32個分歧的字符(也能夠認為圖像的每個像素最多有32種顏色),暗示為a,b,c,d,e...,初始化編譯表:第0項為a,第1項為b,第2項為c...一向到第31項,我們把這32項就稱為根。 入手下手編譯,先定義一個前綴對象Current Prefix,記為[.c.],而今它是空的,然后界說一個當前字符串Current String,符號為[.c.]k,[.c.]就為Current Prefix,k就為當前讀取字符翻譯此刻來讀取數據流的第一個字符,假設為p,那麼Current String就等於[.c.]p(由於[.c.]為空,現實上值就等於p),此刻在編譯表中查找有沒有Current String的值,由於p就是一個根,華頓翻譯社們已初始了32個根,固然可以找到,把p設為Current Prefix的值,不做任何事繼續讀取下一個字符,假定為q,Current String就等於[.c.]q(也就是pq),看看在編譯表中有沒有該值,當然。沒有,這時候華頓翻譯社們要做下面的工作:將Current String的值(也就是pq)添加到編譯表的第32項,把Current Prefix的值(也就是p)在編譯表中的索引輸出到編碼流,點竄Current Prefix為q。繼續往下讀,假如在編譯表中可以查找到Current String的值([.c.]k),則把Current String的值([.c.]k)付與Current Prefix;假如查找不到,則添加Current String的值([.c.]k)到編譯表,把Current Prefix的值([.c.])在編譯表中所對應的索引輸出到編碼流,同時點竄Current Prefix為k ,如許一向輪回下去直到數據流竣事翻譯偽代碼看起來就像下面如許:
|
GIF Trailer - 標識GIF文件結束,固定值0x3B |
|
推荐:1.由於文本的字體(Font)和尺寸(Size)沒有定義,解碼器應該按照情況選擇最合適的; 2.若是一個字符的值小於0x20或大於0xF7,則這個字符被推荐顯示為一個空格(0x20); 3.為了兼容性,最好定義字符單位格的大小為8x8或8x16(寬度x高度)翻譯 ... 在編碼時,數據流是輸入對象(圖像的光柵數據序列),編碼流就是輸出對象(存儲在GIF文件的圖像數據);在解碼時,編碼流則是輸入對象,數據流是輸出對象;而編譯表是在編碼息爭碼時都必要用借助的對象翻譯
字符(Character):最基礎的數據元素,在文本文件中就是一個字節,在光柵數據中就是一個像素的顏色在指定的色彩列表中的索引值; 字符串(String):由幾個一連的字符組成; 前綴(Prefix):也是一個字符串,不外平日用在另外一個字符的前面,而且它的長度可以為0; 根(Root):單個長度的字符串; 編碼(Code):一個數字,依照固定長度(編碼長度)從編碼流中掏出,也是編碼表的映射值; 圖案:一個字符串,按不定長度從數據流中讀出翻譯LZW的緊縮原理:
先來诠釋一下幾個根基概念: LZW緊縮有三個主要的對象:數據流(CharStream)、編碼流(CodeStream)和編譯表(String Table)。 應用法式擴大(Application Extension)
|
LZW Code Size - LZW緊縮的編碼長度,也就是要緊縮的數據的位數 |
|
... |
數據塊 |
|
塊巨細 |
數據塊,假如需要可重復屢次 |
|
編碼數據 |
|
... |
數據塊 |
|
塊終結器 |
一個圖象的數據編碼結束,固定值0 |
|
N+1 |
塊終結器 |
lock Terminator - 標識注釋塊結束,固定值0 |
以下內文出自: http://blog.xuite.net/tzeng015/twblog/113272104-GIF%E5%9C%96%E5%BD%A2%E6%96%87%E4%BB%B6%E6%A0%BC%E5%有關翻譯的問題歡迎諮詢天成翻譯社 | |