// Copyright (c) 2012-2017 VideoStitch SAS // Copyright (c) 2018 stitchEm #ifndef BMPR_HPP_ #define BMPR_HPP_ #include "io.hpp" #include <cassert> #include <fstream> #include <ostream> #include <vector> typedef struct { char* filename; void* buffer; } cache_t; #define MAX_CACHED_FILES (8) static cache_t filesCache[MAX_CACHED_FILES] = { {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}, }; void* cachedFile(const char* filename) { cache_t* free_entry = nullptr; for (int i = 0; i < MAX_CACHED_FILES; i++) { if (filesCache[i].filename) { if (strcmp(filesCache[i].filename, filename) == 0) { return (filesCache[i].buffer); } } else if (free_entry == nullptr) { free_entry = filesCache + i; } } assert(free_entry); free_entry->filename = (char*)malloc(strlen(filename) + 1); strcpy(free_entry->filename, filename); FILE* fd = VideoStitch::Io::openFile(filename, "rb"); assert(fd); fseek(fd, 0, SEEK_END); size_t len = ftell(fd); fseek(fd, 0, SEEK_SET); free_entry->buffer = malloc(len); assert(free_entry->buffer); // we don't care about the return of read #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-result" fread(free_entry->buffer, sizeof(char), len, fd); #pragma GCC diagnostic pop fclose(fd); return (free_entry->buffer); } namespace VideoStitch { namespace Input { class BMPReader { public: BMPReader(const char* filename, std::ostream*) : width(0), height(0), cury(0), bottomup(0), pitch(0) { buffer = (char*)cachedFile(filename); assert(buffer); (void)readHeader(); } ~BMPReader() {} unsigned getWidth() const { return width; } unsigned getHeight() const { return height; } bool ok() const { return true; } /** * Fill in the given buffer with the next row (RGBRGBRGB). * @data must be large enough to hold one row. */ bool getNextRow(unsigned char* data) { char* src = buffer + bmf.bfOffBits; if (cury < height) { if (!bottomup) { src += (height - (cury + 1)) * pitch; } else { src += cury * pitch; } memcpy(data, src, width * 3); cury++; return true; } return false; } private: int readHeader() { memcpy(&bmf, buffer, sizeof(struct bmpfileheader)); memcpy(&bmi, buffer + sizeof(struct bmpfileheader), sizeof(struct bmpinfoheader)); if ((bmf.bfType != 0x4D42) || (bmf.bfReserved1) || (bmf.bfReserved2) || (bmi.biSize != sizeof(struct bmpinfoheader)) || (bmi.biPlanes != 1) || (bmi.biBitCount != 24) || (bmi.biCompression)) { return (-1); } width = bmi.biWidth; bottomup = (int)(bmi.biHeight >> 31); height = (bmi.biHeight ^ bottomup) - bottomup; pitch = (size_t)(unsigned int)((((width * bmi.biPlanes * bmi.biBitCount) + 31) >> 3) & -4); cury = 0; return (0); } private: char* buffer; unsigned int width; unsigned int height; unsigned int cury; int bottomup; size_t pitch; struct __attribute__((__packed__)) bmpfileheader { uint16_t bfType; uint32_t bfSize; uint16_t bfReserved1; uint16_t bfReserved2; uint32_t bfOffBits; } bmf; struct __attribute__((__packed__)) bmpinfoheader { uint32_t biSize; int32_t biWidth; int32_t biHeight; uint16_t biPlanes; uint16_t biBitCount; uint32_t biCompression; uint32_t biSizeImage; int32_t biXPelsPerMeter; int32_t biYPelsPerMeter; uint32_t biClrUsed; uint32_t biClrImportant; } bmi; }; } // namespace Input } // namespace VideoStitch #endif