+1 (315) 557-6473 

Implement Functions To Encode, Decode Message PPM Image In C Assignment Solution.


Instructions

Objective
Write a C assignment program to implement functions to encode, decode message ppm image.
Requirements and Specifications 
For this assignments you will have at a minimal eight files:
  1. driver.c – This is where main lives.
  2. ppm.h – I will provide this file. It will contain the prototypes of the functions I implement. These functions deal specifically with a ppm file. It will also provide the definition of two structs.
    1. One for the header.
    2. One for the pixels
  3. ppm.c – This file is where I implemented the functions listed in the ppm.h file.
  4. EncodeDecode.h – I will provide this file. It will contain additional prototypes of functions I needed to encode and decode a message in an image.
  5. EncodeDecode.c – This file is where I implement the functions listed in EncodeDecode.h
  6. utils.h – this provides the prototypes for two functions needed to check the number of command line arguments passed to the program. It also contains a function that check if the file pointers opened successfully.
  7. utils.c – this file is where I implement the functions for utils.h
  8. makefile
  9. Each of your header files (.h) must have header guards. Points will be deducted if you do not provide header guards I also removed all of the #include statements, you will need to provide these.

Screenshots of output
functions needed to encode and decode message ppm image in C language
Source Code
Driver.c
/*************************
 *Your names
 *CPSC 2310 F21 Section 00?
 *Your emails
 *************************/
#include
#include
#include "utils.h"
#include "EncodeDecode.h"
int main(int argc, char* argv[])
{
    checkArgs(argc, 2);
    FILE* in = fopen(argv[1], "r");
    checkFile(in);
    FILE* out = fopen(argv[2], "w");
    checkFile(out);
    /*This is my test message. It can be something different*/
    char* msg = "I hope this works!";
    encodeMsg(in, out, msg);
    FILE* dec = fopen(argv[2], "r");
    checkFile(dec);
    decodeMsg(dec);
    fclose(in);
    fclose(out);
    fclose(dec);
    return EXIT_SUCCESS;
}
EncodeDecode.c
/*************************
 *Your names
 *CPSC 2310 F21 Section 00?
 *Your emails
 *************************/
#include
#include
#include
#include "EncodeDecode.h"
/* Parameters: pixels - pixel_t double pointer that contains the ppm
 * pixel information.
 * header - header_t that contains the ppm header
 * Return: output - none
 * This function removes the lowest decimal digit (rounds to 0) in all
 * the pixel 2D array
 */
void removeDigit(pixel_t** pixels, header_t header)
{
    int i, j;
    // go through all pixels rows
    for (i = 0; i < header.height; i++)
    {
        // go through all pixels in row
        for (j = 0; j < header.width; j++)
        {
            // remove digit by dividing by 10 and then multiplying by 10
            pixels[i][j].r = (pixels[i][j].r / 10) * 10;
            pixels[i][j].g = (pixels[i][j].g / 10) * 10;
            pixels[i][j].b = (pixels[i][j].b / 10) * 10;
        }
    }
}
/* Parameters: in - FILE pointer pointing to the input PPM file
 * out - FILE pointer pointing to the output PPM file
 * msg - char array containing the message to be encoded
 * Return: output - none
 * This function encodes the given message using the input PPM image
 * and saves the PPM with the encoded message in the output PPM image
 */
void encodeMsg(FILE* in, FILE* out, char* msg)
{
    int i, j, x, y;
    int pixpos, binpos;
    int binary[9];
    header_t header;
    pixel_t** pixels;
    // load header from input image
    header = readHeader(in);
    // load pixels from input image
    pixels = readPixel(in, header);
    // remove the digits in all pixels
    removeDigit(pixels, header);
    // start at position 0 in image
    pixpos = 0;
    // go through all characters in message including the last zero
    for (i = 0; i <= strlen(msg); i++)
    {
        // convert character to binary
        charToBinary(msg[i], binary);
        // start at binary position 0
        binpos = 0;
        // get the 3 required pixels for saving the char
        for (j = 0; j < 3; j++)
        {
            // get pixel position x,y in image
            x = pixpos % header.width;
            y = pixpos / header.width;
            //add the bits of the char
            pixels[y][x].r += binary[binpos++];
            pixels[y][x].g += binary[binpos++];
            pixels[y][x].b += binary[binpos++];
            // advance pixel position
            pixpos++;
        }
    }
    // save file
    writeHeader(out, header);
    writePixels(out, pixels, header);
    // free all allocated memory
    freeMemory(pixels, header);
}
/* Parameters: c - character to be converted
 * bin - integer array where the binary bits will be saved
 * Return: output - none
 * This function converts the given character to a binary number of 9
 * bits. It assumes that the bin array can hold at least 9 values.
 */
