// Image Processing : Homework #2  -  BMP Gray Scale Image Saving //
  // Deadline :  3/10/2004 

_____________________________________________________________________________________

        題目:   將經處理過後的二維陣列結果, 顯示在電腦螢幕上, 
                    並存成灰階模式的 BMP 影像檔。 
_____________________________________________________________________________________

// 將存有處理結果的 2D 陣列, 秀到一個影像物件 GrayImage 中 
GrayImage->Height= ImageHeight;
GrayImage->Width= ImageWidth; 
// 要把 GrayImage 影像物件的 property AutoSize 設為 false 才行

for (i=0;i<ImageHeight;i++)
     for (j=0;j<ImageWidth;j++)
          GrayImage->Canvas->Pixels[j][i]=(TColor)RGB(GrayMatrix[i][j],GrayMatrix[i][j],GrayMatrix[i][j]);

// 將一個彩色影像物件, 儲存成彩色 BMP 檔案格式的指令

if ( SavePictureDialog1->Execute() )
    {
    Image->Picture->SaveToFile(SavePictureDialog1->FileName);
    }
_____________________________________________________________________________________

// 因為 BMP 的儲存格式中, 影像的寬度內定為 4 的倍數,  用一個變數 BMPImageWigth4 紀錄

int    BMPImageWidth4;

Mod4 = ImageWidth % 4;
if ( Mod4 == 0 )
    BMPImageWigth4 = ImageWidth;
else
    BMPImageWigth4 = (((int)((ImageWidth-Mod4)/4))+ 1) * 4 ;

_____________________________________________________________________________________

// 宣告及釋放一個一維陣列的記憶體, 
// 在將影像 output 為 Gray BMP file , 將二維影像轉為一維資料時, 暫存之用

unsigned char *BMPImage;

// free 
 if (BMPImageOpen == 1)
     {
     delete[] BMPImage;
     BMPImageOpen = 0;
     }

// allocate
try {
      BMPImage = new unsigned char [BMPImageWigth4*ImageHeight];
      BMPImageOpen = 1;
      }
 catch (std::bad_alloc) {     // #include <iostream.h>
      ShowMessage("Could not allocate memory...Bye");
      BMPImageOpen = 0;
      exit(-1);
     }
_____________________________________________________________________________________

FILE    *BMPOutput;
char    BMPFileName[45];

// 宣告一個資料型態 BMP_Header_TYPE, 其結構為 BMP 檔頭中, 有關 File Information 的部分
typedef struct {
    unsigned char  bfTYPE[2];            // 固定為 'BM', 用以辨認是否為 DIB
    unsigned char  bfSIZE[4];              // 檔案長度
    short bfRESERVED1;                    // 固定為 0 , 保留未用
    short bfRESERVED2;                    // 固定為 0 , 保留未用
    unsigned char   bfOFFSET[4];       // 儲存圖像資料到檔頭的距離
    } BMP_Header_TYPE;

// 宣告一個變數 Header[1], 其型態為剛剛宣告的 BMP_Header_TYPE
BMP_Header_TYPE Header[1];

// 宣告一個資料型態 BitmapInfoHeader_TYPE
// 其結構為 BMP 檔頭中, 有關 Bitmap Information 的部分
typedef struct {
    unsigned char  biSIZE[4];                          // 宣告圖像基本資料的大小 ( = 40 )
    unsigned char  biWIDTH[4];                     // 圖像的寬度, 以 pixel 為單位
    unsigned char  biHEIGHT[4];                    // 圖像的高度, 以 pixel 為單位
    unsigned char  biPLANES[2];                    // 固定存入 1
    unsigned char  biBITCOUNT[2];               // 宣告每個 pixel 需要多少 bit 儲存 
    unsigned char  biCOMPRESSIOM[4];          // 宣告圖像壓縮方式, 可能的值有 3 種 : 0, 1, 2
    unsigned char  biSIZEIMAGE[4];                 // 影像大小, 以 Byte 為單位 ( W*H*BitCount / 8 )
    unsigned char  biXPELSPERMETER[4];      // 宣告圖像在 X 方向於 1 公尺有多少 pixel , 
    unsigned char  biYPELSPERMETER[4];      // 宣告圖像在 Y 方向於 1 公尺有多少 pixel , 
    unsigned char  biCOLORUSED[4];              // 宣告圖像資料實際用到的顏色數目 ( 0表示用光 )
    unsigned char  biCOLORIMPORTANT[4];  // 宣告調色盤中, 多少顏色在顯示時是重要的
    } BitmapInfoHeader_TYPE;

