Download | Plain Text | No Line Numbers
- /**
- * @module CPixmap
- * @author Guenther Neuwirth (0626638), Manuel Mausz (0728348)
- * @brief Implementation of CFile handling Windows Bitmaps.
- * @date 27.04.2009
- */
-
- #include <sstream>
- #include <iomanip>
- #include <vector>
- #include <boost/algorithm/string/split.hpp>
- #include <boost/algorithm/string.hpp>
- #include <boost/lexical_cast.hpp>
- #include <assert.h>
- #ifdef DEBUG
- # include <iostream>
- #endif
- #include "cpixmap.h"
- #include "cpixelformat_indexed8.h"
-
- using namespace std;
- using namespace boost;
-
- CPixmap::CPixmap()
- : m_imagename("")
- {
- m_types.insert("XPM");
-
- /* add our handlers */
- m_handlers.insert(new CPixelFormat_Indexed8(this));
- }
-
- /*----------------------------------------------------------------------------*/
-
- std::string CPixmap::getLine(std::ifstream& in, bool ignore_comments)
- {
- string line("");
- while(!in.eof() && in.good())
- {
- getline(in, line);
- trim(line);
- /* ignore simple ansi c comments. only one-liners */
- if (ignore_comments && line.find_first_of("/*") == 0)
- continue;
- if (!line.empty())
- break;
- }
- return line;
- }
-
- /*----------------------------------------------------------------------------*/
-
- std::string CPixmap::getCArrayLine(std::ifstream& in)
- {
- string line = getLine(in, true);
- if (line.empty())
- return line;
-
- /* this stuff isn't correct too, but we are no c-parser anyway */
- if (line[0] != '"')
- throw FileError("Pixmap array has invalid c-syntax.");
- if (line[line.length() - 1] != ',' && line[line.length() - 1] != '}')
- throw FileError("Pixmap array has invalid c-syntax.");
- size_t end = line.find_last_of("\"");
- if (end == string::npos)
- throw FileError("Pixmap array has invalid c-syntax.");
-
- return line.substr(1, end - 1);
- }
-
- /*----------------------------------------------------------------------------*/
-
- void CPixmap::read(std::ifstream& in)
- {
- /*
- * <C-Comment> XPM <C-Comment>
- * static char * <pixmap_name>[] = {
- * <Values>
- * <Colors>
- * <Pixels>
- * <Extensions>
- * };
- */
-
- string line, tmp;
- stringstream istr;
- std::vector<std::string> list;
- m_fileheader._XPMEXT = false;
- m_fileheader._HOTSPOT = false;
-
- /* get pixelformat instance first */
- m_pixelformat = NULL;
- set<CPixelFormat *>::iterator it;
- for (it = m_handlers.begin(); it != m_handlers.end(); it++)
- {
- /* we only have one! */
- m_pixelformat = *it;
- break;
- }
- if (m_pixelformat == NULL)
- throw FileError("Pixmap color mode is not supported.");
-
- /* first line has to be PIXMAP_IDENTIFIER */
- line = getLine(in, false);
- if (line != PIXMAP_IDENTIFIER)
- throw FileError("Pixmap has no identifier.");
-
- /* second line is a c array. we don't do much syntax checking */
- line = getLine(in);
- istr.str(line);
- while(m_imagename.empty() && !istr.eof() && istr.good())
- {
- size_t end;
- istr >> tmp;
- if ((end = tmp.find_first_of("[]")) != string::npos)
- {
- /* <xxx>*<imagename>[]<yyy> */
- size_t start = tmp.find_first_of('*');
- start = (start == string::npos) ? 0 : start + 1;
- m_imagename = tmp.substr(start, end - start);
- }
- }
- if (m_imagename.empty())
- throw FileError("Pixmap has no imagename.");
-
- /* additional: check "{" exists */
- assert(!line.empty());
- if (line[line.length() - 1] != '{')
- throw FileError("Pixmap array has no opening bracket.");
-
- /* parse <Values>-section */
- line = getCArrayLine(in);
- if (line.empty())
- throw FileError("Pixmap has no Values-section.");
- algorithm::split(list, line, is_any_of(" \t"));
- if (list.size() < 4)
- throw FileError("Pixmap has invalid Values-section.");
- try
- {
- m_fileheader.width = lexical_cast<uint32_t>(list[0]);
- m_fileheader.height = lexical_cast<uint32_t>(list[1]);
- m_fileheader.nColor = lexical_cast<uint32_t>(list[2]);
- m_fileheader.nChar = lexical_cast<uint32_t>(list[3]);
-
- if (list.size() > 4)
- {
- if (list.size() >= 6)
- {
- m_fileheader._HOTSPOT = true;
- m_fileheader.xHotspot = lexical_cast<uint32_t>(list[4]);
- m_fileheader.yHotspot = lexical_cast<uint32_t>(list[5]);
- }
- if (list.size() != 6)
- {
- if (list[list.size() - 1] != "XPMEXT")
- throw FileError("Unknown parameter count in Values-Section.");
- else
- m_fileheader._XPMEXT = true;
- }
- }
- }
- catch(bad_lexical_cast& ex)
- {
- throw FileError("Value of Values-section is invalid: " + string(ex.what()));
- }
-
- /* parse <Colors>-table */
- string character;
- /* map[id][colortype] = color */
- map<string, map<string, CPixelFormat::RGBPIXEL *> > colors;
- /* map[id] = indices */
- map<string, uint32_t> colornr;
- uint32_t index = 0;
- for(uint32_t i = 0; i < m_fileheader.nColor; i++)
- {
- line = getCArrayLine(in);
- if (line.empty())
- throw FileError("Pixmap has missing colortable-entry.");
- algorithm::split(list, line, is_any_of(" \t"));
- if (list.size() < 3)
- throw FileError("Pixmap colortable-entry is invalid.");
-
- /* read pixel character */
- character = list[0];
- if (character.length() != m_fileheader.nChar)
- throw FileError("Pixmap colorcharacter is invalid.");
- if (colors.find(character) != colors.end())
- throw FileError("Duplicate colorcharacter found.");
-
- /* read colors */
- if ((list.size() - 1) % 2 != 0)
- throw FileError("Pixmap color entrys are invalid.");
- for(uint32_t j = 1; j < list.size(); j = j + 2)
- {
- /* we only support hex-color notations */
- if (list[j + 1].length() != 7)
- throw FileError("Pixmap color value is invalid.");
- if (list[j + 1].at(0) != '#')
- throw FileError("Pixmap color table value is not hexadecimal.");
-
- /* we only support c-colors! - remove only if you free the pixels */
- if (list[j] != "c")
- continue;
-
- CPixelFormat::RGBPIXEL *pixel = new CPixelFormat::RGBPIXEL;
- pixel->red = strtoul(list[j + 1].substr(1, 2).c_str(), NULL, 16);
- pixel->green = strtoul(list[j + 1].substr(3, 2).c_str(), NULL, 16);
- pixel->blue = strtoul(list[j + 1].substr(5, 2).c_str(), NULL, 16);
- colors[ character ][ list[j] ] = pixel;
- }
-
- /* we only support c-colors! */
- if (colors[ character ].find("c") == colors[ character ].end())
- throw FileError("Pixmap color entry has missing c-value.");
-
- /* add pixel to colortable */
- colornr[ character ] = index;
- m_colortable[ index ] = colors[ character ]["c"];
- index++;
- }
-
- /* read pixel data */
- if (getPixelDataSize() > 0)
- {
- if (m_pixeldata != NULL)
- delete[] m_pixeldata;
- m_pixeldata = new uint8_t[getPixelDataSize()];
-
- for (uint32_t y = 0; y < getHeight(); y++)
- {
- line = getCArrayLine(in);
- if (line.empty())
- throw FileError("Pixmap has no pixel data.");
- if (line.length() != getWidth())
- throw FileError("Pixmap pixeldata width is larger than header width.");
-
- /* convert color identifier to our own identifiers */
- for(uint32_t x = 0; x < getWidth(); x++)
- {
- character = line.substr(x * m_fileheader.nChar, m_fileheader.nChar);
- assert(!character.empty());
- if (colornr.find(character) == colornr.end())
- throw FileError("Pixel has no reference in colortable.");
-
- uint32_t offset = y * getWidth() + x;
-
- /* boundary check */
- if (offset * sizeof(uint32_t) + sizeof(uint32_t) > getPixelDataSize())
- throw FileError("Pixel position is out of range.");
-
- *((uint32_t *)m_pixeldata + offset) = colornr[ character ];
- }
- }
- }
-
- /* get extension */
- if (m_fileheader._XPMEXT)
- getline(in, m_fileheader.extension, '}');
- if (!in.good())
- throw FileError("Pixmap array isn't closed properly.");
-
- /* set rowsize */
- m_rowsize = sizeof(uint32_t) * getWidth();
- }
-
- /*----------------------------------------------------------------------------*/
-
- const std::string CPixmap::getXPMColorID(unsigned int index, unsigned int length)
- {
- static const char code[] = PIXMAP_COLORCHARS;
- assert(strlen(code) > 0);
- assert(length > 0);
- string str("");
- for(unsigned int i = length - 1; i > 0; i--)
- {
- str += code[index % strlen(code)];
- index /= strlen(code);
- }
- str += code[index];
- assert(!str.empty());
- return str;
- }
-
- /*----------------------------------------------------------------------------*/
-
- void CPixmap::write(std::ofstream& out)
- {
- m_fileheader.nColor = m_colortable.size();
- m_fileheader.nChar = m_fileheader.nColor / strlen(PIXMAP_COLORCHARS) + 1;
-
- /* header comment */
- out << PIXMAP_IDENTIFIER << endl;
-
- /* variables*/
- assert(!m_imagename.empty());
- out << "static char * " << m_imagename << "[] = {" << endl;
- out << "\"" << m_fileheader.width << " " << m_fileheader.height
- << " " << m_fileheader.nColor << " " << m_fileheader.nChar;
-
- /* optional values */
- if (m_fileheader._HOTSPOT)
- out << " " << m_fileheader.xHotspot << " " << m_fileheader.yHotspot;
- if (m_fileheader._XPMEXT)
- out << " " << "XPMEXT";
- out << "\"," << endl;
-
- /* color table */
- map<uint32_t, CPixelFormat::RGBPIXEL *>::iterator it;
- for (it = m_colortable.begin(); it != m_colortable.end(); it++)
- {
- out << "\"" << getXPMColorID((*it).first, m_fileheader.nChar);
- /* we only support c-colors! */
- out << "\tc #";
- out << setfill('0') << setw(2) << hex << uppercase << (*it).second->red
- << setfill('0') << setw(2) << hex << uppercase << (*it).second->green
- << setfill('0') << setw(2) << hex << uppercase << (*it).second->blue;
- out << "\"," << endl;
- }
-
- /* pixel data */
- for (uint32_t y = 0; y < getHeight(); y++)
- {
- out << "\"";
- for(uint32_t x = 0; x < getWidth(); x++)
- {
- uint32_t offset = y * getWidth() + x;
-
- /* boundary check */
- if (offset * sizeof(uint32_t) + sizeof(uint32_t) > getPixelDataSize())
- throw FileError("Pixel position is out of range.");
-
- uint32_t color = *((uint32_t *)m_pixeldata + offset);
-
- if ((it = m_colortable.find(color)) == m_colortable.end())
- throw FileError("Pixel has no reference in colortable.");
- out << getXPMColorID((*it).first, m_fileheader.nChar);
- }
- out << "\"," << endl;
- }
-
- /* extension */
- if (m_fileheader._XPMEXT)
- out << m_fileheader.extension;
-
- out <<"};";
- }
-
- /*----------------------------------------------------------------------------*/
-
- #ifdef DEBUG
- void CPixmap::dump(std::ostream& out)
- {
- /* values*/
- cout << "[XPM Header Values]" << endl
- << "width=" << m_fileheader.width << endl
- << "height=" << m_fileheader.height << endl
- << "nColor=" << m_fileheader.nColor << endl
- << "nChar=" << m_fileheader.nChar << endl
- << "Hotspot=" << m_fileheader.xHotspot << endl
- << "yHotspot=" << m_fileheader.yHotspot << endl
- << "_HOTSPOT=" << m_fileheader._HOTSPOT << endl
- << "_XPMEXT=" << m_fileheader._XPMEXT << endl
- << "extension=" << m_fileheader.extension << endl
- << endl;
-
- /* colors*/
- map<uint32_t, CPixelFormat::RGBPIXEL *>::iterator it;
- cout << "[Color Table]" << endl;
- for (it = m_colortable.begin(); it != m_colortable.end(); it++)
- {
- out << (*it).first << ": "
- << setfill('0') << setw(3) << (*it).second->red << " "
- << setfill('0') << setw(3) << (*it).second->green << " "
- << setfill('0') << setw(3) << (*it).second->blue << " "
- << endl;
- }
- }
- #endif
-
- /* vim: set et sw=2 ts=2: */
-