#include <stdio.h>
#include <stdlib.h>
#pragma pack(push,2)
typedef struct tagBITMAPFILEHEADER {
unsigned short bfType;
unsigned long bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned long bfOffBits;
} BITMAPFILEHEADER;
#pragma pack(pop)
#pragma pack(push,4)
typedef struct tagBITMAPINFOHEADER{
unsigned long biSize;
long biWidth;
long biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned long biCompression;
unsigned long biSizeImage;
long biXPelsPerMeter;
long biYPelsPerMeter;
unsigned long biClrUsed;
unsigned long biClrImportant;
} BITMAPINFOHEADER;
#pragma pack(pop)
#pragma pack(push,1)
// ピクセル(BGRの順であることに注意)
typedef struct{
unsigned char b;//(0-255)
unsigned char g;//(0-255)
unsigned char r;//(0-255)
} PIXEL ;
// HSV
typedef struct{
unsigned int h; //(0-359)
unsigned char s;//(0-255)
unsigned char v;//(0-255)
}HSV;
#pragma pack(pop)
// イメージデータ構造体
typedef struct{
BITMAPFILEHEADER bmpFile ;
BITMAPINFOHEADER bmpInfo ;
PIXEL* pixel ;
unsigned int pixel_count ;
} IMAGE_DATA ;
// ビットマップデータ読み取り
int ReadBitmapImage ( char* img_file, IMAGE_DATA* image )
{
FILE *bmp;
// ファイルオープン
bmp = fopen ( img_file, "rb" ) ;
if ( bmp==NULL ){
printf ( "Can't open %s\n", img_file ) ;
return 0 ;
}
// ヘッダー読み取り
fread ( &image->bmpFile, sizeof(BITMAPFILEHEADER), 1, bmp ) ;
fread ( &image->bmpInfo, sizeof(BITMAPINFOHEADER), 1, bmp ) ;
// 24bit以外とOS/2ビットマップをはじく
if ( image->bmpInfo.biBitCount!=24 || image->bmpInfo.biSize!=40 ){
printf ( "only 24bit windows bitmaps are supported\n" ) ;
return 0 ;
}
image->pixel_count = image->bmpInfo.biWidth*image->bmpInfo.biHeight ;// ピクセル数
// 色データの読み取り
image->pixel = (PIXEL*)malloc ( sizeof(PIXEL)*image->pixel_count ) ;
fread ( image->pixel, sizeof(PIXEL), image->pixel_count, bmp ) ;
fclose(bmp) ;
return 1 ;
}
// ビットマップ書き出し
// delは書き出し後にピクセルデータを破棄するかしないか
void WriteBitmapData ( char* img_file, IMAGE_DATA* image, int del )
{
FILE *outFile;
outFile = fopen ( img_file, "wb" ) ;
fwrite ( &image->bmpFile, sizeof(BITMAPFILEHEADER), 1, outFile ) ;
fwrite ( &image->bmpInfo, sizeof(BITMAPINFOHEADER), 1, outFile ) ;
fwrite ( image->pixel, sizeof(PIXEL), image->pixel_count, outFile ) ;
fclose(outFile) ;
// ピクセルデータ破棄
if ( del ){
free (image->pixel) ;
}
}
// RGBからVSHへ変換
void RGBtoHSV ( const PIXEL* pixel, HSV* vsh )
{
unsigned char max, min ;
double h ;
max = pixel->r; if(max<pixel->g)max=pixel->g; if(max<pixel->b)max=pixel->b;
min = pixel->r; if(min>pixel->g)min=pixel->g; if(min>pixel->b)min=pixel->b;
vsh->v = max ;
if ( max==0 ){
vsh->s = 0 ;
vsh->h = 0 ;
} else {
vsh->s = (unsigned char)(255.0*(max - min)/(double)max);
h = 1.0/(double)(max - min) ;
if( max==pixel->r ){
h = h*(double)(pixel->g-pixel->b) ;
} else if ( max==pixel->g ){
h = h*(double)(pixel->b-pixel->r) + 2 ;
} else {
h = h*(double)(pixel->r-pixel->g) + 4 ;
}
h *= 60;
if(h < 0) h += 360;
vsh->h = (unsigned int)h;
}
}
// VSHからRGBへ変換
void HSVtoRGB ( const HSV* vsh, PIXEL* pixel )
{
int I, M, N, K;
double F;
if ( vsh->s==0 ){
pixel->r = pixel->g = pixel->b = vsh->v ;
} else {
I = (int)(vsh->h/60.0);
F = vsh->h/60.0 - I;
M = (int)(vsh->v*(1.0 - vsh->s/255.0));
N = (int)(vsh->v*(1.0 - (vsh->s/255.0) * F));
K = (int)(vsh->v*(1.0 - (vsh->s/255.0) * (1.0-F)));
switch(I){
case 0:
pixel->r = vsh->v;
pixel->g = K;
pixel->b = M;
break;
case 1:
pixel->r = N;
pixel->g = vsh->v;
pixel->b = M;
break;
case 2:
pixel->r = M;
pixel->g = vsh->v;
pixel->b = K;
break;
case 3:
pixel->r = M;
pixel->g = N;
pixel->b = vsh->v;
break;
case 4:
pixel->r = K;
pixel->g = M;
pixel->b = vsh->v;
break;
case 5:
pixel->r = vsh->v;
pixel->g = M;
pixel->b = N;
}
}
}
// 輝度変換
void ConvPastel ( IMAGE_DATA* image )
{
unsigned int i ;
HSV hsv ;
// 輝度:元色(0.0)~白(1.0)
double l = 0.4;
for( i = 0 ; i < image->pixel_count ; i++ ){
RGBtoHSV ( image->pixel+i, &hsv ) ;
hsv.h = hsv.h ;
hsv.s = hsv.s-(unsigned char)(hsv.s*l) ;
hsv.v = hsv.v + (unsigned char)((255-hsv.v)*l) ;
HSVtoRGB ( &hsv, image->pixel+i ) ;
}
}
int main ( void )
{
IMAGE_DATA image ;
// 読み取り
if ( !ReadBitmapImage ( "test.bmp", &image ) ){
printf ( "Error\n" ) ;
return 1 ;
}
// 変換
ConvPastel ( &image ) ;
// 書き出し
WriteBitmapData ( "view.bmp", &image, 1 ) ;
return 0 ;
}