RLE行程長度編碼壓縮算法


在看emWIN的時候看到一個圖片壓縮的算法可以有效的對二值圖(簡單的2中顏色或者更多)進行壓縮,壓縮的效果可以節省空間而且不丟失信息!

特點

一種壓縮過的 位圖文件格式,RLE壓縮方案是一種極其成熟的壓縮方案,特點是無損失壓縮,既節省了磁盤空間又不損失任何圖像數據。
游程編碼是一種統計編碼,該編碼屬於無損壓縮編碼。對於二值圖有效。其在對圖像數據進行編碼時,沿一定方向排列的具有相同灰度值的像素可看成是連續符號,用字串代替這些連續符號,可大幅度減少數據量。
行程編碼是連續精確的編碼,在傳輸過程中,如果其中一位符號發生錯誤,即可影響整個編碼序列,使行程編碼無法還原回原始數據。
游程編碼所能獲得的壓縮比有多大,主要取決於圖像本身的特點。如果圖像中具有相同顏色的圖像塊越大,圖像塊數目越少,獲得的壓縮比就越高。反之,壓縮比就越小。

缺點

在打開這種 壓縮文件時,要花費更多時間,此外,一些兼容性不太好的應用程序可能會打不開。
不過RLE還有一個缺點,那要是內容像ABCABCABC的話使用這種算法文件會增大,就是1A1B1C1A1B1C1A1B1C了,更長,就達不到壓縮的效果了。簡單來說,游程編碼就是用一個符號值或串長代替具有相同值的連續符號(連續符號構成了一段連續的“行程”。行程編碼因此而得名),使符號長度少於原始數據的長度

RLE壓縮方式 

ABBBBBBBBA - 1A8B1A
下面都對byte流壓縮。
如輸入數據
LPBTEpByte={1,1,1,1,1,1};
壓縮的數據為6,1
壓縮了4個字符。
但是在 數據流里面不能直接這么替換,而應該使用特殊的 控制字符,否則無法解壓。
比如pByte={6,1,0,1,1,1,1,1,1};
這樣有兩個6,1無法判斷是原有的6,1還是{1,1,1,1,1,1}壓縮后的代碼。
所以應該有控制字符
(1)
為了達到最大壓縮率,可以先掃描源數據流,使用最少出現的字符做 控制字符
如pByte={6,1,0,1,1,1,1,1,1,...};
掃描后發現0為最少出現的字符。
我們使用0作為壓縮的控制,其他字符代表他本身。源數據里面的0,用0,0來表示。
那么pByte壓縮后為
6,1,0,0,0,6,1......
解壓時BYTEa,b,c;
a=依次掃描壓縮數據,如果輸入字符為非 控制字符,則直接輸出到解壓流。
如果為 控制字符,b=其下一字符是否也為控制字符,如果是,在輸出流輸出控制字符的代碼。
如果不是c=讀壓縮流,然后輸出b個c到輸出流。
注意:該處對於>Ctrlcode的編碼需要自己計算偏移.
如ctrl=2.那么n=3時應該修正為2.
剛才介紹的方法是最大壓縮率的,但是因為對每個輸入字符需要檢查,速度不算快。
(2)
為了增加解壓速度,可以采用其他的 編碼方式
主要方法是不對每個輸入字符進行檢查,只檢查較少次就達到幾乎相同的壓縮率。
來看看這個改進的方法。
仔細觀察,其實對不重復的 字符也可以用控制n+數據的方式表示。這里的n帶表n個未壓縮數據。
還是剛才的數據。
pByte={6,1,0,1,1,1,1,1,1}
不用掃描選擇0為控制
壓縮為3,{6,1,0,}0,6,1
nctrlnm
解壓就非常方便了
掃描數據讀一個字符,
{
n=read;
if(n)
{
字符拷貝n個
}
else
{
n=read();
m=read;
write(n個m);
}
}
(3)優化
對(1)的優化。
觀察得知,1,1,1這樣的數據壓縮率為0
 
下面的數組來自於emWIN壓縮的圖標數組:可以看到控制字符為0
/*********************************************************************
*
*       bm0
*/
static GUI_CONST_STORAGE unsigned char _ac0[] = {
  /* RLE: 011 Pixels @ 000,000 */ 11, 0xFF, 
  /* ABS: 010 Pixels @ 011,000 */ 0, 10, 0xF6, 0xA8, 0x48, 0x1D, 0x11, 0x0E, 0x1E, 0x47, 0x8E, 0xE7, 
  /* RLE: 021 Pixels @ 021,000 */ 21, 0xFF, 
  /* ABS: 002 Pixels @ 010,001 */ 0, 2, 0xBF, 0x30, 
  /* RLE: 008 Pixels @ 012,001 */ 8, 0x00, 
  /* ABS: 003 Pixels @ 020,001 */ 0, 3, 0x17, 0x97, 0xFE, 
  /* RLE: 017 Pixels @ 023,001 */ 17, 0xFF, 
  /* ABS: 003 Pixels @ 008,002 */ 0, 3, 0xFE, 0x91, 0x08, 
  /* RLE: 011 Pixels @ 011,002 */ 11, 0x00, 
  /* ABS: 002 Pixels @ 022,002 */ 0, 2, 0x69, 0xF8, 
  /* RLE: 016 Pixels @ 024,002 */ 16, 0xFF, 
  /* RLE: 001 Pixels @ 008,003 */ 1, 0x7B, 
  /* RLE: 005 Pixels @ 009,003 */ 5, 0x00, 
  /* ABS: 004 Pixels @ 014,003 */ 0, 4, 0x03, 0x0E, 0x0F, 0x06, 
  /* RLE: 005 Pixels @ 018,003 */ 5, 0x00, 
  /* ABS: 002 Pixels @ 023,003 */ 0, 2, 0x49, 0xF6, 
  /* RLE: 014 Pixels @ 025,003 */ 14, 0xFF, 
  /* ABS: 013 Pixels @ 007,004 */ 0, 13, 0xBE, 0x04, 0x00, 0x00, 0x00, 0x03, 0x60, 0xC2, 0xED, 0xF1, 0xD3, 0x7F, 0x13, 
  /* RLE: 004 Pixels @ 020,004 */ 4, 0x00, 
  /* RLE: 001 Pixels @ 024,004 */ 1, 0x85, 
  /* RLE: 014 Pixels @ 025,004 */ 14, 0xFF, 
  /* ABS: 006 Pixels @ 007,005 */ 0, 6, 0x4A, 0x00, 0x00, 0x00, 0x06, 0xA2, 
  /* RLE: 006 Pixels @ 013,005 */ 6, 0xFF, 
  /* ABS: 007 Pixels @ 019,005 */ 0, 7, 0xCE, 0x21, 0x00, 0x00, 0x00, 0x19, 0xE4, 
  /* RLE: 012 Pixels @ 026,005 */ 12, 0xFF, 
  /* ABS: 006 Pixels @ 006,006 */ 0, 6, 0xD4, 0x08, 0x00, 0x00, 0x00, 0x7D, 
  /* RLE: 008 Pixels @ 012,006 */ 8, 0xFF, 
  /* ABS: 006 Pixels @ 020,006 */ 0, 6, 0xB8, 0x01, 0x00, 0x00, 0x00, 0x99, 
  /* RLE: 012 Pixels @ 026,006 */ 12, 0xFF, 
  /* ABS: 006 Pixels @ 006,007 */ 0, 6, 0x9B, 0x00, 0x00, 0x00, 0x15, 0xE5, 
  /* RLE: 009 Pixels @ 012,007 */ 9, 0xFF, 
  /* ABS: 005 Pixels @ 021,007 */ 0, 5, 0x48, 0x00, 0x00, 0x00, 0x5F, 
  /* RLE: 012 Pixels @ 026,007 */ 12, 0xFF, 
  /* ABS: 005 Pixels @ 006,008 */ 0, 5, 0x7A, 0x00, 0x00, 0x00, 0x46, 
  /* RLE: 010 Pixels @ 011,008 */ 10, 0xFF, 
  /* ABS: 006 Pixels @ 021,008 */ 0, 6, 0x82, 0x00, 0x00, 0x00, 0x3E, 0xFE, 
  /* RLE: 011 Pixels @ 027,008 */ 11, 0xFF, 
  /* ABS: 005 Pixels @ 006,009 */ 0, 5, 0x71, 0x00, 0x00, 0x00, 0x56, 
  /* RLE: 010 Pixels @ 011,009 */ 10, 0xFF, 
  /* ABS: 006 Pixels @ 021,009 */ 0, 6, 0x93, 0x00, 0x00, 0x00, 0x34, 0xFA, 
  /* RLE: 011 Pixels @ 027,009 */ 11, 0xFF, 
  /* ABS: 005 Pixels @ 006,010 */ 0, 5, 0x70, 0x00, 0x00, 0x00, 0x57, 
  /* RLE: 010 Pixels @ 011,010 */ 10, 0xFF, 
  /* ABS: 006 Pixels @ 021,010 */ 0, 6, 0x94, 0x00, 0x00, 0x00, 0x33, 0xFA, 
  /* RLE: 011 Pixels @ 027,010 */ 11, 0xFF, 
  /* ABS: 005 Pixels @ 006,011 */ 0, 5, 0x71, 0x00, 0x00, 0x00, 0x57, 
  /* RLE: 010 Pixels @ 011,011 */ 10, 0xFF, 
  /* ABS: 006 Pixels @ 021,011 */ 0, 6, 0x94, 0x00, 0x00, 0x00, 0x34, 0xFA, 
  /* RLE: 011 Pixels @ 027,011 */ 11, 0xFF, 
  /* ABS: 005 Pixels @ 006,012 */ 0, 5, 0x71, 0x00, 0x00, 0x00, 0x57, 
  /* RLE: 010 Pixels @ 011,012 */ 10, 0xFF, 
  /* ABS: 006 Pixels @ 021,012 */ 0, 6, 0x94, 0x00, 0x00, 0x00, 0x35, 0xFB, 
  /* RLE: 008 Pixels @ 027,012 */ 8, 0xFF, 
  /* ABS: 010 Pixels @ 003,013 */ 0, 10, 0xCF, 0x69, 0x59, 0x26, 0x00, 0x00, 0x00, 0x1D, 0x58, 0x57, 
  /* RLE: 007 Pixels @ 013,013 */ 7, 0x56, 
  /* ABS: 009 Pixels @ 020,013 */ 0, 9, 0x5B, 0x32, 0x00, 0x00, 0x00, 0x11, 0x53, 0x5E, 0xAF, 
  /* RLE: 005 Pixels @ 029,013 */ 5, 0xFF, 
  /* ABS: 002 Pixels @ 002,014 */ 0, 2, 0xD6, 0x18, 
  /* RLE: 025 Pixels @ 004,014 */ 25, 0x00, 
  /* RLE: 001 Pixels @ 029,014 */ 1, 0xA4, 
  /* RLE: 004 Pixels @ 030,014 */ 4, 0xFF, 
  /* RLE: 001 Pixels @ 002,015 */ 1, 0x7E, 
  /* RLE: 026 Pixels @ 003,015 */ 26, 0x00, 
  /* RLE: 001 Pixels @ 029,015 */ 1, 0x46, 
  /* RLE: 004 Pixels @ 030,015 */ 4, 0xFF, 
  /* RLE: 001 Pixels @ 002,016 */ 1, 0x63, 
  /* RLE: 026 Pixels @ 003,016 */ 26, 0x00, 
  /* RLE: 001 Pixels @ 029,016 */ 1, 0x34, 
  /* RLE: 004 Pixels @ 030,016 */ 4, 0xFF, 
  /* RLE: 001 Pixels @ 002,017 */ 1, 0x64, 
  /* RLE: 026 Pixels @ 003,017 */ 26, 0x00, 
  /* RLE: 001 Pixels @ 029,017 */ 1, 0x35, 
  /* RLE: 004 Pixels @ 030,017 */ 4, 0xFF, 
  /* RLE: 001 Pixels @ 002,018 */ 1, 0x64, 
  /* RLE: 026 Pixels @ 003,018 */ 26, 0x00, 
  /* RLE: 001 Pixels @ 029,018 */ 1, 0x35, 
  /* RLE: 004 Pixels @ 030,018 */ 4, 0xFF, 
  /* RLE: 001 Pixels @ 002,019 */ 1, 0x64, 
  /* RLE: 026 Pixels @ 003,019 */ 26, 0x00, 
  /* RLE: 001 Pixels @ 029,019 */ 1, 0x35, 
  /* RLE: 004 Pixels @ 030,019 */ 4, 0xFF, 
  /* RLE: 001 Pixels @ 002,020 */ 1, 0x64, 
  /* RLE: 026 Pixels @ 003,020 */ 26, 0x00, 
  /* RLE: 001 Pixels @ 029,020 */ 1, 0x35, 
  /* RLE: 004 Pixels @ 030,020 */ 4, 0xFF, 
  /* RLE: 001 Pixels @ 002,021 */ 1, 0x64, 
  /* RLE: 026 Pixels @ 003,021 */ 26, 0x00, 
  /* RLE: 001 Pixels @ 029,021 */ 1, 0x35, 
  /* RLE: 004 Pixels @ 030,021 */ 4, 0xFF, 
  /* RLE: 001 Pixels @ 002,022 */ 1, 0x64, 
  /* RLE: 026 Pixels @ 003,022 */ 26, 0x00, 
  /* RLE: 001 Pixels @ 029,022 */ 1, 0x35, 
  /* RLE: 004 Pixels @ 030,022 */ 4, 0xFF, 
  /* RLE: 001 Pixels @ 002,023 */ 1, 0x64, 
  /* RLE: 026 Pixels @ 003,023 */ 26, 0x00, 
  /* RLE: 001 Pixels @ 029,023 */ 1, 0x35, 
  /* RLE: 004 Pixels @ 030,023 */ 4, 0xFF, 
  /* RLE: 001 Pixels @ 002,024 */ 1, 0x64, 
  /* RLE: 026 Pixels @ 003,024 */ 26, 0x00, 
  /* RLE: 001 Pixels @ 029,024 */ 1, 0x35, 
  /* RLE: 004 Pixels @ 030,024 */ 4, 0xFF, 
  /* RLE: 001 Pixels @ 002,025 */ 1, 0x64, 
  /* RLE: 026 Pixels @ 003,025 */ 26, 0x00, 
  /* RLE: 001 Pixels @ 029,025 */ 1, 0x35, 
  /* RLE: 004 Pixels @ 030,025 */ 4, 0xFF, 
  /* RLE: 001 Pixels @ 002,026 */ 1, 0x64, 
  /* RLE: 026 Pixels @ 003,026 */ 26, 0x00, 
  /* RLE: 001 Pixels @ 029,026 */ 1, 0x35, 
  /* RLE: 004 Pixels @ 030,026 */ 4, 0xFF, 
  /* RLE: 001 Pixels @ 002,027 */ 1, 0x64, 
  /* RLE: 026 Pixels @ 003,027 */ 26, 0x00, 
  /* RLE: 001 Pixels @ 029,027 */ 1, 0x35, 
  /* RLE: 004 Pixels @ 030,027 */ 4, 0xFF, 
  /* RLE: 001 Pixels @ 002,028 */ 1, 0x62, 
  /* RLE: 026 Pixels @ 003,028 */ 26, 0x00, 
  /* RLE: 001 Pixels @ 029,028 */ 1, 0x34, 
  /* RLE: 004 Pixels @ 030,028 */ 4, 0xFF, 
  /* RLE: 001 Pixels @ 002,029 */ 1, 0x6E, 
  /* RLE: 026 Pixels @ 003,029 */ 26, 0x00, 
  /* RLE: 001 Pixels @ 029,029 */ 1, 0x3B, 
  /* RLE: 004 Pixels @ 030,029 */ 4, 0xFF, 
  /* RLE: 001 Pixels @ 002,030 */ 1, 0xB5, 
  /* RLE: 026 Pixels @ 003,030 */ 26, 0x00, 
  /* RLE: 001 Pixels @ 029,030 */ 1, 0x7B, 
  /* RLE: 005 Pixels @ 030,030 */ 5, 0xFF, 
  /* ABS: 003 Pixels @ 003,031 */ 0, 3, 0x94, 0x1F, 0x0D, 
  /* RLE: 020 Pixels @ 006,031 */ 20, 0x0F, 
  /* ABS: 006 Pixels @ 026,031 */ 0, 6, 0x0D, 0x15, 0x6B, 0xF3, 0xFF, 0xFF, 
  0
};  // 416 bytes for 1024 pixels

