From e422cb14e841ae3fc5f3c453070a4a6e599a8af0 Mon Sep 17 00:00:00 2001 From: Lefteris Eleftheriades Date: Sat, 5 Aug 2023 23:32:12 +0300 Subject: [PATCH 1/3] Added support for 32bit bitmap format as saved by paint.net --- source/main.cc | 144 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 140 insertions(+), 4 deletions(-) diff --git a/source/main.cc b/source/main.cc index 7b9322c..3d031ac 100644 --- a/source/main.cc +++ b/source/main.cc @@ -52,13 +52,53 @@ struct DibHeader uint32_t biClrImportant; }; +typedef struct +{ + int32_t ciexyzX; + int32_t ciexyzY; + int32_t ciexyzZ; +} DibCIEXYZ; + +typedef struct +{ + DibCIEXYZ ciexyzRed; + DibCIEXYZ ciexyzGreen; + DibCIEXYZ ciexyzBlue; +} DibCIEXYZTRIPLE; + +typedef struct { + uint32_t bV5Size; + int32_t bV5Width; + int32_t bV5Height; + uint16_t bV5Planes; + uint16_t bV5BitCount; + uint32_t bV5Compression; + uint32_t bV5SizeImage; + int32_t bV5XPelsPerMeter; + int32_t bV5YPelsPerMeter; + uint32_t bV5ClrUsed; + uint32_t bV5ClrImportant; + uint32_t bV5RedMask; + uint32_t bV5GreenMask; + uint32_t bV5BlueMask; + uint32_t bV5AlphaMask; + uint32_t bV5CSType; + DibCIEXYZTRIPLE bV5Endpoints; + uint32_t bV5GammaRed; + uint32_t bV5GammaGreen; + uint32_t bV5GammaBlue; + uint32_t bV5Intent; + uint32_t bV5ProfileData; + uint32_t bV5ProfileSize; + uint32_t bV5Reserved; +} DibHeaderV5; #pragma pack(pop) /** * @brief Saves an Windows Bitmap image (24 BPP). */ -int main_saveBitmap( +int main_saveBitmap24( const uint32_t *data, uint32_t width, uint32_t height, @@ -111,11 +151,63 @@ int main_saveBitmap( return 0; } +int main_saveBitmap32( + const uint32_t* data, + uint32_t width, + uint32_t height, + const string& fileName) +{ + BitmapHeader bh; + DibHeaderV5 dh = { 0 }; + uint16_t suffix; + uint32_t zero = 0; + const uint32_t* ptr; + + ofstream output(fileName.c_str(), std::ios_base::binary); + if (!output.good()) return -1; + + dh.bV5Size = sizeof(DibHeaderV5); + dh.bV5Width = width; + dh.bV5Height = height; + dh.bV5Planes = 1; + dh.bV5BitCount = 32; + dh.bV5Compression = 3; + dh.bV5SizeImage = 0; + dh.bV5XPelsPerMeter = 0x2E23; + dh.bV5YPelsPerMeter = dh.bV5XPelsPerMeter; + dh.bV5ClrUsed = 0; + dh.bV5ClrImportant = 0; + dh.bV5RedMask = 0x00ff0000; + dh.bV5GreenMask = 0x0000ff00; + dh.bV5BlueMask = 0x000000ff; + dh.bV5AlphaMask = 0xff000000; + dh.bV5CSType = 0x57696e20;// 'Win ' + + bh.bfType = 0x4D42; // 'BM' + bh.bfSize = width * height * 4 + sizeof(DibHeaderV5) + sizeof(BitmapHeader); + bh.bfRes1 = 0; + bh.bfOffBits = sizeof(DibHeaderV5) + sizeof(BitmapHeader); + output.write((char*)&bh, sizeof(BitmapHeader)); + output.write((char*)&dh, sizeof(DibHeaderV5)); + + ptr = data + (width * height); + for (uint32_t i = 0; i < height; i++) + { + ptr -= width; + + for (uint32_t j = 0; j < width; ++j) + output.write((char*)(ptr + j), 4); + } + + output.close(); + + return 0; +} /** * @brief Loads an Windows Bitmap image (24 BPP). */ -int main_loadBitmap( +int main_loadBitmap24( const string &fileName, uint32_t *&data, uint16_t &width, @@ -162,6 +254,50 @@ int main_loadBitmap( return 0; } +int main_loadBitmap32( + const string& fileName, + uint32_t*& data, + uint16_t& width, + uint16_t& height) +{ + BitmapHeader bh; + DibHeaderV5 dh; + uint16_t suffix; + uint32_t zero = 0; + uint32_t* ptr; + uint16_t bits; + + ifstream input(fileName.c_str(), std::ios_base::binary); + if (!input.good()) return -1; + + input.read((char*)&bh, 14); + if (bh.bfType != 0x4D42) return -1; + input.read((char*)&dh.bV5Size, sizeof(uint32_t)); + if (dh.bV5Size != sizeof(DibHeaderV5)) return -1; + + input.read((char*)&dh.bV5Width, sizeof(DibHeaderV5) - sizeof(uint32_t)); + width = dh.bV5Width; + height = dh.bV5Height; + if (dh.bV5BitCount != 32) return -1; + + input.seekg(bh.bfOffBits, std::ios_base::_Seekbeg); + + ptr = data = new uint32_t[width * height](); + ptr += width * height; + for (uint32_t i = 0; i < height; i++) + { + ptr -= width; + + for (uint32_t j = 0; j < width; ++j) + { + input.read((char*)(ptr + j), 4); + } + } + + input.close(); + return 0; +} + int main(int argc, char **argv ) { @@ -173,7 +309,7 @@ int main(int argc, char **argv ) // loads the input image uint16_t width, height; uint32_t *image = NULL; - if ( main_loadBitmap(argv[1], image, width, height) != 0) return 1; + if ( main_loadBitmap32(argv[1], image, width, height) != 0) return 1; std::cout << "Resizing '" << argv[1] << "' [" << width << "x" << height << "] by " << factor << 'x' << std::endl; @@ -194,7 +330,7 @@ int main(int argc, char **argv ) std::cout << "Processing time: " << t / (CLOCKS_PER_SEC / 1000) << " ms" << std::endl; // saves the resized image - if ( main_saveBitmap(output, width * factor, height * factor, "output.bmp") != 0 ) return 1; + if ( main_saveBitmap32(output, width * factor, height * factor, "output.bmp") != 0 ) return 1; delete[] image; delete[] output; From 422dfca0970dbef9d3ed84a86dd9539b7187fe85 Mon Sep 17 00:00:00 2001 From: Lefteris Eleftheriades Date: Sun, 6 Aug 2023 00:49:59 +0300 Subject: [PATCH 2/3] moved bitmap code to separate class --- CMakeLists.txt | 4 +- include/Bitmap.h | 285 ++++++++++++++++++++++++++++++++++++++++++++ source/main.cc | 302 ++++------------------------------------------- 3 files changed, 308 insertions(+), 283 deletions(-) create mode 100644 include/Bitmap.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4abc0ad..b8c0037 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ file(GLOB HQX_SOURCES "source/HQ2x.cc" "source/HQ3x.cc") -add_library(hqx ${HQX_SOURCES}) +add_library(hqx ${HQX_SOURCES} "include/Bitmap.h") set_target_properties(hqx PROPERTIES OUTPUT_NAME "hqx" ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" @@ -18,7 +18,7 @@ set_target_properties(hqx PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" PREFIX "lib" ) -add_executable(test "source/main.cc") +add_executable(test "source/main.cc" "include/Bitmap.h") target_link_libraries(test hqx) set_target_properties(test PROPERTIES OUTPUT_NAME "test" diff --git a/include/Bitmap.h b/include/Bitmap.h new file mode 100644 index 0000000..e8703df --- /dev/null +++ b/include/Bitmap.h @@ -0,0 +1,285 @@ +#include +#include + +#pragma pack(push, 1) +struct BitmapHeader +{ + uint16_t bfType; + uint32_t bfSize; + uint32_t bfRes1; + uint32_t bfOffBits; +}; + +struct DibHeader +{ + uint32_t biSize; + uint32_t biWidth; + uint32_t biHeight; + uint16_t biPlanes; + uint16_t biBitCount; + uint32_t biCompression; + uint32_t biSizeImage; + uint32_t biXPelsPerMeter; + uint32_t biYPelsPerMeter; + uint32_t biClrUsed; + uint32_t biClrImportant; +}; + +typedef struct +{ + int32_t ciexyzX; + int32_t ciexyzY; + int32_t ciexyzZ; +} DibCIEXYZ; + +typedef struct +{ + DibCIEXYZ ciexyzRed; + DibCIEXYZ ciexyzGreen; + DibCIEXYZ ciexyzBlue; +} DibCIEXYZTRIPLE; + +typedef struct { + uint32_t bV5Size; + int32_t bV5Width; + int32_t bV5Height; + uint16_t bV5Planes; + uint16_t bV5BitCount; + uint32_t bV5Compression; + uint32_t bV5SizeImage; + int32_t bV5XPelsPerMeter; + int32_t bV5YPelsPerMeter; + uint32_t bV5ClrUsed; + uint32_t bV5ClrImportant; + uint32_t bV5RedMask; + uint32_t bV5GreenMask; + uint32_t bV5BlueMask; + uint32_t bV5AlphaMask; + uint32_t bV5CSType; + DibCIEXYZTRIPLE bV5Endpoints; + uint32_t bV5GammaRed; + uint32_t bV5GammaGreen; + uint32_t bV5GammaBlue; + uint32_t bV5Intent; + uint32_t bV5ProfileData; + uint32_t bV5ProfileSize; + uint32_t bV5Reserved; +} DibHeaderV5; +#pragma pack(pop) + + +class Bitmap { +public: + uint32_t* data; + uint32_t width; + uint32_t height; + uint16_t bitCount; + + + Bitmap( + uint32_t* data, + uint32_t width, + uint32_t height, + uint16_t bitCount + ) + : data(data) + , width(width) + , height(height) + , bitCount(bitCount) + { + } + + Bitmap(std::istream& input) { + load(input); + } + + void save(std::ostream& output) { + if (bitCount == 24) + save24bit(output); + if (bitCount == 32) + save32bit(output); + } + +private: + void save24bit(std::ostream& output) const + { + BitmapHeader bh; + DibHeader dh; + uint16_t suffix; + uint32_t zero = 0; + const uint32_t* ptr; + + suffix = (4 - (3 * width) % 4) % 4; + + dh.biSize = sizeof(DibHeader); + dh.biWidth = width; + dh.biHeight = height; + dh.biPlanes = 1; + dh.biBitCount = 24; + dh.biCompression = 0; + dh.biSizeImage = (uint32_t)((width * 3 + suffix) * height); + dh.biXPelsPerMeter = 0x2E23; + dh.biYPelsPerMeter = dh.biXPelsPerMeter; + dh.biClrUsed = 0; + dh.biClrImportant = 0; + + bh.bfType = 0x4D42; + bh.bfSize = dh.biSizeImage + 0x0036; + bh.bfRes1 = 0; + bh.bfOffBits = 0x0036; + output.write((char*)&bh, sizeof(BitmapHeader)); + output.write((char*)&dh, sizeof(DibHeader)); + + ptr = data + (width * height); + for (uint32_t i = 0; i < height; i++) + { + ptr -= width; + + for (uint32_t j = 0; j < width; ++j) + output.write((char*)(ptr + j), 3); + + if (suffix > 0) + output.write((char*)&zero, suffix); + } + } + + void save32bit(std::ostream& output) const + { + BitmapHeader bh; + DibHeaderV5 dh = { 0 }; + uint16_t suffix; + uint32_t zero = 0; + const uint32_t* ptr; + + dh.bV5Size = sizeof(DibHeaderV5); + dh.bV5Width = width; + dh.bV5Height = height; + dh.bV5Planes = 1; + dh.bV5BitCount = 32; + dh.bV5Compression = 3; + dh.bV5SizeImage = 0; + dh.bV5XPelsPerMeter = 0x2E23; + dh.bV5YPelsPerMeter = dh.bV5XPelsPerMeter; + dh.bV5ClrUsed = 0; + dh.bV5ClrImportant = 0; + dh.bV5RedMask = 0x00ff0000; + dh.bV5GreenMask = 0x0000ff00; + dh.bV5BlueMask = 0x000000ff; + dh.bV5AlphaMask = 0xff000000; + dh.bV5CSType = 0x57696e20;// 'Win ' + + bh.bfType = 0x4D42; // 'BM' + bh.bfSize = width * height * 4 + sizeof(DibHeaderV5) + sizeof(BitmapHeader); + bh.bfRes1 = 0; + bh.bfOffBits = sizeof(DibHeaderV5) + sizeof(BitmapHeader); + output.write((char*)&bh, sizeof(BitmapHeader)); + output.write((char*)&dh, sizeof(DibHeaderV5)); + + ptr = data + (width * height); + for (uint32_t i = 0; i < height; i++) + { + ptr -= width; + + for (uint32_t j = 0; j < width; ++j) + output.write((char*)(ptr + j), 4); + } + } + +public: + int load(std::istream& input) + { + BitmapHeader bh; + input.read((char*)&bh, sizeof(BitmapHeader)); + if (bh.bfType != 0x4D42) return -1; + + uint32_t biSize; + input.read((char*)&biSize, sizeof(uint32_t)); + + if (biSize == sizeof(DibHeader)) + return loadDibHeader(input, bh); + + if (biSize == sizeof(DibHeaderV5)) + return loadV5Header(input, bh); + + return 0; + } + +private: + int loadDibHeader(std::istream& input, const BitmapHeader& bh) + { + DibHeader dh; + input.read((char*)&dh.biWidth, sizeof(DibHeader) - sizeof(uint32_t)); + width = dh.biWidth; + height = dh.biHeight; + bitCount = dh.biBitCount; + + input.seekg(bh.bfOffBits, std::ios_base::_Seekbeg); + if (dh.biBitCount == 24) + return read24bit(input); + + if (dh.biBitCount == 32) + return read32bit(input); + + return -1; + } + + int loadV5Header(std::istream& input, const BitmapHeader& bh) + { + DibHeaderV5 dh; + input.read((char*)&dh.bV5Width, sizeof(DibHeaderV5) - sizeof(uint32_t)); + width = dh.bV5Width; + height = dh.bV5Height; + bitCount = dh.bV5BitCount; + + input.seekg(bh.bfOffBits, std::ios_base::_Seekbeg); + + if (dh.bV5BitCount == 24) + return read24bit(input); + + if (dh.bV5BitCount == 32) + return read32bit(input); + + return -1; + } + + int read24bit(std::istream& input) { + uint16_t suffix; + uint32_t* ptr; + uint32_t zero = 0; + + suffix = (4 - (3 * width) % 4) % 4; + ptr = data = new uint32_t[width * height](); + ptr += width * height; + for (uint32_t i = 0; i < height; i++) + { + ptr -= width; + + for (uint32_t j = 0; j < width; ++j) + { + input.read((char*)(ptr + j), 3); + *(ptr + j) |= 0xFF000000; + } + + if (suffix > 0) + input.read((char*)&zero, suffix); + } + return 0; + } + + int read32bit(std::istream& input) { + uint32_t* ptr; + ptr = data = new uint32_t[width * height](); + ptr += width * height; + for (uint32_t i = 0; i < height; i++) + { + ptr -= width; + + for (uint32_t j = 0; j < width; ++j) + { + input.read((char*)(ptr + j), 4); + } + } + + return 0; + } +}; \ No newline at end of file diff --git a/source/main.cc b/source/main.cc index 3d031ac..cf42dce 100644 --- a/source/main.cc +++ b/source/main.cc @@ -20,285 +20,14 @@ #include #include #include - +#include +#include "Bitmap.h" using std::ifstream; using std::ofstream; using std::string; -#pragma pack(push, 1) - -struct BitmapHeader -{ - uint16_t bfType; - uint32_t bfSize; - uint32_t bfRes1; - uint32_t bfOffBits; -}; - -struct DibHeader -{ - uint32_t biSize; - uint32_t biWidth; - uint32_t biHeight; - uint16_t biPlanes; - uint16_t biBitCount; - uint32_t biCompression; - uint32_t biSizeImage; - uint32_t biXPelsPerMeter; - uint32_t biYPelsPerMeter; - uint32_t biClrUsed; - uint32_t biClrImportant; -}; - -typedef struct -{ - int32_t ciexyzX; - int32_t ciexyzY; - int32_t ciexyzZ; -} DibCIEXYZ; - -typedef struct -{ - DibCIEXYZ ciexyzRed; - DibCIEXYZ ciexyzGreen; - DibCIEXYZ ciexyzBlue; -} DibCIEXYZTRIPLE; - -typedef struct { - uint32_t bV5Size; - int32_t bV5Width; - int32_t bV5Height; - uint16_t bV5Planes; - uint16_t bV5BitCount; - uint32_t bV5Compression; - uint32_t bV5SizeImage; - int32_t bV5XPelsPerMeter; - int32_t bV5YPelsPerMeter; - uint32_t bV5ClrUsed; - uint32_t bV5ClrImportant; - uint32_t bV5RedMask; - uint32_t bV5GreenMask; - uint32_t bV5BlueMask; - uint32_t bV5AlphaMask; - uint32_t bV5CSType; - DibCIEXYZTRIPLE bV5Endpoints; - uint32_t bV5GammaRed; - uint32_t bV5GammaGreen; - uint32_t bV5GammaBlue; - uint32_t bV5Intent; - uint32_t bV5ProfileData; - uint32_t bV5ProfileSize; - uint32_t bV5Reserved; -} DibHeaderV5; -#pragma pack(pop) - - -/** - * @brief Saves an Windows Bitmap image (24 BPP). - */ -int main_saveBitmap24( - const uint32_t *data, - uint32_t width, - uint32_t height, - const string &fileName ) -{ - BitmapHeader bh; - DibHeader dh; - uint16_t suffix; - uint32_t zero = 0; - const uint32_t *ptr; - - ofstream output(fileName.c_str(), std::ios_base::binary); - if (!output.good()) return -1; - - suffix = ((width + 3) & ~0x03) - width; - - dh.biSize = sizeof(DibHeader); - dh.biWidth = width; - dh.biHeight = height; - dh.biPlanes = 1; - dh.biBitCount = 24; - dh.biCompression = 0; - dh.biSizeImage = (uint16_t) ( (width*3+suffix)*height ); - dh.biXPelsPerMeter = 0x2E23; - dh.biYPelsPerMeter = dh.biXPelsPerMeter; - dh.biClrUsed = 0; - dh.biClrImportant = 0; - - bh.bfType = 0x4D42; - bh.bfSize = dh.biSizeImage + 0x0036; - bh.bfRes1 = 0; - bh.bfOffBits = 0x0036; - output.write( (char*) &bh, sizeof(BitmapHeader) ); - output.write( (char*) &dh, sizeof(DibHeader) ); - - ptr = data + (width * height); - for (uint32_t i = 0; i < height; i++) - { - ptr -= width; - - for (uint32_t j = 0; j < width; ++j) - output.write( (char*) (ptr + j), 3 ); - - if (suffix > 0) - output.write( (char*) &zero, suffix ); - } - - output.close(); - - return 0; -} - -int main_saveBitmap32( - const uint32_t* data, - uint32_t width, - uint32_t height, - const string& fileName) -{ - BitmapHeader bh; - DibHeaderV5 dh = { 0 }; - uint16_t suffix; - uint32_t zero = 0; - const uint32_t* ptr; - - ofstream output(fileName.c_str(), std::ios_base::binary); - if (!output.good()) return -1; - - dh.bV5Size = sizeof(DibHeaderV5); - dh.bV5Width = width; - dh.bV5Height = height; - dh.bV5Planes = 1; - dh.bV5BitCount = 32; - dh.bV5Compression = 3; - dh.bV5SizeImage = 0; - dh.bV5XPelsPerMeter = 0x2E23; - dh.bV5YPelsPerMeter = dh.bV5XPelsPerMeter; - dh.bV5ClrUsed = 0; - dh.bV5ClrImportant = 0; - dh.bV5RedMask = 0x00ff0000; - dh.bV5GreenMask = 0x0000ff00; - dh.bV5BlueMask = 0x000000ff; - dh.bV5AlphaMask = 0xff000000; - dh.bV5CSType = 0x57696e20;// 'Win ' - - bh.bfType = 0x4D42; // 'BM' - bh.bfSize = width * height * 4 + sizeof(DibHeaderV5) + sizeof(BitmapHeader); - bh.bfRes1 = 0; - bh.bfOffBits = sizeof(DibHeaderV5) + sizeof(BitmapHeader); - output.write((char*)&bh, sizeof(BitmapHeader)); - output.write((char*)&dh, sizeof(DibHeaderV5)); - - ptr = data + (width * height); - for (uint32_t i = 0; i < height; i++) - { - ptr -= width; - - for (uint32_t j = 0; j < width; ++j) - output.write((char*)(ptr + j), 4); - } - - output.close(); - - return 0; -} - -/** - * @brief Loads an Windows Bitmap image (24 BPP). - */ -int main_loadBitmap24( - const string &fileName, - uint32_t *&data, - uint16_t &width, - uint16_t &height ) -{ - BitmapHeader bh; - DibHeader dh; - uint16_t suffix; - uint32_t zero = 0; - uint32_t *ptr; - uint16_t bits; - - ifstream input(fileName.c_str(), std::ios_base::binary); - if (!input.good()) return -1; - - input.read( (char*) &bh, sizeof(BitmapHeader) ); - if (bh.bfType != 0x4D42) return -1; - input.read( (char*) &dh.biSize, sizeof(uint32_t) ); - if (dh.biSize != 40) return -1; - - input.read( (char*) &dh.biWidth, sizeof(DibHeader) - sizeof(uint32_t) ); - width = dh.biWidth; - height = dh.biHeight; - if (dh.biBitCount != 24) return -1; - - suffix = ((width + 3) & ~0x03) - width; - ptr = data = new uint32_t[width * height](); - ptr += width * height; - for (uint32_t i = 0; i < height; i++) - { - ptr -= width; - - for (uint32_t j = 0; j < width; ++j) - { - input.read( (char*) (ptr + j), 3 ); - *(ptr + j) |= 0xFF000000; - } - - if (suffix > 0) - input.read( (char*) &zero, suffix ); - } - - input.close(); - return 0; -} - -int main_loadBitmap32( - const string& fileName, - uint32_t*& data, - uint16_t& width, - uint16_t& height) -{ - BitmapHeader bh; - DibHeaderV5 dh; - uint16_t suffix; - uint32_t zero = 0; - uint32_t* ptr; - uint16_t bits; - - ifstream input(fileName.c_str(), std::ios_base::binary); - if (!input.good()) return -1; - - input.read((char*)&bh, 14); - if (bh.bfType != 0x4D42) return -1; - input.read((char*)&dh.bV5Size, sizeof(uint32_t)); - if (dh.bV5Size != sizeof(DibHeaderV5)) return -1; - - input.read((char*)&dh.bV5Width, sizeof(DibHeaderV5) - sizeof(uint32_t)); - width = dh.bV5Width; - height = dh.bV5Height; - if (dh.bV5BitCount != 32) return -1; - - input.seekg(bh.bfOffBits, std::ios_base::_Seekbeg); - - ptr = data = new uint32_t[width * height](); - ptr += width * height; - for (uint32_t i = 0; i < height; i++) - { - ptr -= width; - - for (uint32_t j = 0; j < width; ++j) - { - input.read((char*)(ptr + j), 4); - } - } - - input.close(); - return 0; -} - - int main(int argc, char **argv ) { uint32_t factor = 2; @@ -307,31 +36,42 @@ int main(int argc, char **argv ) if (argc == 3) factor = atoi(argv[2]); // loads the input image - uint16_t width, height; - uint32_t *image = NULL; - if ( main_loadBitmap32(argv[1], image, width, height) != 0) return 1; - std::cout << "Resizing '" << argv[1] << "' [" << width << "x" << height << "] by " << + + ifstream input(argv[1], std::ios_base::binary); + if (!input.good()) { + std::cout << "File not found" << std::endl; + return -1; + } + Bitmap bitmap(input); + input.close(); + + std::cout << "Resizing '" << argv[1] << "' [" << bitmap.width << "x" << bitmap.height << "] by " << factor << 'x' << std::endl; clock_t t = clock(); // resize the input image using the given scale factor - uint32_t outputSize = (width * factor) * (height * factor); + uint32_t outputSize = (bitmap.width * factor) * (bitmap.height * factor); uint32_t *output = new uint32_t[outputSize](); HQx *scale; if (factor == 2) scale = new HQ2x(); else scale = new HQ3x(); - scale->resize(image, width, height, output); + scale->resize(bitmap.data, bitmap.width, bitmap.height, output); delete scale; t = clock() - t; std::cout << "Processing time: " << t / (CLOCKS_PER_SEC / 1000) << " ms" << std::endl; // saves the resized image - if ( main_saveBitmap32(output, width * factor, height * factor, "output.bmp") != 0 ) return 1; + ofstream outputFile(argv[1] + std::string(".") + std::to_string(factor) + "x.bmp", std::ios_base::binary); + if (!outputFile.good()) return -1; + + Bitmap bitmapOut(output, bitmap.width * factor, bitmap.height * factor, bitmap.bitCount); + bitmapOut.save(outputFile); + outputFile.close(); - delete[] image; + delete[] bitmap.data; delete[] output; } From 06fba438fe8e1b7ae71b18df3f1020acb5ba32ec Mon Sep 17 00:00:00 2001 From: Lefteris Eleftheriades Date: Sun, 6 Aug 2023 01:00:26 +0300 Subject: [PATCH 3/3] moved bitmap code to cc file. added cast to unsigned type --- CMakeLists.txt | 7 +- include/Bitmap.h | 208 +++-------------------------------------------- source/HQ2x.cc | 4 +- source/HQ3x.cc | 4 +- source/bitmap.cc | 204 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 222 insertions(+), 205 deletions(-) create mode 100644 source/bitmap.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index b8c0037..d7fb371 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,9 +8,10 @@ include_directories( file(GLOB HQX_SOURCES "source/HQx.cc" "source/HQ2x.cc" - "source/HQ3x.cc") + "source/HQ3x.cc" + "source/bitmap.cc") -add_library(hqx ${HQX_SOURCES} "include/Bitmap.h") +add_library(hqx ${HQX_SOURCES}) set_target_properties(hqx PROPERTIES OUTPUT_NAME "hqx" ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" @@ -18,7 +19,7 @@ set_target_properties(hqx PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" PREFIX "lib" ) -add_executable(test "source/main.cc" "include/Bitmap.h") +add_executable(test "source/main.cc") target_link_libraries(test hqx) set_target_properties(test PROPERTIES OUTPUT_NAME "test" diff --git a/include/Bitmap.h b/include/Bitmap.h index e8703df..89212b3 100644 --- a/include/Bitmap.h +++ b/include/Bitmap.h @@ -75,211 +75,23 @@ class Bitmap { uint32_t height; uint16_t bitCount; - Bitmap( uint32_t* data, uint32_t width, uint32_t height, uint16_t bitCount - ) - : data(data) - , width(width) - , height(height) - , bitCount(bitCount) - { - } + ); - Bitmap(std::istream& input) { - load(input); - } + Bitmap(std::istream& input); - void save(std::ostream& output) { - if (bitCount == 24) - save24bit(output); - if (bitCount == 32) - save32bit(output); - } + void save(std::ostream& output); + int load(std::istream& input); private: - void save24bit(std::ostream& output) const - { - BitmapHeader bh; - DibHeader dh; - uint16_t suffix; - uint32_t zero = 0; - const uint32_t* ptr; - - suffix = (4 - (3 * width) % 4) % 4; - - dh.biSize = sizeof(DibHeader); - dh.biWidth = width; - dh.biHeight = height; - dh.biPlanes = 1; - dh.biBitCount = 24; - dh.biCompression = 0; - dh.biSizeImage = (uint32_t)((width * 3 + suffix) * height); - dh.biXPelsPerMeter = 0x2E23; - dh.biYPelsPerMeter = dh.biXPelsPerMeter; - dh.biClrUsed = 0; - dh.biClrImportant = 0; - - bh.bfType = 0x4D42; - bh.bfSize = dh.biSizeImage + 0x0036; - bh.bfRes1 = 0; - bh.bfOffBits = 0x0036; - output.write((char*)&bh, sizeof(BitmapHeader)); - output.write((char*)&dh, sizeof(DibHeader)); - - ptr = data + (width * height); - for (uint32_t i = 0; i < height; i++) - { - ptr -= width; - - for (uint32_t j = 0; j < width; ++j) - output.write((char*)(ptr + j), 3); - - if (suffix > 0) - output.write((char*)&zero, suffix); - } - } - - void save32bit(std::ostream& output) const - { - BitmapHeader bh; - DibHeaderV5 dh = { 0 }; - uint16_t suffix; - uint32_t zero = 0; - const uint32_t* ptr; - - dh.bV5Size = sizeof(DibHeaderV5); - dh.bV5Width = width; - dh.bV5Height = height; - dh.bV5Planes = 1; - dh.bV5BitCount = 32; - dh.bV5Compression = 3; - dh.bV5SizeImage = 0; - dh.bV5XPelsPerMeter = 0x2E23; - dh.bV5YPelsPerMeter = dh.bV5XPelsPerMeter; - dh.bV5ClrUsed = 0; - dh.bV5ClrImportant = 0; - dh.bV5RedMask = 0x00ff0000; - dh.bV5GreenMask = 0x0000ff00; - dh.bV5BlueMask = 0x000000ff; - dh.bV5AlphaMask = 0xff000000; - dh.bV5CSType = 0x57696e20;// 'Win ' - - bh.bfType = 0x4D42; // 'BM' - bh.bfSize = width * height * 4 + sizeof(DibHeaderV5) + sizeof(BitmapHeader); - bh.bfRes1 = 0; - bh.bfOffBits = sizeof(DibHeaderV5) + sizeof(BitmapHeader); - output.write((char*)&bh, sizeof(BitmapHeader)); - output.write((char*)&dh, sizeof(DibHeaderV5)); - - ptr = data + (width * height); - for (uint32_t i = 0; i < height; i++) - { - ptr -= width; - - for (uint32_t j = 0; j < width; ++j) - output.write((char*)(ptr + j), 4); - } - } - -public: - int load(std::istream& input) - { - BitmapHeader bh; - input.read((char*)&bh, sizeof(BitmapHeader)); - if (bh.bfType != 0x4D42) return -1; - - uint32_t biSize; - input.read((char*)&biSize, sizeof(uint32_t)); - - if (biSize == sizeof(DibHeader)) - return loadDibHeader(input, bh); - - if (biSize == sizeof(DibHeaderV5)) - return loadV5Header(input, bh); - - return 0; - } - -private: - int loadDibHeader(std::istream& input, const BitmapHeader& bh) - { - DibHeader dh; - input.read((char*)&dh.biWidth, sizeof(DibHeader) - sizeof(uint32_t)); - width = dh.biWidth; - height = dh.biHeight; - bitCount = dh.biBitCount; - - input.seekg(bh.bfOffBits, std::ios_base::_Seekbeg); - if (dh.biBitCount == 24) - return read24bit(input); - - if (dh.biBitCount == 32) - return read32bit(input); - - return -1; - } - - int loadV5Header(std::istream& input, const BitmapHeader& bh) - { - DibHeaderV5 dh; - input.read((char*)&dh.bV5Width, sizeof(DibHeaderV5) - sizeof(uint32_t)); - width = dh.bV5Width; - height = dh.bV5Height; - bitCount = dh.bV5BitCount; - - input.seekg(bh.bfOffBits, std::ios_base::_Seekbeg); - - if (dh.bV5BitCount == 24) - return read24bit(input); - - if (dh.bV5BitCount == 32) - return read32bit(input); - - return -1; - } - - int read24bit(std::istream& input) { - uint16_t suffix; - uint32_t* ptr; - uint32_t zero = 0; - - suffix = (4 - (3 * width) % 4) % 4; - ptr = data = new uint32_t[width * height](); - ptr += width * height; - for (uint32_t i = 0; i < height; i++) - { - ptr -= width; - - for (uint32_t j = 0; j < width; ++j) - { - input.read((char*)(ptr + j), 3); - *(ptr + j) |= 0xFF000000; - } - - if (suffix > 0) - input.read((char*)&zero, suffix); - } - return 0; - } - - int read32bit(std::istream& input) { - uint32_t* ptr; - ptr = data = new uint32_t[width * height](); - ptr += width * height; - for (uint32_t i = 0; i < height; i++) - { - ptr -= width; - - for (uint32_t j = 0; j < width; ++j) - { - input.read((char*)(ptr + j), 4); - } - } - - return 0; - } + void save24bit(std::ostream& output) const; + void save32bit(std::ostream& output) const; + int loadDibHeader(std::istream& input, const BitmapHeader& bh); + int loadV5Header(std::istream& input, const BitmapHeader& bh); + int read24bit(std::istream& input); + int read32bit(std::istream& input); }; \ No newline at end of file diff --git a/source/HQ2x.cc b/source/HQ2x.cc index 5d0b4dc..e24ee2d 100644 --- a/source/HQ2x.cc +++ b/source/HQ2x.cc @@ -72,7 +72,7 @@ uint32_t *HQ2x::resize( // adjusts the previous and next line pointers if (row > 0) - previous = -width; + previous = -(int)width; else { if (wrapY) @@ -85,7 +85,7 @@ uint32_t *HQ2x::resize( else { if (wrapY) - next = -(width * (height - 1)); + next = -(int)(width * (height - 1)); else next = 0; } diff --git a/source/HQ3x.cc b/source/HQ3x.cc index c35a747..ea66d70 100644 --- a/source/HQ3x.cc +++ b/source/HQ3x.cc @@ -71,7 +71,7 @@ uint32_t *HQ3x::resize( // adjusts the previous and next line pointers if (row > 0) - previous = -width; + previous = -(int)width; else { if (wrapY) @@ -84,7 +84,7 @@ uint32_t *HQ3x::resize( else { if (wrapY) - next = -(width * (height - 1)); + next = -(int)(width * (height - 1)); else next = 0; } diff --git a/source/bitmap.cc b/source/bitmap.cc new file mode 100644 index 0000000..b87b891 --- /dev/null +++ b/source/bitmap.cc @@ -0,0 +1,204 @@ +#include "Bitmap.h" + +Bitmap::Bitmap( + uint32_t* data, + uint32_t width, + uint32_t height, + uint16_t bitCount +) + : data(data) + , width(width) + , height(height) + , bitCount(bitCount) +{ +} + +Bitmap::Bitmap(std::istream& input) { + load(input); +} + +void Bitmap::save(std::ostream& output) { + if (bitCount == 24) + save24bit(output); + if (bitCount == 32) + save32bit(output); +} + +void Bitmap::save24bit(std::ostream& output) const +{ + BitmapHeader bh; + DibHeader dh; + uint16_t suffix; + uint32_t zero = 0; + const uint32_t* ptr; + + suffix = (4 - (3 * width) % 4) % 4; + + dh.biSize = sizeof(DibHeader); + dh.biWidth = width; + dh.biHeight = height; + dh.biPlanes = 1; + dh.biBitCount = 24; + dh.biCompression = 0; + dh.biSizeImage = (uint32_t)((width * 3 + suffix) * height); + dh.biXPelsPerMeter = 0x2E23; + dh.biYPelsPerMeter = dh.biXPelsPerMeter; + dh.biClrUsed = 0; + dh.biClrImportant = 0; + + bh.bfType = 0x4D42; + bh.bfSize = dh.biSizeImage + 0x0036; + bh.bfRes1 = 0; + bh.bfOffBits = 0x0036; + output.write((char*)&bh, sizeof(BitmapHeader)); + output.write((char*)&dh, sizeof(DibHeader)); + + ptr = data + (width * height); + for (uint32_t i = 0; i < height; i++) + { + ptr -= width; + + for (uint32_t j = 0; j < width; ++j) + output.write((char*)(ptr + j), 3); + + if (suffix > 0) + output.write((char*)&zero, suffix); + } +} + +void Bitmap::save32bit(std::ostream& output) const +{ + BitmapHeader bh; + DibHeaderV5 dh = { 0 }; + uint32_t zero = 0; + const uint32_t* ptr; + + dh.bV5Size = sizeof(DibHeaderV5); + dh.bV5Width = width; + dh.bV5Height = height; + dh.bV5Planes = 1; + dh.bV5BitCount = 32; + dh.bV5Compression = 3; + dh.bV5SizeImage = 0; + dh.bV5XPelsPerMeter = 0x2E23; + dh.bV5YPelsPerMeter = dh.bV5XPelsPerMeter; + dh.bV5ClrUsed = 0; + dh.bV5ClrImportant = 0; + dh.bV5RedMask = 0x00ff0000; + dh.bV5GreenMask = 0x0000ff00; + dh.bV5BlueMask = 0x000000ff; + dh.bV5AlphaMask = 0xff000000; + dh.bV5CSType = 0x57696e20;// 'Win ' + + bh.bfType = 0x4D42; // 'BM' + bh.bfSize = width * height * 4 + sizeof(DibHeaderV5) + sizeof(BitmapHeader); + bh.bfRes1 = 0; + bh.bfOffBits = sizeof(DibHeaderV5) + sizeof(BitmapHeader); + output.write((char*)&bh, sizeof(BitmapHeader)); + output.write((char*)&dh, sizeof(DibHeaderV5)); + + ptr = data + (width * height); + for (uint32_t i = 0; i < height; i++) + { + ptr -= width; + + for (uint32_t j = 0; j < width; ++j) + output.write((char*)(ptr + j), 4); + } +} + +int Bitmap::load(std::istream& input) +{ + BitmapHeader bh; + input.read((char*)&bh, sizeof(BitmapHeader)); + if (bh.bfType != 0x4D42) return -1; + + uint32_t biSize; + input.read((char*)&biSize, sizeof(uint32_t)); + + if (biSize == sizeof(DibHeader)) + return loadDibHeader(input, bh); + + if (biSize == sizeof(DibHeaderV5)) + return loadV5Header(input, bh); + + return 0; +} + +int Bitmap::loadDibHeader(std::istream& input, const BitmapHeader& bh) +{ + DibHeader dh; + input.read((char*)&dh.biWidth, sizeof(DibHeader) - sizeof(uint32_t)); + width = dh.biWidth; + height = dh.biHeight; + bitCount = dh.biBitCount; + + input.seekg(bh.bfOffBits, std::ios_base::_Seekbeg); + if (dh.biBitCount == 24) + return read24bit(input); + + if (dh.biBitCount == 32) + return read32bit(input); + + return -1; +} + +int Bitmap::loadV5Header(std::istream& input, const BitmapHeader& bh) +{ + DibHeaderV5 dh; + input.read((char*)&dh.bV5Width, sizeof(DibHeaderV5) - sizeof(uint32_t)); + width = dh.bV5Width; + height = dh.bV5Height; + bitCount = dh.bV5BitCount; + + input.seekg(bh.bfOffBits, std::ios_base::_Seekbeg); + + if (dh.bV5BitCount == 24) + return read24bit(input); + + if (dh.bV5BitCount == 32) + return read32bit(input); + + return -1; +} + +int Bitmap::read24bit(std::istream& input) { + uint16_t suffix; + uint32_t* ptr; + uint32_t zero = 0; + + suffix = (4 - (3 * width) % 4) % 4; + ptr = data = new uint32_t[width * height](); + ptr += width * height; + for (uint32_t i = 0; i < height; i++) + { + ptr -= width; + + for (uint32_t j = 0; j < width; ++j) + { + input.read((char*)(ptr + j), 3); + *(ptr + j) |= 0xFF000000; + } + + if (suffix > 0) + input.read((char*)&zero, suffix); + } + return 0; +} + +int Bitmap::read32bit(std::istream& input) { + uint32_t* ptr; + ptr = data = new uint32_t[width * height](); + ptr += width * height; + for (uint32_t i = 0; i < height; i++) + { + ptr -= width; + + for (uint32_t j = 0; j < width; ++j) + { + input.read((char*)(ptr + j), 4); + } + } + + return 0; +}