From 6587d22d2c84187ff2133e28984a73eb2eaa5001 Mon Sep 17 00:00:00 2001 From: Tobi-D7 Date: Fri, 15 Apr 2022 13:13:38 +0200 Subject: [PATCH] Update --- internal/bmp.cpp | 52 +++++++ internal/bmp.hpp | 368 ++--------------------------------------------- 2 files changed, 65 insertions(+), 355 deletions(-) create mode 100644 internal/bmp.cpp diff --git a/internal/bmp.cpp b/internal/bmp.cpp new file mode 100644 index 0000000..dbf07a0 --- /dev/null +++ b/internal/bmp.cpp @@ -0,0 +1,52 @@ +#include "bmp.hpp" + +#include +#include +#include +#include +#include <3ds.h> +extern "C" +{ + #include "fs.h" +} + +void BMP::PutPixel565(u8* dst, u8 x, u8 y, u16 v){ + dst[(x+(47-y)*48)*3+0]=(v&0x1F)<<3; + dst[(x+(47-y)*48)*3+1]=((v>>5)&0x3F)<<2; + dst[(x+(47-y)*48)*3+2]=((v>>11)&0x1F)<<3; +} + +void BMP::Save(std::string path, BMP::Bitmap *bitmap) +{ + //Handle fileHandle; + FS_OpenArchive(&sdmc_archive, ARCHIVE_SDMC); + + + u32 bytesWritten; + u8 moltiplier = bitmap->bitperpixel >> 3; + u8* tempbuf = (u8*)malloc(0x36+(bitmap->width)*(bitmap->height)*moltiplier); + memset(tempbuf, 0, 0x36+(bitmap->width)*(bitmap->height)*moltiplier); + tempbuf[0x36+(bitmap->width)*(bitmap->height)*moltiplier]=0; + //FS_CreateFile(sdmc_archive, path.c_str(), (u16)(0x36+(bitmap->width)*(bitmap->height)*moltiplier)) + //Result ret = FS_OpenFile(fileHandle, sdmc_archive, path.c_str(), (FS_OPEN_READ | FS_OPEN_WRITE), 0); + if(ret) printf("error"); + *(u16*)&tempbuf[0x0] = 0x4D42; + *(u32*)&tempbuf[0x2] = 0x36 + (bitmap->width)*(bitmap->height)*moltiplier; + *(u32*)&tempbuf[0xA] = 0x36; + *(u32*)&tempbuf[0xE] = 0x28; + *(u32*)&tempbuf[0x12] = bitmap->width; + *(u32*)&tempbuf[0x16] = bitmap->height; + if (moltiplier == 3) *(u32*)&tempbuf[0x1A] = 0x00180001; + else *(u32*)&tempbuf[0x1A] = 0x00200001; + *(u32*)&tempbuf[0x22] = (bitmap->width)*(bitmap->height)*moltiplier; + int i=0; + while (i<((bitmap->width)*(bitmap->height)*moltiplier)){ + tempbuf[0x36+i] = bitmap->pixels[i]; + i++; + } + //FSFILE_Write(fileHandle, &bytesWritten, 0, (u32*)tempbuf, 0x36 + (src->width)*(src->height)*moltiplier, 0x10001); + FS_Write(sdmc_archive, path.c_str(), (u32*)tempbuf, 0x36 + (src->width)*(src->height)*moltiplier, 0x10001); + + free(tempbuf); + FS_CloseArchive(sdmc_archive); +} \ No newline at end of file diff --git a/internal/bmp.hpp b/internal/bmp.hpp index 65aed86..3708cc5 100644 --- a/internal/bmp.hpp +++ b/internal/bmp.hpp @@ -3,359 +3,17 @@ #include #include #include -using namespace std; -#pragma pack(push, 1) +#include <3ds.h> - -struct BMPFileHeader { - uint16_t file_type{ 0x4D42 }; // File type always BM which is 0x4D42 (stored as hex uint16_t in little endian) - uint32_t file_size{ 0 }; // Size of the file (in bytes) - uint16_t reserved1{ 0 }; // Reserved, always 0 - uint16_t reserved2{ 0 }; // Reserved, always 0 - uint32_t offset_data{ 0 }; // Start position of pixel data (bytes from the beginning of the file) -}; - -struct BMPInfoHeader { - uint32_t size{ 0 }; // Size of this header (in bytes) - int32_t width{ 0 }; // width of bitmap in pixels - int32_t height{ 0 }; // height of bitmap in pixels - // (if positive, bottom-up, with origin in lower left corner) - // (if negative, top-down, with origin in upper left corner) - uint16_t planes{ 1 }; // No. of planes for the target device, this is always 1 - uint16_t bit_count{ 0 }; // No. of bits per pixel - uint32_t compression{ 0 }; // 0 or 3 - uncompressed. THIS PROGRAM CONSIDERS ONLY UNCOMPRESSED BMP images - uint32_t size_image{ 0 }; // 0 - for uncompressed images - int32_t x_pixels_per_meter{ 0 }; - int32_t y_pixels_per_meter{ 0 }; - uint32_t colors_used{ 0 }; // No. color indexes in the color table. Use 0 for the max number of colors allowed by bit_count - uint32_t colors_important{ 0 }; // No. of colors used for displaying the bitmap. If 0 all colors are required -}; - -struct BMPColorHeader { - uint32_t red_mask{ 0x00ff0000 }; // Bit mask for the red channel - uint32_t green_mask{ 0x0000ff00 }; // Bit mask for the green channel - uint32_t blue_mask{ 0x000000ff }; // Bit mask for the blue channel - uint32_t alpha_mask{ 0xff000000 }; // Bit mask for the alpha channel - uint32_t color_space_type{ 0x73524742 }; // Default "sRGB" (0x73524742) - uint32_t unused[16]{ 0 }; // Unused data for sRGB color space -}; -#pragma pack(pop) - -struct BMP { - BMPFileHeader file_header; - BMPInfoHeader bmp_info_header; - BMPColorHeader bmp_color_header; - std::vector data; - - - BMP(const char *fname) { - read(fname); - } - - void read(const char *fname) { - std::ifstream inp{ fname, std::ios_base::binary }; - if (inp) { - inp.read((char*)&file_header, sizeof(file_header)); - if(file_header.file_type != 0x4D42) { - throw std::runtime_error("Error! Unrecognized file format."); - } - inp.read((char*)&bmp_info_header, sizeof(bmp_info_header)); - - // The BMPColorHeader is used only for transparent images - if(bmp_info_header.bit_count == 32) { - // Check if the file has bit mask color information - if(bmp_info_header.size >= (sizeof(BMPInfoHeader) + sizeof(BMPColorHeader))) { - inp.read((char*)&bmp_color_header, sizeof(bmp_color_header)); - // Check if the pixel data is stored as BGRA and if the color space type is sRGB - check_color_header(bmp_color_header); - } else { - std::cerr << "Error! The file \"" << fname << "\" does not seem to contain bit mask information\n"; - throw std::runtime_error("Error! Unrecognized file format."); - } - } - - // Jump to the pixel data location - inp.seekg(file_header.offset_data, inp.beg); - - // Adjust the header fields for output. - // Some editors will put extra info in the image file, we only save the headers and the data. - if(bmp_info_header.bit_count == 32) { - bmp_info_header.size = sizeof(BMPInfoHeader) + sizeof(BMPColorHeader); - file_header.offset_data = sizeof(BMPFileHeader) + sizeof(BMPInfoHeader) + sizeof(BMPColorHeader); - } else { - bmp_info_header.size = sizeof(BMPInfoHeader); - file_header.offset_data = sizeof(BMPFileHeader) + sizeof(BMPInfoHeader); - } - file_header.file_size = file_header.offset_data; - - if (bmp_info_header.height < 0) { - throw std::runtime_error("The program can treat only BMP images with the origin in the bottom left corner!"); - } - - data.resize(bmp_info_header.width * bmp_info_header.height * bmp_info_header.bit_count / 8); - - // Here we check if we need to take into account row padding - if (bmp_info_header.width % 4 == 0) { - inp.read((char*)data.data(), data.size()); - file_header.file_size += static_cast(data.size()); - } - else { - row_stride = bmp_info_header.width * bmp_info_header.bit_count / 8; - uint32_t new_stride = make_stride_aligned(4); - std::vector padding_row(new_stride - row_stride); - - for (int y = 0; y < bmp_info_header.height; ++y) { - inp.read((char*)(data.data() + row_stride * y), row_stride); - inp.read((char*)padding_row.data(), padding_row.size()); - } - file_header.file_size += static_cast(data.size()) + bmp_info_header.height * static_cast(padding_row.size()); - } - } - else { - throw std::runtime_error("Unable to open the input image file "+std::string(fname)); - } - } - - BMP(int32_t width, int32_t height, bool has_alpha = true) { - if (width <= 0 || height <= 0) { - throw std::runtime_error("The image width and height must be positive numbers."); - } - - bmp_info_header.width = width; - bmp_info_header.height = height; - if (has_alpha) { - bmp_info_header.size = sizeof(BMPInfoHeader) + sizeof(BMPColorHeader); - file_header.offset_data = sizeof(BMPFileHeader) + sizeof(BMPInfoHeader) + sizeof(BMPColorHeader); - - bmp_info_header.bit_count = 32; - bmp_info_header.compression = 3; - row_stride = width * 4; - data.resize(row_stride * height); - file_header.file_size = file_header.offset_data + data.size(); - } - else { - bmp_info_header.size = sizeof(BMPInfoHeader); - file_header.offset_data = sizeof(BMPFileHeader) + sizeof(BMPInfoHeader); - - bmp_info_header.bit_count = 24; - bmp_info_header.compression = 0; - row_stride = width * 3; - data.resize(row_stride * height); - - uint32_t new_stride = make_stride_aligned(4); - file_header.file_size = file_header.offset_data + static_cast(data.size()) + bmp_info_header.height * (new_stride - row_stride); - } - } - - void write(const char *fname) { - std::ofstream of{ fname, std::ios_base::binary }; - if (of) { - if (bmp_info_header.bit_count == 32) { - write_headers_and_data(of); - } - else if (bmp_info_header.bit_count == 24) { - if (bmp_info_header.width % 4 == 0) { - write_headers_and_data(of); - } - else { - uint32_t new_stride = make_stride_aligned(4); - std::vector padding_row(new_stride - row_stride); - - write_headers(of); - - for (int y = 0; y < bmp_info_header.height; ++y) { - of.write((const char*)(data.data() + row_stride * y), row_stride); - of.write((const char*)padding_row.data(), padding_row.size()); - } - } - } - else { - throw std::runtime_error("The program can treat only 24 or 32 bits per pixel BMP files"); - } - } - else { - throw std::runtime_error("Unable to open the output image file."); - } - } - - void fill_region(uint32_t x0, uint32_t y0, uint32_t w, uint32_t h, uint8_t B, uint8_t G, uint8_t R, uint8_t A) { - if (x0 + w > (uint32_t)bmp_info_header.width || y0 + h > (uint32_t)bmp_info_header.height) { - throw std::runtime_error("The region does not fit in the image!"); - } - - uint32_t channels = bmp_info_header.bit_count / 8; - for (uint32_t y = y0; y < y0 + h; ++y) { - for (uint32_t x = x0; x < x0 + w; ++x) { - data[channels * (y * bmp_info_header.width + x) + 0] = B; - data[channels * (y * bmp_info_header.width + x) + 1] = G; - data[channels * (y * bmp_info_header.width + x) + 2] = R; - if (channels == 4) { - data[channels * (y * bmp_info_header.width + x) + 3] = A; - } - } - } - } - - int OrganizeAverageRed() - { - int ColorRed[bmp_info_header.height][bmp_info_header.width]; - int ColorGreen[bmp_info_header.height][bmp_info_header.width];; - int ColorBlue[bmp_info_header.height][bmp_info_header.width]; - float pixels=bmp_info_header.height*bmp_info_header.width; - float intensity=0; - float sum=0; - uint32_t channels = bmp_info_header.bit_count / 8; - cout << "The Width of the image is " << bmp_info_header.width << endl; - cout << "The height of the image is " << bmp_info_header.height << endl; - for (int y = 0; y < bmp_info_header.height; ++y) { - for (int x = 0; x < bmp_info_header.width; ++x) { - //cout << channels*(y*bmp_info_header.width+x) << endl; - //Read red - ColorBlue[y][x]=data[channels * (y * bmp_info_header.width + x) + 0]; - ColorGreen[y][x]=data[channels * (y * bmp_info_header.width + x) + 1]; - ColorRed[y][x]=data[channels * (y * bmp_info_header.width + x) + 2]; - } - } - for(int y=0; y= (uint32_t)bmp_info_header.width || y0 >= (uint32_t)bmp_info_header.height || x0 < 0 || y0 < 0) { - throw std::runtime_error("The point is outside the image boundaries!"); - } - uint32_t channels = bmp_info_header.bit_count / 8; - data[channels * (y0 * bmp_info_header.width + x0) + 0] = B; - data[channels * (y0 * bmp_info_header.width + x0) + 1] = G; - data[channels * (y0 * bmp_info_header.width + x0) + 2] = R; - if (channels == 4) { - data[channels * (y0 * bmp_info_header.width + x0) + 3] = A; - } - } - - void draw_rectangle(uint32_t x0, uint32_t y0, uint32_t w, uint32_t h, - uint8_t B, uint8_t G, uint8_t R, uint8_t A, uint8_t line_w) { - if (x0 + w > (uint32_t)bmp_info_header.width || y0 + h > (uint32_t)bmp_info_header.height) { - throw std::runtime_error("The rectangle does not fit in the image!"); - } - - fill_region(x0, y0, w, line_w, B, G, R, A); // top line - fill_region(x0, (y0 + h - line_w), w, line_w, B, G, R, A); // bottom line - fill_region((x0 + w - line_w), (y0 + line_w), line_w, (h - (2 * line_w)), B, G, R, A); // right line - fill_region(x0, (y0 + line_w), line_w, (h - (2 * line_w)), B, G, R, A); // left line - } - -private: - uint32_t row_stride{ 0 }; - - void write_headers(std::ofstream &of) { - of.write((const char*)&file_header, sizeof(file_header)); - of.write((const char*)&bmp_info_header, sizeof(bmp_info_header)); - if(bmp_info_header.bit_count == 32) { - of.write((const char*)&bmp_color_header, sizeof(bmp_color_header)); - } - } - - void write_headers_and_data(std::ofstream &of) { - write_headers(of); - of.write((const char*)data.data(), data.size()); - } - - // Add 1 to the row_stride until it is divisible with align_stride - uint32_t make_stride_aligned(uint32_t align_stride) { - uint32_t new_stride = row_stride; - while (new_stride % align_stride != 0) { - new_stride++; - } - return new_stride; - } - - // Check if the pixel data is stored as BGRA and if the color space type is sRGB - void check_color_header(BMPColorHeader &bmp_color_header) { - BMPColorHeader expected_color_header; - if(expected_color_header.red_mask != bmp_color_header.red_mask || - expected_color_header.blue_mask != bmp_color_header.blue_mask || - expected_color_header.green_mask != bmp_color_header.green_mask || - expected_color_header.alpha_mask != bmp_color_header.alpha_mask) { - throw std::runtime_error("Unexpected color mask format! The program expects the pixel data to be in the BGRA format"); - } - if(expected_color_header.color_space_type != bmp_color_header.color_space_type) { - throw std::runtime_error("Unexpected color space type! The program expects sRGB values"); - } - } -}; \ No newline at end of file +namespace BMP +{ + struct Bitmap{ + u32 magic; + u8* pixels; + int width; + int height; + u16 bitperpixel; + }; + void PutPixel565(u8* dst, u8 x, u8 y, u16 v); + void Save(std::string path, BMP::Bitmap *bitmap); +} \ No newline at end of file