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が結局何もしていないのもアレすぎる・・・
*/
/*これからの話
//どうでもいい
*/