1

what is the purpose of even using Fseek() in pset 4 anyhow? I must be missing something

Say we're looking at the original copy.c function.

Basically, this is what I understand what's happening:

What I understand so far:

CONCEPTS

  1. A bitmap file (.bmp file). A .png is just a compressed version of a bmp that is also lossless. https://i.sstatic.net/od4E4.png
  2. This .bmp file has 54 bytes allocated in the bitmapheader. 14 bytes towards bitmapfileheader BF + 40 bytes for bitmapinfoheader BI.
  3. We can see these values in bmp.h . https://i.sstatic.net/gk4Yy.png. Each of those items, bfType, biSize, etc have different byte sizes allocated to them (DWORD, LONG) etc. Wikipedia has a table for these values https://i.sstatic.net/OkAUJ.png
  4. We're using a typedef and struct

BITMAPDATA

  1. We can see the bitmap header data using XXD. https://i.sstatic.net/4jbJV.png.
  2. The left most value is the address of the SCANLINE in hex, which corresponds to decimal values of 0 to 50 depending on whether the variable (such as biWidth) is 2 or 4 bytes (defined by DWORD, LONG, etc in bmp.h) and its offset starting point
  3. The top highlighted area is the header file (some of it is pixel files)

COLOR AND HEX

  1. Computer pixels on the screen are represented by RGB values, but bitmap represents them backwards as BGR
  2. https://i.sstatic.net/oi1Xr.png. Colors are represented as #BGR, or by 2 hex values. Denoting those values in this Copy.c program is through 0x000000, or 0x00 for B for instance
  3. White is #FFFFFF because it takes blue, green ,and red values to make white on a computer screen





STUFF IN COPY.C

FILE* outptr = fopen(outfile, "w");

// write outfile's BITMAPFILEHEADER
fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr);

// write outfile's BITMAPINFOHEADER
fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr);

We're keeping the output file open so we can add stuff into it and close the file later, its similar to open a word doc, adding stuff, and saving/closing. This is through FILE* outptr which is using the argv[2] we put in originally

STUFF IN COPY.C

// determine padding for scanlines int padding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;

// iterate over infile's scanlines
for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)
{
    // iterate over pixels in scanline
    for (int j = 0; j < bi.biWidth; j++)
    {
        // temporary storage
        RGBTRIPLE triple;

        // read RGB triple from infile
        fread(&triple, sizeof(RGBTRIPLE), 1, inptr);

        // write RGB triple to outfile
        fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
    }

    // skip over padding, if any
    fseek(inptr, padding, SEEK_CUR);

    // then add it back (to demonstrate how)
    for (int k = 0; k < padding; k++)
    {
        fputc(0x00, outptr);
    }
}

this is the area that I don't really grasp all the way.

  1. We create a value called padding. This value always ends up being 0,1,2,3 based on its formula, because the scanline needs to be a multiple of 4, due to optimization of CPU usage /architecture defined by intel historically
  2. FORLOOP1 iterating through each row(scanline)
  3. FORLOOP2 iterating through each column within that row
  4. Within FORLOOP1, we are reading BGR values (0x00, 0xFF, etc)
  5. Within FORLOOP1, we look at the padding that might exist in the .bmp file
  6. Within FORLOOP1, we have another forloop designated for outputting padding. Because we're copying the file

I don't get what happens in 5 and 6 that well

I understand that all bmp files need to have a pixel width of a multiple of 4, and there might be padding in that file already. We calculated the amount of padding needed originally. We can count which things have BGR values through RGBtriple, and the rest is padding





TL;DR

Why do we need Fseek() at all?

Couldn't we just go straight to fputc, output the padding, and then go straight to the next scanline?

What am I missing here?

1 Answer 1

3

First the padding. Keep in mind that the input file and the output file may or may not require the same amount of padding. In item 5, you don't examine the padding in the input file, you skip over it to the beginning of the next line. In item 6, you're adding the appropriate amount of padding to the output file. It uses a loop instead of 4 if statements to determine how much padding. It's that simple.

Now for the fseek issue. If you're just copying the file, this does nothing. But if you are scaling the file up, it's another story. It also depends on your approach. Some people create a copy of each line in memory and then print it out n times. While this works, it could be problematic with a massively large bitmap file, or a massively large scale factor of n. It's theoretically possible to run out of memory.

Most people process the image data directly. That means scaling horizontally by outputting each pixel n times and then add the output file padding. But here's the significant part. Enlarging a 2-dimensional image is always a linear, 1-dimensional process. To scale vertically, you have to duplicate the entire row over again so that you have n rows. You can't simply scale each pixel vertically. Rather than saving each row in an array, as discussed above, the program can use fseek to go back to the beginning of the row in the input file to reprocess that row until you have enough copies. THAT's what fseek is for.

If this answers your question, please click on the check mark to accept. Let's keep up on forum maintenance. ;-)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .