剛考完期中考,閒來無事,想到之前有看到別人用C語言來讀取bmp檔,想說自己也來寫一個XD之後過了3、4天才弄出來,看來還需多加磨練XD
程式介面如圖:
而利用C語言讀bmp檔,要先了解C語言中的struct和熟悉bmp的檔案格式,而struct的用法可以在C語言相關的書中找到這邊就不多加敘述,bmp相關的架構可以參考bmp格式
接著另外一個重點就是GLUT,GLUT的簡介如下,更詳細的內容可以參考GLUT介紹:
GLUT(英文全寫:OpenGL Utility Toolkit)是一個處理OpenGL程式的工具庫,負責處理和底層作業系統的呼叫以及I/O,並包括了以下常見的功能:
1.定義以及控制視窗
2.偵測並處理鍵盤及滑鼠的事件
3.以一個函數呼叫繪製某些常用的立體圖形,例如長方體、球、以及猶他茶壺(實心或只有骨架,如glutWireTeapot())
4.提供了簡單選單列的實現
在這邊我用的IDE是DEV C++,可以到工具->檢查更新版本那去找OpenGLUT的相關更新。安裝好之後,在開新專案時,可以找到MultiMedia的頁籤中,找到OpenGLUT,接著打好名稱,按確定,就可以踏入GLUT的世界啦!
而這邊回到重點,我這邊寫的程式的主要是先用C語言中的檔案函數,透過讀二進制的方法,並配合bmp的檔案架構,寫好幾個struct,在將檔案標頭部份讀進struct,而其中代表圖像的像素陣列則是用二維陣列儲存。
這邊要注意的是,bmp檔中像素的是用BGR,所以COLOR那我的宣告是依序是B、G、R這樣就不會有問題了。
而在繪圖時,是將圖片一點一點描繪出來,使用了glColor3f函數和glVertex2i函數,設定顏色和描點。這邊也要注意一點glColor3f函數中的RGB值是照比例來算,所以前面讀出像素陣列的RGB值都要除上255。
而這邊在繪圖部分,則是提供三種功能顯示原圖、灰階圖像、負片,由使用者輸入代碼而定。至於檔案名稱是透過命令列參數讀入。
下面就是程式碼的部分啦!
#include <GL/openglut.h>
#include <stdarg.h>
#include<stdio.h>
#include<stdlib.h>
typedef struct BmpHeader
{
unsigned char HEADER_NAME[2];
unsigned char SIZE[4];
unsigned int UNUSE1;
unsigned int UNUSE2;
unsigned long PIXEL_ARRAY_BEGIN;
}BMP_HEADER;
typedef struct DIBHeader
{
unsigned long DIB_HEADER_SIZE;
unsigned long IMAGE_WIDTH;
unsigned long IMAGE_HEIGHT;
unsigned int PLANE_AMOUNT;
unsigned int BITS_PER_PIXEL;
unsigned long COMPRESSION_USED;
unsigned long PIXEL_ARRAY_SIZE;
unsigned long H_RESOLUTION;
unsigned long V_RESOLUTION;
unsigned long PALETTLE_COLOR;
unsigned long IMPORTANT_COLOR ;
}DIB_HEADER;
typedef struct Color{
unsigned char B;
unsigned char G;
unsigned char R;
}COLOR;
typedef struct image{
BMP_HEADER ImageBMP_HEADER;
DIB_HEADER ImageDIB_HEADER;
}IMAGE;
int LoadFile(FILE*,int,char * [],IMAGE*);
void display();
int Height;
int Width;
IMAGE ReadImage;
COLOR ImageData[600][800];
int OperatorNumber;
int main(int argc,char *argv[])
{
int i,j;
FILE*fptr;
if (LoadFile(fptr,argc,argv,&ReadImage)==-1)
{
system("PAUSE");
return 0;
}
printf("Image information:\n");
printf("Image size:%dKB\n",(54+ReadImage.ImageDIB_HEADER.IMAGE_HEIGHT*ReadImage.ImageDIB_HEADER.IMAGE_WIDTH*24/8)/1024);
printf("Image height:%d\n",ReadImage.ImageDIB_HEADER.IMAGE_HEIGHT);
printf("Image width:%d\n\n",ReadImage.ImageDIB_HEADER.IMAGE_WIDTH);
printf("Input operator number:\n");
printf("0)Show initial image\n1)Change to gray image\n2)Change to negative image\n");
scanf("%d",&OperatorNumber);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowSize(640,640);
glutCreateWindow("Read BMP");
glutDisplayFunc(display);
glPointSize(4.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 640.0, 0.0,480.0);
glutMainLoop();
return 0;
}
int LoadFile(FILE* fptrSet,int main_argc,char *main_argv[],IMAGE *image)
{
int i;
if (main_argc<2)
{
printf("File name cann't be finded!\n");
return -1;
}
else if (main_argc==2)
{
fptrSet=fopen(main_argv[1],"rb");
}else
{
printf("Too many arguments!\n");
return -1;
}
if (fptrSet!=NULL)
{
fread(&(image->ImageBMP_HEADER),sizeof(image->ImageBMP_HEADER),1,fptrSet);
fseek(fptrSet,0x000E,SEEK_SET);
fread(&(image->ImageDIB_HEADER),sizeof(image->ImageDIB_HEADER),1,fptrSet);
Width=image->ImageDIB_HEADER.IMAGE_WIDTH;
Height=image->ImageDIB_HEADER.IMAGE_HEIGHT;
fseek(fptrSet,0x0036,SEEK_SET);
for(int i=0;i<Height;i++)
{
fread(ImageData[i],sizeof(COLOR),Width,fptrSet);
}
if (image->ImageBMP_HEADER.HEADER_NAME[0]=='B'&&image->ImageBMP_HEADER.HEADER_NAME[1]=='M')
{
printf("The image was loaded!\n");
return 0;
}else
{
printf("The image is not bmp!\n");
return -1;
}
}
fclose(fptrSet);
}
void display()
{
float gray;
glClear(GL_COLOR_BUFFER_BIT);
switch (OperatorNumber)
{
case 0:
for (int i=0;i<Height;i++)
{
for (int j=0;j<Width;j++)
{
glBegin(GL_POINTS);
glColor3f((float)ImageData[i][j].R/255,(float)ImageData[i][j].G/255,(float)ImageData[i][j].B/255);
glVertex2i(j,i);
glEnd();
}
}
break;
case 1:
for (int i=0;i<Height;i++)
{
for (int j=0;j<Width;j++)
{
glBegin(GL_POINTS);
gray=((float)ImageData[i][j].R/255+(float)ImageData[i][j].G/255+(float)ImageData[i][j].B/255)/3;
glColor3f(gray,gray,gray);
glVertex2i(j,i);
glEnd();
}
}
break;
case 2:
for (int i=0;i<Height;i++)
{
for (int j=0;j<Width;j++)
{
glBegin(GL_POINTS);
glColor3f((float)(ImageData[i][j].R^255)/255,(float)(ImageData[i][j].G^255)/255,(float)(ImageData[i][j].B^255)/255);
glVertex2i(j,i);
glEnd();
}
}
break;
}
glFlush();
}
需要程式檔及原始碼的朋友請按這裡。接下來就是繼續奮鬥,索貝爾運算子!
