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? 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). Commented Aug 23, 2016 at 23:58
  • what would happen if instead of variable count is set on 2 not 1 ? 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. 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.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.