简体   繁体   中英

creating a bitmap image from existing bitmap, in C

I am writing a C program, which will retrieve the information (header information, pixel information) from a bitmap image, and use that information to create another bitmap image (the new image will obviously be same as the original).

The problem is that, in some cases, extra bytes get added (on their own) to the new image, due to which the image is not formed properly.
In another case, some bytes get missing in the new image, due to which image formation itself fails. (This happens while writing the pixel information. the bitmap header information gets written properly to the new file.)
I have debugged the code but I couldn't find out what is causing this. I'll be glad if somebody could tell me what the error is.

//creating a bitmap file
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<math.h>

long extract(FILE *,long ,int );

long extract(FILE *fp1,long offset,int size)
{
        unsigned char *ptr;
    unsigned char temp='0';
    long value=0L;
    int i;

    //to initialize the ptr
    ptr=&temp;

    //sets the file pointer at specific position i.e. after the offset
    fseek(fp1,offset,SEEK_SET);

    //now fgetcing (size) values starting from the offset
    for(i=1;i<=size;i++)
    {
        fread(ptr,sizeof(char),1,fp1);
        value=(long)(value+(*ptr)*(pow(256,(i-1))));   //combining the values   one after another in a single variable
    }

    return value;
}

int main()
{
    int row,col;
    int i,j,k;
    int dataoffset,offset;
    char magicnum[2];
    FILE *fp1,*fp4;
    clrscr();

    if((fp1=fopen("stripes.bmp","rb"))==NULL)
    {
        printf("\a\nCant open the image.\nSystem is exiting.");
        exit(0);
    }

    if((fp4=fopen("op.bmp","a"))==NULL)
    {
        printf("\n\aError while creating a file.\nSystem is exiting ..... ");
        exit(0);
    }

    fputc((int)extract(fp1,0L,1),fp4);
    fputc((int)extract(fp1,1L,1),fp4);
    fputc((int)extract(fp1,2L,1),fp4);
    fputc((int)extract(fp1,3L,1),fp4);
    fputc((int)extract(fp1,4L,1),fp4);
    fputc((int)extract(fp1,5L,1),fp4);
    fputc((int)extract(fp1,6L,1),fp4);
    fputc((int)extract(fp1,7L,1),fp4);
    fputc((int)extract(fp1,8L,1),fp4);
    fputc((int)extract(fp1,9L,1),fp4);
    fputc((int)extract(fp1,10L,1),fp4);
    fputc((int)extract(fp1,11L,1),fp4);
    fputc((int)extract(fp1,12L,1),fp4);
    fputc((int)extract(fp1,13L,1),fp4);
    fputc((int)extract(fp1,14L,1),fp4);
    fputc((int)extract(fp1,15L,1),fp4);
    fputc((int)extract(fp1,16L,1),fp4);
    fputc((int)extract(fp1,17L,1),fp4);
    fputc((int)extract(fp1,18L,1),fp4);
    fputc((int)extract(fp1,19L,1),fp4);
    fputc((int)extract(fp1,20L,1),fp4);
    fputc((int)extract(fp1,21L,1),fp4);
    fputc((int)extract(fp1,22L,1),fp4);
    fputc((int)extract(fp1,23L,1),fp4);
    fputc((int)extract(fp1,24L,1),fp4);
    fputc((int)extract(fp1,25L,1),fp4);
    fputc((int)extract(fp1,26L,1),fp4);
    fputc((int)extract(fp1,27L,1),fp4);
    fputc((int)extract(fp1,28L,1),fp4);
    fputc((int)extract(fp1,29L,1),fp4);
    fputc((int)extract(fp1,30L,1),fp4);
    fputc((int)extract(fp1,31L,1),fp4);
    fputc((int)extract(fp1,32L,1),fp4);
    fputc((int)extract(fp1,33L,1),fp4);
    fputc((int)extract(fp1,34L,1),fp4);
    fputc((int)extract(fp1,35L,1),fp4);
    fputc((int)extract(fp1,36L,1),fp4);
    fputc((int)extract(fp1,37L,1),fp4);
    fputc((int)extract(fp1,38L,1),fp4);
    fputc((int)extract(fp1,39L,1),fp4);
    fputc((int)extract(fp1,40L,1),fp4);
    fputc((int)extract(fp1,41L,1),fp4);
    fputc((int)extract(fp1,42L,1),fp4);
    fputc((int)extract(fp1,43L,1),fp4);
    fputc((int)extract(fp1,44L,1),fp4);
    fputc((int)extract(fp1,45L,1),fp4);
    fputc((int)extract(fp1,46L,1),fp4);
    fputc((int)extract(fp1,47L,1),fp4);
    fputc((int)extract(fp1,48L,1),fp4);
    fputc((int)extract(fp1,49L,1),fp4);
    fputc((int)extract(fp1,50L,1),fp4);
    fputc((int)extract(fp1,51L,1),fp4);
    fputc((int)extract(fp1,52L,1),fp4);
    fputc((int)extract(fp1,53L,1),fp4);

    //setting the file pointer at the beginning
    rewind(fp1);

/*CHECKING WHETHER THE FILE IS IN BMP FORMAT OR NOT, WE CHECK THE MAGIC NUMBER OF THE FILE, MAGIC NUMBER'S OFFSET IS 0 i.e. IT'S STORED AT THE FRONT OF THE IMAGE, AND THE SIZE IS 2*/

    //at first extracting the magic number
    for(i=0;i<2;i++)
    {
        magicnum[i]=(char)extract(fp1,i,1);
    }

    //now checking
    if((magicnum[0]=='B') && (magicnum[1]=='M'))
        ;
    else
    {
        printf("\aThe image is not a bitmap image.\nSystem is exiting ... ");
        exit(0);
    }

    //storing the header information

    //get the starting position or offset of the data(pixel)

    dataoffset=(int)extract(fp1,10,4);

    //get the number of rows
    row=(int)extract(fp1,22,4);

    //get the number of columns
    col=(int)extract(fp1,18,4);

        //storing the data
    offset=dataoffset;
    for(j=0;j<col;j++)
    {
        for(k=0;k<row;k++)
        {
            for(i=0;i<=2;i++)
            {
                fputc((int)extract(fp1,offset++,1),fp4);
            }
        }
    }


    fcloseall();
    return 0;
}

Make sure you open the output file in binary mode as well.

If you don't do that, the byte value corresponding to '\\n' may be expanded to carriage return and line feed.

Consider this line:

value=(long)(value+(*ptr)*(pow(256,(i-1))));

pow is a floating point function returning a double. This means that (*ptr) is implicitly casted to double. The whole expression (value+(*ptr)*(pow(256,(i-1)))) will be a double. Now this can be larger than 2147483647 which is the largest number a long can hold (on most common 32-bit platforms), and the result when converting an out of range double to long is undefined. See what happens on this example:

#include <stdio.h>

int main(int argc, char **argv) {
  int i;

  for (i = 0; i < 10; i++) {
    double d = 2147483647.0d + i;
    printf("double=%f long=%ld\n", d, (long)d);
  }
  return 0;
}

Here is the output when I run it on my system: (hidden in case you want to guess or test it yourself first):

double=2147483647.000000 long=2147483647
double=2147483648.000000 long=-2147483648
double=2147483649.000000 long=-2147483648
double=2147483650.000000 long=-2147483648
double=2147483651.000000 long=-2147483648
double=2147483652.000000 long=-2147483648
double=2147483653.000000 long=-2147483648
double=2147483654.000000 long=-2147483648
double=2147483655.000000 long=-2147483648
double=2147483656.000000 long=-2147483648

One way to fix it would be to change it to unsigned long instead.

Personally I'd use 1 << (8*(i-1)) instead of pow to avoid messing with floating point, but there is lots of other things that I'd do very different too, but that is probably out of scope for this question (might be a question for the code review site).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM