#include <stdio.h>

#include <stdlib.h>

#include <GL/glut.h>

#include <GL/gl.h>

#include <GL/glu.h>

#include <time.h>

#include <memory.h>

 

#define Width  512

#define Height 512

 

unsigned char                *ipix;

int h, w;

unsigned char **bmp;

 

const size_t BYTES_PER_PIX = 3;

const size_t HEADER_SIZE = 54;

 

// 處理byte order

inline char* PutWord(char* buf, unsigned w)

{

    buf[0] = w;

    buf[1] = w >> 8;

    buf[2] = w >> 16;

    buf[3] = w >> 24;

    return buf + 4;

}

// 假設data每個資料都是一個pixel且使用windowsRGB()編碼

void WriteBMP(const char* fileName, const unsigned* data, size_t width, size_t height)

{

    size_t rowSize = width * BYTES_PER_PIX;

    size_t pad = (4 - (rowSize & 0x03)) & 0x03;

    size_t dataSize = (rowSize + pad) * height;

   

    char header[HEADER_SIZE] = "BM";

    char* ph = header + 2;

    ph = PutWord(ph, dataSize + HEADER_SIZE);

    ph = PutWord(ph, 0);

    ph = PutWord(ph, HEADER_SIZE);

    ph = PutWord(ph, 40);

    ph = PutWord(ph, width);

    ph = PutWord(ph, height);

    *ph++ = 1;

    *ph++ = 0;

    *ph++ = BYTES_PER_PIX * 8;

    *ph++ = 0;

    ph = PutWord(ph, 0);

    ph = PutWord(ph, dataSize);

    ph = PutWord(ph, 0);

    ph = PutWord(ph, 0);

    ph = PutWord(ph, 0);

    ph = PutWord(ph, 0);

 

    FILE* fout = fopen(fileName, "wb");

    char* rowData = (char*) malloc(rowSize + pad);

    size_t i, j, k = 0;

   

    fwrite(header, 1, HEADER_SIZE, fout);

    memset(rowData, 0, rowSize + pad);

   

    for (j = 0; j < height; ++j) {

        for (i = 0; i < width; ++i) {

            char r = data[k];

            char g = data[k] >> 8;

            char b = data[k] >> 16;

            rowData[i*3] = b;

            rowData[i*3+1] = g;

            rowData[i*3+2] = r;

            ++k;

        }

        fwrite(rowData, 1, rowSize + pad, fout);

    }

    free(rowData);

    fclose(fout);

}

int read_bmp(char *filename, unsigned char ***bmp, int *height, int *width)

{   

printf("\n#################### read_bmp ####################\n");

 long *hed;

 int i, j, k, w;

 unsigned char head[1079], l, mod, *tmp_buf;

FILE *f;

 hed = (long *) &head[2];

  f = fopen(filename, "rb");

if ((f = fopen(filename, "rb"))  == NULL) 

  return 1;

 

 

 if (fread(head, 1, 54, f) != 54)

  return 2;

 if (head[0] != 'B' || head[1] != 'M')          // BMP head

  return 3;

 

 fseek(f, 0, SEEK_END);

 if (ftell(f) - hed[0])

  return 4;        // file size != internal record

 mod = head[28];                // bit / pixel

if (mod != 1 && mod != 8)

  return 5;               // 不是黑白或灰階

 

 if (head[30])

  return 6;               // 不會讀壓縮的BMP 

  *width  = hed[4],    *height = hed[5];

  printf("hed[4] = %d hed[5] = %d\n",hed[4],hed[5]);

 if ((tmp_buf = (unsigned char *) malloc(hed[8])) == NULL)

  return 7;               // Not enough Memory

 

 if ( !(*bmp  = (unsigned char **)malloc(*height *sizeof(**bmp))))

  return 8;               // Not enough Memory

 

 if ( (**bmp = (unsigned char *) malloc(*width * *height + 7))  == NULL)

  return 9;               // Not enough Memory

  printf("************************* hed[8] = %d\n",hed[8]); 

 fseek(f, hed[2], SEEK_SET);          // to bmp data start

 if (fread(tmp_buf, 1, (size_t)hed[8]-1, f) != hed[8]-1)   // read error?

  return 10;              // 讀檔有問題

 

 for (w=i=0; i<*height; i++, w+=*width)   // Calculate index for speedup

  (*bmp)[i] = &(**bmp)[w];

 if (mod == 1) {

  w = (int) ( ((*width-1) >> 5) +1 ) << 2;

  for (i=(int)(*height-1); i>=0; i--) {

   for (j=0; j<*width-7; j+=8) {

    l = tmp_buf[i*w + (j>>3)];

    for (k=0; k<8; k++) {

     (**bmp)[(*height-i-1)**width + j + k] = l & 128 ? 0 : 255;

     l <<= 1;

    }

   }

   l = tmp_buf[i*w + (j>>3)];

   for (k=0; k<(*width&7); k++) {

    (**bmp)[(*height-i-1)**width + j + k] = l & 128 ? 0 : 255;

    l <<= 1;

   }

  }

 }

 else if (mod == 8)

 {

  w = (int) (((*width-1)>>2) +1) << 2;

  for (i=(int)(*height-1); i>=0; i--)

  {

   k = *height - i -1;

   for (j=0; j<*width; j++)

    (*bmp)[k][j] = tmp_buf[i*w + j];

  }

 }

 free(tmp_buf);

 if (fclose(f))     return 11; // 不能閉檔

 return 0;                     // 成功

}

 

void OnKey(unsigned char key, int x, int y)

{

        switch(key) {

        case 27:

                glutDestroyWindow( glutGetWindow() );

                free(*bmp);

        free(bmp);   

                exit(0);

                break;

        }

        glutPostRedisplay(); //令視窗重繪

}

 

void display()

{

  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

  glRasterPos2i( -1, -1 );

  glDrawPixels(w, h, GL_LUMINANCE, GL_UNSIGNED_BYTE, *bmp);

  glutSwapBuffers(); //glutSwapBuffers內含glFlush

}

 

 void bmpUpsideDown()

{

  // BMP倒立

   for (int i=h/2; --i>=0; ) {

     int y = h -1 -i;

     for (int j=w; --j>=0; ) {

     char c=bmp[i][j]; bmp[i][j] = bmp[y][j]; bmp[y][j] = c;

    }

  }

}

 

// main

int main(int argc, char **argv)

{

clock_t start, end;

int i, j;

char filename1[] = "Lena512.bmp";

i=read_bmp(filename1, &bmp, &h, &w);

 

if (i == 0)

{

bmpUpsideDown();

char filename2[] = "b.bmp";

WriteBMP(filename2, &bmp, &h, &w);

 

 glutInit(&argc, argv);

 glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA);

 glutInitWindowSize(w, h);

 glutInitWindowPosition (100, 100);

 glutCreateWindow("Hello");

 

 glClearColor (0.0, 0.0, 0.0, 0.0);

 glShadeModel(GL_FLAT);

 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

 glutKeyboardFunc(OnKey);

 glutDisplayFunc(display);

 glutMainLoop();

}

return 0;

}