GUI_CONST_STORAGE GUI_BITMAP bm0 = {
  32, // xSize
  32, // ySize
  32, // BytesPerLine
  GUI_COMPRESS_RLE8, // BitsPerPixel
  (unsigned char *)_ac0,  // Pointer to picture data
  NULL,  // Pointer to palette
  GUI_DRAW_RLEALPHA
};

  方法:

***************************************************************************************************************************************************

1.RLE概述

RLE(Run LengthEncoding行程編碼)算法是一個簡單高效的無損數據壓縮算法,其基本思路是把數據看成一個線性序列,而這些數據序列組織方式分成兩種情況:一種是連續的重復數據塊,另一種是連續的不重復數據塊。對於連續的重復數據快采用的壓縮策略是用一個字節(我們稱之為數據重數屬性)表示數據塊重復的次數,然后在這個數據重數屬性字節后面存儲對應的數據字節本身,例如某一個文件有如下的數據序列AAAAA,在未壓縮之前占用5個字節,而如果使用了壓縮之后就變成了5A,只占用兩個字節,對於連續不重復的數據序列,表示方法和連續的重復數據塊序列的表示方法一樣,只不過前面的數據重數屬性字節的內容為1。一般的這里的數據塊取一個字節,這篇文章中數據塊都默認為一個字節。為了更形象的說明RLE算法的原理我們給出最原始的RLE算法:

 

