「ゲームプログラミング/画像ファイルの作成プログラム」の版間の差分

削除された内容 追加された内容
→‎ランレングス圧縮: typo 機会 -> 機械
1,242 行
 
C言語では、unsigned をつけないchar型で宣言すれば、-128~127を保管できる1バイト整数型になります。
 
 
 
コード例としては、まずいきなりPackBitsのコードを書くのは難しいので、まずランレングスをきちんと作ろう。
 
読み取り対象のテキストファイル "test2.txt" を下記のようにすれば(aが5回連続、bとcとdは不連続、eは6回連続)、
<pre>
aaaaabcdeeeeee
</pre>
 
ランレングスのコードは、
 
<syntaxhighlight lang="C">
// ※注: これはランレングスです。
#include <stdio.h>
#pragma warning(disable : 4996)
 
int main() {
FILE *fp1 = fopen("test2.txt", "rb");
 
if (fp1 == NULL) {
perror("ファイルを開けませんでした。\n");
return 1;
} else {
printf("ファイルをオープンしました。\n");
}
 
char str1[70]; // 表示結果を短くするために数値を微妙に小さくした
printf("機械語を読み取っています。\n"); // 「文字列」ではなく機械語
 
fread(str1, sizeof(char), 50, fp1);
 
printf("ファイルに書いてある機械語\n");
 
for (int i = 0; i < sizeof(str1) / sizeof(str1[0]); i = i + 1) {
printf("%02x ", str1[i]); // 最低でも2桁を表示、の意味
}
 
printf("\n文字の繰り返しを検出しようとしています...\n");
 
int bufRep
[3]; // 繰り返し文字の回数を記録するカウンターをとりあえず3つ用意。
int bufWord[3]; // 繰り返し文字の字を記録するバッファをとりあえず3つ用意
 
bufWord[0] = str1[0];
bufRep[0] = 1;
 
int repFlag = 1;
 
char press1[70]; // 圧縮結果の保存用
int preCount = 0; // 何文字目まで書き込んだかのカウンタ
 
int temp = 0;
int breakFor = 0; // for から抜けるためのフラグ
 
for (temp = 0; temp <= 12; temp = temp + 1) {
 
if (repFlag == 1) {
if (str1[temp + 1] == str1[temp] && str1[temp] != 0) {
bufRep[0] = bufRep[0] + 1;
repFlag = 1;
} else if (str1[temp] != 0) {
repFlag = 0;
press1[0] = bufWord[0];
press1[1] = bufRep[0];
preCount = +2;
breakFor = 1;
break;
} else if (str1[temp] == 0) {
breakFor = 1;
// ヌルが来たら文末などと判断し、他に何もせずに抜け出す
break;
} // else if
 
if (breakFor == 1) {
break;
}
 
} // if
} // for
 
printf("記録する文字1の機械語: %02x \n",
bufWord[0]); // 最低でも2桁を表示、の意味
printf("その文字の現在の回数: %02x \n",
bufRep[0]); // 最低でも2桁を表示、の意味
 
printf("圧縮する文字1の機械語: %02x ",
press1[0]); // 最低でも2桁を表示、の意味
printf("その文字の現在の回数: %02x ",
press1[1]); // 最低でも2桁を表示、の意味
 
printf("\n次の書き込みカウンター位置: %02x \n",
preCount); // 最低でも2桁を表示、の意味
 
printf("\n", preCount); // 最低でも2桁を表示、の意味
 
int hokan = temp; // 次のforの開始番号用
 
int loop = 1;
 
breakFor = 0; // 下記 while のbreak フラグ用
while (breakFor == 0) {
 
hokan = temp;
bufWord[loop] = str1[hokan + 1];
bufRep[loop] = 1;
 
press1[preCount + 0] = bufWord[loop];
press1[preCount + 1] = bufRep[loop];
 
repFlag = 1; // 次のループ用に再セット
for (temp = hokan + 1; temp <= 255; temp = temp + 1) {
if (repFlag == 1) {
 
if (str1[temp + 1] == str1[temp] && str1[temp] != 0) {
bufRep[loop] = bufRep[loop] + 1;
repFlag = 1;
 
} else if (str1[temp] != 0) {
 
repFlag = 0;
press1[preCount + 0] = bufWord[loop];
press1[preCount + 1] = bufRep[loop];
preCount = preCount + 2;
 
break;
} else if (str1[temp] == 0) {
breakFor = 1; // ヌルが来たら文末などと判断し ループから break
break;
}
 
else {
breakFor = 1; // 無限ループ防止のため 想定外の自体はループから break
 
break;
} // else if
} else {
breakFor = 1; // 無限ループ防止のため 想定外の自体はループから break
 
break;
}
 
// if
} // for
 
printf("loop: %02x \n", loop); // 最低でも2桁を表示、
 
printf("記録する文字%dの機械語: %02x \n", loop,
bufWord[loop]); // 最低でも2桁を表示、の意味
printf("その文字の現在の回数: %02x \n",
bufRep[loop]); // 最低でも2桁を表示、の意味
 
printf("圧縮する文字%dの機械語: %02x ", loop,
press1[2 * loop]); // 最低でも2桁を表示、の意味
printf("その文字の現在の回数: %02x ",
press1[2 * loop + 1]); // 最低でも2桁を表示、の意味
 
printf("\n次の書き込みカウンター位置: %02x \n",
preCount); // 最低でも2桁を表示、の意味
 
loop = loop + 1;
} // while
 
printf("\nランレングス的に圧縮のシミュレーション...\n");
 
for (int i = 0; i < preCount + 2; i = i + 1) {
printf("%02x ", press1[i]); // 最低でも2桁を表示、の意味
}
 
fclose(fp1);
printf("\nファイルをクローズしました。\n");
}
</syntaxhighlight>
 
