/** * @module cbitmap * @author Guenther Neuwirth (0626638), Manuel Mausz (0728348) * @brief Abstract implementation of CFile handling Bitmaps. * @date 17.04.2009 */ #include #include #include #include #include "cbitmap.h" using namespace std; /*----------------------------------------------------------------------------*/ CBitmap::~CBitmap() { /* delete pixeldata */ if (m_pixeldata != NULL) delete[] m_pixeldata; m_pixeldata = NULL; /* delete pixelformat handlers */ set::iterator it; for (it = m_handlers.begin(); it != m_handlers.end(); it++) delete *it; m_pixelformat = NULL; /* delete colortable content */ map::iterator it2; for(it2 = m_colortable.begin(); it2 != m_colortable.end(); it2++) delete (*it2).second; } /*----------------------------------------------------------------------------*/ void CBitmap::callFunc(const std::string& func, const std::list& params) { if (func.empty()) throw FileError("Function name is empty."); if (func == "fillrect") fillrect(params); else if (func == "brightness") brightness(params); else if (func == "mirror_x") mirror_x(params); else if (func == "mirror_y") mirror_y(params); else if (func == "invert") invert(params); else throw FileError("Unknown function '" + func + "'."); } /*----------------------------------------------------------------------------*/ void CBitmap::fillrect(std::list params) { /* check prerequirements */ if (params.size() != 7) throw FileError("Invalid number of function parameters (must be 7)."); /* do nothing if no pixel exists */ if (m_pixeldata == NULL || m_pixelformat == NULL) return; /* convert parameters */ uint32_t pparams[7]; int i = 0; try { for(i = 0; i < 7; i++) { pparams[i] = boost::lexical_cast(params.front()); params.pop_front(); } } catch(boost::bad_lexical_cast& ex) { throw FileError("Invalid parameter (" + params.front() + ")."); } /* check parameter values are in range */ if (pparams[0] < 0 || pparams[0] > getWidth() || pparams[1] < 0 || pparams[1] > getHeight()) throw FileError("At least one x/y-parameter is out of range."); /* check parameter values are in range */ CPixelFormat::RGBPIXEL pixel; m_pixelformat->getMaxColor(pixel); if (pparams[4] < 0 || pparams[4] > pixel.red || pparams[5] < 0 || pparams[5] > pixel.green || pparams[6] < 0 || pparams[6] > pixel.blue) throw FileError("At least one pixel color parameter is out of range."); if (pparams[2] < 0 || pparams[2] + pparams[0] > getWidth() || pparams[3] < 0 || pparams[3] + pparams[1] > getHeight()) throw FileError("At least one w/h-parameter is out of range."); /* new pixel data */ pixel.red = pparams[4]; pixel.green = pparams[5]; pixel.blue = pparams[6]; /* call setPixel for every pixel in the rectangel */ /* NOTE: maybe use std::fill() here? */ for(uint32_t i = pparams[0]; i < pparams[2] + pparams[0]; i++) { for(uint32_t j = pparams[1]; j < pparams[3] + pparams[1]; j++) { try { m_pixelformat->setPixel(pixel, i, j); } catch(CPixelFormat::PixelFormatError& ex) { stringstream errstr; errstr << "Can't set pixel (pos=[" << i << "," << j << "] col=[" << pparams[4] << "," << pparams[5] << "," << pparams[6] << "]): " << ex.what(); throw FileError(errstr.str()); } } } } /*----------------------------------------------------------------------------*/ void CBitmap::invert(std::list params) { /* check prerequirements */ if (params.size() != 0) throw FileError("Invalid number of function parameters (must be 0)."); /* do nothing if no pixel exists */ if (m_pixeldata == NULL || m_pixelformat == NULL) return; CPixelFormat::RGBPIXEL pixel; CPixelFormat::RGBPIXEL max; m_pixelformat->getMaxColor(max); if (hasColorTable()) { /* invert every entry in the colortable */ map::iterator it; for (it = m_colortable.begin(); it != m_colortable.end(); it++) { (*it).second->red = max.red - (*it).second->red; (*it).second->green = max.green - (*it).second->green; (*it).second->blue = max.blue - (*it).second->blue; } } else { /* invert per pixel */ for(uint32_t y = 0; y < getHeight(); y++) { for(uint32_t x = 0; x < getWidth(); x++) { try { m_pixelformat->getPixel(pixel, x, y); pixel.red = max.red - pixel.red; pixel.green = max.green - pixel.green; pixel.blue = max.blue - pixel.blue; m_pixelformat->setPixel(pixel, x, y); } catch(CPixelFormat::PixelFormatError& ex) { stringstream errstr; errstr << "Can't invert pixel (pos=[" << x << "," << y << "]): " << ex.what(); throw FileError(errstr.str()); } } } } } /*----------------------------------------------------------------------------*/ void CBitmap::brightness(std::list params) { /* check prerequirements */ if (params.size() != 1) throw FileError("Invalid number of function parameters (must be 1)."); /* do nothing if no pixel exists */ if (m_pixeldata == NULL || m_pixelformat == NULL) return; /* convert parameters */ float factor; try { factor = boost::lexical_cast(params.front()); params.pop_front(); } catch(boost::bad_lexical_cast& ex) { throw FileError("Invalid parameter (" + params.front() + ")."); } /* negative factor doesn't make sense */ if (factor < 0) throw FileError("Brightness parameter must be positive."); CPixelFormat::RGBPIXEL pixel; CPixelFormat::RGBPIXEL max; m_pixelformat->getMaxColor(max); if (hasColorTable()) { /* change every entry in the colortable */ map::iterator it; for (it = m_colortable.begin(); it != m_colortable.end(); it++) { (*it).second->red = min(max.red, static_cast((*it).second->red * factor)); (*it).second->green = min(max.green, static_cast((*it).second->green * factor)); (*it).second->blue = min(max.blue, static_cast((*it).second->blue * factor)); } } else { /* change per pixel */ for(uint32_t y = 0; y < getHeight(); y++) { for(uint32_t x = 0; x < getWidth(); x++) { try { m_pixelformat->getPixel(pixel, x, y); pixel.red = min(max.red, static_cast(pixel.red * factor)); pixel.green = min(max.green, static_cast(pixel.green * factor)); pixel.blue = min(max.blue, static_cast(pixel.blue * factor)); m_pixelformat->setPixel(pixel, x, y); } catch(CPixelFormat::PixelFormatError& ex) { stringstream errstr; errstr << "Can't invert pixel (pos=[" << x << "," << y << "]): " << ex.what(); throw FileError(errstr.str()); } } } } } /*----------------------------------------------------------------------------*/ void CBitmap::mirror_y(std::list params) { /* check prerequirements */ if (params.size() != 0) throw FileError("Invalid number of function parameters (must be 0)."); /* do nothing if no pixel exists */ if (m_pixeldata == NULL || m_pixelformat == NULL) return; uint8_t *buf = new uint8_t[m_rowsize]; for(uint32_t i = 0; i < getHeight()/2; i++) { uint32_t j = getHeight() - i - 1; uint32_t offset = i * m_rowsize; uint32_t backset = j * m_rowsize; /* boundary check */ if (offset + m_rowsize > getPixelDataSize() || backset + m_rowsize > getPixelDataSize()) throw FileError("Mirrored pixel position is out of range."); /* mirroring, backup lower data first */ copy(m_pixeldata + backset, m_pixeldata + backset + m_rowsize, buf); copy(m_pixeldata + offset, m_pixeldata + offset + m_rowsize, m_pixeldata + backset); copy(buf, buf + m_rowsize, m_pixeldata + offset); } delete[] buf; } /*----------------------------------------------------------------------------*/ void CBitmap::mirror_x(std::list params) { /* check prerequirements */ if (params.size() != 0) throw FileError("Invalid number of function parameters (must be 0)."); /* do nothing if no pixel exists */ if (m_pixeldata == NULL || m_pixelformat == NULL) return; /* calc pixelwidth */ unsigned int pixelwidth = (hasColorTable()) ? sizeof(uint32_t) : m_pixelformat->getBitCount()/8; assert(m_rowsize > 0); assert(getHeight() > 0); assert(getWidth() > 0); assert(getPixelDataSize() > 0); uint8_t *buf = new uint8_t[pixelwidth]; for(uint32_t i = 0; i < getHeight(); i++) { uint32_t offset = i * m_rowsize; for(uint32_t j = 0; j <= getWidth()/2; j++) { uint32_t poffset = offset + j * pixelwidth; uint32_t pbackset = offset + getWidth() * pixelwidth - j * pixelwidth; /* boundary check */ if (pbackset > getPixelDataSize()) throw FileError("Mirrored pixel position is out of range."); /* mirroring, backup right data first */ copy(m_pixeldata + pbackset - pixelwidth, m_pixeldata + pbackset, buf); copy(m_pixeldata + poffset, m_pixeldata + poffset + pixelwidth, m_pixeldata + pbackset - pixelwidth); copy(buf, buf + pixelwidth, m_pixeldata + poffset); } } delete[] buf; } /* vim: set et sw=2 ts=2: */