void charToBinary(char c, int *bin)
{
    int i;
    // first bit is always zero (9th bit)
    bin[0] = 0;
    // repeat 8 times for the 8 bits in the char
    for (i = 0; i < 8; i++)
    {
        // if sign is 1, save a 1, otherwise save zero
        bin[i + 1] = (c < 0);
        // shift once to the left to move next bit to msb position
        c <<= 1;
    }
}
/* Parameters: bin - integer array holding a binary number
 * Return: output - character that has been converted from the binary
 * This function converts the given binary number of 9 bits.
 * to a character. It assumes that the bin array holds at least 9 values.
 */
unsigned char binToCharacter(int* bin)
{
    unsigned char c;
    int i;
    // initialize char to zero
    c = 0;
    // repeat 8 times for the 8 bits in the char (first bit is zero)
    for (i = 1; i < 9; i++)
        // shift c and save bit
        c = (c << 1) | bin[i];
    return c;
}
/* Parameters: n - integer with the bit to be saved
 * bin - integer array that will hold the binary number
 * index - integer pointer to an index
 * Return: output - none
 * This function saves the given bit in the binary number of 9 bits at the
 * given index. When the index reaches 9, the binary is converted to a
 * character and then it's printed on the screen. It assumes that the bin
 * array can hold at least 9 values and that the index pointer is not NULL
 */
void queue(int n, int* bin, int* index)
{
    unsigned char c;
    // save the digit, increment the index
    bin[(*index)++] = n;
    // if queue is full
    if (*index >= 9)
    {
        // convert binary to character
        c = binToCharacter(bin);
        // if valid char
        if (c < 255 && c > 0)
            // print character
            printf("%c", c);
        // reset position
        *index = 0;
    }
}
/* Parameters: n - character to be converted
 * bin - integer array where the binary bits will be saved
 * Return: output - none
 * This function converts the given integer to a binary number of 32
 * bits. It assumes that the bin array can hold at least 32 values.
 */
void dec2bin(int* bin, int n)
{
    int i;
    // repeat 32 times for the 32 bits in the int
    for (i = 0; i < 32; i++)
    {
        // if bit sign is 1, save a 1, otherwise save zero
        bin[i] = (n < 0);
        // shift once to the left to move next bit to msb position
        n <<= 1;
    }
}
/* Parameters: in - FILE pointer pointing to the input PPM file
 * Return: output - none
 * This function decodes a message encoded in the input PPM image
 * and prints the decoded message on the screen
 */
void decodeMsg(FILE* in)
{
    int i, j;
    int binpos;
    int binary[9];
    header_t header;
    pixel_t** pixels;
    // load header from input image
    header = readHeader(in);
    // load pixels from input image
    pixels = readPixel(in, header);
    // start at position 0 in binary
    binpos = 0;
    // go through all pixels rows
    for (i = 0; i < header.height; i++)
    {
        // go through all pixels in row
        for (j = 0; j < header.width; j++)
        {
            // get the bits of the char by getting the decimal digit and
            // passing it to queue to be printed
            queue(pixels[i][j].r % 10, binary, &binpos);
            queue(pixels[i][j].g % 10, binary, &binpos);
            queue(pixels[i][j].b % 10, binary, &binpos);
        }
    }
    // free all allocated memory
    freeMemory(pixels, header);
}
EncodeDecode.h
/*************************
 *Your names
 *CPSC 2310 F21 Section 00?
 *Your emails
 *************************/
#ifndef ENCODEDECODE_H
#define ENCODEDECODE_H
#include
#include
#include "ppm.h"
void removeDigit(pixel_t** , header_t );
void encodeMsg(FILE* in, FILE* out, char* msg);
void charToBinary(char , int *);
unsigned char binToCharacter(int*);
void queue(int, int*, int*);
void dec2bin(int*, int);
void decodeMsg(FILE*);
#endif /* ENCODEDECODE_H */
Ppm.c
/*************************
 *Your names
 *CPSC 2310 F21 Section 00?
 *Your emails
 *************************/
