#define _CRT_SECURE_NO_WARNINGS // close security warning #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> // 建立一個3維動態陣列 void deallocateImgArray(unsigned char ***arr3D,int depth,int height); // 釋放一個3維動態陣列 unsigned char*** allocateImgArray(int depth,int hegith,int width); // 分配記憶體給 imgPointer Pair int allocateImgPtr(); // 釋放 imgPointer Pair記憶體 void releaseImgPtr(); // 開啟來源影像檔案 int openSrcFile( const char* srcName); // 開啟目的影像檔案 int openDstFile( const char* dstName); // 關閉 來源影像檔案 和 目的影像檔案 void closeSrcDstFile(); // 初始化BMP影像Header void initHeaderAndParam(); // 寫入Header到目的檔案 void writeHeaderAndParam(); // 來源影像srcImg 轉為 來源影像陣列 void srcImg2imgArraySrc(); // 目的影像陣列 轉為 目的影像dstImg void imgArrayDst2dstImg(); // 從原始影像檔案 讀入 BitMap void InitSrcImgPtr(); void overwrite(); void upsideDown(); void leftRightReverse(); void udlr(); // 建立一個 function ptr table // 0 : overwrite 原始影像拷貝到目的影像 // 1 : upsideDown 原始影像上下顛倒 輸出 到目的影像 // 2 : leftRightReverse 原始影像左右顛倒 輸出 到目的影像 // 3 : udlr 原始影像上下左右顛倒 輸出 到目的影像 void (* operation[])() = { overwrite, upsideDown, leftRightReverse, udlr }; FILE *srcFile = NULL; // src file pointer FILE *dstFile = NULL; // dst file pointer unsigned int width=0,height=0; // 影像寬,影像高 unsigned char* srcImg = NULL; // 以byte操作的原始影像pointer unsigned char* dstImg = NULL; // 以byte操作的目的影像pointer unsigned char ***imgArraySrc=NULL; // 以下標[]操作的原始影像矩陣 unsigned char ***imgArrayDst=NULL; // 以下標[]操作的目的影像矩陣 unsigned char header[54]= { 0x42, // Byte 0 , ID : 'B' as a character 0x4d, // Byte 1 , ID : 'M' as a character 0, 0, 0, 0, // Byte 2 ~ 5 , fileSize 0, 0, // Byte 6 ~ 7 , reserved1 field 0, 0, // Byte 8 ~ 9 , reserved2 field 54, 0, 0, 0, // Byte 10~ 13, header offset in byte 40, 0, 0, 0, // Byte 14~ 17, bitmap info header size in byte 0, 0, 0, 0, // Byte 18~ 21, bmp width 0, 0, 0, 0, // Byte 22~ 25, bmp height 1, 0, // Byte 26~ 27, pixel plannes number, set to 1 forever 0, 0, // Byte 28~ 29, Bit per pixel 24 or 32 0, 0, 0, 0, // Byte 30~ 33, Compression 0, 0, 0, 0, // Byte 34~ 37, bim map size in byte 0, 0, 0, 0, // Byte 38~ 41, horizontal resolution 0, 0, 0, 0, // Byte 42~ 45, vertical resolution 0, 0, 0, 0, // Byte 46~ 49, used colors 0, 0, 0, 0 // Byte 50~ 53, important colors }; unsigned int fileSize=0; // mapping Byte 2 ~ 6 , total 4 byte width unsigned int imageArraySize=0; // imageArraySize unsigned int rgbRawDataOffset=0; // mapping Byte 10 ~ 13 , total 4 byte width unsigned short bitPerPixel=0; // mapping Byte 28 ~ 29, total 2 byte width, record the bit mode used, 24 or 32 unsigned short bytePerPixel=0; // record the pixel byte constant = bitPerPixel / 8 unsigned int rowSize = 0; // record the rowsize after padding // 上下顛倒 void upsideDown() { for(int y = 0; y != height; ++y) { for(int x = 0; x != width; ++x) { unsigned int newYpos = height - 1 - y; // change y coordinate imgArrayDst[ 2 ][ y ][ x ] = imgArraySrc[ 2 ][ newYpos ][ x ]; imgArrayDst[ 1 ][ y ][ x ] = imgArraySrc[ 1 ][ newYpos ][ x ]; imgArrayDst[ 0 ][ y ][ x ] = imgArraySrc[ 0 ][ newYpos ][ x ]; } } return; }//end of function upsideDown // 左右顛倒 void leftRightReverse() { for(int y = 0; y != height; ++y) { for(int x = 0; x != width; ++x) { unsigned int newXpos = width - 1 - x; // change x coordinate imgArrayDst[ 2 ][ y ][ x ] = imgArraySrc[ 2 ][ y ][ newXpos ]; imgArrayDst[ 1 ][ y ][ x ] = imgArraySrc[ 1 ][ y ][ newXpos ]; imgArrayDst[ 0 ][ y ][ x ] = imgArraySrc[ 0 ][ y ][ newXpos ]; } } return; }//end of function leftRightReverse // 上下左右顛倒 void udlr() { for(int y = 0; y != height; ++y) { for(int x = 0; x != width; ++x) { unsigned int newXpos = width - 1 - x; // change x coordinate unsigned int newYpos = height - 1 - y; // change x coordinate imgArrayDst[ 2 ][ y ][ x ] = imgArraySrc[ 2 ][ newYpos ][ newXpos ]; imgArrayDst[ 1 ][ y ][ x ] = imgArraySrc[ 1 ][ newYpos ][ newXpos ]; imgArrayDst[ 0 ][ y ][ x ] = imgArraySrc[ 0 ][ newYpos ][ newXpos ]; } } return; }//end of function leftRightReverse // 純粹覆寫 void overwrite() { for(int y = 0; y != height; ++y) { for(int x = 0; x != width; ++x) { imgArrayDst[ 2 ][ y ][ x ] = imgArraySrc[ 2 ][ y ][ x ]; imgArrayDst[ 1 ][ y ][ x ] = imgArraySrc[ 1 ][ y ][ x ]; imgArrayDst[ 0 ][ y ][ x ] = imgArraySrc[ 0 ][ y ][ x ]; } } return; }//end of function leftRightReverse // 開啟來源影像檔案 int openSrcFile( const char* srcName) { // "R"ead bit map file in "B"inary mode srcFile = fopen(srcName,"rb"); if( srcFile == NULL ) { printf("could not open source bmp file."); return -1; } return 0; }//end of openSrcFile // 開啟目的影像檔案 int openDstFile( const char* dstName) { // "W"rite bit map file in "B"inary mode dstFile = fopen(dstName,"wb"); if( dstFile == NULL ) { printf("could not open dst file."); return -1; } return 0; }//end of openDstFile void closeSrcDstFile() { // close input file stream fclose(srcFile); // close output file stream fclose(dstFile); return; }//end of function closeSrcDstFile void initHeaderAndParam() { // move offset to 10th byte to get rgb raw data offset fseek( srcFile, 10, SEEK_SET); fread( &rgbRawDataOffset, sizeof(unsigned int), 1, srcFile); // read 1 byte from byte 10 to get header offset // move offset to 18 to get width and height fseek( srcFile, 18, SEEK_SET); fread( &width, sizeof(unsigned int), 1, srcFile); // read 4 byte from byte 18 ~ 21 to get image width fread( &height, sizeof(unsigned int), 1, srcFile); // read 4 byte from byte 22 ~ 25 to get image height // move offsetto 28 to get bitPerPixel fseek( srcFile, 28, SEEK_SET); fread( &bitPerPixel, sizeof(unsigned short), 1, srcFile); // read 4 byte from byte 28 ~ 29 to get bitPerPixel // 知道 bitPerPixel 之後,換算成 bytePerPixel bytePerPixel = bitPerPixel / 8 ; // 知道 bitPerPixel 和 width之後,計算 rowSize rowSize = ( ( bitPerPixel * width+ 31 )/32 ) * 4 ; // take padding into consideration // 知道 height 和 rowSzie 計算 imageArraySize imageArraySize = height * rowSize; // 知道 height 和 rowSzie 還有 rgbRawDataOffset 之後,計算整個BMP file大小(包含Header) fileSize = imageArraySize + rgbRawDataOffset; // 影像高 * 每一列的byteSize + rgbRawDataOffset return; }//end of initHeaderAndParam void writeHeaderAndParam() { // write Default header to dstFile from byte 0 fwrite( header, sizeof(unsigned char), rgbRawDataOffset, dstFile); // modify dstFile's header start fseek( dstFile, 2, SEEK_SET); // move offset to 2nd byte to write bmp file size fwrite( &fileSize, sizeof(unsigned int),1, dstFile); fseek( dstFile, 18, SEEK_SET); // move offset to 18th byte to write bit map Width fwrite( &width, sizeof(unsigned int),1, dstFile); fseek( dstFile, 22, SEEK_SET); // move offset to 22th byte to write bit map Height fwrite( &height, sizeof(unsigned int),1, dstFile); fseek( dstFile, 28, SEEK_SET); // move offset to 28th byte to write bitPerPixel fwrite( &bitPerPixel, sizeof(unsigned short),1, dstFile); return; }//end of writeHeaderAndParam int allocateImgPtr() { // allocate memory space for srcImg pointer srcImg = (unsigned char *)malloc( (size_t) imageArraySize ); if( srcImg == NULL ) { printf("malloc srcImge Error"); return -1; } // allocate memory space for dstImg pointer dstImg = (unsigned char *)malloc( (size_t) imageArraySize ); if( dstImg == NULL ) { printf("malloc dstImge Error"); return -1; } return 0; }//end of allocateImgPtr void releaseImgPtr() { // release srcImg memory space free( srcImg ); // release dstImg memory space free( dstImg ); return; }//end of releaseImgPtr void rawCopyImgPtr() { // // RAW COPY scrImg to dstImg //memcpy(dstImg, srcImg, (size_t) height * rowSize ); // return; }//end of rawCopyImgPtr void InitSrcImgPtr() { // move offset to rgbRawDataOffset to get RGB image array fseek(srcFile, rgbRawDataOffset, SEEK_SET); // copy pixel array from srcFile to scrImg fread(srcImg, sizeof(unsigned char), (size_t) imageArraySize, srcFile ); return; }//end of InitSrcImgPtr void writeDstImgPtr() { fseek( dstFile, 54, SEEK_SET); // move offset to 54th byte for writing dstImg to dstFile // write image // 注意:此處大小應為 imageArraySize = height * rowSize fwrite(dstImg, sizeof(unsigned char),(size_t)imageArraySize, dstFile); return; }//end of writeDstImgPtr //allocate a Color Map unsigned char*** allocateImgArray(int depth,int h,int w) { unsigned char ***arr3D=NULL; int i=0,j=0,k=0; arr3D = (unsigned char***)malloc(depth * sizeof(unsigned char **)); for(i=0;i<depth;i++) { arr3D[i] = (unsigned char**)malloc(h * sizeof(char*)); for(j=0;j<h;j++) { arr3D[i][j] = (unsigned char*)malloc(w*sizeof(char)); } } for( i = 0 ; i < depth ; ++i ) { for( j = 0 ; j < h ; ++j ) { for( k = 0 ; k < w ; ++k ) { //printf("%c \n", arr3D[i][j][k]); arr3D[i][j][k]=(unsigned char)'0'; //printf("%c \n", arr3D[i][j][k]); } } } return arr3D; }//End of allocateImgArray //Deallocate Color Map void deallocateImgArray(unsigned char ***arr3D,int depth,int height) { int i,j; for(i=0;i<depth;i++) { for(j=0;j<height;j++) { free(arr3D[i][j]); } free(arr3D[i]); } free(arr3D); }//end of deallocateImgArray // 來源影像 轉為 來源影像陣列 void srcImg2imgArraySrc() { // srcImg 轉 imgArraySrc for(int y = 0; y != height; ++y) { for(int x = 0; x != width; ++x) { imgArraySrc[2][y][x] = *(srcImg + rowSize * y + x*bytePerPixel + 2); // Red channel imgArraySrc[1][y][x] = *(srcImg + rowSize * y + x*bytePerPixel + 1); // Green channel imgArraySrc[0][y][x] = *(srcImg + rowSize * y + x*bytePerPixel + 0); // Blue channel } } return ; }//end of function srImg2imgArraySrc // 目的影像陣列 轉為 目的影像 void imgArrayDst2dstImg() { // imgArrayDst 轉 dstImg for(int y = 0; y != height; ++y) { for(int x = 0; x != width; ++x) { *(dstImg + rowSize * y + x*bytePerPixel + 2) = imgArrayDst[2][y][x]; // Red channel *(dstImg + rowSize * y + x*bytePerPixel + 1) = imgArrayDst[1][y][x]; // Green channel *(dstImg + rowSize * y + x*bytePerPixel + 0) = imgArrayDst[0][y][x]; // Blue channel } } return ; }//end of function imgArrayDst2dstImg int process( const char *srcName, const char *dstName, const int ch) { if( openSrcFile( srcName) == -1 ) return -1; openSrcFile( srcName); // 讀取原始影像檔案 initHeaderAndParam(); // 處始化BMP影像參數 allocateImgPtr(); // 分配記憶體給 影像指標 InitSrcImgPtr(); // 從原始影像檔案 讀入 BitMap 到 來源影像srcImg imgArraySrc = allocateImgArray( 3, height, width); // 替 imgArraySrc 分配空間 imgArrayDst = allocateImgArray( 3, height, width); // 替 imgArrayDst 分配空間 srcImg2imgArraySrc(); // 來源影像srcImg 轉為 來源影像陣列 imgArraySrc // 針對imgArraySrc 和 imgArrayDst 作運算處理,透過 ch 選擇 operation[ch](); imgArrayDst2dstImg(); // 目的影像陣列 imgArrayDst 轉為 目的影像dstImg deallocateImgArray(imgArraySrc,3,height); // 釋放 imgArraySrc deallocateImgArray(imgArrayDst,3,height); // 釋放 imgArrayDst openDstFile(dstName); // 開啟目的影像檔案 writeHeaderAndParam(); // 寫入Header到目的檔案 writeDstImgPtr(); // 把目的影像dstImg 輸出 Bitmap 到 目的影像檔案 releaseImgPtr(); // 釋放 imgPointer Pair記憶體 closeSrcDstFile(); // 關閉 來源影像檔案 和 目的影像檔案 return 0; }//end of readWrite int main() { char inputFilename[128]={0}; char outputFilename[128]={0}; int choice = 0; printf("please input filename to load.\n"); scanf("%s",inputFilename); strcpy(outputFilename,inputFilename); strcat(inputFilename,".bmp"); strcat(outputFilename,"Output.bmp"); printf("\n\nplease intput the procedure you want to carry out\n" "0. copy\n" "1. upside down\n" "2. left-right reverse\n" "3. upside down and left-right reverse\n"); scanf("%d",&choice); process(inputFilename, outputFilename, choice); return 0; }//end of main