2.  原始RLE方法

給出的數據序列為:A-A-A-A-A-B-B-C-D

未壓縮前:A-A-A-A-A-B-B-C-D

(0x41-0x41-0x41-0x41-0x41-0x42-0x42-0x43-0x44)

壓縮后:5-A-2-B-1-C-1-D

(0x05-0x41-0x02-0x42-0x01-0x43-0x01-0x44)

 

從這里我們看到RLE的壓縮和解壓的算法原理非常簡單,實現起來也並不復雜。

在進行壓縮時逐個掃描待壓縮數據,如果碰到某個字節后有重復的字節則計數器就加1(計數器初始值默認為1,也可設置為0),直到找到一個不重復的字節為止,將當前計數器中的值存入數據重數屬性的字節中,將對應的該字節的數據存放在數據字節中,然后計數器置1繼續用同樣的策略掃描剩下的未壓縮文檔的數據。這里需要主意的是,數據重數屬性的單位是一個字節,故最大值為255,因此對於數據序列的某一個數據重復次數大於255時的數據,當計數器記到255時就必須強制將計數器值和當前數據值寫入數據重數屬性字節中和數據字節中,然后計數器置1繼續掃描,直到到達文件末尾。

 

由於壓縮后的數據格式為:數據重數,數據塊值,數據重數,數據塊值……,因此解壓的算法很簡單,就是讀出第一個位置上的數據重數字節存放的數據塊的個數N,然后將第二個位置上的數據字節存放的數據塊向解壓緩沖區寫N份,然后再讀出第三個位置上數據重數字節存放的數據塊的個數M,然后將第四個位置上數據字節存放的數據塊向解壓緩沖區寫M份,直到讀到壓縮數據末尾結束。

