他人の空似自作物置場

LifeGame.zip/LifeGame.c

#include <stdio.h>								//各種宣言、structの半分は無駄
#include <math.h>
#include <stdlib.h>
#include <string.h>

enum {
	ERR_NON,
	ERR_FORMAT
};

typedef struct color {
	unsigned char blue;
	unsigned char green;
	unsigned char red;
	unsigned char Reserved;
}color;

typedef struct bitmap_file_header {
	char bfType[2];
	unsigned int bfSize;
	short bfReserved1;
	short bfReserved2;
	unsigned int bfOffBits;
}HEAD;

typedef struct bitmap_core_header {
	unsigned int biSize;
	int biWidth;
	int biHeight;
	short biPlanes;
	short biBitCount;
	char sin_zero[108];
}BCH;

typedef struct bitmap_info_header {
	unsigned int biSize;
	int biWidth;
	int biHeight;
	short biPlanes;
	short biBitCount;
	int biCompression;
	int biSizeImage;
	int biXPixPerMeter;
	int biYPixPerMeter;
	int biClrUsed;
	int biCirImportant;
	char sin_zero[84];
}BIH;

typedef struct bitmap_info_header2 {
	unsigned int biSize;
	int biWidth;
	int biHeight;
	short biPlanes;
	short biBitCount;
	int biCompression;
	int biSizeImage;
	int biXPixPerMeter;
	int biYPixPerMeter;
	int biClrUsed;
	int biCirImportant;
	char unknown[84];
}BIH2;

typedef struct bitmap_v4_header {
	unsigned int biSize;
	int biWidth;
	int biHeight;
	short biPlanes;
	short biBitCount;
	int biCompression;
	int biSizeImage;
	int biXPixPerMeter;
	int biYPixPerMeter;
	int biClrUsed;
	int biCirImportant;
	char unknown[68];
	char sin_zero[16];
}B4H;

typedef struct bitmap_v5_header {
	unsigned int biSize;
	int biWidth;
	int biHeight;
	short biPlanes;
	short biBitCount;
	int biCompression;
	int biSizeImage;
	int biXPixPerMeter;
	int biYPixPerMeter;
	int biClrUsed;
	int biCirImportant;
	char unknown[84];
}B5H;

typedef struct bitmap {
	HEAD *head;
	BIH *info;
	color *map;
}BMP;

void err(int num){								//errメッセージ出力、本来はここでexitはまずい
	FILE *fp;
	if(num == ERR_NON){
		printf("WindowsBitmapファイルでないか未知のフォーマットです\n読み込みに失敗しました\n");
		exit(1);
	}
	if(num == ERR_FORMAT)printf("未対応のフォーマットです\n読み込みに失敗するか何らかの情報が欠落する可能性があります\n");
}


void change(color *map,int Width,int Height){					//bmp特有の反転記録逆転用
	int i,th,tw;
	color temp;

	th = 0;
	i = 0;
	while(th < Height/2){
		tw = 0;
		while(tw < Width){
			temp.red = map[i].red;
			temp.green = map[i].green;
			temp.blue = map[i].blue;
			map[i].red = map[(Height-1-th)*Width+tw].red;
			map[i].green = map[(Height-1-th)*Width+tw].green;
			map[i].blue = map[(Height-1-th)*Width+tw].blue;
			map[(Height-1-th)*Width+tw].red = temp.red;
			map[(Height-1-th)*Width+tw].green = temp.green;
			map[(Height-1-th)*Width+tw].blue = temp.blue;
			tw++;
			i++;
		}
		th++;
	}
}

