这个代码从图像RGB bmp纯C - Windows操作系统写入灰度bmp有什么问题

时间:2015-08-06 00:20:08

标签: c bmp grayscale

这是我的功能,我根据维基百科BITMAPINFOHEADER使用标题BMP。但是,我收到一个没有任何图像的文件...当填充填充时,进程停止。

 // 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;

}

在灰色输出文件中,我什么都没得到......而且,我想知道是否有办法将24位减少到8位。

PS。我的代码来自reading/writing bmp files in c

该公式来自Create greyscale BMP from RGB BMP

谢谢,

1 个答案:

答案 0 :(得分:0)

您实际上是将32位彩色位图转换为32位灰色位图,方法是将颜色值更改为灰色(您不会以这种方式保存任何空间;位图保持与它一样大是)。 Anayway,它解释了为什么你不需要调整位图头。

但是当你读取每三个字节并且每三个字节改变一次时,你就不会考虑扫描线。

图像由扫描线和像素的扫描线组成。扫描线在偶数字边界上对齐,因此扫描线的最后几个字节未被使用(因此扫描线比其上的所有像素长一些)。

要正确处理输入并创建输出,您的循环必须是:

(编辑:更新为每像素输出使用1个字节):

#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);
}