(原創) 如何使用ANSI C讀寫24/32位元的BMP圖檔? (C/C++) (C) (Image Processing)

Abstract
本文介紹如何使用ANSI C同時讀寫24/32位元的BMP圖檔做簡單的影像處理,並解析BMP格式。

Introduction
(原創) 如何使用ANSI C讀寫24位元的BMP圖檔? (C/C++) (C) (Image Processing)(原創) 如何使用ANSI C讀寫32位元的BMP圖檔? (C/C++) (C) (Image Processing)中,我們發現24位元與32位元BMP格式大致上相同,僅有些許的差異,是否能打造一個能同時讀寫24/32位元BMP圖檔的ANSI C程式?

24位元BMP與32位元BMP的差異
(原創) 如何使用ANSI C讀寫32位元的BMP圖檔? (C/C++) (C) (Image Processing)有詳述兩種BMP的差異,更簡單的說,若我們能從BMP header中得知目前是24位元還是32位元BMP,然後動態的處理1個pixel該用3 byte還是4 byte處理,就能同時讀寫24/32位元BMP。

C語言 / Bmp24_32ReadWrite.c

  1 /* 
  2 (C) OOMusou 2007 http://oomusou.cnblogs.com
  3 
  4 Filename    : Bmp24_32ReadWrite.c
  5 Compiler    : Visual C++ 8.0 / ANSI C
  6 Description : Demo the how to read and write bmp by standard library
  7 Release     : 05/18/2008 1.0
  8 */
  9 #include <stdio.h>
 10 #include <stdlib.h>
 11 
 12 int upside_down(const char *fname_s, const char *fname_t) {
 13   FILE          *fp_s = NULL;    // source file handler
 14   FILE          *fp_t = NULL;    // target file handler 
 15   unsigned int  x,y;             // for loop counter
 16   unsigned int  width, height;   // image width, image height
 17   unsigned char *image_s = NULL; // source image array
 18   unsigned char *image_t = NULL; // target image array
 19   unsigned char R, G, B;         // color of R, G, B
 20   unsigned int y_avg;            // average of y axle
 21   unsigned int y_t;              // target of y axle
 22   
 23   unsigned char header[54= {
 24     0x42,        // identity : B
 25     0x4d,        // identity : M
 26     0000,  // file size
 27     00,        // reserved1
 28     00,        // reserved2
 29     54000// RGB data offset
 30     40000// struct BITMAPINFOHEADER size
 31     0000,  // bmp width
 32     0000,  // bmp height
 33     10,        // planes
 34     240,       // bit per pixel
 35     0000,  // compression
 36     0000,  // data size
 37     0000,  // h resolution
 38     0000,  // v resolution 
 39     0000,  // used colors
 40     0000   // important colors
 41   };
 42   
 43   unsigned int file_size;           // file size
 44   unsigned int rgb_raw_data_offset; // RGB raw data offset
 45   unsigned short bit_per_pixel;     // bit per pixel
 46   unsigned short byte_per_pixel;    // byte per pixel
 47   
 48   fp_s = fopen(fname_s, "rb");
 49   if (fp_s == NULL) {
 50     printf("fopen fp_s error\n");
 51     return -1;
 52   }
 53 
 54   // move offset to 10 to find rgb raw data offset
 55   fseek(fp_s, 10, SEEK_SET);
 56   fread(&rgb_raw_data_offset, sizeof(unsigned int), 1, fp_s);
 57   // move offset to 18    to get width & height;
 58   fseek(fp_s, 18, SEEK_SET); 
 59   fread(&width,  sizeof(unsigned int), 1, fp_s);
 60   fread(&height, sizeof(unsigned int), 1, fp_s);
 61   // get  bit per pixel
 62   fseek(fp_s, 28, SEEK_SET); 
 63   fread(&bit_per_pixel, sizeof(unsigned short), 1, fp_s);
 64   byte_per_pixel = bit_per_pixel / 8;
 65   // move offset to rgb_raw_data_offset to get RGB raw data
 66   fseek(fp_s, rgb_raw_data_offset, SEEK_SET);
 67     
 68   image_s = (unsigned char *)malloc((size_t)width * height * byte_per_pixel);
 69   if (image_s == NULL) {
 70     printf("malloc images_s error\n");
 71     return -1;
 72   }
 73   
 74   image_t = (unsigned char *)malloc((size_t)width * height * byte_per_pixel);
 75   if (image_t == NULL) {
 76     printf("malloc image_t error\n");
 77     return -1;
 78   }
 79   
 80   fread(image_s, sizeof(unsigned char), (size_t)(long)width * height * byte_per_pixel, fp_s);
 81   
 82   // vertical inverse algorithm
 83   y_avg = 0 + (height-1);
 84   
 85   for(y = 0; y != height; ++y) {
 86     for(x = 0; x != width; ++x) {
 87       R = *(image_s + byte_per_pixel * (width * y + x) + 2);
 88       G = *(image_s + byte_per_pixel * (width * y + x) + 1);
 89       B = *(image_s + byte_per_pixel * (width * y + x) + 0);
 90       
 91       y_t = y_avg - y;
 92       
 93       *(image_t + byte_per_pixel * (width * y_t + x) + 2= R;
 94       *(image_t + byte_per_pixel * (width * y_t + x) + 1= G;
 95       *(image_t + byte_per_pixel * (width * y_t + x) + 0= B;
 96     }
 97   }
 98   
 99   // write to new bmp
100   fp_t = fopen(fname_t, "wb");
101   if (fp_t == NULL) {
102     printf("fopen fname_t error\n");
103       return -1;
104     }
105       
106     // file size  
107     file_size = width * height * byte_per_pixel + rgb_raw_data_offset;
108     header[2= (unsigned char)(file_size & 0x000000ff);
109     header[3= (file_size >> 8)  & 0x000000ff;
110     header[4= (file_size >> 16& 0x000000ff;
111     header[5= (file_size >> 24& 0x000000ff;
112     
113     // width
114     header[18= width & 0x000000ff;
115     header[19= (width >> 8)  & 0x000000ff;
116     header[20= (width >> 16& 0x000000ff;
117     header[21= (width >> 24& 0x000000ff;
118     
119     // height
120     header[22= height &0x000000ff;
121     header[23= (height >> 8)  & 0x000000ff;
122     header[24= (height >> 16& 0x000000ff;
123     header[25= (height >> 24& 0x000000ff;
124     
125     // bit per pixel
126     header[28= bit_per_pixel;
127   
128   // write header
129   fwrite(header, sizeof(unsigned char), rgb_raw_data_offset, fp_t);
130   // write image
131     fwrite(image_t, sizeof(unsigned char), (size_t)(long)width * height * byte_per_pixel, fp_t);
132     
133     fclose(fp_s);
134     fclose(fp_t);
135     
136     return 0;
137 }
138 
139 int main() {
140   upside_down("capture32.bmp""capture32_v.bmp");
141 }


原圖(24位元)

clena.jpg


執行結果(24位元)

clena3.jpg


原圖(32位元)

capture32.gif


執行結果(32位元)

capture32_v.gif


34行

240,       // bit per pixel    


暫時將header設定為24位元,後面會依照實際狀況去修改。

45、46行

unsigned short bit_per_pixel;     // bit per pixel
unsigned short byte_per_pixel;    // byte per pixel  


新增兩個變數,判斷bit per pixel與byte per pixel。

61行

// get  bit per pixel
fseek(fp_s, 28, SEEK_SET); 
fread(
&bit_per_pixel, sizeof(unsigned short), 1, fp_s);
byte_per_pixel 
= bit_per_pixel / 8;


從BMP header讀出目前的圖片是24位元還是32位元,並計算出一個pixel是3 byte還是4 byte,之後就依照byte_per_pixel變數去做運算。

之後的程式,凡事遇到處理byte處,就不用寫死3 byte或4 byte了,完全依照byte_per_pixel決定,道理相同,我們就不在多做解釋。

125行

// bit per pixel
header[28= bit_per_pixel;


從新依照實際的bit_per_pixel變數寫入文字檔,不再受限於24 bit。

Conclusion
之所以還分(原創) 如何使用ANSI C讀寫32位元的BMP圖檔? (C/C++) (C) (Image Processing)討論32位元BMP,實為了解說方便,在實務上,建議用此程式,可一次讀寫24/32位元BMP。

See Also
(原創) 如何使用ANSI C讀寫24位元的BMP圖檔? (C/C++) (C) (Image Processing)
(原創) 如何使用ANSI C讀寫32位元的BMP圖檔? (C/C++) (C) (Image Processing)
(原創) 如何將CMOS所擷取的影像傳到PC端? (IC Design) (DE2)
(原創) 如何使用ISO C++讀寫bmp圖檔? (C/C++) (Image Processing)
(原創) 如何使用C++/CLI读/写jpg檔? (C++/CLI)
(原創) 如何用程序的方式载入jpg图形文件? (C#/ASP.NET)

Reference
[1] swwuyamBMP檔案格式
[2] Charles Petzold 1998, Programming Windows, Microsoft Press
瘋小貓的華麗冒險點陣圖(Bitmap)檔案格式
BMP文件格式分析
賴岱佑、劉敏 2007,數位影像處理 技術手冊,文魁資訊
井上誠喜、八木申行、林 正樹、中須英輔、三古公二、奧井誠人 著 2006,吳上立,林宏燉 編譯,C語言數位影像處理,全華出版社

posted on 2008-05-26 00:12  真 OO无双  阅读(7990)  评论(1编辑  收藏  举报

导航