top of page
PD-Logo-Day.png

CS50 Week 4 C — Volume Scaling, Image Filters and JPEG Recovery

  • Writer: Parsa Dev
    Parsa Dev
  • Jan 29
  • 2 min read
A bright London-inspired flat lay showing a MacBook with light-themed code editor open to CS50x Week 4 image filter and JPEG recovery code in C, with warm natural daylight and a blurred Tower Bridge view through a café window. Parsa Dev

Week 4 of CS50x is where things get close to the metal. The three problems this week — Volume, Filter, and Recover — all involve working directly with binary file formats, raw memory buffers, and types that map exactly onto how data sits on disk. Volume is the most straightforward of the three: it takes a WAV audio file, copies the 44-byte header unchanged to an output file, and then reads each 16-bit audio sample one at a time, multiplies it by a scaling factor provided as a command-line argument, and writes the result out. The key decision here is using int16_t (aliased as SAMPLE_AUDIO) rather than a generic buffer type — audio samples in WAV files are signed 16-bit integers, so getting the type right is essential. The header is handled separately as a plain byte array to make sure it passes through without modification, since multiplying header bytes by an audio factor would corrupt the file immediately.

Filter is the week's largest problem, and it is split across four image processing functions in helpers.c. Grayscale averages the red, green, and blue values of each pixel and assigns the result to all three channels, using round() and float casting to avoid integer truncation errors. Reflect swaps pixels symmetrically across the horizontal centre of each row, handling both odd and even widths with separate loop bounds. Blur implements a box blur by averaging each pixel's 3×3 neighbourhood — edge and corner pixels are handled by simply skipping out-of-bounds neighbours and dividing only by the count of valid ones, which is managed through a helper function getBlur that accepts a colour channel index to avoid code repetition. Edges uses the Sobel operator — a classic edge detection algorithm from computer vision — applying two 3×3 convolution kernels (Gx and Gy) separately for the horizontal and vertical gradient of each colour channel, then combining them as sqrt(Gx² + Gy²) and capping at 255. The output of each pixel in edges mode is stored in a temporary copy of the image to make sure the convolution reads from the original values rather than already-modified neighbours.

Recover is probably the most satisfying problem of the week. The task is to reconstruct deleted JPEG files from a raw memory card image, reading through the file 512 bytes at a time. Each 512-byte block is checked for the JPEG signature — 0xff 0xd8 0xff followed by a byte whose upper nibble is 0xe — and when one is found, a new output file is opened with a sequentially numbered name (000.jpg, 001.jpg, and so on). The previous output file is closed before the new one opens, and writing continues block by block until the next signature is found or the input is exhausted. The last file is closed after the loop ends. It is a tight, clean program that teaches you a huge amount about how filesystems actually work — deleted files are not wiped, just marked as available, and knowing the structure of a format's header bytes is all you need to find them again. The full code for this week is on GitHub — browse the Week 4 folder directly, or explore the entire CS50x repository to see the full course progression.


Comments


bottom of page