JPEGハフマン・テーブル – 解読実践(12)

物事には順序が必要です。気が付けば、デバグをするためねにはプログラムを書かねばならない、そのように思いました。
どういう仕様が必要か? ハフマン符号と、その長さを入力すれば、左詰めで1と0のハフマン符号が出力される、それが必要です。
艱難辛苦の末、以下のプログラムを書きました 如何にも単純、しかし作動します。ビット演算の魔術師にかかれば、もっと高速で効率の良いプログラムを書けるでしょう。そんなことわかっています。でも、まずは確実に動くものを造り、それから改良するのです。何しろ僕は、改良が得意な日本人の一人なのですから・・・

void outbit(const int& hc, const int& hb) {
	// 16 bitsの長さ hbのハフマン符号 hcを左詰めで出力する
	
	int mask = 0x01;
	for (int i=hb; i>0; i--) {
		mask <<= (i - 1);
		if ((mask & hc) != 0) {
			std::cout << 1;
		} else {
			std::cout << 0;
		}
		mask = 0x01;
	}
	std::cout << std::endl;
};

JPEGハフマン・テーブル – 解読実践(11)

何か C++の言語仕様に対して根本的に間違っていたような気がします。Webにアクセスしてもう一度考え直しました。前回のプログラム・パーツを以下のように書き換えました

typedef unsigned char u_char;  // u_char型の宣言
typedef struct {
  int HuffBit;  // ハフマン符号のビット長
  int HuffCode; // ハフマン符号
  int HuffVal;  // ハフマン符号の意味する値
} HUFFTAB;   // これでHUFFTABという型を宣言した

u_char BITS[16];  // それぞれのビット長のハフマン符号がいくつあるか
   // 常に16バイトなので静的に配列確保した

// データのセット 実際のプログラムではファイルから読み込む
for (int i=0; i<16; i++) { // データをセット
  BITS[i] = 0x00;
}
BITS[1] = 0x01; BITS[2] = 0x05; BITS[3] = 0x01;
BITS[4] = 0x01; BITS[5] = 0x01; BITS[6] = 0x01; 
BITS[7] = 0x01; BITS[8] = 0x01;

int huffElementNo = 0;
for (int i=0; i<16; i++) {
   huffElementNo += BITS[i]; // これでハフマン符号語の総数を求める
}
//
// ハフマンテーブル領域の動的確保
HUFFTAB *ht = new HUFFTAB[huffElementNo]; 
// これでハフマン表の領域が確保された

これで良いのですよ 今度は間違いない、と確信しています

JPEGハフマン・テーブル – 解読実践(10)

さあここまでで準備できたので、少しはプログラムらしくしてみます


struct HUFFDECODE {
  int numHuffElement;  // ハフマン符号語の総数
  int * HUFFBITS;   // ハフマン符号語長
  int * HUFFCODE;   // ハフマン符号
  int * HUFFVAL;    // ハフマン符号が表すデータ
}

typedef unsigned char u_char;   // 短縮形の定義

u_char BITS[16];  // 何ビットのハフマン符号が存在するか?

// データのセット 実際のプログラムではファイルから読み込む
for (int i=0; i<16; i++) { // データをセット
  BITS[i] = 0x00;
}
BITS[1] = 0x01; BITS[2] = 0x05; BITS[3] = 0x01;
BITS[4] = 0x01; BITS[5] = 0x01; BITS[6] = 0x01; 
BITS[7] = 0x01; BITS[8] = 0x01;

int sum=0;
for (int i=0; i<16; i++) {
  sum += BITS[i]; // これでハフマン符号語の総数を求める
}
//
// ハフマンテーブル領域の動的確保

ああダメだ 挫折 少し頭を冷やしましょう

JPEGハフマン・テーブル – 解読実践(9)

大事なデータを忘れていました。最終的に対応するハフマン符号が意味するのは、その後に続く、つまり緑の部分でした この部分は、ハフマン符号語に続く何ビットがデータを表しているかを示します この部分も配列に入れる必要がありますね そこで追加です

int * HUFFVAL = new int[sum];

うん? 待てよ ということになると動的に確保する三つの配列 つまり HUFFBITS, HUFFCODE, HUFFVALは同じインデックス同志が意味を有する、ということになりますね、だとすれば、これら三つで意味を有するので構造体として一つにまとめる方が論理的に分かりやすいですよね、そこで構造体を定義します さらには、その構造体にインデックス最大値を保持する変数も含めることにしましょう またこれまではハフマン符号語長を保持する配列 HUFFBITSをバイトで確保していましたが、これは最大 16bitsあるのでintにせねばなりませんでした そこで

struct HUFFDECODE {
  int numHuffElement;  // ハフマン符号語の総数
  int * HUFFBITS;   // ハフマン符号語長
  int * HUFFCODE;   // ハフマン符号
  int * HUFFVAL;    // ハフマン符号が表すデータ
}

このような構造体を定義しました ふーっ、道は遠い

そうそう昨日は京都で夜講演があり、久しぶりに京都の町に繰り出しました。とても暑く、また一昨日は大文字送り火だったので、ものすごい混雑でした。