2

I'm currently working on the cs50 pset4. My question is pretty straight forward: How does the line (marked with caps lock comment) "RGBTRIPLE triple;" knows whicht pixel currently to store? I get the concept of the nested loops but I don't see the connection between the loops and the line of code "RGBTRIPLE triple;". Additionally the line after that, the fread() function, asks for the address "&triple" at the beginning. So where does the function gets the information about &triple? I understand that the programm goes over every pixel in the bmp file with these nested loops. Let's say we start the program and it arrives at the loops. So far so good. The program needs to start at the beginning (obviously) but again, where is the information about the starting point? Is it the loops, which all are at 0? Am I thinking too complicated?

Short summary:

  • How does "RGBTRIPLE triple;" work? (With that I mean how does it know what pixels information to save)
  • How does "&triple" gets the required information?
  • Where is the connection between the loops and the current pixel to store/read?

Thanks in advance for your reply! :)

    #include <stdlib.h>
    #include <stdio.h>



    #include "bmp.h"

    int main(int argc, char* argv[])
    {
        // ensure proper usage
        if (argc != 3)
        {
            printf("Usage: ./copy infile outfile\n");
            return 1;
        }


    // remember filenames
    char* infile = argv[1];
    char* outfile = argv[2];

    // open input file 
    FILE* inptr = fopen(infile, "r");
    if (inptr == NULL)
    {
        printf("Could not open %s.\n", infile);
        return 2;
    }

    // open output file
    FILE* outptr = fopen(outfile, "w");
    if (outptr == NULL)
    {
        fclose(inptr);
        fprintf(stderr, "Could not create %s.\n", outfile);
        return 3;
    }

    // read infile's BITMAPFILEHEADER
    BITMAPFILEHEADER bf;
    fread(&bf, sizeof(BITMAPFILEHEADER), 1, inptr);

    // read infile's BITMAPINFOHEADER
    BITMAPINFOHEADER bi;
    fread(&bi, sizeof(BITMAPINFOHEADER), 1, inptr);

    // ensure infile is (likely) a 24-bit uncompressed BMP 4.0
    if (bf.bfType != 0x4d42 || bf.bfOffBits != 54 || bi.biSize != 40 || 
        bi.biBitCount != 24 || bi.biCompression != 0)
    {
        fclose(outptr);
        fclose(inptr);
        fprintf(stderr, "Unsupported file format.\n");
        return 4;
    }

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

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

    // 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;                     //HOW DOES THIS LINE KNOW?

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

    // close infile
    fclose(inptr);

    // close outfile
    fclose(outptr);

    // that's all folks
    return 0;
}

------bmp.h below...------

/**
 * bmp.h
 *
 * Computer Science 50
 * Problem Set 4
 *
 * BMP-related data types based on Microsoft's own.
 */

#include <stdint.h>

/**
 * Common Data Types 
 *
 * The data types in this section are essentially aliases for C/C++ 
 * primitive data types.
 *
 * Adapted from http://msdn.microsoft.com/en-us/library/cc230309.aspx.
 * See http://en.wikipedia.org/wiki/Stdint.h for more on stdint.h.
 */
typedef uint8_t  BYTE;
typedef uint32_t DWORD;
typedef int32_t  LONG;
typedef uint16_t WORD;

/**
 * BITMAPFILEHEADER
 *
 * The BITMAPFILEHEADER structure contains information about the type, size,
 * and layout of a file that contains a DIB [device-independent bitmap].
 *
 * Adapted from http://msdn.microsoft.com/en-us/library/dd183374(VS.85).aspx.
 */
typedef struct 
{ 
    WORD   bfType; 
    DWORD  bfSize; 
    WORD   bfReserved1; 
    WORD   bfReserved2; 
    DWORD  bfOffBits; 
} __attribute__((__packed__)) 
BITMAPFILEHEADER; 

/**
 * BITMAPINFOHEADER
 *
 * The BITMAPINFOHEADER structure contains information about the 
 * dimensions and color format of a DIB [device-independent bitmap].
 *
 * Adapted from http://msdn.microsoft.com/en-us/library/dd183376(VS.85).aspx.
 */
typedef struct
{
    DWORD  biSize; 
    LONG   biWidth; 
    LONG   biHeight; 
    WORD   biPlanes; 
    WORD   biBitCount; 
    DWORD  biCompression; 
    DWORD  biSizeImage; 
    LONG   biXPelsPerMeter; 
    LONG   biYPelsPerMeter; 
    DWORD  biClrUsed; 
    DWORD  biClrImportant; 
} __attribute__((__packed__))
BITMAPINFOHEADER; 

/**
 * RGBTRIPLE
 *
 * This structure describes a color consisting of relative intensities of
 * red, green, and blue.
 *
 * Adapted from http://msdn.microsoft.com/en-us/library/aa922590.aspx.
 */
typedef struct
{
    BYTE  rgbtBlue;
    BYTE  rgbtGreen;
    BYTE  rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;
1
  • I didn't get how is the pixel varying in the inner for loop. Because SEEK_CUR is outside of the inner loop. Commented Mar 3, 2017 at 16:03

1 Answer 1

10

You have mixed them a little in your head but we are here. :)

Firstly, the line

RGBTRIPLE triple;

doesn't get a pixel, it just declares a variable, of type RGBTRIPLE with the name triple. It would be the same as

int count;

nothing less, nothing more.

All the information, is passed to triple, through fread().

fread() takes 4 arguments:

  1. buffer - pointer to the array where the read objects are stored
    In our case it's the pointer of triple (hence &triple)
  2. size - size of each object in bytes
    In our case it's the sizeof(RGBTRIPLE)
  3. count - the number of the objects to be read
    In our case it's 1 because we read one pixel at a time
  4. stream - the stream to read
    In our case it's the stream of the file we have opened.

When you open the input file, you get a pointer at the beginning of the file stream, and with each fread() on that stream, the pointer moves SEEK_CUR at the next part of the stream that you are going to read. So every time you call fread(), you store a new pixel in triple, and SEEK_CUR moves to the next pixel.

Just to clarify, the first fread()s you use, don't read pixels, but the headers of the file, which come first, and then the pixels follow.

If you need more explanation leave a comment bellow. Happy coding! :)

6
  • Thank you very much for your fast reply Chris! :) So can you go into a little bit more detail? For example, when does the pointer gets set? After I opened the file with "fopen()" or after my first use of the function "fread()"? And on which byte does it gets set? on the 1st or on the 0th? Or is it just set before the bytes and waits until further action?
    – C4zZ
    Commented Aug 23, 2016 at 19:47
  • Imagine the file stream as an array. When you open the file you are at the 0th index. The first time you will read something, that something will start from the 0th byte in that file. You can change the index using fseek(), telling it to move at the beginning of the file (SEEK_SET) in relation to where you are now (SEEK_CUR) or at the end of the file (SEEK_END).
    – ChrisG
    Commented Aug 23, 2016 at 23:58
  • what would happen if instead of variable count is set on 2 not 1 ?
    – koko loko
    Commented Feb 9, 2018 at 5:44
  • Then fread() would read the equivalent of 2*sizeof(RGBTRIPLE) amount from the file.In any case fread() reads size*count Bytes from stream, and puts it into buffer.
    – ChrisG
    Commented Feb 10, 2018 at 11:55
  • is that mean that nesting loops are useless ? because in the way you explained we are not gonna do anything with nesting loops and fread() and fseek() are sufficient. Commented Jan 25, 2019 at 15:51

You must log in to answer this question.

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