// 宣告一個變數 BitmapInfoHeader[1]
// 其型態為剛剛宣告的 BitmapInfoHeader_TYPE
BitmapInfoHeader_TYPE BitmapInfoHeader[1];

// 宣告一個資料型態 Palette_COLOR_TYPE
// 其結構為 BMP 檔頭中, 有關 Palette  的部分
typedef struct {
    unsigned char BLUE;
    unsigned char GREEN;
    unsigned char RED;
    unsigned char RESERVED;
    } Palette_COLOR_TYPE;

// 宣告 256 個變數 PaletteColors[256] 用來儲存調色盤的顏色, 
// 型態為剛宣告的 Palette_COLOR_TYPE
Palette_COLOR_TYPE  PaletteColors[256];

// 宣告 2 個變數; 儲存檔案結束控制碼
unsigned char FILEEND[2];                          // 檔案的最後有 2 個 byte 的 0

_____________________________________________________________________________________

        int i,j;
        int BMPFileSize, BMPImageSize;
        int BMPHeight, BMPWidth;

        if ( BMPSaveDialog->Execute() )
           {
           strcpy(BMPFileName,BMPSaveDialog->FileName.c_str());
           if ((BMPOutput = fopen(BMPFileName,"wb"))==NULL)
           {
             ShowMessage("Can't Open"+BMPSaveDialog->FileName);
                if ( errno==ENOENT )     //  必須要加入此行 #include <errno.h> 在程式最前面才行
             ShowMessage(IntToStr(errno));
             close(1);                           //  必須要加入此行 #include <io.h> 在程式最前面才行
          }
        }

        Header[0].bfTYPE[0] = 66; //"B"
        Header[0].bfTYPE[1] = 77; //"M"

        BMPFileSize = 1080 + ImageWidth * ImageHeight;
        Header[0].bfSIZE[0]= (unsigned char)(BMPFileSize % 256);
        BMPFileSize = BMPFileSize >> 8;
        Header[0].bfSIZE[1]=(unsigned char)(BMPFileSize % 256);
        BMPFileSize = BMPFileSize >> 8;
        Header[0].bfSIZE[2]=(unsigned char)(BMPFileSize % 256);
        BMPFileSize = BMPFileSize >> 8;
        Header[0].bfSIZE[3]=(unsigned char)(BMPFileSize % 256);

        Header[0].bfRESERVED1 = 0;
        Header[0].bfRESERVED2 = 0;

        Header[0].bfOFFSET[0] = 54;    //  4 * 256 + 54 = 1078
        Header[0].bfOFFSET[1] = 4;
        Header[0].bfOFFSET[2] = 0;
        Header[0].bfOFFSET[3] = 0;

        fwrite(Header,1,14,BMPOutput);

        BitmapInfoHeader[0].biSIZE[0] = 40;
        BitmapInfoHeader[0].biSIZE[1] = 0;
        BitmapInfoHeader[0].biSIZE[2] = 0;
        BitmapInfoHeader[0].biSIZE[3] = 0;

        BMPWidth = ImageWidth;
        BitmapInfoHeader[0].biWIDTH[0]= (unsigned char)(BMPWidth % 256);
        BMPWidth = BMPWidth >> 8;
        BitmapInfoHeader[0].biWIDTH[1]=(unsigned char)(BMPWidth % 256);
        BMPWidth = BMPWidth >> 8;
        BitmapInfoHeader[0].biWIDTH[2]=(unsigned char)(BMPWidth % 256);
        BMPWidth = BMPWidth >> 8;
        BitmapInfoHeader[0].biWIDTH[3]=(unsigned char)(BMPWidth % 256);

        BMPHeight = ImageHeight;
        BitmapInfoHeader[0].biHEIGHT[0]= (unsigned char)(BMPHeight % 256);
        BMPHeight = BMPHeight >> 8;
        BitmapInfoHeader[0].biHEIGHT[1]=(unsigned char)(BMPHeight % 256);
        BMPHeight = BMPHeight >> 8;
        BitmapInfoHeader[0].biHEIGHT[2]=(unsigned char)(BMPHeight % 256);
        BMPHeight = BMPHeight >> 8;
        BitmapInfoHeader[0].biHEIGHT[3]=(unsigned char)(BMPHeight % 256);

        BitmapInfoHeader[0].biPLANES[0] = 1;
        BitmapInfoHeader[0].biPLANES[1] = 0;

        BitmapInfoHeader[0].biBITCOUNT[0] = 8;
        BitmapInfoHeader[0].biBITCOUNT[1] = 0;

        BitmapInfoHeader[0].biCOMPRESSIOM[0] = 0;   // 沒有壓縮
        BitmapInfoHeader[0].biCOMPRESSIOM[1] = 0;
        BitmapInfoHeader[0].biCOMPRESSIOM[2] = 0;
        BitmapInfoHeader[0].biCOMPRESSIOM[3] = 0;

        BMPImageSize = ImageHeight*ImageWidth;
        BitmapInfoHeader[0].biSIZEIMAGE[0]= (unsigned char)(BMPImageSize % 256);
        BMPImageSize = BMPImageSize >> 8;
        BitmapInfoHeader[0].biSIZEIMAGE[1]=(unsigned char)(BMPImageSize % 256);
        BMPImageSize = BMPImageSize >> 8;
        BitmapInfoHeader[0].biSIZEIMAGE[2]=(unsigned char)(BMPImageSize % 256);
        BMPImageSize = BMPImageSize >> 8;
        BitmapInfoHeader[0].biSIZEIMAGE[3]=(unsigned char)(BMPImageSize % 256);

        BitmapInfoHeader[0].biXPELSPERMETER[0] = 18; // 72 dpi ,   (100 / 2.54)*72 = 2834
        BitmapInfoHeader[0].biXPELSPERMETER[1] = 11;
        BitmapInfoHeader[0].biXPELSPERMETER[2] = 0;
        BitmapInfoHeader[0].biXPELSPERMETER[3] = 0;

        BitmapInfoHeader[0].biYPELSPERMETER[0] = 18; // 72 dpi
        BitmapInfoHeader[0].biYPELSPERMETER[1] = 11;
        BitmapInfoHeader[0].biYPELSPERMETER[2] = 0;
        BitmapInfoHeader[0].biYPELSPERMETER[3] = 0;

        BitmapInfoHeader[0].biCOLORUSED[0] = 0;
        BitmapInfoHeader[0].biCOLORUSED[1] = 0;
        BitmapInfoHeader[0].biCOLORUSED[2] = 0;
        BitmapInfoHeader[0].biCOLORUSED[3] = 0;

        BitmapInfoHeader[0].biCOLORIMPORTANT[0] = 0;
        BitmapInfoHeader[0].biCOLORIMPORTANT[1] = 0;
        BitmapInfoHeader[0].biCOLORIMPORTANT[2] = 0;
        BitmapInfoHeader[0].biCOLORIMPORTANT[3] = 0;

        fwrite(BitmapInfoHeader,1,40,BMPOutput);

    // 設定灰階影像調色盤的值
        for (i=0;i<256;i++)
           {
           PaletteColors[i].BLUE = (unsigned char) i ;
           PaletteColors[i].GREEN = (unsigned char) i;
           PaletteColors[i].RED = (unsigned char) i;
           PaletteColors[i].RESERVED = (unsigned char) 0;
           }
        // 將調色盤寫入檔案中
        fwrite(PaletteColors,256,4,BMPOutput);

        // 將二維的影像資料轉成一維的資料, 方便輸出
        for (i=0;i<ImageHeight;i++)
           for (j=0;j<ImageWidth;j++)
                BMPImage[i*BMPImageWigth4+j] = ImageMatrix[ImageHeight-i-1][j];

        fwrite(BMPImage,1,ImageHeight*BMPImageWigth4,BMPOutput);
        FILEEND[0] = 0;
        FILEEND[1] = 0;
        fwrite(FILEEND,2,1,BMPOutput);

        fclose(BMPOutput);

__________________________________________________________________________________

  Last Modification : 02/22/2004 
  by Yeuan-Kuen Lee, CSIE, MCU