1.圧縮の原理


原理は単純でデータが連続で続いていたら、そやつらを符号化するだけです。

#ref(): File not found: "gazou1.jpg" at page "もっとも単純なランレングス圧縮"


ここで注意しておきたいのはデータが連続しないときも符号をつかないといけないということです。
でないとプログラム側がデータか符号かがわかりませんから。
つまりこの圧縮方法だとよほどデータが連続してないと圧縮前よりデータ量が増えてしまうということです。
これは次回に解消します。


2.解凍の原理


符号どうりにデータを展開します。


3.圧縮結果

1.ACジャパン あいさつの魔法.mp3

1.15MB → 2.21MB  圧縮率191.69%

増えた!

2.はいから亭 メニュー.txt

1.86KB → 3.68KB  圧縮率198.11%

増えた!

3.どーなつ先輩の亡骸.JPG

595KB → 1.14MB  圧縮率196.82%

増えた!

4.どーなつ先輩の亡骸.bmp 256色

3.23MB → 699KB 圧縮率21.10%


5.どーなつ先輩の亡骸.bmp 16色

1.61MB → 136KB 圧縮率5.89%


5.どーなつ先輩の亡骸.bmp 白黒

417KB →  40.4KB 圧縮率9.69%


総評

普通のデータでは連続しているデータは少なく、連続していない場合符号化の時点で1byteが2byteぶんのデータサイズになるのでほぼ2倍のデータ量になります。
画像ファイルで白黒より16色のほうが圧縮率がいいのは白黒ではデータが連続し過ぎているというのがひとつの理由です。
あるデータが何回続くのかを1byteで記録しているので255回の連続までしか記録できません。
また白黒は文字通り白と黒しかありませんから1ドットを1bitで表現できます。
これを利用するとさらに圧縮率が高まります。


Sample



#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#include<string.h>

#define EXP_DATA   0
#define EXP_SYMBOL 1

void RLECompressFile(char *read_file_name);
void RLEDecompressFile(char *read_file_name);

int main(int argc, char *argv[])
{
	int input;

	//コマンドライン引数の例外
	if((argc - 1) != 1) {
		printf("ファイルを指定してください\n");
		return 0;
	}

	//圧縮or解凍
	do {
		printf("圧縮→'c' 解凍→'t' 終了→'q'\n");
		input = getch();
		switch(input) {
			case 'c':
				printf("ファイルを圧縮します\n\n");
				printf("%s\n", argv[1]);
				RLECompressFile(argv[1]);
				break;
			case 't':
				printf("ファイルを解凍します\n");
				printf("%s\n", argv[1]);
				RLEDecompressFile(argv[1]);
				break;
			case 'q':
				printf("終了します\n");
				return 0;
			default:
				printf("もう一度入力してください\n");
		}
	}while((input != 'c') && input != 't');

	return 0;
}

//ファイルを圧縮する関数
//引数1:ファイルの名前
void RLECompressFile(char *read_file_name)
{
	FILE *read_fp;
	FILE *write_fp;
	fpos_t rfile_size = 0;
	fpos_t wfile_size = 0;
	fpos_t file_pos = 0;

	unsigned char *read_data;
	unsigned char write_data[2];	//write_data[0] → データ   write_data[1] → 何回続くか
	fpos_t i;
	unsigned char equ_counter = 1;
	char write_file_name[_MAX_PATH];


	//読み込みファイル
	if((read_fp = fopen(read_file_name, "rb")) == NULL) {
		printf("ファイルが開けません(read)\n");
		exit(0);
	}

	//新規ファイル
	strcpy(write_file_name, read_file_name);
	strcat(write_file_name, ".rrr");	//拡張子をrrrに
	if((write_fp = fopen(write_file_name, "wb")) == NULL) {
		printf("ファイルが開けません(write)\n");
		exit(0);
	}

	//ファイルサイズ取得
	file_pos = fseek(read_fp, 0, SEEK_END);
	fgetpos(read_fp, &rfile_size);
	fseek(read_fp, file_pos, SEEK_SET); 
	printf("圧縮前 %dbyte\n", rfile_size);


	//メモリ確保
	read_data = (unsigned char*)malloc(rfile_size);

	//読み込み
	fread(read_data, sizeof(unsigned char), rfile_size, read_fp);


	//圧縮と書き込み
	for(i = 1; i < rfile_size + 1; i++) {
		for(equ_counter = 1; equ_counter < 256; equ_counter++) {
			if(read_data[i] == read_data[i - 1]) {
				i++;
				continue;
			}else {
				break;
			}
		}

		write_data[EXP_DATA] = read_data[i - 1];
		write_data[EXP_SYMBOL] = equ_counter;
		fwrite(write_data, sizeof(unsigned char), 2, write_fp);
	}

	fgetpos(write_fp, &wfile_size);
	printf("圧縮後 %dbyte\n", wfile_size);
	printf("圧縮率 %f%%\n\n", ((float)wfile_size / (float)rfile_size) * 100.0);

	fclose(read_fp);
	fclose(write_fp);

	free(read_data);
}

//ファイルを解凍する関数
//引数1:ファイルの名前
void RLEDecompressFile(char *read_file_name)
{
	FILE *read_fp;
	FILE *write_fp;
	fpos_t rfile_size = 0;
	fpos_t wfile_size = 0;
	fpos_t file_pos = 0;

	unsigned char *read_data;
	fpos_t i, j;
	unsigned char equ_counter = 1;
	char write_file_name[_MAX_PATH];


	//読み込みファイル
	if((read_fp = fopen(read_file_name, "rb")) == NULL) {
		printf("ファイルが開けません(read)\n");
		exit(0);
	}

	//新規ファイル
	strcpy(write_file_name, read_file_name);
	write_file_name[strlen(write_file_name) - 4] = '\0';
	if((write_fp = fopen(write_file_name, "wb")) == NULL) {
		printf("ファイルが開けません(write)\n");
		exit(0);
	}

	//ファイルサイズ取得
	file_pos = fseek(read_fp, 0, SEEK_END);
	fgetpos(read_fp, &rfile_size);
	fseek(read_fp, file_pos, SEEK_SET); 

	//メモリ確保
	read_data = (unsigned char*)malloc(rfile_size);

	//読み込み
	fread(read_data, sizeof(unsigned char), rfile_size, read_fp);


	//解答と書き込み
	for(i = 0; i < rfile_size; i += 2) {
		for(j = 0; j < read_data[i + 1]; j++) {
			fwrite(&read_data[i], sizeof(char), 1, write_fp);
		}
	}

	fclose(read_fp);
	fclose(write_fp);

	free(read_data);
}

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2014-06-28 (土) 01:50:22 (3582d)