home *** CD-ROM | disk | FTP | other *** search
/ DOS/V Power Report 2001 January / VPR0101A.BIN / OLS / LZR100 / lzr100.lzh / Source / Pure / GIFDecode.cpp next >
C/C++ Source or Header  |  2000-10-07  |  8KB  |  227 lines

  1. /*--------------------------------------------------------------------------------------*/
  2. /*    非LZW理論GIFデコーダー本体 実装ファイル    Ver 1.00                                    */
  3. /*    for VisualStudio6.0 only                                                            */
  4. /*    ※実際の展開処理を行い、DIBとして返却します。                                        */
  5. /*    Copyright (C) 2000 DJ☆Uchi [H.Uchida]                                                */
  6. /*--------------------------------------------------------------------------------------*/
  7. #include "GIFDecode.h"
  8.  
  9.  
  10. /*--------------------------------------------------------------------------------------*/
  11. /*    GifDecode()                                                                            */
  12. /*    GIF画像(最初の一枚のみ)を展開する。                                                */
  13. /*    ※入力はGIFデータ、出力はDIB。                                                        */
  14. /*    ※ここでは主にデコードの前処理を行います。                                            */
  15. /*--------------------------------------------------------------------------------------*/
  16. void GifDecode(BYTE *rgb, BYTE *gif, DWORD width, DWORD height,
  17.                DWORD align, DWORD inter ,WORD color, DWORD size)
  18. {
  19.     //GIFデータ解析用構造体初期化
  20.     GIFDECODESTATUS gs;
  21.     gs.code_size    = gif[0];                //コードサイズ取得
  22.     gs.bit_size        = gs.code_size + 1;        //CBL初期化(コードサイズ+1)
  23.     gs.clear_code    = 1 << gs.code_size;    //クリアコード設定(2^コードサイズ)
  24.     gs.end_code        = gs.clear_code + 1;    //エンドコード設定(2^コードサイズ+1)
  25.     gs.entry        = 0;                    //デコード位置初期化(0)
  26.     gs.bit_pt        = 8;                    //ビットポインタ初期化(8bit=1byte)
  27.     gs.next_block    = 1;                    //次ブロック位置初期化(先頭ブロック)
  28.     gs.data_size    = size;                    //GIFデータサイズ取得
  29.  
  30.     //DIBデータ書き込み用構造体初期化
  31.     RGBDECODESTATUS rs;
  32.     rs.gs            = &gs;                    //GIFDECODESTATUS構造体参照用ポインタ取得
  33.     rs.rgb_pt        = 0;                    //展開データ書き込み位置初期化
  34.     rs.rgb_offset    = (height - 1) * align;    //書き込み位置オフセット
  35.     rs.rgb_width    = width;                //DIB横pixel数取得
  36.     rs.rgb_height    = height;                //DIB縦pixel数取得
  37.     rs.rgb_align    = align;                //DIBアラインメント値取得
  38.     rs.rgb_color    = color;                //DIBカラービット値取得
  39.     rs.rgb_line        = 0;                    //展開データ書き込みライン初期化
  40.     rs.inter_offset    = 8;                    //インタレースオフセット初期化
  41.     rs.inter_flag    = inter;                //インタレースフラグ取得
  42.  
  43.     //エンドコードが現れるまでひたすらループ
  44.     while (lzw_string(rgb, gif, &rs, gs.entry++) != gs.end_code);
  45.  
  46.     return;
  47. }
  48.  
  49.  
  50. /*--------------------------------------------------------------------------------------*/
  51. /*    GetCode()                                                                            */
  52. /*    可変ビット長入力関数。                                                                */
  53. /*    ※指定された位置(x番目)の符号化コードを取り出す。                                    */
  54. /*    ※取り出したデータはそのままデコード処理に渡されます。                                */
  55. /*--------------------------------------------------------------------------------------*/
  56. WORD GetCode(BYTE *gif, GIFDECODESTATUS *gs, int x)
  57. {
  58.     //GIFの符号化コードは可変ビット長で隙間無く埋められているため、
  59.     //任意の位置の符号化コードを一発で取り出すことは不可能です。
  60.     //その為、先頭から順に目的の符号化コードをサーチしていきます。
  61.  
  62.     DWORD code = 0;
  63.     DWORD bit_pt = gs->bit_pt;
  64.     DWORD pt;
  65.     DWORD next_block = gs->next_block;
  66.     DWORD bit_size = gs->code_size + 1;
  67.     int bit_limit = (1 << bit_size) - gs->end_code - 2;
  68.  
  69.     //目的の位置に達するまで読み飛ばす。
  70.     int j = 0;
  71.     while (j < x) {
  72.         pt = bit_pt >> 3;
  73.         while ((bit_pt + bit_size - 1) >> 3 >= pt) {
  74.             if (pt == next_block) {
  75.                 next_block += gif[pt++] + 1;
  76.                 bit_pt += 8;
  77.             }
  78.             pt++;
  79.         }
  80.         bit_pt += bit_size;
  81.         if ((j++ > bit_limit) && (bit_size < 12)) {
  82.             bit_size++;
  83.             bit_limit = (1 << bit_size) - gs->end_code - 2;
  84.         }
  85.     }
  86.  
  87.     //目的の位置に達した。
  88.     pt = bit_pt >> 3;
  89.     //サイズオーバーフローの場合、強制的にエンドコードを返す(破損ファイル対策)
  90.     if (pt + 2 > gs->data_size) return (WORD)gs->end_code;
  91.     //目的の位置に達したので、その場所の符号化コードを取得する。
  92.     int i = 0;
  93.     while ((bit_pt + bit_size - 1) >> 3 >= pt) {
  94.         if (pt == next_block) {
  95.             next_block += gif[pt++] + 1;
  96.             bit_pt += 8;
  97.         }
  98.         code += gif[pt++] << i;
  99.         i += 8;
  100.     }
  101.     //得られたコードの余分なビットを切りとばす。(マスキング処理)
  102.     code = (code >> (bit_pt & 0x07)) & ((1 << bit_size) - 1);
  103.  
  104.     //取り出した符号化コードがクリアコードだった場合。
  105.     if (code == gs->clear_code) {
  106.         gs->bit_pt = bit_pt + bit_size;
  107.         gs->next_block = next_block;
  108.         gs->entry = 0;
  109.     }
  110.  
  111.     return (WORD)code;
  112. }
  113.  
  114.  
  115. /*--------------------------------------------------------------------------------------*/
  116. /*    lzw_string()                                                                        */
  117. /*    非LZW理論展開関数(コア)                                                            */
  118. /*    ※非LZW理論の核。                                                                    */
  119. /*    ※指定された符号化コードに対する展開データを返します。                                */
  120. /*--------------------------------------------------------------------------------------*/
  121. WORD lzw_string(BYTE *rgb, BYTE *gif, RGBDECODESTATUS *rs, int x)
  122. {
  123.     //配列から符号化コードを一つ取り出します。
  124.     WORD code = GetCode(gif, rs->gs, x);
  125.  
  126.     //符号化コードが”色数”より小さい場合
  127.     if (code < rs->gs->clear_code) {
  128.         //符号化コードをそのままDIBに書き込む。
  129.         rgb_write(rgb, rs, code);
  130.  
  131.     //符号化コードがクリアコードやエンドコードである場合
  132.     } else if (code <= rs->gs->end_code) {
  133.         return code;
  134.  
  135.     //符号化コードが未知のものである場合
  136.     } else if (code > rs->gs->end_code + x) {
  137.         lzw_string(rgb, gif, rs, --x);
  138.         lzw_char(rgb, gif, rs, --x);
  139.  
  140.     //符号化コードが”色数+1”より大きい場合
  141.     } else {
  142.         lzw_string(rgb, gif, rs, code - rs->gs->end_code - 1);
  143.         lzw_char(rgb, gif, rs, code - rs->gs->end_code);
  144.     }
  145.  
  146.     return 0;
  147. }
  148.  
  149.  
  150. /*--------------------------------------------------------------------------------------*/
  151. /*    lzw_char()                                                                            */
  152. /*    非LZW理論展開関数(サブ)                                                            */
  153. /*    ※非LZW理論の核。                                                                    */
  154. /*    ※指定された符号化コードに対する展開データの先頭1つを返します。                    */
  155. /*--------------------------------------------------------------------------------------*/
  156. void lzw_char(BYTE *rgb, BYTE *gif, RGBDECODESTATUS *rs, int x)
  157. {
  158.     //配列から符号化コードを一つ取り出します。
  159.     WORD code = GetCode(gif, rs->gs, x);
  160.  
  161.     //符号化コードが”色数”より小さい場合
  162.     if (code < rs->gs->clear_code) {
  163.         rgb_write(rgb, rs, code);
  164.  
  165.     //符号化コードが未知のものである場合
  166.     } else if (code > rs->gs->end_code + x) {
  167.         lzw_char(rgb, gif, rs, --x);
  168.  
  169.     //符号化コードが”色数+1”より大きい場合
  170.     } else {
  171.         lzw_char(rgb, gif, rs, code - rs->gs->end_code - 1);
  172.     }
  173. }
  174.  
  175.  
  176. /*--------------------------------------------------------------------------------------*/
  177. /*    rgb_write()                                                                            */
  178. /*    DIB画像データ書き込み関数。                                                            */
  179. /*    ※展開された画像データをDIBとして書き込みます。                                        */
  180. /*--------------------------------------------------------------------------------------*/
  181. void rgb_write(BYTE *rgb, RGBDECODESTATUS *rs, WORD code)
  182. {
  183.     //DIBに画像データを書き込みます。
  184.     //モノクロや16色の場合はビット単位での書き込みになる為、マスキング処理を行います。
  185.     DWORD i, j;
  186.     if (rs->rgb_color == 1) {            //モノクロ画像の場合
  187.         i = rs->rgb_offset + (rs->rgb_pt >> 3);
  188.         j = 7 - (rs->rgb_pt & 0x07);
  189.         rgb[i] = (rgb[i] & ~(1 << j)) | (code << j);
  190.     } else if (rs->rgb_color == 4) {    //16色画像の場合
  191.         i = rs->rgb_offset + (rs->rgb_pt >> 1);
  192.         j = (rs->rgb_pt & 0x01) << 2;
  193.         rgb[i] = (rgb[i] & (0x0F << j)) | (code << (4 - j));
  194.     } else {                            //256色の場合
  195.         rgb[rs->rgb_offset + rs->rgb_pt] = (BYTE)code;
  196.     }
  197.  
  198.     //書き込み位置をインクリメント
  199.     rs->rgb_pt++;
  200.     //書き込み位置がラインの終端に達した場合
  201.     if (rs->rgb_pt == rs->rgb_width) {
  202.         if (rs->inter_flag) {    //インタレースGIFの場合
  203.             //インタレースラインが画面下端に達した場合
  204.             if (rs->rgb_line + rs->inter_offset >= rs->rgb_height){
  205.                 if ((rs->rgb_line & 0x07) == 0) {
  206.                     rs->rgb_offset = (rs->rgb_height - 5) * rs->rgb_align;
  207.                     rs->rgb_line = 4;
  208.                 } else if (rs->inter_offset == 8) {
  209.                     rs->rgb_offset = (rs->rgb_height - 3) * rs->rgb_align;
  210.                     rs->rgb_line = 2;
  211.                     rs->inter_offset = 4;
  212.                 } else if (rs->inter_offset == 4) {
  213.                     rs->rgb_offset = (rs->rgb_height - 2) * rs->rgb_align;
  214.                     rs->rgb_line = 1;
  215.                     rs->inter_offset = 2;
  216.                 }
  217.             } else {
  218.                 rs->rgb_offset -= rs->rgb_align * rs->inter_offset;
  219.                 rs->rgb_line += rs->inter_offset;
  220.             }
  221.         } else {                //リニアGIFの場合
  222.             rs->rgb_offset -= rs->rgb_align;
  223.         }
  224.         rs->rgb_pt = 0;
  225.     }
  226. }
  227.