MP 2: PNG Chunks

Due Date: Completed and turned in via git before September 10, 2021 at 11:59pm
Points: MP 2 is worth 50 points

Overview

Your second C program explores the implementation and use of a widely-used technical specification. You will implement a small part of the PNG technical specification and use your implementation to hide a GIF within a PNG file.

  • You will implement part of a published technical specification, specifically the Portable Network Graphics (PNG) Specification (Second Edition).
  • You will read and write files with specification-defined binary data.
  • You will explore cross-platform byte ordering (endianness).
  • You will use your knowledge of the PNG specification to hide a GIF inside of a PNG.

File: 240.png

File: sample/natalia.png

File: sample/waf.png
All of these images look the same, but two have a hidden GIF inside of them!

Initial Files

In your CS 240 directory, merge the initial starting files with the following commands:

git fetch release
git merge release/mp2 -m "Merging initial files"

Part 1: Implementing the PNG File Format

The World Wide Web Consortium (W3C) is “an international community where [many] work together to develop Web standards”. One of the web standards that the W3C published and maintains is the “Portable Network Graphics (PNG) Specification (Second Edition)”. This specification fully and completely defines how PNG image files work.

To complete Part 1 of this MP, you must complete a small PNG library that reads the “PNG signature” and “chunks” found in PNG files:

  • Read the PNG specification to understand the “PNG signature” and “chunks”.
  • Implement lib/png.c (and the struct in lib/png.h) to complete Part 1.
  • We have included lib/crc.{c,h} that defines crc32(const void *data, size_t n_bytes, uint32_t* crc). This function takes in a pointer to data of n_bytes and writes the 32-bit CRC value into the address provided by crc.
    • Your library must calculate and write the CRC when writing PNG chunks.

The design on the PNG library is a file-stream based library where you need only to return the next chunk in the file. Therefore, it is highly recommended you only read the data necessary to complete the function and read the next part of the file the next time a library function is called.

  • For example, PNG_open requires only that you verify the “PNG signature”. It is recommended you do not read any additional data beyond the signature.
  • Similarly, PNG_read requires you to return data about the next PNG chunk. It is recommended you only read the data for one chunk when this function is called.
  • You can create a data structure to store the full PNG in memory as soon as the file is open but this is not recommended.

You will need to open a file for reading or writing in C. The following C library calls may be helpful:

Running Your Program

  • In your terminal, type make test to compile the test suite.
  • Run ./test "[part=1]" to run the tests that have been tagged with [part=1] (covering this portion of the MP).

Part 2: Understanding the Provided Code

In this MP, we have provided two programs that are already complete:

  1. A complete program that analyzes a PNG file, png-analyze.c.
  2. A complete program that reads and rewrites the PNG file using the provided PNG library, png-rewrite.c.

The png-analyze.c and png-rewrite.c files use your library from Part 1. If your library is not complete, these programs will not run correctly! Here are several example runs of the programs that you should run to explore what the provided code does for you:

  • Run make to compile,
  • Run ./png-analyze 240.png to view the chunks in 240.png
  • Run ./png-analyze sample/natalia.png to view the chunks in sample/natalia.png
  • Run ./png-analyze sample/waf.png to view the chunks in sample/waf.png
  • Notice that sample/natalia.png and sample/waf.png both have a uiuc chunk – this is our hidden GIF file! You will need to extract it from the PNG file.

Part 3: Extract the Hidden uiuc Chunk

Complete png-extractGIF.c to extract the uiuc chunk from the PNG file specified in the command line (argv[1]) and save the data from the uiuc chunk into the GIF file specified in the command line (argv[2]). You will almost certainly find the provided png-analyze.c as a great starting point for your code.

The hidden GIFs in the files within the sample folder are valid GIF and should be able to be opened by any program that can open images if extracted correctly.

Testing Your Code

Once you have finished png-extractGIF.c, make sure to test it before moving on to Part 3! To do so:

  • Run make to compile,
  • Run ./png-extractGIF sample/natalia.png natalia.gif to extract the hidden GIF from Natalia’s file,
  • Run ./png-extractGIF sample/waf.png waf.gif to extract the hidden GIF from Wade’s file,
  • View natalia.gif and waf.gif to see the hidden GIFs you extracted. (If they don’t appear as valid GIFs, something went wrong in your extraction.)

Finally, you can also run the test suite we have provided:

  • Run ./test "[part=3]" to run the tests that have been tagged with [part=3].

Part 4: Hide Your Own GIF

Complete png-hideGIF.c to hide a GIF file within a uiuc chunk in a provided PNG file. The first command line argument (argv[1]) is the normal PNG file that needs to be modified to hide an GIF image and the second argument (argv[2]) is the GIF to be hidden.

You will need to open a new file to read the contents of the GIF file. The following C library calls may be helpful:

Your png-hideGIF.c file will be very similar to the provided png-rewrite.c program except that you need to add an additional PNGChunk somewhere between IHDR and IEND (it cannot be before the IHDR chunk or after the IEND chunk, but it otherwise can be anywhere in between the two chunks).

Testing Your Code

Once complete, make sure to test your program:

  • Use png-analyze to make sure the hidden uiuc chunk is present,
  • Use your png-extractGIF program to ensure you can extract the GIF you hide in the file,
  • Finally, post your PNG file to the class CampusWire or Discord and share your hidden image with the all of us! :)

As a final check, run ./test to ensure you pass all test cases.

Submit

When you have completed your program, double-check all parts run without errors and gets the result your expect. When you are ready, submit the code via the following git commands:

git add -A
git commit -m "MP submission"
git push

You can verify your code was successfully submitted by viewing your git repo on github.com.