#include
#include
#include
#include "ppm.h"
/* Parameters: f - FILE pointer to an input ppm file
 * Return: output - header_t that contains the ppm header
 * This function reads the PPM header information from the given file.
 */
header_t readHeader(FILE* f)
{
    header_t header;
    // read the magic numbers
    fread(header.magicNum, 2, 1, f);
    // clear whitespace and comments
    ckws_comments(f);
    // read the width
    fscanf(f, "%d", &header.width);
    // clear whitespace and comments
    ckws_comments(f);
    // read the height
    fscanf(f, "%d", &header.height);
    // clear whitespace and comments
    ckws_comments(f);
    // read the max value
    fscanf(f, "%d", &header.maxVal);
    // read the last whitespace
    fgetc(f);
    return header;
}
/* Parameters: f - FILE pointer to an input ppm file
 * header - header_t that contains the ppm header
 * Return: output - pixel_t double pointer that contains the ppm
 * pixel information.
 * This function reads the PPM pixel information from the given file.
 * It allocates a 2D array to read the pixel data and returns it.
 */
pixel_t** readPixel(FILE* f, header_t header)
{
    pixel_t** pixels;
    int i;
    int j;
    int bytes;
    char buffer[2];
    // number of bytes per sample (r,g,b), 1 if < 256, 2 otherwise
    bytes = (header.maxVal < 256) ? 1 : 2;
    // allocate space for all row pointers
    pixels = (pixel_t**) malloc(header.height * sizeof(pixel_t*));
    // go through all pixels rows
    for (i = 0; i < header.height; i++)
    {
        // allocate space for all pixels in the row
        pixels[i] = (pixel_t*) malloc(header.width * sizeof(pixel_t));
        // go through all pixels in row
        for (j = 0; j < header.width; j++)
        {
            // read the red part
            fread(buffer, bytes, 1, f);
            // if maxvalue fits in 1 byte
            if (header.maxVal < 256)
                pixels[i][j].r = buffer[0];
            // if maxvalue fits in 2 bytes, first byte is msb
            else
                pixels[i][j].r = (buffer[0] << 8) | buffer[1];
            // read the green part
            fread(buffer, bytes, 1, f);
            // if maxvalue fits in 1 byte
            if (header.maxVal < 256)
                pixels[i][j].g = buffer[0];
            // if maxvalue fits in 2 bytes, first byte is msb
            else
                pixels[i][j].g = (buffer[0] << 8) | buffer[1];
            // read the blue part
            fread(buffer, bytes, 1, f);
            // if maxvalue fits in 1 byte
            if (header.maxVal < 256)
                pixels[i][j].b = buffer[0];
            // if maxvalue fits in 2 bytes, first byte is msb
            else
                pixels[i][j].b = (buffer[0] << 8) | buffer[1];
        }
    }
    return pixels;
}
/* Parameters: f - FILE pointer to an output ppm file
 * header - header_t that contains the ppm header
 * Return: output - none
 * This function writes the PPM header information into the given file.
 */
void writeHeader(FILE* f, header_t header)
{
    // write the magic numbers
    fprintf(f, "%c%c\n", header.magicNum[0], header.magicNum[1]);
    // write the width x height
    fprintf(f, "%d %d\n", header.width, header.height);
    // write the max value and newline
    fprintf(f, "%d\n", header.maxVal);
}
/* Parameters: f - FILE pointer to an output ppm file
 * pixels - pixel_t double pointer that contains the ppm
 * pixel information.
 * header - header_t that contains the ppm header
 * Return: output - none
 * This function writes the PPM pixel information into the given file.
 */
