+1 (315) 557-6473 

Instant GIF Image Viewer Homework Help

Students who need GIF image viewer homework help can now breathe a sigh of relief. In an instant, they can send us the details of their programming homework and our experts will handle it on their behalf. Our GIF image viewer homework help service is your best chance of scoring a straight A, beating your stringent deadline and getting in the good books of your professor. Do not wait until it is too late. Hire our GIF image viewer project helpers ASAP!

A Program that Display’s GIF Image Viewer

The Graphics Interchange Format (GIF) image file is widely used to store, send, and display images on a computer. It is known for compressing files into a smaller size without losing any image quality. We call this lossless compression.
In this homework, we ask that you open a GIF file and display its contents onto the console. The official GIF documentation is on the blackboard (spec-gif89a.txt) or at https://www.w3.org/Graphics/GIF/spec-gif87.txt. More information and guidelines may be found on different websites. This is real-world homework, meaning that you are working on a practical problem. We expect that all students will use the internet and textbook resources to learn concepts needed for this homework, which may have not been tested in the drills.
Code your program to display GIF IMAGE VIEWER at the start of the program. Then ask the user to Enter the file name: You should then open the file using the fstream data type.
Using the fstream data type, read each section of the file, including the header, logical screen descriptor, global color table, image descriptor, table-based image data, and trailer. You do not need to implement the comment extension, plain text extension, or application extension sections; if they are present in a file, skip them.
Each section of the GIF file must be decoded according to the GIF documentation. Based on the described format, read the file and display its contents in an organized manner (see Example Program Output). As you enter each section of the GIF file, display that you have identified the section (e.g., ">> read header") and then proceed with reading its specific contents and displaying it on the console.
When you reach the Table Based Image data, you will need to extract the image from the LZW data compression format, which has been slightly modified for use in GIF. The algorithm is well described on different websites:
https://www.w3.org/Graphics/GIF/spec-gif89a.txt
https://en.wikipedia.org/wiki/GIF
http://giflib.sourceforge.net/whatsinagif/index.html
Once you have extracted the image data, display its indices; and then its red, green, and blue pixel values. Your objective is to reproduce the Program Output shown on the next page.

Program Output

GIF IMAGE VIEWER
Enter file name:
  squares.gif
  >> read header
Header:
signature: GIF
  version: 87a
  >> read logical screen descriptor
Logical Screen Descriptor:
width: 10
height: 10
global ct flag: 1
color res: 2
sort flag: 0
global ct size: 1
background color i: 0
aspect ratio: 0  

>> read global color table
Global Color Table:
#0 255 255 255
#1 255 0 0
#2 0 0 255
#3 0 255 0

>> read image descriptor

Image Descriptor: 0
left position:
top position: 0
image width: 10
image height: 10
local ct flag: 0
interlace flag: 0
sort flag: 0
reserved: 0
local ct size: 0
>> read table based image data
  Table Based Image Data:
  LZW Minimum Code Size: 2
Color Table: 255
#0 255 255
#1 255 0 0
#2 0 0 255
#3 0 255 0
Initial Code Table:
#0 0    
#1 1    

l#2 2

#3 3

#4 -1

#5 -2

Block Bytes:

block size: 26

byte #0: 132

byte #1: 143

byte #2: 16

byte #3: 27

byte #4: 226

byte #5: 98

byte #6: 88

byte #7: 123

byte #8: 145

byte #9: 61

byte #10: 168

byte #11: 44

byte #12: 5

byte #13: 163

byte #14: 15

byte #15: 105

byte #16: 120

byte #17: 31

byte #18: 19

byte #19: 122

byte #20: 32

byte #21: 103

byte #22: 146

byte #23: 73

byte #24: 82

byte #25: 0

Code Stream:

code #0: 4

code #1: 0

code #2: 6

code #3: 7

code #4: 8

code #5: 0

code #6: 1

code #7: 11

