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, 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.
In your CS 340 directory, merge the initial starting files with the following commands:
git fetch release git merge release/mp2 --allow-unrelated-histories -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”.
- Note: integer fields within PNG chunks (specifically the data length and CRC fields) are stored in network byte order, but modern systems store integers in memory in various different byte orders (see Endianness on Wikipedia). Your code will need to convert between host byte order and network byte order formats when reading and writing integer fields of PNG chunks.
- You may find functions like
ntohlhelpful for converting values between host and network byte order.
lib/png.h) to complete Part 1.
- We have included
crc32(const void *data, size_t n_bytes, uint32_t* crc). This function takes in a pointer to
n_bytesand writes the 32-bit CRC value into the address provided by
- 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_openrequires only that you verify the “PNG signature”. It is recommended you do not read any additional data beyond the signature.
PNG_readrequires 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:
fopen(reference), to open a new file. Use
"r+"as the second parameter to open the file for reading and
"w"as the second parameter to open the file for writing.
fwrite(reference), to write to an open file.
fclose(reference), to close an open file.
Running Your Program
- In your terminal, type
make testto compile the test suite.
./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:
- A complete program that analyzes a PNG file,
- A complete program that reads and rewrites the PNG file using the provided PNG library,
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:
./png-analyze 340.pngto view the chunks in
./png-analyze sample/natalia.pngto view the chunks in
./png-analyze sample/waf.pngto view the chunks in
- Notice that
sample/waf.pngboth have a
uiucchunk – this is our hidden GIF file! You will need to extract it from the PNG file.
Part 3: Extract the Hidden
png-extractGIF.c to extract the
uiuc chunk from the PNG file specified in the command line (
argv) and save the data from the
uiuc chunk into the GIF file specified in the command line (
argv). 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:
./png-extractGIF sample/natalia.png natalia.gifto extract the hidden GIF from Natalia’s file,
./png-extractGIF sample/waf.png waf.gifto extract the hidden GIF from Wade’s file,
waf.gifto 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:
./test "[part=3]"to run the tests that have been tagged with
Part 4: Hide Your Own GIF
png-hideGIF.c to hide a GIF file within a
uiuc chunk in a provided PNG file. The first command line argument (
argv) is the normal PNG file that needs to be modified to hide an GIF image and the second argument (
argv) is the GIF to be hidden.
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
IEND (it cannot be before the
IHDR chunk or after the
IEND chunk, but it otherwise can be anywhere in between the two chunks).
Share in #mp2-showcase
Share your PNG with hidden GIF in Discord in #mp2-showcase for +2 EC! I’ll look at all of them and we’ll showcase the best of them in lecture! :)
Testing Your Code
Once complete, make sure to test your program:
png-analyzeto make sure the hidden
uiucchunk is present,
- Use your
png-extractGIFprogram to ensure you can extract the GIF you hide in the file,
- Finally, post your PNG file to the class Discord and share your hidden image with the all of us! :)
As a final check, run
./test to ensure you pass all test cases.
For full credit, your MP must run “valgrind clean”.
- On Windows/WSL, you can directly run valgrind with
On macOS, you can run valgrind via a docker container:
Only once, you need to build your docker container using:
docker build -t cs340 .
Then, you can run valgrind with the following commands:
docker run --rm -it -v `pwd`:/mp2 cs340 "make clean" docker run --rm -it -v `pwd`:/mp2 cs340 "make test" docker run --rm -it -v `pwd`:/mp2 cs340 "valgrind --leak-check=full --show-leak-kinds=all ./test"
In your solution, you must only modify the following files. Modifications of other files may break things:
Submission and Grading
Just Keep Letting Me Nerd Out Please!This MP has a JKLMNOP. Once you have completed the MP, you can nerd out with the PNG specification a little bit more in MP2's JKLMNOP project.
Once you have locally passed all the tests, you will need to submit and grade your code. First commit using the standard git commands:
git add -A git commit -m "MP submission" git push
The initial grading is done via a manual GitHub Action. You MUST complete this step before the deadline to earn any points for the MP:
- Navigate to your repository on https://github.com/cs340-illinois.
- Click on the “Action” Tab
- Choose “mp2 autograding”
- Click the green “Run Workflow” button (located on the blue bar)
- Press “Run Workflow”
- You will trigger a GitHub Action that will complete the grading run!
The 40 points for this MP are split in the following way:
|Description||CS 340 Course Points|
|autograding||26.67 (scaled from 100 in the GitHub Action)|
|valgrind||13.33 (scaled from 50 in the GitHub Action)|