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: */