C Review: Binary Image Memory Reading/Writing
Due Date: 2/27/26
Description
In this homework, you will be learning to manipulate information using raw binary. In order to visualize the various binary operations we are doing, we will be using the PBM/PGM/PPM image formats as a way of quickly writing pixel information directly to memory.
For more info on the PBM/PGM/PPM file format, the Wikipedia page for them is a pretty good resource along side the specifications that I could find:
The spark notes version is that "Netpbm" or "Network Portable Bitmap Format" is a collection of tools and specifications for portable graphics file formats. They have three main types of portable formats that can be opened by nearly any text editor:
- PBM (Portable BitMap Format) - Each pixel is either a 1 or 0, for white or black respectively
- PGM (Portable GreyMap Format) - Typically, each pixel can be any number between 0-255 signifying how grey the pixel is, with 0 being black and 255 being white
- PPM (Portable PixMap Format) - Each pixel now has three numbers ranging from 0-255, for each red, green, and blue color channels
Each type of file defines ways of writing pixels to an image file in a very general way, it is so general I can show the raw form of the file format. The basic one, PBM, binary numbers, 0 to turn off a pixel and 1 to turn it on. The following .pbm file stores a happy face:
P1
10 10
1
0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 1 0 0
0 0 1 0 0 0 0 1 0 0
0 0 1 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 1
0 1 0 0 0 0 0 0 1 0
0 0 1 1 1 1 1 1 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
Let's explain line-by-line:
P2- This is the "magic number" it ultimately decides what format we are using.P2specifically refers to the Portable GreyMap Format in ascii, rather than in raw bytes, more on this later.10 10- After the magic number, there is two numbers to represent the width and height in that order. These are used to read the rest of the file, automatically making sure that each pixel is put in the correct location.1- This is the scale of all of the numbers, this is saying that the grey scale is maxed at 1 meaning there is only black, 0, and white 10 0 0 0 ...- This is the actual contents of the file. For black and white grey scale images each number represents the value for that pixel to be drawn to the screen.
That "magic number" is the format that is used for identifying how the data will be stored, either as ascii chars that are viewable, or raw binary format for being compact and closer to reality. These are the magic numbers for .pbm, .pgm, and .ppm
P1,P2,P3= ASCII format (human-readable)P4,P5,P6= Raw binary format (more compact)
Fortunately, Sublime Text and other text editors like VSCode and view this images as they live update. Unfortunately, Sublime Text only supports it for .pgm and .ppm and only in magic number modes P5 and P6, meaning you will only be able to view the ones after you have generated in binary. With this in mind, we will be focusing on .pgm and .ppm and be generating in raw binary and then viewing the files.
These types of files were picked for this assignment because they are a simple format that represents very closely to how we write directly to memory. With this in mind, we will only be allowing the the use of C binary and hexadecimal numbers for all values other than powers of 2 (0, 1, 2, 4, 8, 16, ...) and heavily relying on C binary/bitwise operators.
To use C binary and hexadecimal number representations:
- Prefix with
0bfor binary numbers0b1010for the number 10
- Prefix with
0xfor hex numbers0xABCfor the number 2748
Using these ideas in this homework you will:
- Write/edit simple binary images in black and white
- Write more complex color images
Section 1: Black and White & Greyscale Images
- Random Noise (BW and Greyscale)
- Bit-Plane an Image
- Bitwise Patterns
Section 2: Color Images
- Random Noise
- Bitwise Patterns
- Bit-Plane an Image
- Color Channel Fragmentation and Mixing
Section 1: Black and White & Greyscale Images
Click here, to download the starting point that I have created for you. It is also on Brightspace, under Content->Homework 1. Unzip it into the place you are completing Homework 1, Section 1.
This code will output a simple greyscale image that is a gradient that goes from left to right. Nothing special.
It also contains the images you will read in and use for the parts that require inputs.
Overview
Using the starting point as a going off point you are to create a C project with two main files for this section:
black_and_white.c- Function declarations for each problem without them being usedmain.c- Using all of the aforementioned functions to generate all images in the current directory with correct names- Should
#include "black_and_white.c"
- Should
All generated images are to be saved as .pgm files in this section.
Task 1: Random Noise Generator (15 points)
Create a function that generates random noise images in both black & white and greyscale
Function signature:
void generate_random_noise_bw(const char* filename, int width, int height);
void generate_random_noise_grey(const char* filename, int width, int height);
Requirements:
- Use
rand()to generate random pixel values - For black & white: each pixel should be randomly 0 or 1
- This means that the max value must be set at 1
- For greyscale: each pixel should be a random value between 0-255
- Write in binary format (P5)
- Both images should be 256x256 pixels
Hints:
- Use
rand() % 2for binary values - Use
rand() % 0xFFfor greyscale values - Remember to seed the random number generator with
srand(time(NULL))in main
Task 2: Bit-Plane Extraction (20 points)
Create a function that extracts individual bit planes from a greyscale image.
Function signature:
Requirements:
- Read a PGM image
- Extract the specified bit plane (0-7, where 0 is LSB and 7 is MSB)
- Create a new PGM where pixels are either 0 or 255 based on that bit
- Use bitwise AND operation to check if a bit is set
- Must use binary/hex number representation (0b...)(0x...)
Example: If a pixel value is 0b10110101 (181):
- Bit plane 0 (LSB): 1 → output 255
- Bit plane 4: 0 → output 0
- Bit plane 7 (MSB): 1 → output 255
Task 3: Bitwise Pattern Generation (25 points)
Create functions that generate images using bitwise operations on pixel coordinates.
Function signatures:
void generate_xor_pattern(const char* filename, int width, int height);
void generate_and_pattern(const char* filename, int width, int height);
void generate_or_pattern(const char* filename, int width, int height);
Requirements:
- For each pixel at position (x, y), calculate the pixel value using:
- x XOR y
- x AND y
- x OR y
- All operations must use binary operators and hex notation
- Generate 256x256 images
- Output as PGM files
Hints:
- These operations create interesting geometric patterns
- The XOR pattern is particularly famous for creating diagonal lines
Section 1 Grading Rubric
- Task 1: Random noise generation (15 points)
- Task 2: Bit-plane extraction (20 points)
- Task 3: Bitwise patterns (25 points)
- Code style and comments (10 points)
- Proper binary/hex notation usage (10 points)
- Memory management (10 points)
- Proper file I/O (10 points)
- Total: 100 points
Section 2: Color Images
Overview
Now you'll work with PPM (color) images. Each pixel has three color channels: Red, Green, and Blue, each ranging from 0-255.
This calls for the P6 magic number.
In the section folder, create a new file color_images.c with the following functions and use them in main.c the same as the previous.
Task 1: Color Random Noise (15 points)
Create a function that generates random color noise.
Function signature:
Requirements:
- Generate 256x256 image
- Each color channel (R, G, B) should be random (0-255)
- Write in binary format (P6)
- Must write RGB values sequentially for each pixel
Task 2: Color Bitwise Patterns (20 points)
Create functions that generate color patterns using bitwise operations.
Function signatures:
void generate_rgb_pattern_1(const char* filename, int width, int height);
void generate_rgb_pattern_2(const char* filename, int width, int height);
void generate_rgb_pattern_3(const char* filename, int width, int height);
Requirements:
- Create three DIFFERENT color pattern generators
- Each function must generate a 256x256 PPM image
- Each color channel (R, G, B) must be calculated using a DIFFERENT combination of:
- The pixel's x-coordinate
- The pixel's y-coordinate
- At least TWO different bitwise operations per pattern
- You must use at least 4 of these bitwise operations across all three patterns:
- XOR (
^) - AND (
&) - OR (
|) - Left shift (
<<) - Right shift (
>>) - NOT (
~)
- XOR (
- Each channel's formula must produce values in the range 0-255
- You may NOT use the same formula for all three channels in a single pattern
- All numeric constants must be in hexadecimal (0x...) or binary (0b...) notation
Examples of valid operations:
// Using coordinates with bitwise ops
R = (x ^ y) & 0xFF; // XOR coordinates, mask to byte
G = ((x << 2) | y) & 0xFF; // Shift and OR
B = (~(x & y)) & 0xFF; // AND then invert
Grading:
- Pattern 1: Uses at least 2 different bitwise operators (7 points)
- Pattern 2: Uses at least 2 different bitwise operators, different from pattern 1 (7 points)
- Pattern 3: Most creative/interesting pattern (6 points)
Hints:
- Start by experimenting with simple combinations
- The
& 0xFFoperation ensures your result stays in 0-255 range - Different shift amounts create different visual effects
- Combining operators (like
(x ^ y) & (x | y)) creates complex patterns - View your images to see if they're interesting before submitting!
Task 3: Bit-Plane Color Extraction (20 points)
Extract bit planes from color images for each channel separately.
Function signature:
void extract_color_bit_plane(const char* input_file, const char* output_file,
char channel, int bit_position);
Requirements:
channelparameter: 'R', 'G', or 'B'- Extract specified bit plane from chosen channel
- Output a greyscale PGM showing that bit plane
- Other channels' bits should be ignored
For this ones implementation, show each channel in a different image.
Task 4: Channel Fragmentation and Mixing (25 points)
Create functions to separate and recombine color channels.
Function signatures:
void separate_channels(const char* input_file, const char* r_out,
const char* g_out, const char* b_out);
void mix_channels(const char* input_file_a, const char* input_file_b,
const char* output_file);
Requirements:
separate_channels: Create three color images, for each color channel, where all other color channels are removedmix_channels: Take two images and xor their color channels together
Section 2 Grading Rubric
- Task 1: Color random noise (15 points)
- Task 2: Color bitwise patterns (20 points)
- Task 3: Color bit-plane extraction (20 points)
- Task 4: Channel operations (25 points)
- Code style and comments (10 points)
- Proper binary/hex notation (10 points)
- Total: 100 points
Submission Guidelines
What to Submit
Section 1 (in folder named section1/):
black_and_white.c- Your function implementationsmain.c- Driver program that calls all functions- All generated
.pgmfiles from your program
Section 2 (in folder named section2/):
color_images.c- Your function implementationsmain.c- Driver program that calls all functions (can include black_and_white.c if you want both sections in one main)- All generated
.ppmand.pgmfiles from your program