BMP *loadbmp(char fname[]){							//bmp読み込み、エラー処理が若干甘い。出力無しならまずここが怪しい
	color *map,col[256];
	HEAD h;
	BIH info;
	BMP *bmp;
	FILE *fp;
	int i,temp,tw,th,bit;
	unsigned char a;

	fp = fopen(fname,"rb");

	fread(h.bfType,1,2,fp);							//ファイルヘッダ読み込み
	if(h.bfType[0] != 'B' || h.bfType[1] != 'M'){
		err(ERR_NON);
	}
	fread(&(h.bfSize),4,1,fp);
	fread(&(h.bfReserved1),2,1,fp);
	fread(&(h.bfReserved2),2,1,fp);
	fread(&(h.bfOffBits),4,1,fp);

	fread(&(info.biSize),4,1,fp);						//画像情報読み込み
	if(info.biSize < 12 || info.biSize > 124){
			err(ERR_NON);
	} else if(info.biSize >= 12){						//BitmapCoreHeader
		fread(&(info.biWidth),4,1,fp);
		fread(&(info.biHeight),4,1,fp);
		fread(&(info.biPlanes),2,1,fp);
		if(info.biPlanes != 1){
			err(ERR_NON);
		}
		fread(&(info.biBitCount),2,1,fp);
		if(info.biBitCount != 1 && info.biBitCount != 4 && info.biBitCount != 8 && info.biBitCount != 16 && info.biBitCount != 24 && info.biBitCount != 32){
			err(ERR_NON);
		}
		if(info.biSize >= 40){						//BitmapInfoHeader
			fread(&(info.biCompression),4,1,fp);
			if(info.biCompression < 0 || info.biCompression > 3){
				err(ERR_NON);
			}
			fread(&(info.biSizeImage),4,1,fp);
			fread(&(info.biXPixPerMeter),4,1,fp);
			fread(&(info.biYPixPerMeter),4,1,fp);
			fread(&(info.biClrUsed),4,1,fp);
			fread(&(info.biCirImportant),4,1,fp);
			if(info.biSize >= 64){					//BitmapInfoHeader2
				err(ERR_FORMAT);
				if(info.biSize >= 108){				//BitmapV4Header
					if(info.biSize >= 124){			//BitmapV5Header
					}
				}
			}
		}
	}

	temp = ((info.biWidth*info.biBitCount) % (4*8));			//pixelデータ(画像本データ)読み込み
	map = (color *)malloc(sizeof(color)*info.biWidth*info.biHeight+temp);
	switch(info.biBitCount){
		case 1:
		case 4:
		case 8:								//動作不可、手直しが必要
			fread(col,1,pow(2,info.biBitCount),fp);
			i = 0;
			while(i < pow(2,info.biBitCount)){
				printf("r%3d:g%3d:b%3d\n",col[i].red,col[i].green,col[i].blue);
				i++;
			}
			th = 0;
			while(th < info.biHeight){
				tw = 0;
				while(tw < info.biWidth){
					fread(&a,1,1,fp);
					bit = 0;
					while(bit < 8){
						i = (a>>(8-info.biBitCount))&((int)pow(2,info.biBitCount)-1);
						memcpy(&(map[th*info.biWidth+tw]),&(col[i]),sizeof(color));
						a = a << info.biBitCount;
						bit += info.biBitCount;
						tw++;
					}
				}
				th++;
			}
			break;
		case 16:
		case 24:							//テスト済み、手元の10枚では動作
			i = 0;
			while(i < info.biHeight*info.biWidth){
				tw = 0;
				while(tw < info.biWidth){
					fread(&(map[i+tw]),1,3,fp);
					//fprintf(stderr,"%02x%02x%02x ",map[i+tw].red,map[i+tw].green,map[i+tw].blue);
					map[i+tw].Reserved = 0;
					tw++;
				}
				i += info.biWidth;
				fread(&(map[i]),1,temp/8,fp);
			}
			break;
		case 32:							//未テスト
			i = 0;
			while(i < info.biHeight*info.biWidth){
				fread(&(map[i]),1,4,fp);
				i++;
			}
			break;
		default:
			break;
	}
	fclose(fp);

	bmp = (BMP *)malloc(sizeof(BMP));					//返却用に整備、本来は関数先頭でやるべき
	bmp->map = map;
	bmp->head = (HEAD *)malloc(sizeof(HEAD));
	memcpy(bmp->head,&h,sizeof(HEAD));
	bmp->info = (BIH *)malloc(sizeof(BIH));
	memcpy(bmp->info,&info,sizeof(BIH));
	return bmp;
}

void print_html1(int width,int height,FILE *fp){				//LifeGameの本体、templateファイル化するべき
	fprintf(fp,"<html><head>\n<title>pakuri</title>\n<script language=\"JavaScript\">\nvar dx=%d;\nvar dy=%d;\nvar max=dx*dy;\nvar kari;\nvar kariv;\n\nvar pow=new Array(max);\nvar bef=new Array(max);\nvar aft=new Array(max);\n",width,height);
}

void print_html2(FILE *fp){
	fprintf(fp,"\n\nfor(j=0;j<dy;j++){\n\tfor(i=0;i<dx;i++){\n\t\taft[j*dx+i]=syo[(dy-j-1)*dx+i];\n\t}\n}\nfunction update(){\n\tfor(i=0;i<max;i++){\n\t\tif(bef[i]!=aft[i]){\n\t\t\t");
}

void print_html3(FILE *fp){
	fprintf(fp,"\t\t\t}\n\t\t}\n\t\tbef[i]=aft[i];\n\t}\n\tfor(i=0;i<max;i++){\n\t\tif(bef[i]!=0){\n\t\t\tpow[i]=Math.random();\n\t\t}\n\t}\n\tfor(j=0;j<dy;j++){\n\t\tfor(i=0;i<dx;i++){\n\t\t\tkari=bef[j*dx+i];kariv=pow[j*dx+i];\n\t\t\tif(bef[j*dx+i]!=0){\n\t\t\t\tif(i-1>=0){\n\t\t\t\t\tif(bef[j*dx+i-1]!=0){\n\t\t\t\t\t\tif(kariv<pow[j*dx+i-1]){\n\t\t\t\t\t\t\tkariv=pow[j*dx+i-1];kari=bef[j*dx+i-1];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(i+1<dx){\n\t\t\t\t\tif(bef[j*dx+i+1]!=0){\n\t\t\t\t\t\tif(kariv<pow[j*dx+i+1]){\n\t\t\t\t\t\t\tkariv=pow[j*dx+i+1];\n\t\t\t\t\t\t\tkari=bef[j*dx+i+1];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(j-1>=0){\n\t\t\t\t\tif(bef[(j-1)*dx+i]!=0){\n\t\t\t\t\t\tif(kariv<pow[(j-1)*dx+i]){\n\t\t\t\t\t\t\tkariv=pow[(j-1)*dx+i];\n\t\t\t\t\t\t\tkari=bef[(j-1)*dx+i];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(j+1<dy){\n\t\t\t\t\tif(bef[(j+1)*dx+i]!=0){\n\t\t\t\t\t\tif(kariv<pow[(j+1)*dx+i]){\n\t\t\t\t\t\t\tkariv=pow[(j+1)*dx+i];\n\t\t\t\t\t\t\tkari=bef[(j+1)*dx+i];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\taft[j*dx+i]=kari;\n\t\t}\n\t}\n\tsetTimeout(update,100);\n}\n</script></head>\n<body onLoad=\"update()\">\n<script language=\"JavaScript\">\nfor(j=0;j<dy;j++){\n\tfor(i=0;i<dx;i++){\n\t\tdocument.write(\"<img src>\");\n\t}\n\tdocument.write(\"<br>\");\n}\n</script>\n</body></html>");
}
int table_art(BMP *bmp){							//テーブルアート作成関数だったもの
	int i,th,tw,count,max,mn;						//LifeGameの出力もここからやっている
	color *col,temp;
	int *ccol,*map;
	FILE *fp,*fpp;
	unsigned char image[1024];
	char s[256];
										//この辺からデータ分解など
	map = (int *)malloc(sizeof(int)*bmp->info->biWidth*bmp->info->biHeight+1);
	col = (color *)malloc(sizeof(color)*bmp->info->biWidth*bmp->info->biHeight+1);
	ccol = (int *)malloc(sizeof(int)*bmp->info->biWidth*bmp->info->biHeight+1);
	if(map == NULL || col == NULL || ccol == NULL){
		fprintf(stderr,"malloc Failed\n");
		exit(0);
	}
	memset(col,0,sizeof(color)*bmp->info->biWidth*bmp->info->biHeight+1);
	col[0].red = 255;
	col[0].green = 255;
	col[0].blue = 255;
	ccol[0] = 1;
	th = 0;
	while(th < bmp->info->biHeight){
		tw = 0;
		while(tw < bmp->info->biWidth){
			i = th*bmp->info->biWidth+tw;
			count = 0;
			while((ccol[count] > 0) && (bmp->map[i].red != col[count].red || bmp->map[i].green != col[count].green && bmp->map[i].blue != col[count].blue)){
				count++;
			}
			col[count].red = bmp->map[i].red;
			col[count].green = bmp->map[i].green;
			col[count].blue = bmp->map[i].blue;
			ccol[count]++;
			map[i] = count;
			tw++;
		}
		th++;
	}
	count = 0;
	max = 0;
	while(ccol[count] != 0){
		if(max < ccol[count]){
			mn = count;
			max = ccol[count];
		}
		count++;
	}
	max = count;

	fpp = fopen("LifeGame.html","w");					//lifegame出力部
	print_html1(bmp->info->biWidth,bmp->info->biHeight,fpp);
	fprintf(fpp,"var syo=new Array(\n");
	th = 0;
	while(th < bmp->info->biHeight){
		tw = 0;
		while(tw < bmp->info->biWidth){
			i = th*bmp->info->biWidth+tw;
			if(i > 0){fprintf(fpp,",");}
			fprintf(fpp,"%d",map[i]);
			tw++;
		}
		fprintf(fpp,"\n");
		th++;
	}
	fprintf(fpp,");\n");
	print_html2(fpp);

	fp = fopen("color/template.bmp","rb");					//種画像データ作成
	fread(image,1,54,fp);
	fclose(fp);
	i = 0;
	while(i < max){
		count = 0;
		while(count < 12*12){
			image[54+count*3] = col[i].blue;
			image[55+count*3] = col[i].green;
			image[56+count*3] = col[i].red;
			count++;
		}
		sprintf(s,"color/%d.bmp",i);
		fp = fopen(s,"wb");
		fwrite(image,1,54+12*12*3,fp);
		fclose(fp);
		if(i > 0)fprintf(fpp,"\t\t\t} else ");
		fprintf(fpp,"if(aft[i]==%d){\n",i);
		fprintf(fpp,"\t\t\t\tdocument.images[i].src=\"color/%d.bmp\";\n",i);
		i++;
	}
	print_html3(fpp);
	fclose(fpp);

	change(bmp->map,bmp->info->biWidth,bmp->info->biHeight);		//ここで画像上下反転

	fp = fopen("table.html","w");						//テーブルアート出力
	th = 0;
	fprintf(fp,"<table width=\"%d\" height=\"%d\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" style=\"table-layout: fixed\" bgcolor=\"#%02x%02x%02x\">\n",bmp->info->biWidth,bmp->info->biHeight,col[mn].red,col[mn].green,col[mn].blue);
	//fprintf(fp,<html><head></head><body><table cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n");
	while(th < bmp->info->biHeight){
		fprintf(fp,"<tr>");
		tw = 0;
		while(tw < bmp->info->biWidth){
			i = th*bmp->info->biWidth+tw;
			fprintf(fp,"<td");
			if(col[mn].red != bmp->map[i].red || col[mn].green != bmp->map[i].green || col[mn].blue != bmp->map[i].blue){
				fprintf(fp," bgcolor=\"#%02x%02x%02x\"",bmp->map[i].red,bmp->map[i].green,bmp->map[i].blue);
			}
			count = 1;
			if(tw != 0){
				while(tw < bmp->info->biWidth && bmp->map[i].red == bmp->map[i+1].red && bmp->map[i].green == bmp->map[i+1].green && bmp->map[i].blue == bmp->map[i].blue){
					i++;
					tw++;
					count++;
				}
				if(count > 1){
					fprintf(fp," colspan=\"%d\"",count);
				}
			}
			fprintf(fp," width=\"%d\"></td>",count);
			tw++;
		}
		fprintf(fp,"</tr>\n");
		th++;
	}
	fprintf(fp,"</table></body></html>\n");
	fclose(fp);
	free(ccol);
	free(map);
	free(col);

	return max;
}

