/** * @module cbitmap * @author Manuel Mausz, 0728348 * @brief Implementation of CFile handling Windows Bitmaps. * @date 17.04.2009 */ #include #include #ifdef DEBUG # include #endif #include "cbitmap.h" #include "cpixelformat_24.h" using namespace std; CBitmap::~CBitmap() { if (m_pixeldata != NULL) delete[] m_pixeldata; m_pixeldata = NULL; if (m_pixelformat != NULL) delete m_pixelformat; m_pixelformat = NULL; } /*----------------------------------------------------------------------------*/ void CBitmap::read(std::ifstream& in) { /* read and check file header */ in.read(reinterpret_cast(&m_fileheader), sizeof(m_fileheader)); if (m_fileheader.bfType[0] != 'B' || m_fileheader.bfType[1] != 'M') throw FileError("Imagefile has invalid Bitmap header."); /* bfSize is unreliable (http://de.wikipedia.org/wiki/Windows_Bitmap) */ if (m_fileheader.bfSize < 0) throw FileError("Bitmap filesize is less than zero?"); /* read and check info header */ in.read(reinterpret_cast(&m_infoheader), sizeof(m_infoheader)); if (m_infoheader.biSize != 40) throw FileError("Bitmap info header size is invalid."); if (m_infoheader.biPlanes != 1) throw FileError("Bitmap color planes is not set to 1."); if (m_infoheader.biCompression != 0) throw FileError("Bitmap compression is set but not supported."); if (m_infoheader.biSizeImage < 0) throw FileError("Bitmap image size is less than zero?"); if (m_infoheader.biClrUsed != 0 || m_infoheader.biClrImportant != 0) throw FileError("Bitmap colortable is used but not supported."); /* currently only 24bit */ if (m_infoheader.biBitCount != 24) throw FileError("Bitmap bitcount is not supported."); /* read pixel data using separate class */ if (m_infoheader.biSizeImage > 0) { if (m_pixeldata != NULL) delete[] m_pixeldata; m_pixeldata = new uint8_t[m_infoheader.biSizeImage]; in.read(reinterpret_cast(m_pixeldata), m_infoheader.biSizeImage); } /* create pixelformat instance */ if (m_pixelformat != NULL) delete m_pixelformat; m_pixelformat = NULL; if (m_infoheader.biBitCount == 24) m_pixelformat = new CPixelFormat_24(this); } /*----------------------------------------------------------------------------*/ void CBitmap::write(std::ofstream& out) { /* set header values */ m_fileheader.bfSize = m_infoheader.biSizeImage + sizeof(m_infoheader) + sizeof(m_fileheader); /* write file header */ out.write(reinterpret_cast(&m_fileheader), sizeof(m_fileheader)); /* write info header */ out.write(reinterpret_cast(&m_infoheader), sizeof(m_infoheader)); /* write pixel data */ if (m_pixeldata != NULL) out.write(reinterpret_cast(m_pixeldata), m_infoheader.biSizeImage); } /*----------------------------------------------------------------------------*/ 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 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)."); /* 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() + ")."); } /* width and height can be negativ */ uint32_t width = static_cast(abs(m_infoheader.biWidth)); uint32_t height = static_cast(abs(m_infoheader.biHeight)); /* check parameter values are in range */ if (pparams[0] < 0 || pparams[0] > width || pparams[1] < 0 || pparams[1] > height) throw FileError("At least one x/y-parameter is out of range."); if (pparams[2] < 0 || pparams[2] + pparams[0] > width || pparams[3] < 0 || pparams[3] + pparams[1] > height) throw FileError("At least one w/h-parameter is out of range."); if (pparams[4] < 0 || pparams[4] > 255 || pparams[5] < 0 || pparams[5] > 255 || pparams[6] < 0 || pparams[6] > 255) throw FileError("At least one pixel color parameter is out of range."); /* call setPixel for every pixel in the rectangel */ if (m_pixeldata != NULL && m_pixelformat != NULL) { 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(&pparams[4], 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()); } } } } } /*----------------------------------------------------------------------------*/ #ifdef DEBUG void CBitmap::dump(std::ostream& out) { out << "Bitmap File Header:" << endl << " bfType=" << m_fileheader.bfType[0] << m_fileheader.bfType[1] << ", bfSize=" << m_fileheader.bfSize << ", bfReserved=" << m_fileheader.bfReserved << ", bfOffBits=" << m_fileheader.bfOffBits << endl; out << "Bitmap Info Header:" << endl << " biSize=" << m_infoheader.biSize << ", biWidth=" << m_infoheader.biWidth << ", biHeight=" << m_infoheader.biHeight << ", biPlanes=" << m_infoheader.biPlanes << endl << " biBitCount=" << m_infoheader.biBitCount << ", biCompression=" << m_infoheader.biCompression << ", biSizeImage=" << m_infoheader.biSizeImage << endl << " biXPelsPerMeter=" << m_infoheader.biXPelsPerMeter << ", biYPelsPerMeter=" << m_infoheader.biYPelsPerMeter << ", biClrUsed=" << m_infoheader.biClrUsed << ", biClrImportant=" << m_infoheader.biClrImportant << endl; } #endif /* vim: set et sw=2 ts=2: */