code #8: 1

code #9: 2

code #10: 14

code #11: 2

code #12: 6

code #13: 12

code #14: 13

code #15: 15

code #16: 17

code #17: 12

code #18: 15

code #19: 16

code #20: 10

code #21: 22

code #22: 20

code #23: 0

code #24: 3

code #25: 29

Version 1.00

code #26: 3

code #27: 18

code #28: 6

code #29: 30

code #30: 31

code #31: 12

code #32: 33

code #33: 30

code #34: 32

code #35: 28

code #36: 38

code #37: 36

code #38: 9

code #39: 9

  code #40: 5

Index Stream:

i_stream size: 100

0000000000

0111122220

0111122220

0111122220

0111122220

0333311110

0333311110

0333311110

0333311110

0000000000

Image Data - Red Channel 255 255 255 255
255 255 255 255 255 255
255 255 255 255 255 0 0 0 0 255
255 255 255 255 255 0 0 0 0 255
255 255 255 255 255 0 0 0 0 255
255 255 255 255 255 0 0 0 0 255
255 0 0 0 0 255 255 255 255 255
255 0 0 0 0 255 255 255 255 255
255 0 0 0 0 255 255 255 255 255
255 0 0 0 0 255 255 255 255 255
255 255 255 255 255 255 255 255 255 255
Image Data - Green Channel 255 255 255 255
255 255 255 255 255 255
255 0 0 0 0 0 0 0 0 255
255 0 0 0 0 0 0 0 0 255
255 0 0 0 0 0 0 0 0 255
255 0 0 0 0 0 0 0 0 255
255 255 255 255 255 0 0 0 0 255
255 255 255 255 255 0 0 0 0 255
255 255 255 255 255 0 0 0 0 255
255 255 255 255 255 0 0 0 0 255
255 255 255 255 255 255 255 255 255 255
Image Data - Blue Channel 255 255 255 255
255 255 255 255 255 255
255 0 0 0 0 255 255 255 255 255
255 0 0 0 0 255 255 255 255 255
255 0 0 0 0 255 255 255 255 255
255 0 0 0 0 255 255 255 255 255
255 0 0 0 0 0 0 0 0 255
255 0 0 0 0 0 0 0 0 255
   
255 0 0 0 0 0 0 0 0 255
255 0 0 0 0 0 0 0 0 255
255 255 255 255 255 255 255 255 255 255

>> read trailer

  >> program ended

Code Solution

#include

#include

#include

#include

#include

using namespace std;

// Read a 2 byte integer from file

int read2bytes(ifstream &file)

{

    char bytes[2];

    int val;

    file.read(bytes,2);

    val = ((static_cast(bytes[1]) & 0xFF) << 8);

    val |= static_cast(bytes[0]) & 0xFF;

    return val;

}

// print the color table

void print_color_table(char *ctable, int ctsize)

{

    for (int i = 0; i < ctsize; i++)

    {

        cout << "#" << i << " ";

        for (int j = 0; j < 3; j++)

        {

            cout << " " << (static_cast(ctable[i * 3 + j]) & 0xFF);

        }

        cout << endl;

    }

}

// convert the block bytes to an index stream

vector get_index_stream(vector data, int bits, vector > codes)