int main(void){									//呼んで渡して後始末だけ
	BMP *bmp;
	int i,th,tw,len,max;
	char s[256];

	bmp = loadbmp("a.bmp");
	//printf("%c%c\n%d\n%d\n%d\n%d\n",bmp->head->bfType[0],bmp->head->bfType[1],bmp->head->bfSize,bmp->head->bfReserved1,bmp->head->bfReserved2,bmp->head->bfOffBits);
	//printf("sizeof(BCH)=%d,sizeof(BIH)=%d,sizeof(B4H)=%d,sizeof(B5H)=%d\n",sizeof(BCH),sizeof(BIH),sizeof(B4H),sizeof(B5H));
	//printf("biSize=%d\nbiWidth=%d\nbiHeight=%d\nbiPlanes=%d\nbiBitCount=%d\nbiCompression=%d\nbiSizeImage=%d\nbiXPixPerMeter=%d\nbiYPixPerMeter=%d\nbiClrUsed=%d\nbiCirImportant=%d\n",bmp->info->biSize,bmp->info->biWidth,bmp->info->biHeight,bmp->info->biPlanes,bmp->info->biBitCount,bmp->info->biCompression,bmp->info->biSizeImage,bmp->info->biXPixPerMeter,bmp->info->biYPixPerMeter,bmp->info->biClrUsed,bmp->info->biCirImportant);

	max = table_art(bmp);
	sprintf(s,"%d",max);
	len = strlen(s);
	sprintf(s,"\%0%dd,",len);

	th = 0;
	while(th < bmp->info->biHeight){
		tw = 0;
		while(tw < bmp->info->biWidth){
			i = th*bmp->info->biWidth+tw;
			tw++;
		}
		th++;
	}

	free(bmp->map);
	free(bmp->info);
	free(bmp->head);
	free(bmp);
	system("table.html\n");
	system("LifeGame.html\n");
	return 0;
}

/*作成動機
//某動画サービスで見たゲームを知り合いのすごい人が気に留めていたので興味本位
//わざわざbmp部分自作の動機
//Windowsの32bit→16bit変換に欠陥があるらしいので。
//32bit→16bitで単純に落とすと端数が出るので丸める、そのせい同じ色でも必ず同じ結果にはならないらしい(100%透過でゴミが残るのが一番の問題)
//しかもWin32APIは画像を読み込んだ時点でディスプレイモードにあわせて勝手に落としてくれやがるのだ。
//なので勉強をかねて自作。(その辺で拾えって?bccで使えるライブラリ落ちているわけが(ry)
//(要するに「16bitカラー厨でいつかやろうと思っていたからついで」というだけ)
*/

/*雑記
//下位互換が維持されているらしく前Verの機能はパレット以外は丸々使える、楽でいい
//何気に圧縮方式にpngやjpegが使えるらしい、一般に使われていないってことはxpでは非対応なのだろうか?
//ついでにWindows3.0時代からRGB3+予約1と4バイト保持されている、これ透過に使えるはずなのだが未だに放置されているとは不憫だ・・・
*/

/*現状
//パレットは未対応、その上XPデフォのペイントで出る24bitしかテストしてない
//コード的には32bitもいけそうだが32bitのbmpを持ってないので不明
//圧縮・アルファ&マスク対応版・特殊解像度などその他は完全に動きません。
//
*/

/*性能
//自分の環境でLifeGameは100*100ぐらいのサイズが限界
//テーブルアートは時間さえかければいつかは表示される
*/

/*コーディング的な話
//sql作成支援するツールから流れに流れてなぜかこんなものになりました
//そのためまともな設計思想がありません、継ぎ接ぎだらけ
//print_htmlとかtable_artとか特にひどい、mainが結局何もしていないのもアレすぎる・・・
*/

/*これからの話
//どうでもいい
*/