Home
Netbeans Eclipse Qt Java
Games
College of Engineering Aeronautics and Astronautics Agricultural and Biological Engineering Biomedical Engineering Chemical Engineering Civil Engineering Construction Engineering and Management Electrical and Computer Engineering Engineering Education Engineering Professional Education Environmental and Ecological Engineering Industrial Engineering Materials Engineering Mechanical Engineering Nuclear Engineering
EPICS (Engineering Projects In Community Service) First-Year Engineering Program First-Year Engineering Honors Program Global Engineering Program Minority Engineering Program Professional Practice (Co-Op) Program Women in Engineering Program
College Administration Schools Programs All Groups All People ECN Webmail
Purdue Home

 

Exercise 4

Binary Files and Dynamic Memory (Inverting a BMP Image)

Due Date - February 25, 2012 @ 12:00pm

Introduction

So far we have only looked at text files in this class, but most of the realistic files in a filesystem are actually binary.  This means that the data they contain is not necessarily restricted to the alphanumeric characters you will find in a text file and which you can edit in a text editor.  Examples of binary file formats include MP3, DOC, JPG, and many other files that are not restricted to raw ASCII text.  In this exercise, we will see how to write C programs that are capable of reading and writing binary files.  We will study a specific file format for image data called BMP that is commonly used in the Windows operating system.  Most web browsers are also able to read and display BMP files.

Assignment

      Write a C program that reads an image from a binary BMP file on disk, inverts all of the pixels, and saves the image as a new BMP file.

Information about BMP image files

The BMP file format is one of the easier formats out there, but it still has a lot of complex support for extensions, compression, and various color models.  To make this exercise manageable, we are going to be focusing exclusively on 24-bit uncompressed BMP files.   We have provided a function called BMP_checkValid() that ensures that the file you are trying to read fulfills these constraints.  Your code should call BMP_checkValid() to ensure that this is the case.

In general, BMP files consist of a 54-byte header (defined in the file bmp.h that we provide in the next section) followed by image data.  The header has the same format for all 24-bit BMP images, and contains information about the size of the image, its dimensions, its color model, and so on.  Immediately following the header is a large chunk of bytes that contain the color values for the image, arranged in a sequence of rows (in other words, the first values are for the first row, then the second, then the third, etc).  Color values in 24-bit BMP are represented by three bytes: one for red (0-255), one for green (0-255), and one for blue (0-255).  These three bytes uniquely represent a particular color for that particular pixel in the image.

In this assignment, we are not going to worry too much about the exact contents and dimensions of the image since we are not going to try to display it on the screen (there are other programs for this).  Instead, we are going to simply invert all of the bytes in the image data part of the file, and then store it back on disk.  This is good because BMP files have fancy ways of padding each row so that it is a multiple of four.  Don't worry about this here: if we make sure to read all of the bytes from the file into memory, invert those bytes, and then save them back, we are sure that the output file is going to be correct. Inverting a byte "value" is simply the same as replacing it doing "value=255-value".  If you think about it, for color this will result in the complementary color being chosen (black becomes white, etc).

Reading a BMP file consists of the following steps:

  1. Open a binary file for reading
  2. Read the 54-byte header into memory
  3. Check that the data in the header is valid (use BMP_checkValid given in bmp.c)
  4. Allocate space for the image data
  5. Read the image data (which is the file size minus the 54 bytes of the header)
  6. Close the file

Saving a BMP file is similar:

  1. Open a binary file for writing
  2. Write the 54-byte header into the file
  3. Write the image data into the file (again, the file size from the header minus 54 bytes)
  4. Close the file

Skeleton Code and Output code

We have provided you skeleton code for this assignment that consists of all of the headers and structures needed to load and save a BMP file, as well as some of the code for how to manage this.  You will only have to fill in the missing parts in bmp.c as well as write a new file called main.c that fulfills the below specification and utilizes the functions in bmp.h and bmp.c.

  • bmp.h - header file  (do not change)
  • bmp.c - source file (fill in the empty functions)

