#include "BMP.h" #include <stdexcept> // destructor BMP::~BMP() { // dtor Clear(); } // Copy constructor BMP::BMP(const BMP& other) { copy(other); } // Assignment operator BMP& BMP::operator=(const BMP& other) { if (&other != this) { Clear(); copy(other); } return *this; } // copy helper method bool BMP::copy(const BMP& other) { this->m_fileHeader = new BMPFILEHEADER; this->m_infoHeader = new BMPINFOHEADER; this->m_pixels = new unsigned char[other.m_pixelsSize]; // if memory creation fails, return false if (this->m_fileHeader == nullptr || this->m_infoHeader == nullptr || this->m_pixels == nullptr) { return false; } // copy contents Headers from other BMP object to this memcpy(this->m_fileHeader, other.m_fileHeader, sizeof(BMPFILEHEADER)); memcpy(this->m_infoHeader, other.m_infoHeader, sizeof(BMPINFOHEADER)); // copy pixel data from other BMP to this memcpy(this->m_pixels, other.m_pixels, other.m_pixelsSize); return true; } void BMP::Clear() { delete[] m_fileHeader; delete[] m_infoHeader; delete[] m_pixels; m_fileHeader = nullptr; m_infoHeader = nullptr; m_pixels = nullptr; } // reads in a BMP file of the fileName string bool BMP::readInBMP(const std::string& fileName) { // check filename contains a .bmp ext if (fileName.find(".bmp") == std::string::npos) { throw std::invalid_argument("Error: \"" + fileName + "\" does not contain a .bmp extension"); } unsigned char* datBuff[2] = {nullptr, nullptr}; // Header buffers // File needs to be read in binary std::ifstream file(fileName, std::ios::binary); if (!file) { throw std::runtime_error("Failed to open bitmap: \"" + fileName + "\""); } file.exceptions(std::ifstream::failbit | std::ifstream::badbit); // Allocate byte memory that will hold the two headers datBuff[0] = new unsigned char[sizeof(BMPFILEHEADER)]; datBuff[1] = new unsigned char[sizeof(BMPINFOHEADER)]; try { file.read((char*)datBuff[0], sizeof(BMPFILEHEADER)); file.read((char*)datBuff[1], sizeof(BMPINFOHEADER)); } catch (const std::ifstream::failure&) { throw std::runtime_error("Exception reading headers in file: \"" + fileName + "\""); } // Construct the values from the buffers m_fileHeader = reinterpret_cast<BMPFILEHEADER*>(datBuff[0]); m_infoHeader = reinterpret_cast<BMPINFOHEADER*>(datBuff[1]); // Check if the file is an actual BMP file if (m_fileHeader->bfType != BMP_BYTE_CODE) { throw std::runtime_error("File \"" + fileName + "\" has non BMP bytecode in header"); } // Get the true size of the image m_pixelsSize = m_infoHeader->biWidth * m_infoHeader->biHeight * m_infoHeader->biBitCount; // Create memory with size read in from bmp header m_pixels = new unsigned char[m_pixelsSize]; if (m_pixels == nullptr) { throw std::runtime_error("Failed to create heap Memory"); } try { // Go to where image data starts, then read in image data file.seekg(m_fileHeader->bfOffBits); file.read((char*)m_pixels, m_infoHeader->biSizeImage); } catch (const std::ifstream::failure&) { throw std::runtime_error("Exception reading pixel data in file: \"" + fileName + "\""); } return true; } // BMP format File Header getter BMPFILEHEADER* BMP::getFileHeader() const { return m_fileHeader; } // BMP format Information Header getter BMPINFOHEADER* BMP::getInfoHeader() const { return m_infoHeader; } // pixel pointer getter unsigned char* BMP::getPixels() { return m_pixels; } // Rotates the image of a read in BMP image void BMP::rotateBMP(double degrees) { unsigned char* rotatedPixels = new unsigned char[m_pixelsSize]; double radians = (degrees * glm::pi<double>()) / 180; double xOrigin = 0.5 * (m_infoHeader->biWidth - 1); // point to rotate about double yOrigin = 0.5 * (m_infoHeader->biHeight - 1); // center of image // static cast unsigned int width and height once int width = static_cast<int>(m_infoHeader->biWidth); int height = static_cast<int>(m_infoHeader->biHeight); // rotation for (int x = 0; x < width; ++x) { for (int y = 0; y < height; ++y) { long double a = x - xOrigin; long double b = y - yOrigin; int xx = (int)(+a * std::cos(radians) - b * std::sin(radians) + xOrigin); int yy = (int)(+a * std::sin(radians) + b * std::cos(radians) + yOrigin); if (xx >= 0 && xx < width && yy >= 0 && yy < height) { rotatedPixels[(y * height + x) * 3 + 0] = m_pixels[(yy * height + xx) * 3 + 0]; rotatedPixels[(y * height + x) * 3 + 1] = m_pixels[(yy * height + xx) * 3 + 1]; rotatedPixels[(y * height + x) * 3 + 2] = m_pixels[(yy * height + xx) * 3 + 2]; } } } delete[] m_pixels; m_pixels = rotatedPixels; }