代碼如下:為了顯示更清楚(將數據重數屬性字節中的ASCII碼值轉換成了真實的數值,即本該為0x03的就用0x51表示)

 

[cpp]  view plain copy print ?
 
  1. #include<stdio.h>  
  2. #include<string.h>  
  3. #include<malloc.h>  
  4. #define MAX_SIZE 4096  
  5. /** 
  6. 實現了一個簡化版的RLE壓縮算法,該算法要求字符重復次數不超過79個(127-48) 
  7. 如果是可打印的,則為78吧~ 因為127的ASCII碼對應的字符Del是不可打印的 
  8. */  
  9. void CompressRLE(char* input ,char* output)  
  10. {  
  11.     int i,j,k = 0;  
  12.     for(i = 0; i < strlen(input); i++)  
  13.     {  
  14.         //直到找到和當前字符不相等的下個字符為止  
  15.         for(j = i;input[j] == input[i];j++)  
  16.             ;  
  17.         /*存放重復計數*/  
  18.         output[k++] = j - i + '0';  
  19.         /*存放重復的字符*/  
  20.         output[k++] = input[i];  
  21.         i = j - 1;   
  22.     }  
  23.     output[k] = '\0';  
  24. }  
  25.   
  26. void UnCompressRLE(char* input ,char* output)  
  27. {  
  28.     int i,j,count;  
  29.     for(i = 0; i < strlen(input);i = i + 2)  
  30.     {  
  31.         count = 0;/*當前重復字符計數*/  
  32.         /*在當前解壓字符串后存放原串剩余字符*/  
  33.         for( j = strlen(output); count < (input[i]-'0');j++)  
  34.         {  
  35.             output[j] = input[i+1];  
  36.             count ++;  
  37.         }  
  38.     }  
  39.     output[j] = '\0';  
  40. }  
  41. void main()  
  42. {  
  43.     char* input = (char*)malloc(MAX_SIZE);  
  44.     char* output = (char*)malloc(2*MAX_SIZE);  
  45.     char* result = (char*)malloc(MAX_SIZE);  
  46.   
  47.     memset(input,0,MAX_SIZE);  
  48.     memset(output,0,2*MAX_SIZE);  
  49.     memset(result,0,MAX_SIZE);  
  50.     printf("please input a string:\n");  
  51.     scanf("%s",input);  
  52.     printf("input = %s\n",input);  
  53.     CompressRLE(input,output);  
  54.     printf("output = %s\n",output);  
  55.     UnCompressRLE(output,result);  
  56.     printf("result = %s",result);  
  57.   
  58. }  

 

 

