====== cs19s23as08: Bitmap Image Modification ======
===== Goals =====
* Practice working with explicitly binary data in C++.
* Learn a bit about one of the simplest image file formats.
-----
====== Prerequisites ======
This assignment requires familiarity with the [[:lecture materials/]] presented in class through [[:lecture materials/week 08]].
-----
====== Background: The BMP File Format ======
The [[https://en.wikipedia.org/wiki/BMP_file_format|BMP file format]] is among the simplest image representation formats; possibly //the// simplest. There are various versions of the format, and the format is able to support several kinds of color values and compression. But the simplest and most common bitmap files are not compressed.
For our purposes, assume that a BMP file consists of 24-bit RGB pixels and is composed of the following "structures" (i.e., segments of data) in the following order:
^ Structure name ^ Size ^ Contents ^
| BMP file header | 14 bytes | General information about the file |
| DIB header | Varies | Information about the image, e.g. width and height |
| Pixel array | Based on image dimensions and pixel type | Component values for each pixel |
The Wikipedia article linked above has a lot more information on the format. However, here is a thorough description of what you need to know about each structure for this assignment:
===== BMP File Header =====
This structure consists of 14 bytes, as follows:
^ File offset ^ Size (bytes) ^ Purpose ^
| ''0x00'' | 2 | The bytes ''0x42'' and ''0x4d'' (characters '''B''' and '''M''') identify this file as a bitmap image |
| ''0x02'' | 4 | The size of the BMP file in bytes (should match the actual file size) |
| ''0x06'' | 2 | Reserved; actual value depends on the application that creates the image |
| ''0x08'' | 2 | Reserved; actual value depends on the application that creates the image |
| ''0x0a'' | 4 | The offset, i.e. starting address, of the byte where the bitmap image data (pixel array) can be found. |
===== DIB Header =====
This structure immediately follows the BMP header and consists of a variable number of bytes, as follows:
^ File Offset ^ Size (bytes) ^ Description ^
| ''0x0e'' | 4 | The size of this header. |
| ''0x12'' | 4 | The bitmap width in pixels (signed 32-bit integer) |
| ''0x16'' | 4 | The bitmap height in pixels (signed 32-bit integer) |
| ''0x1a'' | 2 | The number of color planes (must be 1) |
| ''0x1c'' | 2 | The number of bits per pixel. In our case, this should be 24. |
| ''0x1e'' | 4 | The compression method being used. In our case, this should be 0. |
| ''0x22'' | 4 | The image size. This is the size of the raw bitmap data (pixel array). |
| ''0x26'' | 4 | The horizontal resolution of the image (pixels per meter), as a signed 32-bit integer. |
| ''0x2a'' | 4 | The vertical resolution of the image (pixels per meter), as a signed 32-bit integer. |
| ''0x2e'' | 4 | The number of colors in the color palette. In our case, this should be 0. |
| ''0x32'' | 4 | The number of important colors used, or 0 when every color is important. In our case, this should be 0. |
===== Pixel Array ======
This structure contains **component values for every pixel in the image**.
- The pixel array begins at the file offset specified in the BMP file header.
- Each pixel value is composed of 3 bytes, which represent a 24-bit RGB color, i.e. 3 8-bit unsigned integers.
- Pixel values are presented **row-by-row** starting with the bottom row((This is [[https://stackoverflow.com/questions/8346115/why-are-bmps-stored-upside-down|due to some troublesome mathematicians]], as is often the case 😉.)), i.e. the entire bottom row of pixels, then the row second from the bottom, etc.
- Each row is **padded to a multiple of 4 bytes in size**, if necessary.
===== Example =====
A very small (2x2-pixel) BMP file is available at ''/srv/datasets/simple.bmp'', or [[https://jeff.cis.cabrillo.edu/datasets/simple.bmp|via HTTP]]. (This is the same image described in [[https://en.wikipedia.org/wiki/BMP_file_format#Example_1|Example 1]] of Wikipedia's article.)
Here it is, surrounded by a 10-pixel padded bordering box (you probably can't see the image very easily!):
And here is how it would look if it were resized to 200x200 pixels:
On the command line, we could inspect the contents of this file as 1-byte hexadecimal values using the ''hexdump'' utility:
hexdump -C /srv/datasets/simple.bmp
''hexdump'' gives the following output, in which each line displays the file offset in hexadecimal, followed by sixteen space-separated, two column, hexadecimal bytes, followed by the same sixteen bytes presented as printable characters (or periods if not printable), enclosed in ''|'' characters.:
00000000 42 4d 46 00 00 00 00 00 00 00 36 00 00 00 28 00 |BMF.......6...(.|
00000010 00 00 02 00 00 00 02 00 00 00 01 00 18 00 00 00 |................|
00000020 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000030 00 00 00 00 00 00 00 00 ff ff ff ff 00 00 ff 00 |................|
00000040 00 00 ff 00 00 00 |......|
00000046
The first 14 bytes constitute the BMP File Header: ''42 4d 46 00 00 00 00 00 00 00 36 00 00 00''
Note the bytes ''42 4d'' initially, i.e. the characters ''B'' and ''M''. The next 4 bytes (''46 00 00 00'') are the file size. While this looks to be (and is) the value ''0x46000000'', note that this does not mean the file is size ''1174405120'', which is [[https://jeff.cis.cabrillo.edu/tools/converter?hexadecimal=46000000|how we would normally interpret 0x46000000]]. This is because BMP files (and most modern CPUs) represent integers in [[https://en.wikipedia.org/wiki/Endianness|"little-endian"]] format, meaning that the **bytes are ordered from least significant to most significant**, unlike how we usually write integers for human benefit. This means the way we would normally write that value in hexadecimal is ''0x00000046'', [[https://jeff.cis.cabrillo.edu/tools/converter?hexadecimal=00000046|which is 70 in decimal]]. The size of this file is indeed 70 bytes:
$ stat -c '%s' /srv/datasets/simple.bmp
70
The next 40 bytes constitute the DIB Header: ''28 00 00 00 02 00 00 00 02 00 00 00 01 00 18 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00''
Note that ''0x28000000'' is the header size (little-endian 40), and the next 8 bytes are the image width and height, both 2 in this case: ''0x02000000 0x02000000''.
From offset ''0x36'' to the end of the file is the pixel array: ''00 00 ff ff ff ff 00 00 ff 00 00 00 ff 00 00 00''
The first row of pixels: ''00 00 ff ff ff ff 00 00''
The second row of pixels: ''ff 00 00 00 ff 00 00 00''
Note that first-row pixel values ''00 00 ff'' and ''ff ff ff'' are the colors red ''(255, 0, 0)'' and white ''(255, 255, 255)'', respectively, and that even pixel values are stored as little-endian integers, i.e. BGR instead of RGB.
-----
====== Assignment ======
You shall write a C++ program that applies one of six different modifications to an existing 24-bit RGB BMP image file and produces another BMP image file containing the result. The resulting image shall only differ in pixel values, i.e. all header and other metadata shall pass through unchanged. The general syntax shall be:
executable input_file output_file modification
The six available modifications are described below, using sample executable ''cs19_bmp_mod'' (which is available on the server) as an example, and file ''[[https://jeff.cis.cabrillo.edu/datasets/cabrillo-logo.bmp|/srv/datasets/cabrillo-logo.bmp]]'' as input.
Perform these modifications by working with the raw contents of the file. Use only standard C++ and the C++ standard library. Do not use any image-specific third-party code!
===== Modification -brighten =====
''-brighten'' increases the intensity of each pixel component by a factor given as a subsequent command-line argument, e.g in the following that increases the intensity by 25%:
cs19_bmp_mod /srv/datasets/cabrillo-logo.bmp cabrillo-logo-brighten-25.bmp -brighten 25
Original image:
{{ :cabrillo-logo.bmp?nolink |Cabrillo College logo}}
Modified image:
{{ :cabrillo-logo-brighten-25.bmp?nolink |Cabrillo College logo with pixel components brightened by 25%}}
===== Modification -darken =====
''-darken'' decreases the intensity of each pixel component by a factor given as a subsequent command-line argument, e.g in the following that decreases the intensity by 25%:
cs19_bmp_mod /srv/datasets/cabrillo-logo.bmp cabrillo-logo-darken-25.bmp -darken 25
Original image:
{{ :cabrillo-logo.bmp?nolink |Cabrillo College logo}}
Modified image:
{{ :cabrillo-logo-darken-25.bmp?nolink |Cabrillo College logo with pixel components darkened by 25%}}
===== Modification -desaturate =====
''-desaturate'' converts all colors in the image to corresponding shades of gray, where each component in each pixel is assigned the average of all of the pixel's original components, e.g in the following:
cs19_bmp_mod /srv/datasets/cabrillo-logo.bmp cabrillo-logo-desaturate.bmp -desaturate
Original image:
{{ :cabrillo-logo.bmp?nolink |Cabrillo College logo}}
Modified image:
{{ :cabrillo-logo-desaturate.bmp?nolink |Cabrillo College logo with pixel components desaturated via the average of components}}
===== Modification -invert =====
''-invert'' inverts all pixel components, e.g in the following:
cs19_bmp_mod /srv/datasets/cabrillo-logo.bmp cabrillo-logo-invert.bmp -invert
Original image:
{{ :cabrillo-logo.bmp?nolink |Cabrillo College logo}}
Modified image:
{{ :cabrillo-logo-invert.bmp?nolink |Cabrillo College logo with pixel components inverted}}
===== Modification -hflip =====
''-hflip'' flips the image horizontally.
cs19_bmp_mod /srv/datasets/cabrillo-logo.bmp cabrillo-logo-hflip.bmp -hflip
Original image:
{{ :cabrillo-logo.bmp?nolink |Cabrillo College logo}}
Modified image:
{{ :cabrillo-logo-hflip.bmp?nolink |Cabrillo College logo flipped horizontally}}
===== Modification -vflip =====
''-vflip'' flips the image vertically.
cs19_bmp_mod /srv/datasets/cabrillo-logo.bmp cabrillo-logo-vflip.bmp -vflip
Original image:
{{ :cabrillo-logo.bmp?nolink |Cabrillo College logo}}
Modified image:
{{ :cabrillo-logo-vflip.bmp?nolink |Cabrillo College logo flipped vertically}}
===== Leaderboard =====
As submissions are received, this leaderboard will be updated with the top-performing fully/nearly functional solutions, with regard to execution speed.
Rank | Test Time (s) | Memory Usage (kB) | SLOC (lines) | User |
-----
====== Submission ======
Submit your source-code file(s) via [[info:turnin]].
{{https://jeff.cis.cabrillo.edu/images/feedback-robot.png?nolink }} //**Feedback Robot**//
This project has a feedback robot that will run some tests on your submission and provide you with a feedback report via email within roughly one minute.
Please read the feedback carefully.
====== Due Date and Point Value ======
Due at 23:59:59 on the date listed on the [[:syllabus|syllabus]].
''Assignment 08'' is worth **60 points of extra credit!**
Possible point values per category:
---------------------------------------
Modifications (must work perfectly):
-brighten 10
-darken 10
-desaturate 10
-invert 10
-hflip 10
-vflip 10
Possible deductions:
Style and practices 10–20%
---------------------------------------