{

    vector istream;

    int initbits = bits;

    int bit = 0;

    int bitpos = 0;

    unsigned code = 0;

    unsigned i = 0;

    int n = 0;

    unsigned startcode = codes.size() - 2;

    unsigned endcode = codes.size() - 1;

    // read initializer

    for (i = 0; i < data.size() && bit < bits; bit++)

    {

        int b = (data[i] & (1 << bitpos))? 1 : 0;

        code |= (b << bit);

        bitpos++;

        if (bitpos == 8)

        {

            bitpos = 0;

            i++;

        }

    }

    cout << "code #" << (n++) << ": " << code << endl;

    bool first = true;

    unsigned prevcode = code;

    code = 0;

    bit = 0;

    for (; i < data.size(); )

    {

        int b = (data[i] & (1 << bitpos))? 1 : 0;

        code |= (b << bit);

        bit++;

        if (bit == bits) // a new code is complete

        {

            cout << "code #" << (n++) << ": " << code << endl;

            if (first) // first code

            {

                for (unsigned j = 0; j < codes[code].size(); j++)

                    istream.push_back(codes[code][j]);

                first = false;

            }

            else

            {

                if (code == startcode) // restart code table

                {

                    codes.resize(endcode + 1); // remove all but initial codes

                    bits = initbits; // reset code size

                    first = true;

                }

                else if (code == endcode)

                    break;

                else if (code < codes.size()) // if in table

                {

                    for (unsigned j = 0; j < codes[code].size(); j++)

                        istream.push_back(codes[code][j]);

                    int k = codes[code][0];

                    vector prevk = codes[prevcode];

                    prevk.push_back(k);

                    codes.push_back(prevk);

                }

                else

                {

                    int k = codes[prevcode][0];

                    for (unsigned j = 0; j < codes[prevcode].size(); j++)

                        istream.push_back(codes[prevcode][j]);

                    istream.push_back(k);

                    vector prevk = codes[prevcode];

                    prevk.push_back(k);

                    codes.push_back(prevk);

                }

                if (codes.size() >= static_cast(1 << bits)) // if size reached number of bits

                {

                    bits++; // use one more bit

                    if (bits > 12) // limit to 12 bits

                        bits = 12;

                }

            }

            prevcode = code;

            code = 0;

            bit = 0;

        }

        bitpos++;

        if (bitpos == 8)

        {

            bitpos = 0;

            i++;

        }

    }

    return istream;

}

// read graphic control extension

bool read_graphic_ctl_ext(ifstream &file)

{

    char block[6];

    file.read(block, 6); // read whole block

    if (!file)

    {

        cout << "Error: error reading file" << endl;

        return false;

    }

    if (block[5] != 0)

    {

        cout << "Error: Invalid block terminator" << endl;

        return false;

    }

    return true;

}

// read all the data subblocks until a block terminator is found

bool read_subblocks(ifstream &file)

{

    int size = -1;

    while (size != 0)

    {

        char byte;

        file.read(&byte, 1); // read size

        if (!file)

            return false;

        size = static_cast(byte) & 0xFF;

        if (size != 0)

        {

            char block[size];

            file.read(block, size); // read block

            if (!file)

                return false;

        }

    }

    return true;

}

// read plaintext extension

bool read_plaintext(ifstream &file)

{

    char block[13];

    file.read(block, 13); // read whole block

    if (!read_subblocks(file)) // read all subblocks

    {

        cout << "Error: Invalid block data" << endl;

        return false;

    }

    return true;

}

// read application extension

bool read_application(ifstream &file)

{

    char block[12];

    file.read(block, 12); // read whole block

    if (!read_subblocks(file)) // read all subblocks

    {

        cout << "Error: Invalid block data" << endl;

        return false;

    }

    return true;

}

// read comment extension

bool read_comment(ifstream &file)

{

    if (!read_subblocks(file)) // read all subblocks

    {

        cout << "Error: Invalid block data" << endl;

        return false;

    }

    return true;

}

// print the given color channel (0=R, 1=G, 2=B) of the image using the given

// index stream and color table

void print_image_channel(int wid, int hei, vector istream, char *ctable, int channel)

{

    for (int i = 0; i < hei; i++)

    {

        for (int j = 0; j < wid; j++)

        {

            int pos = istream[i * wid + j];

            cout << setw(5) << left << (static_cast(ctable[pos * 3 + channel]) & 0xFF);

        }

        cout << endl;

    }

}

// read an image

bool read_image(ifstream &file, char *ctable, int ctsize)

