What is wrong with this code for writing grey-scale bmp from an image RGB bmp pure C - Windows OS

匆匆过客 提交于 2019-12-02 22:49:28

问题


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,


回答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);
}   


来源:https://stackoverflow.com/questions/31844871/what-is-wrong-with-this-code-for-writing-grey-scale-bmp-from-an-image-rgb-bmp-pu

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!