実験結果
<pre>
ファイルをオープンしました。
機械語を読み取っています。
ファイルに書いてある機械語
61 61 61 61 61 62 63 64 65 65 65 65 65 65 00 00 ffffff98 55 51 0
ffffb4 00 ffffffeb fffffffe fffffffe 07 00 00 ffffffc0 19 40 00
fffff9a 2c ffffffc4 00 00 00 00 50 fffffff2 53 00 00 00 00 00 10
00 00 00 00 00 00 00 00
文字の繰り返しを検出しようとしています...
記録する文字1の機械語: 61
その文字の現在の回数: 05
圧縮する文字1の機械語: 61 その文字の現在の回数: 05
次の書き込みカウンター位置: 02
 
loop: 01
記録する文字1の機械語: 62
その文字の現在の回数: 01
圧縮する文字1の機械語: 62 その文字の現在の回数: 01
次の書き込みカウンター位置: 04
loop: 02
記録する文字2の機械語: 63
その文字の現在の回数: 01
圧縮する文字2の機械語: 63 その文字の現在の回数: 01
次の書き込みカウンター位置: 06
loop: 03
記録する文字3の機械語: 64
その文字の現在の回数: 01
圧縮する文字3の機械語: 64 その文字の現在の回数: 01
次の書き込みカウンター位置: 08
loop: 04
記録する文字4の機械語: 65
その文字の現在の回数: 06
圧縮する文字4の機械語: 65 その文字の現在の回数: 06
次の書き込みカウンター位置: 0a
loop: 05
記録する文字5の機械語: 00
その文字の現在の回数: 01
圧縮する文字5の機械語: 00 その文字の現在の回数: 01
次の書き込みカウンター位置: 0a
 
ランレングス的に圧縮のシミュレーション...
61 05 62 01 63 01 64 01 65 06 00 01
ファイルをクローズしました。
</pre>
 
のような実行結果になる。
 
あとはこのコードを、PackBitsになるように改良していけばいいだけである。
 
=== ASCII文字の英文の圧縮の原理 ===