void writePixels(FILE* f, pixel_t** pixels, header_t header)
{
    int i;
    int j;
    int bytes;
    char buffer[2];
    // number of bytes per sample (r,g,b), 1 if < 256, 2 otherwise
    bytes = (header.maxVal < 256) ? 1 : 2;
    // go through all pixels rows
    for (i = 0; i < header.height; i++)
    {
        // go through all pixels in row
        for (j = 0; j < header.width; j++)
        {
            // if maxvalue fits in 1 byte
            if (bytes == 1)
                buffer[0] = pixels[i][j].r;
            // if maxvalue fits in 2 bytes, first byte is msb
            else
            {
                buffer[0] = pixels[i][j].r >> 8;
                buffer[1] = pixels[i][j].r;
            }
            // write the red part
            fwrite(buffer, bytes, 1, f);
            // if maxvalue fits in 1 byte
            if (bytes == 1)
                buffer[0] = pixels[i][j].g;
            // if maxvalue fits in 2 bytes, first byte is msb
            else
            {
                buffer[0] = pixels[i][j].g >> 8;
                buffer[1] = pixels[i][j].g;
            }
            // write the green part
            fwrite(buffer, bytes, 1, f);
            // if maxvalue fits in 1 byte
            if (bytes == 1)
                buffer[0] = pixels[i][j].b;
            // if maxvalue fits in 2 bytes, first byte is msb
            else
            {
                buffer[0] = pixels[i][j].b >> 8;
                buffer[1] = pixels[i][j].b;
            }
            // write the blue part
            fwrite(buffer, bytes, 1, f);
        }
    }
}
/* Parameters: f - FILE pointer pointing to a ppm input file
 * Return: output - none
 * This function removes all the whitespace and comments found from
 * the current position.
 */
void ckws_comments (FILE *f)
{
    int c;
    while (1)
    {
        // ignore all whitespace
        while (isspace(c = fgetc(f)));
        // if a comment
        if (c == '#')
            // read until newline
            while ((c = fgetc(f)) != '\n');
        // if not a comment
        else
        {
            // undo the last read
            ungetc(c, f);
            // exit the loop to return
            break;
        }
    }
}
/* Parameters: pixels - pixel_t double pointer that contains the ppm
 * pixel information.
 * header - header_t that contains the ppm header
 * Return: output - none
 * This function frees all the allocated memory used by the pixel 2D array
 */
void freeMemory(pixel_t** pixels, header_t header)
{
    int i;
    // go through all pixels rows
    for (i = 0; i < header.height; i++)
        // free space for all pixels
        free(pixels[i]);
    // free space for all rows
    free(pixels);
}
Ppm.h
/*************************
 *Your names
 *CPSC 2310 F21 Section 00?
 *Your emails
 *************************/
#ifndef PPM_H
#define PPM_H
#include
typedef struct
{
    unsigned char r;
    unsigned char g;
    unsigned char b;
}pixel_t;
typedef struct
{
    char magicNum[3];
    int width;
    int height;
    int maxVal;
}header_t;
header_t readHeader(FILE*);
pixel_t** readPixel(FILE*, header_t);
void writeHeader(FILE*, header_t);
void writePixels(FILE*, pixel_t**, header_t);
void ckws_comments (FILE *);
void freeMemory(pixel_t**, header_t);
#endif /* PPM_H */
Utils.c
/*************************
 *Your names
 *CPSC 2310 F21 Section 00?
 *Your emails
 *************************/
#include
#include
#include "utils.h"
/* Parameters: argc - number of command line arguments
 * n - required number of command line arguments
 * Return: output - none
 * This function verifies that the number of command line arguments
 * is at least the required n. If not, it exits with error.
 */
void checkArgs(int argc, int n)
{
    // if not enough arguments, exit with error
    if (argc < n)
    {
        fprintf(stderr, "Error: Not enough command line arguments\n");
        exit(EXIT_FAILURE);
    }
}
/* Parameters: f - FILE pointer pointing to a file that has been opened
 * Return: output - none
 * This function verifies that the file has been opened coorrectly.
 * If not, it exits with error.
 */
void checkFile(FILE* f)
{
    // if file was not opened, exit with error
    if (f == NULL)
    {
        fprintf(stderr, "Error: Unable to open file\n");
        exit(EXIT_FAILURE);
    }
}
Utils.h
/*************************
 *Your names
 *CPSC 2310 F21 Section 00?
 *Your emails
 *************************/
#ifndef UTILS_H
#define UTILS_H
#include
void checkArgs(int, int);
void checkFile(FILE*);
#endif /* UTILS_H */