-1

This is my function, I am using the headers BMP according to wikipedia BITMAPINFOHEADER. But, I am getting a file without any image...when putting padding, the process stops.

 // Structures for header info
 #pragma pack(push,1)
 /* Windows 3.x bitmap file header */
 typedef struct {
      char         filetype[2];   /* magic - always 'B' 'M' */
      unsigned int filesize;
      short        reserved1;
      short        reserved2;
      unsigned int dataoffset;    /* offset in bytes to actual bitmap data */
  } file_header;

  /* Windows 3.x bitmap full header, including file header */
 typedef struct {
      file_header  fileheader;
      unsigned int headersize;
      int          width;
      int          height;
      short        planes;
      short        bitsperpixel;  /* we only support the value 24 here */
      unsigned int compression;   /* we do not support compression */
      unsigned int bitmapsize;
      int          horizontalres;
      int          verticalres;
      unsigned int numcolors;
      unsigned int importantcolors;
  } bitmap_header;
  #pragma pack(pop)


int RGB2GREY(char* input, char *greyImage) {

  //variable declaration:
  FILE *fp, *grey;
  bitmap_header* hp;
  int n;
  char *data;
  int oldBitsperpixel;

  //Open input file:
  fp = fopen(input, "rb");
  if(fp==NULL){
     //cleanup
  }

  //Read the input file headers:
  hp=(bitmap_header*)malloc(sizeof(bitmap_header));
  if(hp==NULL)
      return 3;

  n=fread(hp, sizeof(bitmap_header), 1, fp);
  if(n<1){
     //cleanup
  }

  //Read the data of the image:
  data = (char*)malloc(sizeof(char)*hp->bitmapsize);
  if(data==NULL){
      //cleanup
  }
  //Put me in the position after header...
  fseek(fp,sizeof(char)*hp->fileheader.dataoffset,SEEK_SET);
  printf("Width %d and Height %d\n",hp->width,hp->height);

  int i, j;
  unsigned char BGR[3];
  unsigned colorIntensity[3];
  /*unsigned char bmppad[hp->width] = {0};*/

  printf("New bitmapSize %d\n\n",hp->bitsperpixel);

  //Open greayImage file:
  grey = fopen(greyImage, "wb");
  if(grey==NULL){
    //cleanup
  }
  //Writes the header
  n=fwrite(hp,sizeof(char),sizeof(bitmap_header),grey);
  if(n<1){
      //cleanup
  }
  //Again going to position after header
  fseek(out,sizeof(char)*hp->fileheader.dataoffset,SEEK_SET);
  for (i=0; i<hp->height; i++){
    for (j=0; j<hp->width; j++){
        //Reading pixel by pixel  
        fread(BGR, 3, 1, fp); //1 unsigned char of 3 positions
        unsigned char colorGrey;
        colorGrey = (unsigned char) 0.3*BGR[2] + 0.6*BGR[1]  + 0.1*BGR[0];
        colorIntensity[2] = colorGrey;
        colorIntensity[1] = colorGrey;
        colorIntensity[0] = colorGrey;
        /*printf("B %d G %d R %d ",BGR[0],BGR[1],BGR[2]);
        printf("Gray %d ",colorIntensity);*/
        fwrite(colorIntensity, 3, 1, grey);
    }
    /*
    // Adding pad option1 
    //fwrite(bmppad, sizeof(bmppad), 1, grey); 
    //Adding pad option2
    for (j=0; j>hp->width; j++){
        fwrite(0, 1, 1, grey);
    }*/
}
fclose(fp);
fclose(grey);
free(hp);
free(data);
return 0;

}

In the grey output file, I get nothing...moreover, I wonder if there is a way to reduce from 24 to 8 bits.

ps. My code came from reading/writing bmp files in c

The formula came from Create greyscale BMP from RGB BMP

Thanks,

Community
  • 1
  • 1
