A Program that Display’s GIF Image Viewer
Program Output
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 |
#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 |
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
val |= static_cast
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
}
cout << endl;
}
}
// convert the block bytes to an index stream
vector
{
vector
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.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.push_back(k);
codes.push_back(prevk);
}
if (codes.size() >= static_cast
{
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
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
{
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
}
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
cout << "Color Table:" << endl;
print_color_table(ctable, ctsize/3);
cout << endl;
cout << "Initial Code Table:" << endl;
vector
for (int i = 0; i < ctsize/3; i++)
{
vector
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.push_back(0);
code.push_back(indices);
}
vector
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
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
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
data.push_back(byte);
cout << "byte #" << i << ": " << byte << endl;
}
cout << endl;
}
}
cout << "Code Stream:" << endl;
vector
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
cout << "aspect ratio: " << (static_cast
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
{
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;
}