3.RLE改進一(PCX文件的處理方法)

 

 

雖然上述算法實現起來很容易,但是它的一個明顯的缺點就是如果要壓縮的數據很少有連續重復的數據塊,采用上訴壓縮算法之后數據量反而會“膨脹”,最壞情況下就是所有的數據都不連續重復,則壓縮后的數據量會增大一倍。因此就提出了一種改進的RLE算法。算法思路和原始RLE算法大致相當,對於重復的連續數據塊依然采用上述算法,不同的是對於不重復的數據塊,不會再在它前面插入標志重復次數的字節了,而是直接將該不重復的數據塊寫入壓縮文件。這樣即使原文件所有的數據都不是連續重復出現的,壓縮后的文件也不會膨脹。但是這樣簡單的邏輯顯然是不行的,這里的一個問題就是在解壓縮的時候,如何判斷一個字節是原始數據字節還是數據重數字節標志。為了解決這個問題,我們將數據重數字節的高兩位置1,用字節剩下的六位來表示(此時能表示的最大長度為63)數據重數,這樣在解壓的時候如果遇到的字節高兩位不全為1則一定是數據字節,但是這里還有一個問題是,如果遇見的字節的高兩位全1是就不能判斷是數據重數字節還是數據字節,因此,光處理數據重數屬性字節的高位是不行的,實現的辦法只能是,在數據壓縮的時候如果發現數據的高兩位是1只能再在該數據字節前面插入數據重數字節,置其值為1(此時由於高兩位作為標記位已經置為1,故這里實際存儲的是0XC1)。這樣這個改進的RLE算法就完成了,其平均壓縮率也比原始RLE算法更高,但是相對的壓縮速度就稍微慢了。同樣的與原始RLE算法一樣也有最大長度問題,處理方法與原始RLE一樣。

 

下面是RLE改進一的形象舉例說明:給出的數據序列為:A-A-A-A-A-B-B-C-D

未壓縮前:A-A-A-A-A-B-B-C-D

(0x41-0x41-0x41-0x41-0x41-0x42-0x42-0x43-0x44)

壓縮后:5-A-2-B-C-D

(0xC5-0x41-0xC2-0x42-0x43-0x44)

 

該算法的解壓算法很簡單,就是將讀取器指針指向第一個字節,逐個讀取每個字節,判斷該字節高兩位是否全為1,如果是,則表示該字節是數據重數字節,則從該字節后六位讀取重復次數N,然后將下一個字節向解壓緩沖區寫入N份,令讀取器加指針加2接着讀取下面的字節,如果該字節高兩位不全為1,則表明該字節是數據字節,故將該字節直接寫入解壓緩沖區,並使讀取器指針加1接着讀取下面的字節,直到讀取器指針達到文件末尾為止。

 

 4.RLE改進二

 