Jotasmall
  • 41
  • 8
  • 1
    Common BMP problem: `bitmap_header` likely needs to be `packed`. Post your definition of it and also post your system's size of that data structure. (Used in `write(hp,sizeof(char),sizeof(bitmap_header),grey);`) – chux - Reinstate Monica Aug 06 '15 at 03:31
  • It is not a BMP header problem, I am wasting a lot of memory to get the same bmp file only changing all three channels into the same value of gray...just as mentioned by Paul...I know I will need to change the palette of colors, but one step by time. – Jotasmall Aug 06 '15 at 09:18
  • Note: File formats like `.bmp` call for exact width integers. Good that code used packed structures, yet instead of `short,int,` code really should be using `int16_t, int32_t`. – chux - Reinstate Monica Aug 06 '15 at 21:56

1 Answers1

1

You are essentially turning a 32-bit color bitmap into a 32-bit grey bitmap by changing the color values in a way that they appear grey (you are not saving any space in this way; the bitmap stays as large as it was). Anayway, it explains why you do not need to adapt the bitmap header.

But when you read every three bytes and change every three bytes, you do not take scanlines into account.

An image consists of scanlines and a scanline consits of pixels. Scanlines are alligned on even word boundaries so the last few bytes of a scanline are unused (and the scanline is thus a bit longer than all the pixels on it).

To properly process the input and create the output, your loop must be:

(EDIT: updated to use 1 byte per pixel output):

#pragma pack(push,1)
typedef struct {
    unsigned char rgbBlue;
    unsigned char rgbGreen;
    unsigned char rgbRed;
    unsigned char rgbReserved;
} pal_entry;    
#pragma pack(pop)

int ToGreyScale(FILE *fp, FILE *grey, bitmap_header *hp)
{
    int i, j;
    int iScanlineSizeIn = ((hp->width * hp->bitsperpixel) + 31) / 32 * 4;
    int iScanlineSizeOut= ((hp->width *        8        ) + 31) / 32 * 4;
    unsigned char *scanlineIn = malloc(iScanlineSizeIn), *pIn;
    unsigned char *scanlineOut= malloc(iScanlineSizeOut), *pOut;
    pal_entry pal[256];

    for (i=0; i<256; i++)   // create a gray scale palette
        {pal[i].rgbBlue= i; pal[i].rgbGreen= i; pal[i].rgbRed= i;}

    hp->bitsperpixel= 8;    // set output bits-per-pixel
    hp->fileheader.filesize= sizeof(bitmap_header) + sizeof(pal) + hp->width*iScanlineSizeOut;

    fwrite(hp, sizeof(bitmap_header), 1, grey);     // write the header...
    fwrite(pal, 256*sizeof(pal_entry), 1, grey);    //..followed by palette

    for (i=0; i<hp->height; i++)
    {
        if (fread(scanlineIn, iScanlineSizeIn, 1, fp) != 1) return(0);
        pIn = scanlineIn;
        pOut= scanlineOut;
        for (j=0; j<hp->width; j++)
        {
            *pOut++ = (unsigned char) ((0.1 * *pIn++) + (0.6 * *pIn++) + (0.3 * *pIn++));
        }
        fwrite(scanlineOut, iScanlineSizeOut, 1, grey);
    }
    free(scanlineIn);
    free(scanlineOut);
    return(1);
}   
Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41
  • Hi Paul, thanks, I did the editions on my code and it worked. So, is the problem caused by paddings bytes? – Jotasmall Aug 06 '15 at 09:39
  • Paul, could you help me to know how may I change the variable palette into a 256 grayscale into the header in order to get a lower size image? – Jotasmall Aug 06 '15 at 09:42
  • I updated the solution to use 1 byte per pixel output. Couldn't check if it will work. – Paul Ogilvie Aug 06 '15 at 11:13
  • This time it produce no output readable :/ but I open the picture in a virtual linux machine and the file contains 3 gray prictures divided by a green line... – Jotasmall Aug 06 '15 at 12:26
  • Yes, I did some research and as soon as bits-per-pixel is less than 32, it expects a palette. I updated the solution, could you check it? – Paul Ogilvie Aug 06 '15 at 13:01
  • Hi Paul, it prints something similar, with a big black space up and three pictures in grey scale in the third last part of the picture.... – Jotasmall Aug 06 '15 at 13:12
  • The code as currently published works. I tested it. There was a minor update, namely to set the filesize in the file header. – Paul Ogilvie Aug 06 '15 at 13:27
  • Thanks Paul, I appreciate your help! – Jotasmall Aug 07 '15 at 00:20