diff options
| author | BossCode45 <boss@tehbox.org> | 2025-06-27 17:58:36 +1200 |
|---|---|---|
| committer | BossCode45 <boss@tehbox.org> | 2025-07-24 12:48:21 +1200 |
| commit | 078b4e08fe3bccb7424dac76e158bf8bf48a182d (patch) | |
| tree | a4f84f3fc346053c1c41990be4cc0867ab206cf5 /src | |
| parent | eed164fa72297efb69b624f3c58cb5deb339a974 (diff) | |
| download | tehimage-078b4e08fe3bccb7424dac76e158bf8bf48a182d.tar.gz tehimage-078b4e08fe3bccb7424dac76e158bf8bf48a182d.zip | |
feat: Made it so that you can now convert between image subclasses
Also added the bitmap image subclass
note: this is pretty hacky in how it works
Diffstat (limited to 'src')
| -rw-r--r-- | src/BMPImage.cpp | 49 | ||||
| -rw-r--r-- | src/BMPImage.h | 15 | ||||
| -rw-r--r-- | src/PNGImage.cpp | 148 | ||||
| -rw-r--r-- | src/PNGImage.h | 12 | ||||
| -rw-r--r-- | src/image.cpp | 3 | ||||
| -rw-r--r-- | src/image.h | 43 |
6 files changed, 180 insertions, 90 deletions
diff --git a/src/BMPImage.cpp b/src/BMPImage.cpp new file mode 100644 index 0000000..71e5317 --- /dev/null +++ b/src/BMPImage.cpp @@ -0,0 +1,49 @@ +#include "BMPImage.h" + +#include <iostream> + +using std::cout, std::endl; + +int BMPImage::readFromFile(std::string filename) +{ + cout << "Not implemented" << endl; + return 2; +}; + +int BMPImage::writeToFile(std::string filename) +{ + FILE* fd = fopen(filename.c_str(), "w"); + char magic[] = "BM"; + fwrite(magic, sizeof(char), 2, fd); + uint32_t fileSize = 14 + 12 + width*height*/*(bitDepth/8)*/8*3; + fwrite(&fileSize, sizeof(uint32_t), 1, fd); + char zero[] = "\0\0\0\0"; + fwrite(zero, sizeof(char), 4, fd); + uint32_t offset = 26; + fwrite(&offset, sizeof(uint32_t), 1, fd); + uint32_t headerSize = 12; + fwrite(&headerSize, sizeof(uint32_t), 1, fd); + uint16_t width = this->width; + uint16_t height = this->height; + uint16_t colorPlanes = 1; + uint16_t bitsPerPixel = /*bitDepth*/8*3; + fwrite(&width, sizeof(uint16_t), 1, fd); + fwrite(&height, sizeof(uint16_t), 1, fd); + fwrite(&colorPlanes, sizeof(uint16_t), 1, fd); + fwrite(&bitsPerPixel, sizeof(uint16_t), 1, fd); + + for(int y = height-1; y >= 0; y--) + { + for(int x = 0; x < width; x++) + { + Pixel<uint8_t> pixel = getPixel<uint8_t>(x, y); + fwrite(&pixel.b, bitDepth/8, 1, fd); + fwrite(&pixel.g, bitDepth/8, 1, fd); + fwrite(&pixel.r, bitDepth/8, 1, fd); + } + } + + fclose(fd); + + return 0; +}; diff --git a/src/BMPImage.h b/src/BMPImage.h new file mode 100644 index 0000000..697c72d --- /dev/null +++ b/src/BMPImage.h @@ -0,0 +1,15 @@ +#pragma once + +#include "image.h" +#include <cstdint> +#include <cstring> + +class BMPImage : public Image +{ +private: +public: + template<std::derived_from<Image> T> BMPImage(const T& other) : Image(other) { } + + int readFromFile(std::string filename) override; + int writeToFile(std::string filename) override; +}; diff --git a/src/PNGImage.cpp b/src/PNGImage.cpp index b7f28ce..50df7c6 100644 --- a/src/PNGImage.cpp +++ b/src/PNGImage.cpp @@ -14,9 +14,7 @@ using std::cout, std::endl; -PNGImage::PNGImage(std::string filename) - :reader(filename) - ,idatData() +PNGImage::PNGImage() { //cout << "Reader good" << endl; REGISTER_CHUNK_READER(IHDR); @@ -32,11 +30,6 @@ PNGImage::PNGImage(std::string filename) //cout << "Chunk readers loaded" << endl; - char signature[8]; - uint8_t expected[] = {137, 80, 78, 71, 13, 10, 26, 10}; - reader.readBytes(signature, 8); - if(strncmp(signature, (char*)expected, 8) != 0) - cout << "UH OH" << endl; idatData = nullptr; idatDataSize = 0; @@ -50,14 +43,39 @@ PNGImage::~PNGImage() idatDataSize = 0; } +int PNGImage::readFromFile(std::string filename) +{ + std::unique_ptr<Reader> readerMem(new Reader(filename)); + reader = readerMem.get(); + + char signature[8]; + uint8_t expected[] = {137, 80, 78, 71, 13, 10, 26, 10}; + reader->readBytes(signature, 8); + if(strncmp(signature, (char*)expected, 8) != 0) + { + cout << "Not a PNG" << endl; + return 1; + } + + while (readNextChunk()) {} + + return 0; +}; + +int PNGImage::writeToFile(std::string filename) +{ + cout << "Not implemented" << endl; + return 2; +}; + bool PNGImage::readNextChunk() { if(end) return false; - uint32_t chunkSize = reader.readData<uint32_t>(); + uint32_t chunkSize = reader->readData<uint32_t>(); char chunkType[4]; - reader.readBytes(chunkType, 4); + reader->readBytes(chunkType, 4); std::string chunkName(chunkType, 4); cout << "-------------" << endl; cout << "|Chunk: " << chunkName << "|" << endl; @@ -66,7 +84,7 @@ bool PNGImage::readNextChunk() if(chunkReaders.count(chunkName) == 0) { cout << "Chunk reader not found!!!" << endl; - reader.skipBytes(chunkSize + 4); + reader->skipBytes(chunkSize + 4); if(islower(chunkType[0])) { cout << "\tAble to skip chunk" << endl; @@ -79,20 +97,20 @@ bool PNGImage::readNextChunk() void(PNGImage::*chunkReader)(uint32_t chunkSize) = chunkReaders.find(chunkName)->second; (this->*chunkReader)(chunkSize); - reader.skipBytes(4); // CRC + reader->skipBytes(4); // CRC return true; } DEFINE_CHUNK_READER(IHDR) { - width = reader.readData<uint32_t>(); - height = reader.readData<uint32_t>(); - bitDepth = reader.readData<uint8_t>(); - colorType = reader.readData<uint8_t>(); - compressionMethod = reader.readData<uint8_t>(); - filterMethod = reader.readData<uint8_t>(); - interlaceMethod = reader.readData<uint8_t>(); + width = reader->readData<uint32_t>(); + height = reader->readData<uint32_t>(); + bitDepth = reader->readData<uint8_t>(); + colorType = reader->readData<uint8_t>(); + compressionMethod = reader->readData<uint8_t>(); + filterMethod = reader->readData<uint8_t>(); + interlaceMethod = reader->readData<uint8_t>(); cout << "Width: " << width << ", Height: " << height << ", Bit depth: " << 0+bitDepth << ", Color type: " << 0+colorType << ", Compression method: " << 0+compressionMethod << ", Filter method: " << 0+filterMethod << ", Interlace method: " << 0+interlaceMethod << endl; if(colorType != 2 && colorType != 6) @@ -108,6 +126,7 @@ DEFINE_CHUNK_READER(IHDR) bpp = colorValues * (bitDepth/8); unsigned long imageDataSize = width * height * bpp; + //imageDataSize = imageDataSize; cout << "Assigning " << imageDataSize << " bytes for image" << endl; @@ -127,48 +146,48 @@ DEFINE_CHUNK_READER(iCCP) { cout << "!!! iCCP chunk reader not finished !!!" << endl; std::string profileName; - char c = reader.readByte(); + char c = reader->readByte(); chunkSize--; while(c != 0) { profileName.push_back(c); - c = reader.readByte(); + c = reader->readByte(); chunkSize--; } cout << profileName << endl; - uint8_t compresssionMethod = reader.readByte(); + uint8_t compresssionMethod = reader->readByte(); chunkSize--; cout << 0+compresssionMethod << endl; - uint8_t CMF = reader.readByte(); + uint8_t CMF = reader->readByte(); uint8_t CM = CMF & 0b00001111; uint8_t CINFO = (CMF & 0b11110000) >> 4; chunkSize--; - uint8_t FLG = reader.readByte(); + uint8_t FLG = reader->readByte(); bool check = (CMF * 256 + FLG)%31 == 0; bool FDICT = FLG & 0b00100000; uint8_t FLEVEL = FLG & 0b11000000; chunkSize--; cout << std::bitset<4>(CM) << ", " << std::bitset<4>(CINFO) << ", " << (check?"Valid":"Failed checksum") << ", " << (FDICT?"Dict is present":"No dict present") << ", " << std::bitset<2>(FLEVEL) << endl; char compressedData[chunkSize - 4]; - reader.readBytes(compressedData, chunkSize - 4); + reader->readBytes(compressedData, chunkSize - 4); const int compressedSize = chunkSize - 4; - uint32_t checkValue = reader.readData<uint32_t>(); + uint32_t checkValue = reader->readData<uint32_t>(); //end = true; } DEFINE_CHUNK_READER(sRGB) { - renderingIntent = reader.readData<uint8_t>(); + renderingIntent = reader->readData<uint8_t>(); cout << "Rendering intent: " << 0+renderingIntent << endl; } DEFINE_CHUNK_READER(eXIf) { char endian[4]; - reader.readBytes(endian, 4); + reader->readBytes(endian, 4); for(int i = 0; i < 2; i++) { cout << endian[i]; @@ -179,7 +198,7 @@ DEFINE_CHUNK_READER(eXIf) } cout << endl; char rest[chunkSize - 4]; - reader.readBytes(rest, chunkSize - 4); + reader->readBytes(rest, chunkSize - 4); cout << std::hex; for(int i = 0; i < chunkSize - 4; i++) { @@ -191,25 +210,25 @@ DEFINE_CHUNK_READER(eXIf) DEFINE_CHUNK_READER(iDOT) { cout << "!!! Ignoring iDOT !!!" << endl; - reader.skipBytes(chunkSize); + reader->skipBytes(chunkSize); } DEFINE_CHUNK_READER(pHYs) { - pixelsPerX = reader.readData<uint32_t>(); - pixelsPerY = reader.readData<uint32_t>(); - unit = reader.readData<uint8_t>(); + pixelsPerX = reader->readData<uint32_t>(); + pixelsPerY = reader->readData<uint32_t>(); + unit = reader->readData<uint8_t>(); cout << "Pixels per unit (x): " << pixelsPerX << ", Pixels per unit (y): " << pixelsPerY << ", unit: " << 0+unit << endl; } DEFINE_CHUNK_READER(tIME) { - year = reader.readData<uint16_t>(); - month = reader.readData<uint8_t>(); - day = reader.readData<uint8_t>(); - hour = reader.readData<uint8_t>(); - minute = reader.readData<uint8_t>(); - second = reader.readData<uint8_t>(); + year = reader->readData<uint16_t>(); + month = reader->readData<uint8_t>(); + day = reader->readData<uint8_t>(); + hour = reader->readData<uint8_t>(); + minute = reader->readData<uint8_t>(); + second = reader->readData<uint8_t>(); cout << "Image last modified: " << 0+hour << ":" << 0+minute << ":" << 0+second << " " << 0+day << "-" << 0+month << "-" << 0+year << endl; } @@ -217,22 +236,22 @@ DEFINE_CHUNK_READER(tEXt) { std::string keyword; - char c = reader.readByte(); + char c = reader->readByte(); chunkSize--; while(c != 0) { keyword.push_back(c); - c = reader.readByte(); + c = reader->readByte(); chunkSize--; } cout << keyword << endl; std::string textString; - c = reader.readByte(); + c = reader->readByte(); chunkSize--; while(chunkSize > 0) { textString.push_back(c); - c = reader.readByte(); + c = reader->readByte(); chunkSize--; } textString.push_back(c); @@ -243,11 +262,11 @@ DEFINE_CHUNK_READER(IDAT) { if(idatDataSize == 0) { - uint8_t CMF = reader.readByte(); + uint8_t CMF = reader->readByte(); uint8_t CM = (CMF & 0b11110000) >> 4; uint8_t CINFO = CMF & 0b00001111; chunkSize--; - uint8_t FLG = reader.readByte(); + uint8_t FLG = reader->readByte(); bool check = (CMF * 256 + FLG)%31 == 0; bool FDICT = FLG & 0b00000100; uint8_t FLEVEL = FLG & 0b00000011; @@ -257,7 +276,7 @@ DEFINE_CHUNK_READER(IDAT) } idatData = (uint8_t *)realloc(idatData, idatDataSize + chunkSize); - reader.readBytes((char *)&idatData[idatDataSize], chunkSize); + reader->readBytes((char *)&idatData[idatDataSize], chunkSize); idatDataSize += chunkSize; /* @@ -268,7 +287,7 @@ DEFINE_CHUNK_READER(IDAT) //cout << (int)puff((unsigned char*)imageData, &imageDataSize, (const unsigned char*)compressedData, &compressedSize) << endl; */ - //uint32_t checkValue = reader.readData<uint32_t>(); + //uint32_t checkValue = reader->readData<uint32_t>(); //end = true; } @@ -293,28 +312,7 @@ DEFINE_CHUNK_READER(IEND) uint8_t* pngImageData = new uint8_t[imageDataSize]; cout << "My inflate " << zlib.decodeData(idatData, idatDataSize, pngImageData, imageDataSize) << endl; end = true; - reader.close(); - - - FILE* fd = fopen("tmp.bmp", "w"); - char magic[] = "BM"; - fwrite(magic, sizeof(char), 2, fd); - uint32_t fileSize = 14 + 12 + width*height*/*(bitDepth/8)*/8*3; - fwrite(&fileSize, sizeof(uint32_t), 1, fd); - char zero[] = "\0\0\0\0"; - fwrite(zero, sizeof(char), 4, fd); - uint32_t offset = 26; - fwrite(&offset, sizeof(uint32_t), 1, fd); - uint32_t headerSize = 12; - fwrite(&headerSize, sizeof(uint32_t), 1, fd); - uint16_t width = this->width; - uint16_t height = this->height; - uint16_t colorPlanes = 1; - uint16_t bitsPerPixel = /*bitDepth*/8*3; - fwrite(&width, sizeof(uint16_t), 1, fd); - fwrite(&height, sizeof(uint16_t), 1, fd); - fwrite(&colorPlanes, sizeof(uint16_t), 1, fd); - fwrite(&bitsPerPixel, sizeof(uint16_t), 1, fd); + reader->close(); #define imageDataIndex(x, y) imageData[y*width*bpp + x] #define pngImageDataIndex(x, y) pngImageData[y*(width*bpp + 1) + x + 1] @@ -361,17 +359,5 @@ DEFINE_CHUNK_READER(IEND) #undef pngImageDataIndex #undef filterByte - for(int y = height-1; y >= 0; y--) - { - for(int x = 0; x < width; x++) - { - Pixel<uint8_t> pixel = getPixel<uint8_t>(x, y); - fwrite(&pixel.b, bitDepth/8, 1, fd); - fwrite(&pixel.g, bitDepth/8, 1, fd); - fwrite(&pixel.r, bitDepth/8, 1, fd); - } - } - delete [] pngImageData; - fclose(fd); } diff --git a/src/PNGImage.h b/src/PNGImage.h index 23c32a0..e937212 100644 --- a/src/PNGImage.h +++ b/src/PNGImage.h @@ -6,6 +6,7 @@ #include <cstddef> #include <cstdint> #include <map> +#include <memory> #include <string> #include <vector> @@ -13,15 +14,20 @@ #define REGISTER_CHUNK_READER(X) chunkReaders.insert({#X, &PNGImage::X}) #define DEFINE_CHUNK_READER(X) void PNGImage::X(uint32_t chunkSize) -class PNGImage : Image +class PNGImage : public Image { private: ZLibInflator zlib; uint8_t* idatData; unsigned long idatDataSize; public: - PNGImage(std::string filename); + PNGImage(); ~PNGImage(); + + template<std::derived_from<Image> T> PNGImage(const T& other) : Image(other) { } + + int readFromFile(std::string filename) override; + int writeToFile(std::string filename) override; // sRGB uint8_t renderingIntent; @@ -56,5 +62,5 @@ private: bool end = false; - Reader reader; + Reader *reader; }; diff --git a/src/image.cpp b/src/image.cpp index 35941e5..f819b94 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -2,9 +2,8 @@ Image::~Image() { - if(width != 0 && height != 0) + if(width != 0) { delete[] imageData; } } - diff --git a/src/image.h b/src/image.h index f4071ea..52f4279 100644 --- a/src/image.h +++ b/src/image.h @@ -1,7 +1,8 @@ #pragma once -#include <cstddef> #include <cstdint> +#include <cstring> +#include <string> template <typename T> struct Pixel @@ -9,6 +10,14 @@ struct Pixel T r, g, b, a; }; +struct ImageData +{ + + + + + //unsigned long imageDataSize = 0; +}; class Image { @@ -19,7 +28,16 @@ protected: public: Image() = default; ~Image(); + + template<std::derived_from<Image> T> + Image(const T& other); + + virtual int readFromFile(std::string filename) = 0; + virtual int writeToFile(std::string filename) = 0; + template <typename T> + Pixel<T> getPixel(unsigned int x, unsigned int y); + uint32_t width = 0; uint32_t height = 0; uint8_t bitDepth; @@ -27,12 +45,29 @@ public: uint8_t compressionMethod; uint8_t filterMethod; uint8_t interlaceMethod; - - template <typename T> - Pixel<T> getPixel(unsigned int x, unsigned int y); }; + +template<std::derived_from<Image> T> Image::Image(const T& other) +{ + this->colorValues = other.colorValues; + this->bpp = other.bpp; + + this->width = other.width; + this->height = other.height; + this->bitDepth = other.bitDepth; + this->colorType = other.colorType; + this->compressionMethod = other.compressionMethod; + this->filterMethod = other.filterMethod; + this->interlaceMethod = other.interlaceMethod; + + unsigned long imageDataSize = width * height * bpp; + imageData = new uint8_t[imageDataSize]; + mempcpy(imageData, other.imageData, imageDataSize); +} + + template <typename T> Pixel<T> Image::getPixel(unsigned int x, unsigned int y) { |