上述優化后的RLE算法,在原始數據普遍大於192(0xC0)的情況下,其優化效果相對於優化前的算法沒有明顯改善。原因在於,原始的RLE算法和改進后的RLE算法對於連續出現的不重復數據的處理方式都是一個一個處理的,沒有把不重復數據作為一個整體進行處理。RLE改進二算法的優化思想就是對連續的不重復數據的處理和連續重復數據的處理統一起來,不論數據是否連續重復,都在之前設置一個數據重數字節,這樣在解壓的時候就不需要區分是數據重數字節還是原始數據字節了。唯一需要區分的是后面跟的數據類型。區分的方法就是數據重數字節的最高位,如果最高位是1則表示后面跟的是連續重復的數據,如果最高位是0則表示后面跟的是連續不重復的數據。標志字節的低7位存儲數值(最大值是127),對於連續重復的數據,這個數字表示需要重復的次數,對於連續不重復數據,這個數字表示連續不重復數據塊的長度。需要注意的是,只有重復次數超過2的數據才被認為是連續重復數據,因為如果數據的重復次數是2,壓縮后加上標志字節后總的長度沒有變化,因此沒有必要處理。

 

下面是該RLE改進二的形象舉例說明:給出的數據序列為:A-A-A-A-A-B-B-C-D

未壓縮前:A-A-A-A-A-B-B-C-D

(0x41-0x41-0x41-0x41-0x41-0x42-0x42-0x43-0x44)

壓縮后:5-A-4-B-B-C-D

 

該RLE改進二的算法的壓縮算法設計如下:掃描指針從數據開始處讀取數據,並依次向后掃描各個字節,每向后讀取一個字節計數器加1,在掃描的同時比較每個字節是否相同,這樣就會有兩種情況:一種情況是掃描過程中前三個字節出現的都是連續重復的字節,則將計數器最高位置1,然后繼續掃描,直到出現1個不相同的字節,此時令掃描指針回退1個字節,計數器減1,然后將計數器的值寫入數據重數字節中,並將當前掃描指針指向字節寫到隨后的數據字節中。另一種情況是掃描過程中前兩個字節就不相同,則將計數器最高位置0,然后接着向后掃描,若在此后的掃描過程中出現連續3個相同的字節,則停止掃描,並令掃描指針回退到初始值,計數器減3,然后將當前計數器的值寫入數據重數字節中,並將當前掃描指針指向字節及其后N個字節寫到隨后的數據字節中。

 

 RLE改進二的解壓縮算法很簡單,因為壓縮后的格式是:數據重數,數據塊(組),數據重數,數據塊(組)……,因此從頭掃描,取出數據重數字節並判斷其標志位,若為1,則將接下來的一個字節向解壓緩沖區寫N份(這里的N是由數據重數字節低七位計算出來的),然后掃描指針加2,接着向后掃描。若為0,則將數據重數字節后面的N個字節都寫入解壓緩沖區,然后掃描指針加N+1,接着向后掃描。整個解壓過程直到掃描指針獨到整個數據尾部為止。

 

5.RLE改進三

 

以上算法中塊數屬性占用一個字節,原始RLE算法能表示的最大的數據重數為MAX=255,RLE改進一中由於高兩位做了標記位,則能表示的最大數據重數為MAX=63,RLE改進二中由於高一位做了標記位,則能表示的最大數據重數為MAX=127,所以如果某數據塊重復次數超過了最大值MAX,則按以上各算法,該連續重數的數據塊只能被分割成多個(數據重數,數據塊)對來表示,這樣就加大了空間的開銷。

 

針對上訴算法中出現的連續重復數據塊數超過MAX值的情況,規定如果數據重數字節的值為FF則在其后的一個字節仍為數據重數字節,最終的值為這幾個數據重數字節值的和,如果特殊的,某數據塊連續重復數正好是MAX值,則在該數據塊對應的數據重數字節F后再添加一個數據重數字節置其值為0x00。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM