開発環境 |
Microsoft Visual C++ 2010 Express (SP1) |
実行環境 |
Microsoft Windows XP Home Edition (SP3) |
プロジェクトの種類 |
Win32 コンソール アプリケーション |
プロジェクト名 |
lzwenc |
アプリケーションの種類 |
コンソール アプリケーション |
追加のオプション |
空のプロジェクト |
LZWの勉強用で制限事項、改良の余地多々あり。
参考
- GIFフォーマットの詳細 http://www.tohoho-web.com/wwwgif.htm
- 時雨エノキオプト-アセンブリホール2nd-自作ソフト-GIFデコーダ http://www.geocities.jp/warotarock/asen2ndgif001.html
- 辞書テーブルを利用しない新LZW法 http://homepage1.nifty.com/uchi/lzw.htm
- GIF89a Specification http://www.w3.org/Graphics/GIF/spec-gif89a.txt
- LZW and GIF explained http://www.martinreddy.net/gfx/2d/GIF-comp.txt
lzwenc.c
#include <stdio.h> // printf
#include <stdlib.h> // _countof
#include <string.h> // memcmp
// 型定義
typedef unsigned char UCHAR;
typedef unsigned short USHORT;
typedef struct {
USHORT usCode;
UCHAR ucCodeSize;
} SCode;
// グローバル変数
static UCHAR g_aucCharStream[] = { // 文字データ(コード化対象)
//1, 255, 1, 255, 1, 255, 1, 255,
0, 0, 0, 0, 0, 0, 0, 0,
};
static int g_aiStringTable[0x1000]; // 辞書テーブル
static int g_iStringIndex; // 辞書の指標
static int g_iStringStart; // 辞書の先頭
static SCode g_aCodeStream[1024]; // コード化されたデータ
static int g_iCodeIndex = 0; // コード化されたデータの指標
// 関数プロトタイプ宣言
int ClearStringTable(int iCurrentIndex);
int SearchStringTable(int iCurrentIndex, int iCharIndex);
int AddStringTable(int iCharIndex);
int AddCodeStream(int iCode, int iCodeSize);
int PrintCodeStream(void);
int PrintCodeBitStream(void);
int PrintBitStream(int iCode, int iCodeSize);
void PrintByte(UCHAR ucByte);
int main()
{
int iCharIndex; // 文字の指標
int iCurrentIndex; // 現在の文字列の指標
int iCurrentCode; // 現在の文字列のコード
int iStringCode; // 辞書のコード
int iLZWMinimumCodeSize = 8;// 最小コードビット数
int iClearCode; // クリアコード
int iCodeSize; // コードのビット数
int iCodeNext; // コードのビット数拡大値
// クリアコードの設定など
iClearCode = 1 << iLZWMinimumCodeSize;
if (iLZWMinimumCodeSize < 2) {
iLZWMinimumCodeSize = 2;
}
g_iStringStart = iClearCode + 2;
// 現在の文字列に最初の文字をセットする
iCurrentIndex = 0;
iCurrentCode = g_aucCharStream[iCurrentIndex];
// 辞書テーブルのクリア
ClearStringTable(iCurrentIndex);
iCodeSize = iLZWMinimumCodeSize + 1;
AddCodeStream(iClearCode, iCodeSize); // Clear code
iCodeNext = 1 << iCodeSize;
for (iCharIndex = 1; iCharIndex < _countof(g_aucCharStream); iCharIndex++) {
// 文字の指標を1つ進め、現在の文字列から辞書のコードを検索する
iStringCode = SearchStringTable(iCurrentIndex, iCharIndex);
if (0 <= iStringCode) {
// 辞書にあれば、現在の文字列のコードに辞書のコードを保存する
iCurrentCode = iStringCode;
} else {
// 辞書になければ、現在の文字列を辞書に追加
AddStringTable(iCharIndex);
// 現在の文字列のコードを出力
AddCodeStream(iCurrentCode, iCodeSize);
// 現在の文字列を更新する
iCurrentIndex = iCharIndex;
iCurrentCode = g_aucCharStream[iCurrentIndex];
// コードのビット数拡大チェック
if (iCodeNext <= g_iStringIndex) {
iCodeSize++;
if (12 < iCodeSize) {
// 辞書テーブルのクリア
ClearStringTable(iCurrentIndex);
iCodeSize = iLZWMinimumCodeSize + 1;
AddCodeStream(iClearCode, iCodeSize);
}
iCodeNext = 1 << iCodeSize;
}
}
}
// 現在の文字列のコードを出力
AddCodeStream(iCurrentCode, iCodeSize);
AddCodeStream(iClearCode + 1, iCodeSize); // End of Information code
PrintCodeStream();
PrintCodeBitStream();
return 0;
}
// 辞書テーブルのクリア
int ClearStringTable(int iCurrentIndex)
{
g_iStringIndex = g_iStringStart;
g_aiStringTable[g_iStringStart - 1] = iCurrentIndex;
return 0;
}
// 辞書テーブルの検索
// 戻り値:-1=辞書にない 0以上=辞書のコード
int SearchStringTable(int iCurrentIndex, int iCharIndex)
{
UCHAR* pucCurrent; // 現在の文字列のポインタ
int iCurrentLen; // 現在の文字列の長さ
int iPrevIndex; // 前の指標
int iNowIndex; // 今の指標
int iStringLen; // 辞書の文字列の長さ
int i;
// 指標が同じなら、そこにある文字を辞書のコードとする
if (iCurrentIndex == iCharIndex) {
return g_aucCharStream[iCurrentIndex];
}
iCurrentLen = iCharIndex - iCurrentIndex + 1;
pucCurrent = g_aucCharStream + iCurrentIndex;
iPrevIndex = g_aiStringTable[g_iStringStart - 1];
for (i = g_iStringStart; i < g_iStringIndex; i++) {
iNowIndex = g_aiStringTable[i];
iStringLen = iNowIndex - iPrevIndex + 1;
if (iStringLen == iCurrentLen &&
memcmp(pucCurrent, g_aucCharStream + iPrevIndex, iCurrentLen) == 0) {
return i;
}
iPrevIndex = iNowIndex;
}
return -1;
}
// 辞書テーブルの追加
int AddStringTable(int iCharIndex)
{
if (_countof(g_aiStringTable) <= g_iStringIndex) {
return -1;
}
g_aiStringTable[g_iStringIndex] = iCharIndex;
g_iStringIndex++;
return 0;
}
// コード化されたデータの追加
int AddCodeStream(int iCode, int iCodeSize)
{
if (_countof(g_aCodeStream) <= g_iCodeIndex) {
return -1;
}
g_aCodeStream[g_iCodeIndex].usCode = iCode;
g_aCodeStream[g_iCodeIndex].ucCodeSize = iCodeSize;
g_iCodeIndex++;
return 0;
}
// コード化されたデータの出力
int PrintCodeStream(void)
{
int i;
for (i = 0; i < g_iCodeIndex; i++) {
printf("%d:%u %u\n", i, g_aCodeStream[i].usCode, g_aCodeStream[i].ucCodeSize);
}
return 0;
}
// コード化されたデータをビットストリーム出力する
int PrintCodeBitStream(void)
{
int i;
for (i = 0; i < g_iCodeIndex; i++) {
PrintBitStream(g_aCodeStream[i].usCode, g_aCodeStream[i].ucCodeSize);
}
PrintBitStream(-1, 0);
return 0;
}
// ビットストリーム出力
int PrintBitStream(int iCode, int iCodeSize)
{
static UCHAR ucBits = 0;
static int iBits = 0;
if (iCode < 0) {
PrintByte(ucBits);
return 0;
}
ucBits = (iCode << iBits) | ucBits;
iBits += iCodeSize;
while (8 <= iBits) {
PrintByte(ucBits);
iBits -= 8;
ucBits = (iCode >> (iCodeSize - iBits));
}
return 0;
}
// バイト出力
void PrintByte(UCHAR ucByte)
{
char acBuf[16];
_itoa_s(0x100 | ucByte, acBuf, _countof(acBuf), 2);
printf("0x%02X:%.4s %.4s\n", ucByte, acBuf + 1, acBuf + 5);
}
出力
0:256 9
1:0 9
2:258 9
3:259 9
4:258 9
5:257 9
0x00:0000 0000
0x01:0000 0001
0x08:0000 1000
0x1C:0001 1100
0x28:0010 1000
0x30:0011 0000
0x20:0010 0000
最終更新:2012年09月01日 16:48