The first of these headers, called BITMAPFILEHEADER, is 14 bytes long. (Recall that 1 byte equals 8 bits.)
The second of these headers, called BITMAPINFOHEADER, is 40 bytes long.
Immediately following these headers is the actual bitmap: an array of bytes, triples of which represent a pixel’s color.
However, BMP stores these triples backwards (i.e., as BGR), with 8 bits for blue, followed by 8 bits for green, followed by 8 bits for red.
(Some BMPs also store the entire bitmap backwards, with an image’s top row at the end of the BMP file. But we’ve stored this problem set’s BMPs as described herein, with each bitmap’s top row first and bottom row last.)
Okay, CS50 IDE only showed you the bytes in these BMPs. How do we actually get at them programmatically? Well, in copy.c is a program whose sole purpose in life is to create a copy of a BMP. Of course, you could just use cp for that. But cp isn’t going to help Mr. Boddy. Let’s hope that copy.c does!
Go ahead and compile copy.c into a program called copy using make. (Remember how?) Then execute a command like the below.
./copy smiley.bmp copy.bmp
If you then execute ls (with the appropriate switch), you should see that smiley.bmp and copy.bmp are indeed the same size. Let’s double-check that they’re actually the same! Execute the below.
diff smiley.bmp copy.bmp
So how now did that copy get made? It turns out that copy.c relies on bmp.h. Let’s take a look. Open up bmp.h, and you’ll see actual definitions of those headers we’ve mentioned, adapted from Microsoft’s own implementations thereof. In addition, that file defines BYTE, DWORD, LONG, and WORD, data types normally found in the world of Windows programming. Notice how they’re just aliases for primitives with which you are (hopefully) already familiar. It appears that BITMAPFILEHEADER and BITMAPINFOHEADER make use of these types.
This file also defines a struct called RGBTRIPLE that, quite simply, "encapsulates" three bytes: one blue, one green, and one red (the order, recall, in which we expect to find RGB triples actually on disk).
Why are these structs useful?
Rather than think of some file as one long sequence of bytes, we can instead think of it as a sequence of structs.
Now... answer all the questions in the readme
# Questions ## What's `stdint.h`? It declare sets of integer types that have specified widths. ## What's the point of using `uint8_t`, `uint32_t`, `int32_t`, and `uint16_t` in a program? So that you know exactly how much space your structs will take up. ## How many bytes is a `BYTE`, a `DWORD`, a `LONG`, and a `WORD`, respectively? 1, 4, 4, 2 ## What (in ASCII, decimal, or hexadecimal) must the first two bytes of any BMP file be? Leading bytes used to identify file formats (with high probability) are generally called "magic numbers." BM - The file type; must be BM. ## What's the difference between `bfSize` and `biSize`? bfSize is the size, in bytes, of the bitmap file whereas biSize is the number of bytes required by BITMAPFILEHEADER, the difference will be the size of the image data, presumably. ## What does it mean if `biHeight` is negative? If biHeight is negative, the bitmap is a top-down DIB and its origin is the upper-left corner. ## What field in `BITMAPINFOHEADER` specifies the BMP's color depth (i.e., bits per pixel)? biBitCount ## Why might `fopen` return `NULL` in lines 24 and 32 of `copy.c`? if there is an error opening the file ("Upon successful completion fopen(), fdopen() and freopen() return a FILE pointer. Otherwise, NULL is returned" - https://linux.die.net/man/3/fopen) ## Why is the third argument to `fread` always `1` in our code? Because each reads only a single data item (argument 3 is nmemb - the number of members) ## What value does line 65 of `copy.c` assign to `padding` if `bi.biWidth` is `3`? 3 (three) int padding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4; RGBTRIPLE is 3 (bytes); 3 * 3 is 9; 9 % 4 is 1; 4 - 1 is 3; 3 % 4 is 3; ## What does `fseek` do? The fseek() function sets the file position indicator for the stream pointed to by stream. The new position, measured in bytes, is obtained by adding offset bytes to the position specified by whence. ## What is `SEEK_CUR`? The Current Position Indicator. If whence is set to SEEK_CUR the offset is relative to the current position indicator. ## Whodunit? TODO
Implement a program called whodunit that reveals Mr. Boddy’s drawing in such a way that you can recognize whodunit.
Implement your program in a file called whodunit.c in a directory called whodunit.
Your program should accept exactly two command-line arguments: the name of an input file to open for reading followed by the name of an output file to open for writing.
If your program is executed with fewer or more than two command-line arguments, it should remind the user of correct usage, as with fprintf (to stderr), and main should return 1.
If the input file cannot be opened for reading, your program should inform the user as much, as with fprintf (to stderr), and main should return 2.
If the output file cannot be opened for writing, your program should inform the user as much, as with fprintf (to stderr), and main should return 3.
If the input file is not a 24-bit uncompressed BMP 4.0, your program should inform the user as much, as with fprintf (to stderr), and main should return 4.
Upon success, main should 0.