home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DOS/V Power Report 2001 January
/
VPR0101A.BIN
/
OLS
/
LZR100
/
lzr100.lzh
/
Source
/
Pure
/
GIFDecode.cpp
next >
Wrap
C/C++ Source or Header
|
2000-10-07
|
8KB
|
227 lines
/*--------------------------------------------------------------------------------------*/
/* 非LZW理論GIFデコーダー本体 実装ファイル Ver 1.00 */
/* for VisualStudio6.0 only */
/* ※実際の展開処理を行い、DIBとして返却します。 */
/* Copyright (C) 2000 DJ☆Uchi [H.Uchida] */
/*--------------------------------------------------------------------------------------*/
#include "GIFDecode.h"
/*--------------------------------------------------------------------------------------*/
/* GifDecode() */
/* GIF画像(最初の一枚のみ)を展開する。 */
/* ※入力はGIFデータ、出力はDIB。 */
/* ※ここでは主にデコードの前処理を行います。 */
/*--------------------------------------------------------------------------------------*/
void GifDecode(BYTE *rgb, BYTE *gif, DWORD width, DWORD height,
DWORD align, DWORD inter ,WORD color, DWORD size)
{
//GIFデータ解析用構造体初期化
GIFDECODESTATUS gs;
gs.code_size = gif[0]; //コードサイズ取得
gs.bit_size = gs.code_size + 1; //CBL初期化(コードサイズ+1)
gs.clear_code = 1 << gs.code_size; //クリアコード設定(2^コードサイズ)
gs.end_code = gs.clear_code + 1; //エンドコード設定(2^コードサイズ+1)
gs.entry = 0; //デコード位置初期化(0)
gs.bit_pt = 8; //ビットポインタ初期化(8bit=1byte)
gs.next_block = 1; //次ブロック位置初期化(先頭ブロック)
gs.data_size = size; //GIFデータサイズ取得
//DIBデータ書き込み用構造体初期化
RGBDECODESTATUS rs;
rs.gs = &gs; //GIFDECODESTATUS構造体参照用ポインタ取得
rs.rgb_pt = 0; //展開データ書き込み位置初期化
rs.rgb_offset = (height - 1) * align; //書き込み位置オフセット
rs.rgb_width = width; //DIB横pixel数取得
rs.rgb_height = height; //DIB縦pixel数取得
rs.rgb_align = align; //DIBアラインメント値取得
rs.rgb_color = color; //DIBカラービット値取得
rs.rgb_line = 0; //展開データ書き込みライン初期化
rs.inter_offset = 8; //インタレースオフセット初期化
rs.inter_flag = inter; //インタレースフラグ取得
//エンドコードが現れるまでひたすらループ
while (lzw_string(rgb, gif, &rs, gs.entry++) != gs.end_code);
return;
}
/*--------------------------------------------------------------------------------------*/
/* GetCode() */
/* 可変ビット長入力関数。 */
/* ※指定された位置(x番目)の符号化コードを取り出す。 */
/* ※取り出したデータはそのままデコード処理に渡されます。 */
/*--------------------------------------------------------------------------------------*/
WORD GetCode(BYTE *gif, GIFDECODESTATUS *gs, int x)
{
//GIFの符号化コードは可変ビット長で隙間無く埋められているため、
//任意の位置の符号化コードを一発で取り出すことは不可能です。
//その為、先頭から順に目的の符号化コードをサーチしていきます。
DWORD code = 0;
DWORD bit_pt = gs->bit_pt;
DWORD pt;
DWORD next_block = gs->next_block;
DWORD bit_size = gs->code_size + 1;
int bit_limit = (1 << bit_size) - gs->end_code - 2;
//目的の位置に達するまで読み飛ばす。
int j = 0;
while (j < x) {
pt = bit_pt >> 3;
while ((bit_pt + bit_size - 1) >> 3 >= pt) {
if (pt == next_block) {
next_block += gif[pt++] + 1;
bit_pt += 8;
}
pt++;
}
bit_pt += bit_size;
if ((j++ > bit_limit) && (bit_size < 12)) {
bit_size++;
bit_limit = (1 << bit_size) - gs->end_code - 2;
}
}
//目的の位置に達した。
pt = bit_pt >> 3;
//サイズオーバーフローの場合、強制的にエンドコードを返す(破損ファイル対策)
if (pt + 2 > gs->data_size) return (WORD)gs->end_code;
//目的の位置に達したので、その場所の符号化コードを取得する。
int i = 0;
while ((bit_pt + bit_size - 1) >> 3 >= pt) {
if (pt == next_block) {
next_block += gif[pt++] + 1;
bit_pt += 8;
}
code += gif[pt++] << i;
i += 8;
}
//得られたコードの余分なビットを切りとばす。(マスキング処理)
code = (code >> (bit_pt & 0x07)) & ((1 << bit_size) - 1);
//取り出した符号化コードがクリアコードだった場合。
if (code == gs->clear_code) {
gs->bit_pt = bit_pt + bit_size;
gs->next_block = next_block;
gs->entry = 0;
}
return (WORD)code;
}
/*--------------------------------------------------------------------------------------*/
/* lzw_string() */
/* 非LZW理論展開関数(コア) */
/* ※非LZW理論の核。 */
/* ※指定された符号化コードに対する展開データを返します。 */
/*--------------------------------------------------------------------------------------*/
WORD lzw_string(BYTE *rgb, BYTE *gif, RGBDECODESTATUS *rs, int x)
{
//配列から符号化コードを一つ取り出します。
WORD code = GetCode(gif, rs->gs, x);
//符号化コードが”色数”より小さい場合
if (code < rs->gs->clear_code) {
//符号化コードをそのままDIBに書き込む。
rgb_write(rgb, rs, code);
//符号化コードがクリアコードやエンドコードである場合
} else if (code <= rs->gs->end_code) {
return code;
//符号化コードが未知のものである場合
} else if (code > rs->gs->end_code + x) {
lzw_string(rgb, gif, rs, --x);
lzw_char(rgb, gif, rs, --x);
//符号化コードが”色数+1”より大きい場合
} else {
lzw_string(rgb, gif, rs, code - rs->gs->end_code - 1);
lzw_char(rgb, gif, rs, code - rs->gs->end_code);
}
return 0;
}
/*--------------------------------------------------------------------------------------*/
/* lzw_char() */
/* 非LZW理論展開関数(サブ) */
/* ※非LZW理論の核。 */
/* ※指定された符号化コードに対する展開データの先頭1つを返します。 */
/*--------------------------------------------------------------------------------------*/
void lzw_char(BYTE *rgb, BYTE *gif, RGBDECODESTATUS *rs, int x)
{
//配列から符号化コードを一つ取り出します。
WORD code = GetCode(gif, rs->gs, x);
//符号化コードが”色数”より小さい場合
if (code < rs->gs->clear_code) {
rgb_write(rgb, rs, code);
//符号化コードが未知のものである場合
} else if (code > rs->gs->end_code + x) {
lzw_char(rgb, gif, rs, --x);
//符号化コードが”色数+1”より大きい場合
} else {
lzw_char(rgb, gif, rs, code - rs->gs->end_code - 1);
}
}
/*--------------------------------------------------------------------------------------*/
/* rgb_write() */
/* DIB画像データ書き込み関数。 */
/* ※展開された画像データをDIBとして書き込みます。 */
/*--------------------------------------------------------------------------------------*/
void rgb_write(BYTE *rgb, RGBDECODESTATUS *rs, WORD code)
{
//DIBに画像データを書き込みます。
//モノクロや16色の場合はビット単位での書き込みになる為、マスキング処理を行います。
DWORD i, j;
if (rs->rgb_color == 1) { //モノクロ画像の場合
i = rs->rgb_offset + (rs->rgb_pt >> 3);
j = 7 - (rs->rgb_pt & 0x07);
rgb[i] = (rgb[i] & ~(1 << j)) | (code << j);
} else if (rs->rgb_color == 4) { //16色画像の場合
i = rs->rgb_offset + (rs->rgb_pt >> 1);
j = (rs->rgb_pt & 0x01) << 2;
rgb[i] = (rgb[i] & (0x0F << j)) | (code << (4 - j));
} else { //256色の場合
rgb[rs->rgb_offset + rs->rgb_pt] = (BYTE)code;
}
//書き込み位置をインクリメント
rs->rgb_pt++;
//書き込み位置がラインの終端に達した場合
if (rs->rgb_pt == rs->rgb_width) {
if (rs->inter_flag) { //インタレースGIFの場合
//インタレースラインが画面下端に達した場合
if (rs->rgb_line + rs->inter_offset >= rs->rgb_height){
if ((rs->rgb_line & 0x07) == 0) {
rs->rgb_offset = (rs->rgb_height - 5) * rs->rgb_align;
rs->rgb_line = 4;
} else if (rs->inter_offset == 8) {
rs->rgb_offset = (rs->rgb_height - 3) * rs->rgb_align;
rs->rgb_line = 2;
rs->inter_offset = 4;
} else if (rs->inter_offset == 4) {
rs->rgb_offset = (rs->rgb_height - 2) * rs->rgb_align;
rs->rgb_line = 1;
rs->inter_offset = 2;
}
} else {
rs->rgb_offset -= rs->rgb_align * rs->inter_offset;
rs->rgb_line += rs->inter_offset;
}
} else { //リニアGIFの場合
rs->rgb_offset -= rs->rgb_align;
}
rs->rgb_pt = 0;
}
}