/* chc.cpp */ #include using namespace std; // .bmp ファイルのヘッダー 少し省略しています typedef struct { char bfType[2]; // 'BM' int bfSize; // ファイルサイズ、4 byte char bfReserved1[2]; // 常に 0 char bfReserved2[2]; int bfOffBits; // ファイル先頭から画像データまでのオフセット int bcSize; // ヘッダーサイズ int bcWidth; // 画像の幅 (ピクセル) int bcHeight; // 画像の高さ (ピクセル)、負数なら画像データは上から下 short int bcPlanes; // プレーン数、常に 1 short int bcBitCount; // 1 画素あたりのデータサイズ (bit)、256 色ビットマップなら 8 int biCompresson; // 圧縮形式、0:無圧縮 int biSizeImage; // 画像データ部のサイズ (byte) int biPad[4]; } bmp_hdr; int _a, _v; // command line argument unsigned char *p0; // malloc() で確保したメモリーの先頭アドレス int bsz = 600*600+1200; bmp_hdr* q; // カラーコード変換表 unsigned char c_code[] = { 0, 0xf8, 0xf7, 0xf9, 0xfa, 0xfc, 0xfb, 0xfd, 0xfe, 0xff, 0x00 }; // オマケあり // カラーバー画像の作成 int c_bar(unsigned char* s0, int sz) { unsigned char* d; unsigned char c; int i, j; // i : 縦方向、j : 横方向 float x; printf("c_bar: adress 0x%x, size %d\n", s0, sz); // 描画領域 // d = s0; printf(" %x %x %x\n", *(d-1), *d, *(d+1)); i = 2 + 256 + 3; // width j = 2 + 26 + 2; // hight // q->bfSize = sizeof(bmp_hdr) + i * j; // これは、うまくいかなかった q->bcWidth = i; q->bcHeight = j; // q->biSizeImage = i * j; // 同上 for (i = 0; i < 26; i += 1) { d = s0 + 264*(i+2) + 2; // 左下隅に XY 各 2 dot を開ける for (j = 0; j < 256; j += 1) { x = j / 256.0; // 注: 0 <= x < 1.0、そのような関数を使う予定なので c = (10.0 * x); // 0 <= c < 10 *d++ = c_code[c]; // カラーコードに変換 /* if (i == 0 && c != prc) { // カラーコード変換範囲の確認 printf("%3d: x = %f, c %02x, c_code[c] %02x\n", j, x, c, c_code[c]); prc = c; } */ } *d = (i/2 & 1) ? 0xff : 0; // 白・黒、縦の点線 } return 0; } // 描画 計算式: x = i * j / 262144 int chc1(unsigned char* s0) { unsigned char* d; unsigned char c; int i, j; float x; for (i = 0; i < 512; i += 1) { d = s0 + 600*(i+2) + 2; // 左下隅に XY 各 2 dot を開ける 600 は bmp 画像の横幅 for (j = 0; j < 512; j += 1) { x = ((float)i * (float)j) / (512.0*512.0); // 注: 0 <= x < 1.0 c = (10.0 * x); // 0 <= c < 10 *d++ = c_code[c]; // 変換表を使います } *d = (i/4 & 1) ? 0 : 0xff; // 白・黒、縦の点線 } // オマケの 256 全色カラーバー for (i = 514; i < 524; i += 1) { d = s0 + 600*(i+2) + 2; for (j = 0; j < 256; j += 1) { c = (unsigned char)((j == 10) ? 9 : j); // 0x0a を描くと、妙なことが起こります *d++ = c; *d++ = c; } *d = (i/2 & 1) ? 0 : 0xff; // 白・黒、縦の点線 } return 0; } float b0[512], b1[512]; // 画像の、行データ(横方向) // 朱に交われば赤くなる(argv: "chc 2" と "chc 3" では初期値が違うだけ) upd_b0(int n) { float m = 0.5; // 両隣の影響係数 float md = 1/(2*m + 1); int j, k; for (k = 0; k < n; k++) { // 一回では変化が僅かなので、何回もくりかえす for (j = 1; j < 512-1; j++) // j の範囲に注意 結果は一時 b1[] に置く b1[j] = md*(m*b0[j-1] + b0[j] + m*b0[j+1]); for (j = 1; j < 512-1; j++) b0[j] = b1[j]; // b0[] 全体を更新 } return 0; } // いいかげんな拡散シミュレーション(一次元世界) int chc2(unsigned char* s0, int f) { // 初期値 f == 0 なら _-_ 型、f == 1 なら ∧ 型 unsigned char* d; unsigned char c; int i, j; float x; q->bcWidth = 2+512+2; q->bcHeight = 2+512+2; for (i = 0; i < 512; i += 1) { d = s0 + 516*(i+2) + 2; // 左下隅に XY 各 2 dot 開ける for (j = 0; j < 512; j += 1) { if (i == 0) { // 最下行の初期化 if (f) { x = j/512.0; // 0 <= x < 1 x = (1.0-1e-3)*((x < 0.5) ? 2.0*x : 2.0-2.0*x); // 最初の係数は ∧ のピーク値 } else x = (j > 256-52 && j < 256+52) ? (1.0-1e-3) : 0; // 黒白黒のライン b0[j] = x; // b0[j] の初期化 c = (10.0*x); // 0 <= c < 10 *d++ = c_code[c]; // 初期値も描画しておく } else { c = 10.0*b0[j]; // b0[] から変換して描画領域に *d++ = c_code[c]; } } // *d = (i % 4) ? 0 : 0xff; // 縦の点線 upd_b0((f > 0) ? 140 : 80); // 拡散の演算、b0[] 更新 } printf("chc2(): b0[1..3] %f %f %f\n", b0[1], b0[2], b0[3]); // 最終行の左端の値確認 return 0; } // 円形の描画領域 int chc4(unsigned char* s0) { unsigned char* d; unsigned char c; float ox = 256, oy = 256; // 円の中心座標 float xd, xe, xf; int i, j; q->bcWidth = 2+512+2; q->bcHeight = 2+512+2; for (i = 0; i < 512; i += 1) { d = s0 + 516*(i+2) + 2; // 左下隅に XY 各 2 dot 開ける for (j = 0; j < 512; j += 1) { xd = pow(ox-i, 2); xe = pow(oy-j, 2); xf = pow(xd+xe, 0.5); // (ox, oy) からの距離 if (xf < 240.0) { // 円内か否かの判定 c = (10.0-1e-3) - xf/24.0; *d++ = c_code[c]; } else d += 1; } // *d = 0x0; } d = s0 + 600*(i+2) + 2; for (j = 0; j < 512; j += 1) *d++ = 0x0; return 0; } // 2点間の距離の計算 float dist2(int ox, int oy, int i, int j) { float xd, xe, xf; xd = pow(ox - i, 2); xe = pow(oy - j, 2); xf = pow(xd + xe, 0.5); // (ox, oy) からの距離 return xf; } // 双子山の等高線図 高さごとに色分け int chc5(unsigned char* s0) { unsigned char* d; unsigned char c; int o1x = 512*(1/3.0), o1y = 512*(2/3.0); // 円の中心座標 int o2x = 512*(2/3.0), o2y = 512*(1/3.0); float df1, df2, x; int i, j; q->bcWidth = 2+512+2; q->bcHeight = 2+512+2; for (i = 0; i < 512; i += 1) { d = s0 + 516*(i+2) + 2; // 左下隅に XY 各 2 dot 開ける for (j = 0; j < 512; j += 1) { df1 = dist2(o1x, o1y, i, j); df2 = dist2(o2x, o2y, i, j); x = sqrt(df1 * df2); // 幾何平均でございます // if (i==256 && j==256) printf("x: %f\n", x); if (x < 243.0) { // 描画範囲内か否かの判定 c = (10.0-1e-3) - (x/24.3); *d++ = c_code[c]; } else d += 1; } } return 0; } int main(int argc, char* argv[]) { FILE* fp; // 入出力ファイルの FILE* size_t n; // fread() などの戻り値 unsigned char* s; /* printf("char: %d\n", sizeof(char)); printf("short: %d\n", sizeof(short)); printf("int: %d\n", sizeof(int)); printf("long: %d\n", sizeof(long)); // printf("long long: %d\n", sizeof(long long)); printf("float: %d\n", sizeof(float)); printf("double: %d\n\n", sizeof(double)); */ // コマンドライン アーギュメント の処理 if (argc > 1) { if (sscanf(argv[1], "%x", &_v)) { _a = 1; printf("_a %d, _v %d\n", _a, _v); } } else { printf("No command argument\n"); return 0; } // malloc() 実行 p0 = (unsigned char *)malloc(bsz); if (!p0) { printf("malloc() fail.\n"); return -1; } printf("p0 0x%x, size %d\n", p0, bsz); // 読み込み fp = fopen("white.bmp", "r"); // cf. small.bmp if (!fp) { printf("fopen(r) fail.\n"); return -1; } n = fread(p0, sizeof(unsigned char), bsz, fp); // ホントは size を調べるべき printf("%d byte read.\n", n); if (n <= 0) return -1; fclose(fp); // ファイル *.bmp のヘッダーを表示 q = (bmp_hdr *)(p0-2); // 謎の -2 です s = (unsigned char *)p0; printf("%c%c, ", *s, *(s+1)); printf("fSize %d, offset 0x%x, width %d, height %d, planes %d, bit/px %d\n", q->bfSize, q->bfOffBits, q->bcWidth, q->bcHeight, q->bcPlanes, q->bcBitCount); printf("compr %d, imSize %d, biPad 0x%x 0x%x 0x%x 0x%x\n", q->biCompresson, q->biSizeImage, q->biPad[0], q->biPad[1], q->biPad[2], q->biPad[3]); if (q->biSizeImage < 600*600) { printf("'white.bmp' too small.\n"); return -1; } // ヘッダーの内容が妥当であるかのチェックは、だいぶ省略 // 出力ファイル open fp = fopen("chc.bmp", "w"); if (!fp) { printf("fopen(w) fail.\n"); return -1; } // 描画 if (_v == 0xc) c_bar(p0 + q->bfOffBits, q->biSizeImage); else if (_v == 1) chc1(p0 + q->bfOffBits); else if (_v == 2) chc2(p0 + q->bfOffBits, 0); // f == 0 なら _-_ 型、f == 1 なら ∧ 型 else if (_v == 3) chc2(p0 + q->bfOffBits, 1); else if (_v == 4) chc4(p0 + q->bfOffBits); else if (_v == 5) chc5(p0 + q->bfOffBits); // ファイル書き込み n = fwrite(p0, sizeof(unsigned char), n, fp); printf("chc.bmp: %d byte written.\n", n); // 終了 fclose(fp); free(p0); system("mspaint chc.bmp"); // mspaint 実行 return 0; }