Skip to content

Instantly share code, notes, and snippets.

@OxiBo
Last active July 28, 2017 05:07
Show Gist options
  • Save OxiBo/1f5f19d3aa7da1de0de73f89435e49cf to your computer and use it in GitHub Desktop.
Save OxiBo/1f5f19d3aa7da1de0de73f89435e49cf to your computer and use it in GitHub Desktop.
CS50 week4 pset4 whodunit
/**
* RGBTRIPLE
*
* This structure describes a color consisting of relative intensities of
* red, green, and blue.
*
* Adapted from https://msdn.microsoft.com/en-us/library/dd162939(v=vs.85).aspx.
*/
typedef struct
{
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;
1. What’s stdint.h?
<stdint.h> is a header file in the C standard library that has to be included in a program, if you need to
declare sets of integer types having specified widths, and define corresponding sets of macros.
It shall also define macros that specify limits of integer types corresponding to types defined in other standard headers.
The exact-width types and their corresponding ranges are only included in that header if they exist for that specific compiler/processor.
2. What’s the point of using uint8_t, uint32_t, int32_t, and uint16_t in a program?
Using uint8_t, uint32_t, int32_t, and uint16_t in a program is needed to make it clear that you intend to use data in specific way and
your data type is going to be of certain ranges. Using those types will let you use data within the ranges you need,
also knowing how wide your data type is going to be (for exapmple: uint32_t is going to be exactly 32 bits
with the maximum value 2^32-1 which equals 4,294,967,295)
3. How many bytes is a BYTE, a DWORD, a LONG, and a WORD, respectively?
BYTE (uint8_t) is 8 bits (1 byte);
DWORD (uint32_t) is 32 bits (4 bytes);
LONG (int32_t) is 32 bits (4 bytes);
WORD (uint16_t) is 16 bits(2 bytes)
4. 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."
The first two bytes of any BMP file are used to identify the file. A typical application reads this block (the first two bytes)
first to ensure that the file is actually a BMP file and that it is not damaged.
The first 2 bytes of the BMP file format are the character "B" and "M" in ASCII or 0x4D42 in hexadecimal.
All of the integer values are stored in little-endian format (i.e. least-significant byte first).
5. What’s the difference between bfSize and biSize?
bfSize (is a member (field) of the BITMAPFILEHEADER structure (struct) which contains information about the type,
size, and layout of a file that contains a DIB) represents the size, in bytes, of the bitmap file.
biSize (is a member (field) of the BITMAPINFOHEADER structure (struct) which contains information about the dimensions
and color format of a DIB) represents the number of bytes required by the structure.
6. What does it mean if biHeight is negative?
If biHeight is negative, it means that the bitmap is a top-down DIB and its origin is the upper-left corner.
7. What field in BITMAPINFOHEADER specifies the BMP’s color depth (i.e., bits per pixel)?
biBitCount specifies the number of bits-per-pixel. The biBitCount member of the BITMAPINFOHEADER structure
determines the number of bits that define each pixel and the maximum number of colors in the bitmap.
8. Why might fopen return NULL in lines 24 and 32 of copy.c?
Fopen is supposed to return a file pointer for the new file. We check if it is not equal to NULL to make sure
we get legitimate pointer back. Reasons why fopen might return NULL (not limited to):
- the file doesn't exist;
- the file is opened in a mode that doesn't allow other accesses;
- the network is down;
- the file exists, but you don't have permissions;
- fopen cannot return legitimate pointer back.
9. Why is the third argument to fread always 1 in our code?
Argument 1 in fread function means that fread will read one element from a given file, namely
reads infile's BITMAPFILEHEADER, infile's BITMAPINFOHEADER, RGB triple from infile.
10. What value does line 65 of copy.c assign to padding if bi.biWidth is 3?
int padding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
(4-(3*3(RGBTRIPLE equals 3 bytes)%4)%4=3. so int paddling is equals 3.
If the width is 3, padding is necessary since the scanline must be a multiple of 4.
3 bytes are added to bring the scanline to 12 bytes.
(3 pixels) × (3 bytes per pixel) + (3 bytes of padding) = 12 bytes, which is indeed a multiple of 4.
11. What does fseek do?
Fseek allows to remind or fast-forward within a file (changes the location of the file pointer).
In copy.c fseek skips over padding, if any, and looks for the next pixel.
12. What is SEEK_CUR?
This is an integer constant which, when used as the whence argument to the fseek function, specifies that the padding provided
is relative to the current file position. SEEK_CUR moves file pointer position to given location.
(The value of whence must be one of the constants SEEK_SET, SEEK_CUR, or SEEK_END,
to indicate whether the offset is relative to the beginning of the file, the current file position,
or the end of the file, respectively.)
(Function: int fseek (FILE *stream, long int offset, int whence).
/**
* CS50 week4 pset4 whodunit
*/
/**
* Copies a BMP piece by piece, just because.
*/
#include <stdio.h>
#include <stdlib.h>
#include "bmp.h"
int main(int argc, char *argv[])
{
// ensure proper usage
if (argc != 3)
{
fprintf(stderr, "Usage: ./whodunit 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)
{
fprintf(stderr, "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;
// read RGB triple from infile
fread(&triple, sizeof(RGBTRIPLE), 1, inptr);
//change RGB triples to change the image
if(triple.rgbtRed==0xff)
{
triple.rgbtBlue=triple.rgbtBlue/20;
triple.rgbtGreen=triple.rgbtGreen/20;
triple.rgbtRed=triple.rgbtRed/100;
}
// 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);
// success
return 0;
}
_________________
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment