Download | Plain Text | Line Numbers
/**
* @module cbitmap
* @author Guenther Neuwirth (0626638), Manuel Mausz (0728348)
* @brief Abstract implementation of CFile handling Bitmaps.
* @date 17.04.2009
*/
#include <algorithm>
#include <boost/lexical_cast.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <assert.h>
#include "cbitmap.h"
using namespace std;
/*----------------------------------------------------------------------------*/
CBitmap::~CBitmap()
{
/* delete pixeldata */
if (m_pixeldata != NULL)
delete[] m_pixeldata;
m_pixeldata = NULL;
/* delete pixelformat handlers */
set<CPixelFormat *>::iterator it;
for (it = m_handlers.begin(); it != m_handlers.end(); it++)
delete *it;
m_pixelformat = NULL;
/* delete colortable content */
map<uint32_t, CPixelFormat::RGBPIXEL *>::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<std::string>& 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<std::string> 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<uint32_t>(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<std::string> 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<uint32_t, CPixelFormat::RGBPIXEL *>::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<std::string> 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<float>(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<uint32_t, CPixelFormat::RGBPIXEL *>::iterator it;
for (it = m_colortable.begin(); it != m_colortable.end(); it++)
{
(*it).second->red = min(max.red, static_cast<uint32_t>((*it).second->red * factor));
(*it).second->green = min(max.green, static_cast<uint32_t>((*it).second->green * factor));
(*it).second->blue = min(max.blue, static_cast<uint32_t>((*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<uint32_t>(pixel.red * factor));
pixel.green = min(max.green, static_cast<uint32_t>(pixel.green * factor));
pixel.blue = min(max.blue, static_cast<uint32_t>(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<std::string> 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<std::string> 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: */