{

    cout << ">> read image descriptor\n" << endl;

    int lpos = read2bytes(file);

    int rpos = read2bytes(file);

    int wid = read2bytes(file);

    int hei = read2bytes(file);

    char packed;

    file.read(&packed, 1);

    if (!file)

    {

        cout << "Error: Invalid image descriptor" << endl;

        return false;

    }

    int localct = ((packed >> 7) & 1);

    int lctsize = (packed & 7);

    cout << "Image Descriptor:" << endl;

    cout << "left position: " << lpos << endl;

    cout << "top position: " << rpos << endl;

    cout << "image width: " << wid << endl;

    cout << "image height: " << hei << endl;

    cout << "local ct flag: " << localct << endl;

    cout << "interlace flag: " << ((packed >> 6) & 1) << endl;

    cout << "sort flag: " << ((packed >> 5) & 1) << endl;

    cout << "reserved: " << ((packed >> 3) & 3) << endl;

    cout << "local ct size: " << ctsize << endl;

    cout << endl;

    if (localct == 1) // if local color table

    {

        int ltablesize = 3 * (1 << (lctsize + 1));

        char loctable[ltablesize];

        file.read(loctable, ltablesize);

        if (!file)

        {

            cout << "Error: Invalid local color table" << endl;

            return false;

        }

    }

    char minlzw;

    cout << ">> read table based image data\n" << endl;

    cout << "Table Based Image Data:\n" << endl;

    file.read(&minlzw, 1);

    if (!file)

    {

        cout << "Error: Invalid image data" << endl;

        return false;

    }

    cout << "LZW Minimum Code Size: " << (static_cast(minlzw) & 0xFF) << "\n" << endl;

    cout << "Color Table:" << endl;

    print_color_table(ctable, ctsize/3);

    cout << endl;

    cout << "Initial Code Table:" << endl;

    vector > code;

    for (int i = 0; i < ctsize/3; i++)

    {

        vector indices;

        indices.push_back(i);

        code.push_back(indices);

    }

    // push dummy entries if number of colors < 2^lzw size

    for (int i = ctsize/3; i < (1 << minlzw); i++)

    {

        vector indices;

        indices.push_back(0);

        code.push_back(indices);

    }

    vector i1, i2;

    i1.push_back(-1);

    i2.push_back(-2);

    code.push_back(i1);

    code.push_back(i2);

    for (unsigned i = 0; i < code.size(); i++)

    {

        cout << "#" << i << " " << code[i][0] << endl;

    }

    cout << endl;

    int size = -1;

    vector data;

    while (size != 0) // read all data blocks

    {

        char byte;

        file.read(&byte, 1); // read size

        if (!file)

        {

            cout << "Error: Invalid image data block" << endl;

            return false;

        }

        size = static_cast(byte) & 0xFF;

        if (size != 0)

        {

            char block[size];

            file.read(block, size); // read block

            if (!file)

            {

                cout << "Error: Invalid image data block" << endl;

                return false;

            }

            cout << "Block bytes:" << endl;

            cout << "block size: " << size << endl;

            for (int i = 0; i < size; i++)

            {

                int byte = static_cast(block[i]) & 0xFF;

                data.push_back(byte);

                cout << "byte #" << i << ": " << byte << endl;

            }

            cout << endl;

        }

    }

    cout << "Code Stream:" << endl;

    vector istream = get_index_stream(data, minlzw + 1, code);

    cout << endl;

    cout << "Index Stream:" << endl;

    cout << "i_stream size: " << istream.size() << endl;

    for (int k = 0, j = 0; j < hei; j++)

    {

        for (int i = 0; i < wid; i++)

        {

            cout << istream[k++];

        }

        cout << endl;

    }

    cout << endl;

    cout << "Image Data - Red Channel" << endl;

    print_image_channel(wid, hei, istream, ctable, 0);

    cout << endl;

    cout << "Image Data - Green Channel" << endl;

    print_image_channel(wid, hei, istream, ctable, 1);

    cout << endl;

    cout << "Image Data - Blue Channel" << endl;

    print_image_channel(wid, hei, istream, ctable, 2);

    cout << endl;

    return true;

}

