#include <stdio.h>
#pragma pack(1) //##### コンパイラ依存 ##### 少なくともgccとVC++は使える
//BMPファイルヘッダ構造体
typedef struct {
unsigned short type;
unsigned long size;
unsigned short reserved1;
unsigned short reserved2;
unsigned long offset;
}bmpfileheader_t;
//BMP情報ヘッダ構造体
typedef struct {
unsigned long size;
long width;
long height;
unsigned short plane;
unsigned short bit;
unsigned long copmress;
unsigned long sizeimage;
long x_permeter;
long y_permeter;
unsigned long color;
unsigned long index;
}bmpinfoheader_t;
typedef struct {
//24bitBMPファイルはB,G,Rの順で並んでいる
unsigned char b;
unsigned char g;
unsigned char r;
}rgb_t;
typedef struct {
long h;
unsigned char s;
unsigned char v;
}hsv_t;
void rgb2hsv(rgb_t*, hsv_t*); //RGB->HSV変換
#pragma pack()
void main(int argc, char *argv[])
{
FILE *fp;
bmpfileheader_t bf;
bmpinfoheader_t ih;
rgb_t rgb;
hsv_t hsv;;
int padding;
int x, y;
//引数が無い場合
if(argc < 2)
return;
//ファイルオープン
if((fp = fopen(argv[1], "rb")) == NULL) {
printf("Can't open %s", argv[1]);
fclose(fp);
return;
}
//ファイルヘッダを読む
if(fread((void *)&bf, sizeof(bmpfileheader_t), 1, fp) !=1) {
puts("Failed to get BMPHEADER.");
fclose(fp);
return;
}
//情報ヘッダを読む
if(fread((void *)&ih, sizeof(bmpinfoheader_t), 1, fp) !=1) {
puts("Failed to get INFOHEADER.");
fclose(fp);
return;
}
//BMP形式ではない場合
if(bf.type != 0x4d42) { //0x4d42 = BM(リトルエンディアン)
puts("Not BMP file.");
fclose(fp);
return;
}
//OS/2形式のBMPは対応しない
if(ih.size != sizeof(bmpinfoheader_t)) {
printf("Unsupported format.");
fclose(fp);
return;
}
//24ビット以外は対応しない(手抜き)
if(ih.bit != 24) {
puts("Unsupported Colorbit.");
fclose(fp);
return;
}
padding = ih.width % 4; //パディングを計算
x = 1; y = ih.height; //左下から右上へ
if(fseek(fp, bf.offset, SEEK_SET) != 0) { //ピクセルのデータまで移動
printf("Failed to seek");
fclose(fp);
return;
}
while((fread((void *)&rgb, sizeof(rgb_t), 1, fp)) == 1) { //EOFまで1ピクセル分のデータを繰り返し読み込み
printf("X:%5d: Y:%5d R:G:B|%3d:%3d:%3d ->", x, y, rgb.r, rgb.g, rgb.b);
rgb2hsv(&rgb, &hsv);
printf("H:S:V|%3d:%3d:%3d\n", hsv.h, hsv.s, hsv.v);
x++;
if(x > ih.width) { //右端に達したら
x = 1; y--;
fseek(fp, padding, SEEK_CUR); //パディングを飛ばす
}
}
fclose(fp);
}
void rgb2hsv(rgb_t *rgb, hsv_t *hsv)
{
unsigned char max, min;
if(rgb->r >= rgb->g && rgb->r >= rgb->b)
max = rgb->r;
if(rgb->g >= rgb->r && rgb->g >= rgb->b)
max = rgb->g;
if(rgb->b >= rgb->r && rgb->b >= rgb->g)
max = rgb->b;
if(rgb->r <= rgb->g && rgb->r <= rgb->b)
min = rgb->r;
if(rgb->g <= rgb->r && rgb->g <= rgb->b)
min = rgb->g;
if(rgb->b <= rgb->r && rgb->b <= rgb->g)
min = rgb->b;
hsv->v = max; //vを計算
if(hsv->v == 0){ //v=0の時、sは未定義で完全な黒色
hsv->h = 0; hsv->s = 0; hsv->v = 0;
return;
}
hsv->s = 255 * (max - min) / max; //sを計算
if(hsv->s == 0) { //s=0の時hは未定義
hsv->h = 0;
return;
}
//hを計算
if(max == rgb->r)
hsv->h = 60 * (rgb->b - rgb->g) / (max - min);
if(max == rgb->g)
hsv->h = 60 * (2 + (rgb->r - rgb->b) / (max - min));
if(max == rgb->b)
hsv->h = 60 * (4 + (rgb->g - rgb->r) / (max - min));
if(hsv->h < 0)
hsv += 360;
return;
}