Specifications

  1. You should use the following print statement if the user does not give enough command line arguments (and exit with EXIT_FAILURE):
    printf("Usage: ex4 <source> <destination>\n");
  2. You should use the following print statement if unable to open the input file (and exit with EXIT_FAILURE):
    printf("Unable to open input file!\n");
  3. You should use the following print statement if the dynamic memory is not allocated properly (and exit with EXIT_FAILURE):
    printf("Unable to allocate memory!\n");
  4. You should use the following print statement if the input BMP file is not valid (use BMP_checkValid) (and exit with EXIT_FAILURE):
    printf("BMP file not valid!\n");
  5. You should use the following print statement if the unable to open the output file (and exit with EXIT_FAILURE):
    printf("Unable to open output file!\n");
  6. The source file (argv[1]) and the destination file (argv[2]) are command-line arguments.
  7. Your program should first read the source file from disk, then invert all of the pixels in the image in memory, and then save back the file to the disk using the destination filename as the new name.
  8. Reading a BMP file from disk consists of opening a binary file for reading, reading the header, and then reading the image data.  After having read the header (using fread), the fields "width" and "height" in BMP_Header will be filled in with the dimensions of the image data, and the "bits" field will say how large each pixel is in bits.  Divide the bits by 8 to find out the number of bytes to load for each pixel.
  9. Loading image data should be done by reading the remainder of the contents of the file (header.size - sizeof(BMP_Header)) using fread. The image data will come directly after the BMP_Header data in the file.
  10. You have to use the function BMP_printHeader( ) as specified inside bmp.c function BMP_load(); See bmp.c.
  11. Your BMP loading function does not need to work for all .bmp files (the BMP standard allows for compression, different bitdepths, and colormaps).  It need only work for 24-bit RGB images with no colormap.  If you want to try this with other images beyond the ones we provide below, make sure you save the .bmp file with RLE (compression) disabled and with 24-bit colorspace.
  12. Inverting an RGB color pixel consists of reading the byte as "value" for the pixel, and replacing it with "255 - value".  This should be done for all components (red, green, blue) for each pixel.
  13. Saving a BMP file is similar to loading it.  First write the BMP_Header you loaded using fwrite, and then iteratively write each pixel using fwrite after the header.
  14. Note! There exist freely available BMP file loaders and savers with C source code on the Internet. Copying from these is cheating!  You are supposed to write the code yourself and you are required to use the structures and functions in our bmp.h and bmp.c files, you may not change any of these.

Warning

You cannot use anything like the following:

    int num_pixels = 0;
    ... /* find the number of pixels */
    int array[num_pixels]; 

You have to use malloc and free.

Compile and Execute

You will need to create a Makefile to compile your code.  You can find an introduction on Makefiles here.  You should use "gcc -Wall" instead of "gcc".  This will turn on warning messages.  Treat warning messages seriously because warnings are very likely errors.

Warning messages are often indications of errors. For this assignment, you lose 0.1 point for each warning message. The command will generate an executable file called "ex4."

To execute this program, type

./ex4 <srcfile.bmp> <dstfile.bmp>

The second argument (argv[1]) is the file to load and the third argument (argv[2]) is the file to save to (will be created).

Testcases

You can find a suite of testcases here (normal and inverted BMP files).

Submission Procedure

   Create a zip file contain the following files

  • At least 2 .c files and 1 .h file (bmp.h, bmp.c, and your own .c file with the main() function)
  • Makefile - The makefile should produced the executable "ex4".

   and then submit to the course grading website

You need to provide a user name and a password through Blackboard before submission.  The user name and the password are different from your Purdue career account.

.h Files

A .h file, short for header file,  typically contains the following

  • All the the C library files that your program will need (i.e. stdio.h, stdlib.h, etc.)
  • All constants you will need.  Constants can be defined using the #define command.  An example would be  "#define MAXLEN 102".
  • All function headers  for the function in your program. 

Once completed, your .h file should be included in your .c file.  This is done by typing the following: #include "filename.h"

Memory Management

Memory management (allocation and release) is an important part of ECE 264. You have to allocate enough memory to make your program work. You have to allocate and release memory as needed. You are not allowed to allocate a large piece of memory regardless of the input size. We will restrict stack size to prevent that. You will receve heavy penalty (50%) if your program does not release all memory (i.e. memory leak). We will use valgrind to check for memory leaks.

Grading

The maximum score for this exercise is 2.0 points.