int main()

{

    cout << "GIF IMAGE VIEWER\n" << endl;

    cout << "Enter file name:" << endl;

    string filename;

    cin >> filename;

    cout << endl;

    ifstream file(filename.c_str(), ifstream::binary);

    if (!file.is_open())

    {

        cout << "Error: Unable to open file: \"" << filename << "\"" << endl;

        return 1;

    }

    cout << ">> read header\n" << endl;

    char header[6];

    file.read(header, 6);

    if (header[0] != 'G' || header[1] != 'I' || header[2] != 'F') //if not gif

    {

        cout << "Error: File is not a GIF" << endl;

        return 1;

    }

    cout << "Header:" << endl;

    cout << "signature: ";

    for (int i = 0; i < 3; i++)

        cout << header[i];

    cout << endl;

    cout << "version: ";

    for (int i = 0; i < 3; i++)

        cout << header[i + 3];

    cout << "\n" << endl;

    cout << ">> read logical screen descriptor\n" << endl;

    short width, height;

    char packed, bgcolor, ratio;

    width = read2bytes(file);

    height = read2bytes(file);

    file.read(&packed, 1);

    file.read(&bgcolor, 1);

    file.read(&ratio, 1);

    int globalct = ((packed >> 7) & 1);

    int ctsize = (packed & 7);

    cout << "Logical Screen Descriptor:" << endl;

    cout << "width: " << width << endl;

    cout << "height: " << height << endl;

    cout << "global ct flag: " << globalct << endl;

    cout << "color res: " << ((packed >> 4) & 7) << endl;

    cout << "sort flag: " << ((packed >> 3) & 1) << endl;

    cout << "global ct size: " << ctsize << endl;

    cout << "background color i: " << (static_cast(bgcolor) & 0xFF) << endl;

    cout << "aspect ratio: " << (static_cast(ratio) & 0xFF) << endl;

    cout << endl;

    int tablesize = 3 * (1 << (ctsize + 1));

    char ctable[tablesize];

    if (globalct == 1) // if global color table

    {

        cout << ">> read global color table\n" << endl;

        file.read(ctable, tablesize);

        cout << "Global Color Table:" << endl;

        print_color_table(ctable, tablesize/3);

        cout << endl;

    }

    char ident = 0;

    char label = 0;

    // read data stream until trailer

    while (ident != 0x3B)

    {

        file.read(&ident, 1); // read block identifier/label

        if (!file)

        {

            cout << "Error: Invalid reading data stream" << endl;

            return 1;

        }

        switch (ident)

        {

        case 0x2c: // image

            if (!read_image(file, ctable, tablesize))

                return 1;

            break;

        case 0x21: // extension block

            file.read(&label, 1); // read extension block label

            if (!file)

            {

                cout << "Error: Invalid reading extension block" << endl;

                return 1;

            }

            switch (static_cast(label) & 0xFF)

            {

            case 0xF9:

                if (!read_graphic_ctl_ext(file))

                    return 1;

                break;

            case 0x01: // plaintext

                if (!read_plaintext(file))

                    return 1;

                break;

            case 0xFF: // application

                if (!read_application(file))

                    return 1;

                break;

            case 0xFE: // comment

                if (!read_comment(file))

                    return 1;

                break;

            default:

                cout << "Error: Invalid extension block" << endl;

                return 1;

            }

            break;

        case 0x3B: // trailer

            cout << ">> read trailer\n" << endl;

            break;

        default:

            cout << "Error: Invalid block" << endl;

            return 1;

        }

    }

    cout << ">> program ended" << endl;

    file.close();

    return 0;

}

Related Blogs