aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDylan <boss@tehbox.org>2025-10-07 18:45:28 +1300
committerDylan <boss@tehbox.org>2025-10-07 19:31:32 +1300
commit328e2464c81b0dfce623d4fbe9617ef79d6ed3c1 (patch)
treeecccb3c6583640af4792efa93ff280f17b4f707a
parent308b65134bd9d185741a612bfad3cca80ddddc48 (diff)
downloadtehimage-328e2464c81b0dfce623d4fbe9617ef79d6ed3c1.tar.gz
tehimage-328e2464c81b0dfce623d4fbe9617ef79d6ed3c1.zip
feat: Added cpp namespacev0.0.2
All functions and classes are now behind the cpp namespace `TehImage`
-rw-r--r--GNUmakefile4
-rw-r--r--libTehImage.nix14
-rw-r--r--src/BMPImage.cpp81
-rw-r--r--src/BMPImage.h21
-rw-r--r--src/PNGImage.cpp613
-rw-r--r--src/PNGImage.h87
-rw-r--r--src/image.cpp39
-rw-r--r--src/image.h61
-rw-r--r--src/reader.cpp149
-rw-r--r--src/reader.h41
-rw-r--r--src/zlib.cpp519
-rw-r--r--src/zlib.h95
-rw-r--r--test/main.cpp4
13 files changed, 892 insertions, 836 deletions
diff --git a/GNUmakefile b/GNUmakefile
index ae7e0db..4f3b83b 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -9,8 +9,8 @@ INSTALL_DIR = $(out)
# Flags
CXX := g++
-CXXFLAGS := -std=c++23 -fsanitize=address -g
-LINKFLAGS := -static-libasan
+CXXFLAGS := -std=c++23 # -fsanitize=address -g
+LINKFLAGS := #-static-libasan
TEST_CXXFLAGS := -std=c++23 -I$(INCLUDE_DIR) -fsanitize=address -g
TEST_LINKFLAGS := -L$(LIB_DIR) -ltehimage -static-libasan
diff --git a/libTehImage.nix b/libTehImage.nix
index d113fd3..d7a9f77 100644
--- a/libTehImage.nix
+++ b/libTehImage.nix
@@ -1,19 +1,25 @@
{
stdenv,
fetchgit,
+ pkgs
}:
stdenv.mkDerivation {
pname = "libTehImage";
- version = "0.0.1";
+ version = "0.0.2";
#outputs = [ "out" "dev" ];
+ buildInputs = [
+ pkgs.gcc
+ pkgs.gnumake
+ ];
+
src = fetchgit {
- url = "https://git.tehbox.org/cgit/boss/tehimage.git";
- rev = "v0.0.1";
- hash = "sha256-S3daS6seroaQJDFbcar+RjVXVV3RciHSx9e0iC+i6+0=";
+ url = "https://git.tehbox.org/boss/tehimage.git";
+ rev = "v0.0.2";
+ hash = "sha256-+kvBfhIqKW5MmtWSZYLUXpOJg14pZ9Qor1N18vcZ2Fc=";
};
preInstall = "mkdir -p $out/include";
diff --git a/src/BMPImage.cpp b/src/BMPImage.cpp
index b9b2c96..b0b7c55 100644
--- a/src/BMPImage.cpp
+++ b/src/BMPImage.cpp
@@ -5,48 +5,53 @@
using std::cout, std::endl;
-int BMPImage::readFromFile(std::string filename)
+namespace TehImage
{
- cout << "Not implemented" << endl;
- return 2;
-};
-int BMPImage::writeToFile(std::string filename)
-{
- FILE* fd = fopen(filename.c_str(), "w");
- char magic[] = "BM";
- uint32_t fileSize = 14 + 12 + width*height*/*(bitDepth/8)*/8*3;
- char zero[] = "\0\0\0\0";
- uint32_t offset = 26;
- uint32_t headerSize = 12;
- uint16_t width = this->width;
- uint16_t height = this->height;
- uint16_t colorPlanes = 1;
- uint16_t bitsPerPixel = /*bitDepth*/8*3;
-
- fwrite(magic, sizeof(char), 2, fd);
- fwrite(&fileSize, sizeof(uint32_t), 1, fd);
- fwrite(zero, sizeof(char), 4, fd);
- fwrite(&offset, sizeof(uint32_t), 1, fd);
- fwrite(&headerSize, sizeof(uint32_t), 1, fd);
-
- 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--)
+ int BMPImage::readFromFile(std::string filename)
+ {
+ cout << "Not implemented" << endl;
+ return 2;
+ };
+
+ int BMPImage::writeToFile(std::string filename)
{
- for(int x = 0; x < width; x++)
+ FILE* fd = fopen(filename.c_str(), "w");
+ char magic[] = "BM";
+ uint32_t fileSize = 14 + 12 + width*height*/*(bitDepth/8)*/8*3;
+ char zero[] = "\0\0\0\0";
+ uint32_t offset = 26;
+ uint32_t headerSize = 12;
+ uint16_t width = this->width;
+ uint16_t height = this->height;
+ uint16_t colorPlanes = 1;
+ uint16_t bitsPerPixel = /*bitDepth*/8*3;
+
+ fwrite(magic, sizeof(char), 2, fd);
+ fwrite(&fileSize, sizeof(uint32_t), 1, fd);
+ fwrite(zero, sizeof(char), 4, fd);
+ fwrite(&offset, sizeof(uint32_t), 1, fd);
+ fwrite(&headerSize, sizeof(uint32_t), 1, fd);
+
+ 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--)
{
- Pixel& pixel = (*this)[x,y];
- fwrite(&pixel.b, sizeof(uint8_t), 1, fd);
- fwrite(&pixel.g, sizeof(uint8_t), 1, fd);
- fwrite(&pixel.r, sizeof(uint8_t), 1, fd);
+ for(int x = 0; x < width; x++)
+ {
+ Pixel& pixel = (*this)[x,y];
+ fwrite(&pixel.b, sizeof(uint8_t), 1, fd);
+ fwrite(&pixel.g, sizeof(uint8_t), 1, fd);
+ fwrite(&pixel.r, sizeof(uint8_t), 1, fd);
+ }
}
- }
- fclose(fd);
+ fclose(fd);
- return 0;
-};
+ return 0;
+ };
+
+}
diff --git a/src/BMPImage.h b/src/BMPImage.h
index 52db0b1..651192b 100644
--- a/src/BMPImage.h
+++ b/src/BMPImage.h
@@ -4,13 +4,18 @@
#include <cstdint>
#include <cstring>
-class BMPImage : public Image
+namespace TehImage
{
-private:
-public:
- // template<std::derived_from<Image> T> BMPImage(const T& other) : Image(other) { }
- BMPImage(const Image& other) : Image(other) {}
+
+ class BMPImage : public Image
+ {
+ private:
+ public:
+ // template<std::derived_from<Image> T> BMPImage(const T& other) : Image(other) { }
+ BMPImage(const Image& other) : Image(other) {}
- int readFromFile(std::string filename) override;
- int writeToFile(std::string filename) override;
-};
+ int readFromFile(std::string filename) override;
+ int writeToFile(std::string filename) override;
+ };
+
+}
diff --git a/src/PNGImage.cpp b/src/PNGImage.cpp
index 7df04ad..9ba7404 100644
--- a/src/PNGImage.cpp
+++ b/src/PNGImage.cpp
@@ -15,385 +15,390 @@
using std::cout, std::endl;
-PNGImage::PNGImage()
+namespace TehImage
{
- //cout << "Reader good" << endl;
- REGISTER_CHUNK_READER(IHDR);
- REGISTER_CHUNK_READER(iCCP);
- REGISTER_CHUNK_READER(sRGB);
- REGISTER_CHUNK_READER(eXIf);
- REGISTER_CHUNK_READER(iDOT);
- REGISTER_CHUNK_READER(pHYs);
- REGISTER_CHUNK_READER(tIME);
- REGISTER_CHUNK_READER(tEXt);
- REGISTER_CHUNK_READER(IDAT);
- REGISTER_CHUNK_READER(IEND);
- //cout << "Chunk readers loaded" << endl;
+ PNGImage::PNGImage()
+ {
+ //cout << "Reader good" << endl;
+ REGISTER_CHUNK_READER(IHDR);
+ REGISTER_CHUNK_READER(iCCP);
+ REGISTER_CHUNK_READER(sRGB);
+ REGISTER_CHUNK_READER(eXIf);
+ REGISTER_CHUNK_READER(iDOT);
+ REGISTER_CHUNK_READER(pHYs);
+ REGISTER_CHUNK_READER(tIME);
+ REGISTER_CHUNK_READER(tEXt);
+ REGISTER_CHUNK_READER(IDAT);
+ REGISTER_CHUNK_READER(IEND);
+ //cout << "Chunk readers loaded" << endl;
- idatData = nullptr;
- idatDataSize = 0;
- //cout << "PNG image initialised" << endl;
-}
-PNGImage::~PNGImage()
-{
- free(idatData);
- idatData = nullptr;
- idatDataSize = 0;
-}
+ idatData = nullptr;
+ 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 << "PNG image initialised" << endl;
+ }
+ PNGImage::~PNGImage()
{
- cout << "Not a PNG" << endl;
- return 1;
+ free(idatData);
+ idatData = nullptr;
+ idatDataSize = 0;
}
- while (readNextChunk()) {}
+ 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;
-};
+ return 0;
+ };
-int PNGImage::writeToFile(std::string filename)
-{
- cout << "Not implemented" << endl;
- return 2;
-};
+ 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>();
-
- char chunkType[4];
- reader->readBytes(chunkType, 4);
- std::string chunkName(chunkType, 4);
- debug(
- cout << "-------------" << endl;
- cout << "|Chunk: " << chunkName << "|" << endl;
- cout << "-------------" << endl;
- );
-
- if(chunkReaders.count(chunkName) == 0)
+ bool PNGImage::readNextChunk()
{
- cout << "Chunk reader not found!!!" << endl;
- reader->skipBytes(chunkSize + 4);
- if(islower(chunkType[0]))
+ if(end)
+ return false;
+ uint32_t chunkSize = reader->readData<uint32_t>();
+
+ char chunkType[4];
+ reader->readBytes(chunkType, 4);
+ std::string chunkName(chunkType, 4);
+ debug(
+ cout << "-------------" << endl;
+ cout << "|Chunk: " << chunkName << "|" << endl;
+ cout << "-------------" << endl;
+ );
+
+ if(chunkReaders.count(chunkName) == 0)
{
- cout << "\tAble to skip chunk" << endl;
- return true;
+ cout << "Chunk reader not found!!!" << endl;
+ reader->skipBytes(chunkSize + 4);
+ if(islower(chunkType[0]))
+ {
+ cout << "\tAble to skip chunk" << endl;
+ return true;
+ }
+ cout << "\tFatal error" << endl;
+ return false;
}
- cout << "\tFatal error" << endl;
- return false;
- }
- void(PNGImage::*chunkReader)(uint32_t chunkSize) = chunkReaders.find(chunkName)->second;
- (this->*chunkReader)(chunkSize);
+ void(PNGImage::*chunkReader)(uint32_t chunkSize) = chunkReaders.find(chunkName)->second;
+ (this->*chunkReader)(chunkSize);
- reader->skipBytes(4); // CRC
+ reader->skipBytes(4); // CRC
- return true;
-}
+ 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>();
- 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)
- throw std::invalid_argument("Only color types 2 and 6 are supported");
-
- if(bitDepth != 8)
- throw std::invalid_argument("Only bit depth of 8 is supported");
-
- switch(colorType)
+ DEFINE_CHUNK_READER(IHDR)
{
- case 2: colorValues = 3; break;
- case 6: colorValues = 4; break;
- }
+ 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)
+ throw std::invalid_argument("Only color types 2 and 6 are supported");
+
+ if(bitDepth != 8)
+ throw std::invalid_argument("Only bit depth of 8 is supported");
+
+ switch(colorType)
+ {
+ case 2: colorValues = 3; break;
+ case 6: colorValues = 4; break;
+ }
- bpp = colorValues * (bitDepth/8);
+ bpp = colorValues * (bitDepth/8);
- // unsigned long imageDataSize = width * height * bpp;
- // imageDataSize = imageDataSize;
+ // unsigned long imageDataSize = width * height * bpp;
+ // imageDataSize = imageDataSize;
- // cout << "Assigning " << imageDataSize << " bytes for image" << endl;
+ // cout << "Assigning " << imageDataSize << " bytes for image" << endl;
- pixels = std::make_unique<Pixel[]>(width * height);
+ pixels = std::make_unique<Pixel[]>(width * height);
/*
- Scanline<RGBPixel<uint8_t>>* lines = new Scanline<RGBPixel<uint8_t>> [height];
- for(int i = 0; i < height; i++)
- {
- lines[i].pixels = new RGBPixel<uint8_t>[width];
- }
- imageData = (uint8_t*)lines;
+ Scanline<RGBPixel<uint8_t>>* lines = new Scanline<RGBPixel<uint8_t>> [height];
+ for(int i = 0; i < height; i++)
+ {
+ lines[i].pixels = new RGBPixel<uint8_t>[width];
+ }
+ imageData = (uint8_t*)lines;
*/
-}
+ }
-DEFINE_CHUNK_READER(iCCP)
-{
- std::string profileName;
- char c = reader->readByte();
- chunkSize--;
- while(c != 0)
+ DEFINE_CHUNK_READER(iCCP)
{
- profileName.push_back(c);
- c = reader->readByte();
+ std::string profileName;
+ char c = reader->readByte();
chunkSize--;
- }
- cout << profileName << endl;
- uint8_t compresssionMethod = reader->readByte();
- chunkSize--;
- cout << 0+compresssionMethod << endl;
- uint8_t CMF = reader->readByte();
- uint8_t CM = CMF & 0b00001111;
- uint8_t CINFO = (CMF & 0b11110000) >> 4;
- chunkSize--;
- uint8_t FLG = reader->readByte();
- bool check = (CMF * 256 + FLG)%31 == 0;
- bool FDICT = FLG & 0b00100000;
- uint8_t FLEVEL = FLG & 0b11000000;
- chunkSize--;
- if(CM != 8)
- cout << "Invalid CM: " << 0+CM << endl;
- cout << 0+CM << ", " << 0+CINFO << ", " << (check?"Valid":"Failed checksum") << ", " << (FDICT?"Dict is present":"No dict present") << ", " << 0+FLEVEL << endl;
- char compressedData[chunkSize - 4];
- reader->readBytes(compressedData, chunkSize - 4);
-
- char outData[1024];
-
- ZLibInflator inflator;
- inflator.decodeData((uint8_t*)compressedData, chunkSize - 4, (uint8_t*)outData, 1024);
-
- cout << "iCCP not supported" << endl;
-
- uint32_t checkValue = reader->readData<uint32_t>();
+ while(c != 0)
+ {
+ profileName.push_back(c);
+ c = reader->readByte();
+ chunkSize--;
+ }
+ cout << profileName << endl;
+ uint8_t compresssionMethod = reader->readByte();
+ chunkSize--;
+ cout << 0+compresssionMethod << endl;
+ uint8_t CMF = reader->readByte();
+ uint8_t CM = CMF & 0b00001111;
+ uint8_t CINFO = (CMF & 0b11110000) >> 4;
+ chunkSize--;
+ uint8_t FLG = reader->readByte();
+ bool check = (CMF * 256 + FLG)%31 == 0;
+ bool FDICT = FLG & 0b00100000;
+ uint8_t FLEVEL = FLG & 0b11000000;
+ chunkSize--;
+ if(CM != 8)
+ cout << "Invalid CM: " << 0+CM << endl;
+ cout << 0+CM << ", " << 0+CINFO << ", " << (check?"Valid":"Failed checksum") << ", " << (FDICT?"Dict is present":"No dict present") << ", " << 0+FLEVEL << endl;
+ char compressedData[chunkSize - 4];
+ reader->readBytes(compressedData, chunkSize - 4);
- //end = true;
-}
+ char outData[1024];
-DEFINE_CHUNK_READER(sRGB)
-{
- renderingIntent = reader->readData<uint8_t>();
- cout << "Rendering intent: " << 0+renderingIntent << endl;
-}
+ ZLibInflator inflator;
+ inflator.decodeData((uint8_t*)compressedData, chunkSize - 4, (uint8_t*)outData, 1024);
-DEFINE_CHUNK_READER(eXIf)
-{
- char endian[4];
- reader->readBytes(endian, 4);
- for(int i = 0; i < 2; i++)
- {
- cout << endian[i];
+ cout << "iCCP not supported" << endl;
+
+ uint32_t checkValue = reader->readData<uint32_t>();
+
+ //end = true;
}
- for(int i = 2; i < 4; i++)
+
+ DEFINE_CHUNK_READER(sRGB)
{
- cout << " " << 0+endian[i];
+ renderingIntent = reader->readData<uint8_t>();
+ cout << "Rendering intent: " << 0+renderingIntent << endl;
}
- cout << endl;
- char rest[chunkSize - 4];
- reader->readBytes(rest, chunkSize - 4);
- cout << std::hex;
- for(int i = 0; i < chunkSize - 4; i++)
+
+ DEFINE_CHUNK_READER(eXIf)
{
- cout << 0+rest[i] << " ";
+ char endian[4];
+ reader->readBytes(endian, 4);
+ for(int i = 0; i < 2; i++)
+ {
+ cout << endian[i];
+ }
+ for(int i = 2; i < 4; i++)
+ {
+ cout << " " << 0+endian[i];
+ }
+ cout << endl;
+ char rest[chunkSize - 4];
+ reader->readBytes(rest, chunkSize - 4);
+ cout << std::hex;
+ for(int i = 0; i < chunkSize - 4; i++)
+ {
+ cout << 0+rest[i] << " ";
+ }
+ cout << std::dec << endl;
}
- cout << std::dec << endl;
-}
-
-DEFINE_CHUNK_READER(iDOT)
-{
- cout << "!!! Ignoring iDOT !!!" << endl;
- reader->skipBytes(chunkSize);
-}
-
-DEFINE_CHUNK_READER(pHYs)
-{
- 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>();
- cout << "Image last modified: " << 0+hour << ":" << 0+minute << ":" << 0+second << " " << 0+day << "-" << 0+month << "-" << 0+year << endl;
-}
+ DEFINE_CHUNK_READER(iDOT)
+ {
+ cout << "!!! Ignoring iDOT !!!" << endl;
+ reader->skipBytes(chunkSize);
+ }
-DEFINE_CHUNK_READER(tEXt)
-{
-
- std::string keyword;
- char c = reader->readByte();
- chunkSize--;
- while(c != 0)
+ DEFINE_CHUNK_READER(pHYs)
{
- keyword.push_back(c);
- c = reader->readByte();
- chunkSize--;
+ 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;
}
- cout << keyword << endl;
- std::string textString;
- c = reader->readByte();
- chunkSize--;
- while(chunkSize > 0)
+
+ DEFINE_CHUNK_READER(tIME)
{
- textString.push_back(c);
- c = reader->readByte();
- chunkSize--;
+ 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;
}
- textString.push_back(c);
- cout << textString << endl;
-}
-DEFINE_CHUNK_READER(IDAT)
-{
- if(idatDataSize == 0)
+ DEFINE_CHUNK_READER(tEXt)
{
- uint8_t CMF = reader->readByte();
- uint8_t CM = CMF & 0b00001111;
- uint8_t CINFO = (CMF & 0b11110000) >> 4;
+
+ std::string keyword;
+ char c = reader->readByte();
chunkSize--;
- uint8_t FLG = reader->readByte();
- bool check = (CMF * 256 + FLG)%31 == 0;
- bool FDICT = FLG & 0b00000100;
- uint8_t FLEVEL = FLG & 0b00000011;
+ while(c != 0)
+ {
+ keyword.push_back(c);
+ c = reader->readByte();
+ chunkSize--;
+ }
+ cout << keyword << endl;
+ std::string textString;
+ c = reader->readByte();
chunkSize--;
- if(CM != 8)
- cout << "Invalid CM: " << 0+CM << endl;
- cout << 0+CM << ", " << 0+CINFO << ", " << (check?"Valid":"Failed checksum") << ", " << (FDICT?"Dict is present":"No dict present") << ", " << 0+FLEVEL << endl;
- idatData = (uint8_t*)malloc(0);
+ while(chunkSize > 0)
+ {
+ textString.push_back(c);
+ c = reader->readByte();
+ chunkSize--;
+ }
+ textString.push_back(c);
+ cout << textString << endl;
}
- idatData = (uint8_t *)realloc(idatData, idatDataSize + chunkSize);
- reader->readBytes((char *)&idatData[idatDataSize], chunkSize);
- idatDataSize += chunkSize;
+ DEFINE_CHUNK_READER(IDAT)
+ {
+ if(idatDataSize == 0)
+ {
+ uint8_t CMF = reader->readByte();
+ uint8_t CM = CMF & 0b00001111;
+ uint8_t CINFO = (CMF & 0b11110000) >> 4;
+ chunkSize--;
+ uint8_t FLG = reader->readByte();
+ bool check = (CMF * 256 + FLG)%31 == 0;
+ bool FDICT = FLG & 0b00000100;
+ uint8_t FLEVEL = FLG & 0b00000011;
+ chunkSize--;
+ if(CM != 8)
+ cout << "Invalid CM: " << 0+CM << endl;
+ cout << 0+CM << ", " << 0+CINFO << ", " << (check?"Valid":"Failed checksum") << ", " << (FDICT?"Dict is present":"No dict present") << ", " << 0+FLEVEL << endl;
+ idatData = (uint8_t*)malloc(0);
+ }
+
+ idatData = (uint8_t *)realloc(idatData, idatDataSize + chunkSize);
+ reader->readBytes((char *)&idatData[idatDataSize], chunkSize);
+ idatDataSize += chunkSize;
- /*
- unsigned long compressedSize = chunkSize - 4;
+ /*
+ unsigned long compressedSize = chunkSize - 4;
- unsigned long imageDataSize = height * (width * 3 + 1);
- cout << zlib.decodeData((uint8_t*)compressedData, compressedSize, imageData, imageDataSize) << endl;
- //cout << (int)puff((unsigned char*)imageData, &imageDataSize, (const unsigned char*)compressedData, &compressedSize) << endl;
- */
+ unsigned long imageDataSize = height * (width * 3 + 1);
+ cout << zlib.decodeData((uint8_t*)compressedData, compressedSize, imageData, imageDataSize) << endl;
+ //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;
-}
+ //end = true;
+ }
-uint8_t paethPredictor(uint8_t a, uint8_t b, uint8_t c)
-{
- int p = a + b - c;
- int pa = abs(p - a);
- int pb = abs(p - b);
- int pc = abs(p - c);
- if (pa <= pb && pa <= pc)
- return a;
- else if (pb <= pc)
+ uint8_t paethPredictor(uint8_t a, uint8_t b, uint8_t c)
+ {
+ int p = a + b - c;
+ int pa = abs(p - a);
+ int pb = abs(p - b);
+ int pc = abs(p - c);
+ if (pa <= pb && pa <= pc)
+ return a;
+ else if (pb <= pc)
return b;
- else
- return c;
-}
+ else
+ return c;
+ }
-DEFINE_CHUNK_READER(IEND)
-{
- unsigned long imageDataSize = height * (width * bpp + 1);
- uint8_t* pngImageData = new uint8_t[imageDataSize];
- uint8_t* rawImage = new uint8_t[width * height * bpp];
- cout << "My inflate " << zlib.decodeData(idatData, idatDataSize, pngImageData, imageDataSize) << endl;
- end = true;
- reader->close();
+ DEFINE_CHUNK_READER(IEND)
+ {
+ unsigned long imageDataSize = height * (width * bpp + 1);
+ uint8_t* pngImageData = new uint8_t[imageDataSize];
+ uint8_t* rawImage = new uint8_t[width * height * bpp];
+ cout << "My inflate " << zlib.decodeData(idatData, idatDataSize, pngImageData, imageDataSize) << endl;
+ end = true;
+ reader->close();
#define imageDataIndex(x, y) rawImage[y*width*bpp + x]
#define pngImageDataIndex(x, y) pngImageData[y*(width*bpp + 1) + x + 1]
#define filterByte(y) pngImageDataIndex(-1, y)
- for(int y = 0; y < height; y++)
- {
- for(int x = 0; x < width*bpp; x++)
+ for(int y = 0; y < height; y++)
{
- if(filterByte(y) == 0)
- {
- imageDataIndex(x, y) = pngImageDataIndex(x, y);
- }
- else if(filterByte(y) == 1)
- {
- uint8_t sub = pngImageDataIndex(x, y);
- uint8_t raw = (x>=bpp)?imageDataIndex((x-bpp), y):0;
- imageDataIndex(x, y) = sub + raw;
- }
- else if(filterByte(y) == 2)
- {
- uint8_t up = pngImageDataIndex(x, y);
- uint8_t prior = (y>=1)?imageDataIndex(x, (y-1)):0;
- imageDataIndex(x, y) = up + prior;
- }
- else if(filterByte(y) == 3)
+ for(int x = 0; x < width*bpp; x++)
{
- uint8_t avg = pngImageDataIndex(x, y);
- uint8_t a = (x>=bpp)?imageDataIndex((x-bpp), y):0;
- uint8_t b = (y>=1)?imageDataIndex(x, (y-1)):0;
- imageDataIndex(x, y) = avg + std::floor((a + b)/2);
+ if(filterByte(y) == 0)
+ {
+ imageDataIndex(x, y) = pngImageDataIndex(x, y);
+ }
+ else if(filterByte(y) == 1)
+ {
+ uint8_t sub = pngImageDataIndex(x, y);
+ uint8_t raw = (x>=bpp)?imageDataIndex((x-bpp), y):0;
+ imageDataIndex(x, y) = sub + raw;
+ }
+ else if(filterByte(y) == 2)
+ {
+ uint8_t up = pngImageDataIndex(x, y);
+ uint8_t prior = (y>=1)?imageDataIndex(x, (y-1)):0;
+ imageDataIndex(x, y) = up + prior;
+ }
+ else if(filterByte(y) == 3)
+ {
+ uint8_t avg = pngImageDataIndex(x, y);
+ uint8_t a = (x>=bpp)?imageDataIndex((x-bpp), y):0;
+ uint8_t b = (y>=1)?imageDataIndex(x, (y-1)):0;
+ imageDataIndex(x, y) = avg + std::floor((a + b)/2);
- }
- else if(filterByte(y) == 4)
- {
- uint8_t a = (x>=bpp)?imageDataIndex((x-bpp), y):0;
- uint8_t b = (y>=1)?imageDataIndex(x, (y-1)):0;
- uint8_t c = (x>=bpp && y>=1)?imageDataIndex((x-bpp), (y-1)):0;
- uint8_t paeth = pngImageDataIndex(x, y);
- uint8_t predictor = paethPredictor(a, b, c);
- imageDataIndex(x, y) = paeth + predictor;
- }
- else
- {
- cout << "No method for filter type: " << (int)filterByte(y) << ", row: " << y << endl;
- throw std::invalid_argument("Filter type not implemented");
+ }
+ else if(filterByte(y) == 4)
+ {
+ uint8_t a = (x>=bpp)?imageDataIndex((x-bpp), y):0;
+ uint8_t b = (y>=1)?imageDataIndex(x, (y-1)):0;
+ uint8_t c = (x>=bpp && y>=1)?imageDataIndex((x-bpp), (y-1)):0;
+ uint8_t paeth = pngImageDataIndex(x, y);
+ uint8_t predictor = paethPredictor(a, b, c);
+ imageDataIndex(x, y) = paeth + predictor;
+ }
+ else
+ {
+ cout << "No method for filter type: " << (int)filterByte(y) << ", row: " << y << endl;
+ throw std::invalid_argument("Filter type not implemented");
+ }
}
}
- }
#undef imageDataIndex
#undef pngImageDataIndex
#undef filterByte
- for(int y = 0; y < height; y++)
- {
- for(int x = 0; x < width; x++)
+ for(int y = 0; y < height; y++)
{
- (*this)[x, y].r = rawImage[(y*width + x)*colorValues];
- (*this)[x, y].g = rawImage[(y*width + x)*colorValues + 1*bitDepth/8];
- (*this)[x, y].b = rawImage[(y*width + x)*colorValues + 2*bitDepth/8];
- (*this)[x, y].a = (colorValues == 4)?rawImage[(y*width + x)*colorValues]:255;
+ for(int x = 0; x < width; x++)
+ {
+ (*this)[x, y].r = rawImage[(y*width + x)*colorValues];
+ (*this)[x, y].g = rawImage[(y*width + x)*colorValues + 1*bitDepth/8];
+ (*this)[x, y].b = rawImage[(y*width + x)*colorValues + 2*bitDepth/8];
+ (*this)[x, y].a = (colorValues == 4)?rawImage[(y*width + x)*colorValues]:255;
+ }
}
- }
- delete [] pngImageData;
- delete [] rawImage;
+ delete [] pngImageData;
+ delete [] rawImage;
+ }
+
}
diff --git a/src/PNGImage.h b/src/PNGImage.h
index 31ed429..3c1bf1f 100644
--- a/src/PNGImage.h
+++ b/src/PNGImage.h
@@ -14,54 +14,59 @@
#define REGISTER_CHUNK_READER(X) chunkReaders.insert({#X, &PNGImage::X})
#define DEFINE_CHUNK_READER(X) void PNGImage::X(uint32_t chunkSize)
-class PNGImage : public Image
+namespace TehImage
{
-private:
- ZLibInflator zlib;
- uint8_t* idatData;
- unsigned long idatDataSize;
-public:
- PNGImage();
- ~PNGImage();
- // template<std::derived_from<Image> T> PNGImage(const T& other) : Image(other) { }
- PNGImage(const Image& other) : Image(other) {}
+ class PNGImage : public Image
+ {
+ private:
+ ZLibInflator zlib;
+ uint8_t* idatData;
+ unsigned long idatDataSize;
+ public:
+ PNGImage();
+ ~PNGImage();
- int readFromFile(std::string filename) override;
- int writeToFile(std::string filename) override;
+ // template<std::derived_from<Image> T> PNGImage(const T& other) : Image(other) { }
+ PNGImage(const Image& other) : Image(other) {}
+
+ int readFromFile(std::string filename) override;
+ int writeToFile(std::string filename) override;
- // sRGB
- uint8_t renderingIntent;
+ // sRGB
+ uint8_t renderingIntent;
- // pHYs
- uint32_t pixelsPerX;
- uint32_t pixelsPerY;
- uint8_t unit;
+ // pHYs
+ uint32_t pixelsPerX;
+ uint32_t pixelsPerY;
+ uint8_t unit;
- // tIME
- uint16_t year;
- uint8_t month;
- uint8_t day;
- uint8_t hour;
- uint8_t minute;
- uint8_t second;
+ // tIME
+ uint16_t year;
+ uint8_t month;
+ uint8_t day;
+ uint8_t hour;
+ uint8_t minute;
+ uint8_t second;
- bool readNextChunk();
+ bool readNextChunk();
-private:
- std::map<std::string, void(PNGImage::*)(uint32_t chunkSize)> chunkReaders;
- CHUNK_READER(IHDR);
- CHUNK_READER(iCCP);
- CHUNK_READER(sRGB);
- CHUNK_READER(eXIf);
- CHUNK_READER(iDOT);
- CHUNK_READER(pHYs);
- CHUNK_READER(tIME);
- CHUNK_READER(tEXt);
- CHUNK_READER(IDAT);
- CHUNK_READER(IEND);
+ private:
+ std::map<std::string, void(PNGImage::*)(uint32_t chunkSize)> chunkReaders;
+ CHUNK_READER(IHDR);
+ CHUNK_READER(iCCP);
+ CHUNK_READER(sRGB);
+ CHUNK_READER(eXIf);
+ CHUNK_READER(iDOT);
+ CHUNK_READER(pHYs);
+ CHUNK_READER(tIME);
+ CHUNK_READER(tEXt);
+ CHUNK_READER(IDAT);
+ CHUNK_READER(IEND);
+
+ bool end = false;
- bool end = false;
+ Reader *reader;
+ };
- Reader *reader;
-};
+}
diff --git a/src/image.cpp b/src/image.cpp
index 77fe63c..e20b05e 100644
--- a/src/image.cpp
+++ b/src/image.cpp
@@ -2,24 +2,29 @@
#include <algorithm>
#include <cstdint>
-Image::Image(const Image& other)
+namespace TehImage
{
- this->colorValues = other.colorValues;
- this->bpp = other.bpp;
+
+ Image::Image(const Image& 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;
+ 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;
- pixels = std::make_unique<Pixel[]>(width*height);
- std::copy_n(other.pixels.get(), width*height, pixels.get());
-}
+ pixels = std::make_unique<Pixel[]>(width*height);
+ std::copy_n(other.pixels.get(), width*height, pixels.get());
+ }
-Pixel& Image::operator[](int x, int y)
-{
- return pixels[x + y*width];
-};
+ Pixel& Image::operator[](int x, int y)
+ {
+ return pixels[x + y*width];
+ };
+
+}
diff --git a/src/image.h b/src/image.h
index 7a7ba31..d6fec04 100644
--- a/src/image.h
+++ b/src/image.h
@@ -5,34 +5,39 @@
#include <memory>
#include <string>
-struct Pixel
+namespace TehImage
{
- uint8_t r, g, b, a;
-};
-class Image
-{
-protected:
- std::unique_ptr<Pixel[]> pixels;
- // uint8_t* imageData;
- uint8_t colorValues;
- uint8_t bpp;
-public:
- Image() = default;
-
- // template<std::derived_from<Image> T>
- Image(const Image& other);
-
- virtual int readFromFile(std::string filename) = 0;
- virtual int writeToFile(std::string filename) = 0;
+ struct Pixel
+ {
+ uint8_t r, g, b, a;
+ };
+
+ class Image
+ {
+ protected:
+ std::unique_ptr<Pixel[]> pixels;
+ // uint8_t* imageData;
+ uint8_t colorValues;
+ uint8_t bpp;
+ public:
+ Image() = default;
+
+ // template<std::derived_from<Image> T>
+ Image(const Image& other);
+
+ virtual int readFromFile(std::string filename) = 0;
+ virtual int writeToFile(std::string filename) = 0;
- Pixel& operator[](int x, int y);
-
- uint32_t width = 0;
- uint32_t height = 0;
- uint8_t bitDepth;
- uint8_t colorType;
- uint8_t compressionMethod;
- uint8_t filterMethod;
- uint8_t interlaceMethod;
-};
+ Pixel& operator[](int x, int y);
+
+ uint32_t width = 0;
+ uint32_t height = 0;
+ uint8_t bitDepth;
+ uint8_t colorType;
+ uint8_t compressionMethod;
+ uint8_t filterMethod;
+ uint8_t interlaceMethod;
+ };
+
+}
diff --git a/src/reader.cpp b/src/reader.cpp
index 57c474b..f8b053f 100644
--- a/src/reader.cpp
+++ b/src/reader.cpp
@@ -8,103 +8,108 @@
#include <cstring>
#include <iostream>
-Reader::Reader(std::string filename)
+namespace TehImage
{
- file = fopen(filename.c_str(), "rb");
- refreshBuffer();
- ready = true;
-}
-Reader::~Reader()
-{
- if(ready)
- fclose(file);
-}
-char Reader::readByte()
-{
- if(pos == BUFFER_SIZE)
+ Reader::Reader(std::string filename)
+ {
+ file = fopen(filename.c_str(), "rb");
refreshBuffer();
- return buffer[pos++];
-}
+ ready = true;
+ }
+ Reader::~Reader()
+ {
+ if(ready)
+ fclose(file);
+ }
-void Reader::refreshBuffer()
-{
+ char Reader::readByte()
+ {
+ if(pos == BUFFER_SIZE)
+ refreshBuffer();
+ return buffer[pos++];
+ }
+
+ void Reader::refreshBuffer()
+ {
fread(buffer, sizeof(buffer), 1, file);
pos = 0;
-}
+ }
-template<> uint8_t Reader::readData<uint8_t>()
-{
- return readByte();
-}
+ template<> uint8_t Reader::readData<uint8_t>()
+ {
+ return readByte();
+ }
-template<> uint16_t Reader::readData<uint16_t>()
-{
- uint16_t num = 0;
- for(int i = 0; i < 2; i++)
+ template<> uint16_t Reader::readData<uint16_t>()
{
- num += readByte() << (8 * (1-i));
+ uint16_t num = 0;
+ for(int i = 0; i < 2; i++)
+ {
+ num += readByte() << (8 * (1-i));
+ }
+ return num;
}
- return num;
-}
-template<> uint32_t Reader::readData<uint32_t>()
-{
- uint32_t num = 0;
- for(int i = 0; i < 4; i++)
+ template<> uint32_t Reader::readData<uint32_t>()
{
- uint8_t byte = readByte();
- debug(std::cout << std::hex << 0+byte << " ");
- num += byte << (8 * (3-i));
+ uint32_t num = 0;
+ for(int i = 0; i < 4; i++)
+ {
+ uint8_t byte = readByte();
+ debug(std::cout << std::hex << 0+byte << " ");
+ num += byte << (8 * (3-i));
+ }
+ debug(std::cout << std::dec << std::endl);
+ return num;
}
- debug(std::cout << std::dec << std::endl);
- return num;
-}
-template<> uint64_t Reader::readData<uint64_t>()
-{
- uint64_t num = 0;
- for(int i = 0; i < 8; i++)
+ template<> uint64_t Reader::readData<uint64_t>()
{
- num += readByte() << (8 * (7-i));
+ uint64_t num = 0;
+ for(int i = 0; i < 8; i++)
+ {
+ num += readByte() << (8 * (7-i));
+ }
+ return num;
}
- return num;
-}
-void Reader::readBytes(char* out, size_t len)
-{
- while(len > 0)
+ void Reader::readBytes(char* out, size_t len)
{
- size_t bytesToRead = std::min(len, BUFFER_SIZE - pos);
- if(bytesToRead == 0)
+ while(len > 0)
{
- refreshBuffer();
- continue;
+ size_t bytesToRead = std::min(len, BUFFER_SIZE - pos);
+ if(bytesToRead == 0)
+ {
+ refreshBuffer();
+ continue;
+ }
+ memcpy(out, buffer + pos, bytesToRead);
+ out += bytesToRead;
+ len -= bytesToRead;
+ pos += bytesToRead;
}
- memcpy(out, buffer + pos, bytesToRead);
- out += bytesToRead;
- len -= bytesToRead;
- pos += bytesToRead;
}
-}
-void Reader::skipBytes(size_t len)
-{
- while(len > 0)
+ void Reader::skipBytes(size_t len)
{
- size_t bytesToRead = std::min(len, BUFFER_SIZE - pos);
- if(bytesToRead == 0)
+ while(len > 0)
{
- refreshBuffer();
- continue;
+ size_t bytesToRead = std::min(len, BUFFER_SIZE - pos);
+ if(bytesToRead == 0)
+ {
+ refreshBuffer();
+ continue;
+ }
+ len -= bytesToRead;
+ pos += bytesToRead;
}
- len -= bytesToRead;
- pos += bytesToRead;
}
-}
-void Reader::close()
-{
- fclose(file);
- ready = false;
+ void Reader::close()
+ {
+ fclose(file);
+ ready = false;
+ }
+
}
diff --git a/src/reader.h b/src/reader.h
index ab01092..a4f913c 100644
--- a/src/reader.h
+++ b/src/reader.h
@@ -4,30 +4,35 @@
#include <cstdio>
#include <string>
-#define BUFFER_SIZE 1024
+#define BUFFER_SIZE 4096
-class Reader
+namespace TehImage
{
-public:
- //Bytes are big endian
- Reader(std::string file);
- ~Reader();
- template <typename T>
+ class Reader
+ {
+ public:
+ //Bytes are big endian
+ Reader(std::string file);
+ ~Reader();
+
+ template <typename T>
T readData();
- char readByte();
+ char readByte();
+
+ void readBytes(char* out, size_t len);
- void readBytes(char* out, size_t len);
+ void skipBytes(size_t len);
- void skipBytes(size_t len);
+ void close();
+ private:
+ char buffer[BUFFER_SIZE];
+ size_t pos;
+ FILE* file;
+ bool ready = false;
- void close();
-private:
- char buffer[BUFFER_SIZE];
- size_t pos;
- FILE* file;
- bool ready = false;
+ void refreshBuffer();
+ };
- void refreshBuffer();
-};
+}
diff --git a/src/zlib.cpp b/src/zlib.cpp
index c53502c..97f2ded 100644
--- a/src/zlib.cpp
+++ b/src/zlib.cpp
@@ -11,346 +11,351 @@
using std::cout, std::endl;
-void ZLibInflator::calculateCodes(uint8_t* lengths, uint16_t* codesOut, int codeCount)
+namespace TehImage
{
- const int biggestLen = 15;
- uint16_t lenCounts[biggestLen + 1];
- memset(lenCounts, 0, (biggestLen + 1)*sizeof(uint16_t));
- for(int i = 0; i < codeCount; i++)
- lenCounts[lengths[i]]++;
+ void ZLibInflator::calculateCodes(uint8_t* lengths, uint16_t* codesOut, int codeCount)
+ {
+ const int biggestLen = 15;
+
+ uint16_t lenCounts[biggestLen + 1];
+ memset(lenCounts, 0, (biggestLen + 1)*sizeof(uint16_t));
+ for(int i = 0; i < codeCount; i++)
+ lenCounts[lengths[i]]++;
- lenCounts[0] = 0;
+ lenCounts[0] = 0;
- uint16_t nextCodes[biggestLen + 1];
- uint16_t code = 0;
- for(int bits = 1; bits < biggestLen + 1; bits++)
- {
- code = (code + lenCounts[bits - 1]) << 1;
- nextCodes[bits] = code;
+ uint16_t nextCodes[biggestLen + 1];
+ uint16_t code = 0;
+ for(int bits = 1; bits < biggestLen + 1; bits++)
+ {
+ code = (code + lenCounts[bits - 1]) << 1;
+ nextCodes[bits] = code;
+ }
+
+ for(int i = 0; i < codeCount; i++)
+ {
+ uint8_t len = lengths[i];
+ if(len == 0)
+ continue;
+ codesOut[i] = nextCodes[len]++;
+ }
}
- for(int i = 0; i < codeCount; i++)
+ void ZLibInflator::buildHuffmanTree(uint8_t* lengths, uint16_t* codes, int codeCount)
{
- uint8_t len = lengths[i];
- if(len == 0)
- continue;
- codesOut[i] = nextCodes[len]++;
+ buildHuffmanTree(lengths, codes, codeCount, &tree);
}
-}
-
-void ZLibInflator::buildHuffmanTree(uint8_t* lengths, uint16_t* codes, int codeCount)
-{
- buildHuffmanTree(lengths, codes, codeCount, &tree);
-}
-void ZLibInflator::buildHuffmanTree(uint8_t* lengths, uint16_t* codes, int codeCount, HuffmanTree* tree)
-{
- for(uint16_t i = 0; i < codeCount; i++)
+ void ZLibInflator::buildHuffmanTree(uint8_t* lengths, uint16_t* codes, int codeCount, HuffmanTree* tree)
{
- uint16_t code = codes[i];
- uint8_t len = lengths[i];
- if(len == 0)
- continue;
- HuffmanTree* current = tree;
- for(int j = 0; j < len; j++)
+ for(uint16_t i = 0; i < codeCount; i++)
{
- bool right = code & (0b1 << (len - 1 - j));
- if(right)
+ uint16_t code = codes[i];
+ uint8_t len = lengths[i];
+ if(len == 0)
+ continue;
+ HuffmanTree* current = tree;
+ for(int j = 0; j < len; j++)
{
- if(current->right != nullptr)
- current = current->right;
- else
+ bool right = code & (0b1 << (len - 1 - j));
+ if(right)
{
- current->right = new HuffmanTree();
- current = current->right;
+ if(current->right != nullptr)
+ current = current->right;
+ else
+ {
+ current->right = new HuffmanTree();
+ current = current->right;
+ }
}
- }
- else
- {
- if(current->left != nullptr)
- current = current->left;
else
{
- current->left = new HuffmanTree();
- current = current->left;
+ if(current->left != nullptr)
+ current = current->left;
+ else
+ {
+ current->left = new HuffmanTree();
+ current = current->left;
+ }
}
}
+ current->val = i;
}
- current->val = i;
}
-}
-void ZLibInflator::buildStaticHuffmanTree()
-{
- if(staticTree)
- return;
- cout << "Building static tree" << endl;
- buildStaticHuffmanTree(&tree, &distTree);
- staticTree = true;
- haveTree = true;
-}
-void ZLibInflator::buildStaticHuffmanTree(HuffmanTree* treeOut, HuffmanTree* distTreeOut)
-{
- const int codeCount = 288;
- uint8_t lens[codeCount];
- uint16_t codes[codeCount];
- for(int i = 0; i < codeCount; i++)
+ void ZLibInflator::buildStaticHuffmanTree()
{
- if(i < 144)
- lens[i] = 8;
- else if(i < 256)
- lens[i] = 9;
- else if(i < 280)
- lens[i] = 7;
- else if(i < 288)
- lens[i] = 8;
+ if(staticTree)
+ return;
+ cout << "Building static tree" << endl;
+ buildStaticHuffmanTree(&tree, &distTree);
+ staticTree = true;
+ haveTree = true;
}
- calculateCodes(lens, codes, codeCount);
- buildHuffmanTree(lens, codes, codeCount, treeOut);
+ void ZLibInflator::buildStaticHuffmanTree(HuffmanTree* treeOut, HuffmanTree* distTreeOut)
+ {
+ const int codeCount = 288;
+ uint8_t lens[codeCount];
+ uint16_t codes[codeCount];
+ for(int i = 0; i < codeCount; i++)
+ {
+ if(i < 144)
+ lens[i] = 8;
+ else if(i < 256)
+ lens[i] = 9;
+ else if(i < 280)
+ lens[i] = 7;
+ else if(i < 288)
+ lens[i] = 8;
+ }
+ calculateCodes(lens, codes, codeCount);
+ buildHuffmanTree(lens, codes, codeCount, treeOut);
- uint8_t nDistCodes = 32;
- uint8_t distCodeLens[nDistCodes];
- uint16_t distCodes[nDistCodes];
+ uint8_t nDistCodes = 32;
+ uint8_t distCodeLens[nDistCodes];
+ uint16_t distCodes[nDistCodes];
- for(int i = 0; i < nDistCodes; i++)
- distCodeLens[i] = i;
+ for(int i = 0; i < nDistCodes; i++)
+ distCodeLens[i] = i;
- calculateCodes(distCodeLens, distCodes, nDistCodes);
- buildHuffmanTree(distCodeLens, distCodes, nDistCodes, distTreeOut);
-}
+ calculateCodes(distCodeLens, distCodes, nDistCodes);
+ buildHuffmanTree(distCodeLens, distCodes, nDistCodes, distTreeOut);
+ }
-void ZLibInflator::buildDynamicHuffmanTree(StreamData* stream)
-{
- if(haveTree)
+ void ZLibInflator::buildDynamicHuffmanTree(StreamData* stream)
{
- tree.free();
- distTree.free();
+ if(haveTree)
+ {
+ tree.free();
+ distTree.free();
+ }
+ buildDynamicHuffmanTree(stream, &tree, &distTree);
+ haveTree = true;
}
- buildDynamicHuffmanTree(stream, &tree, &distTree);
- haveTree = true;
-}
-void ZLibInflator::buildDynamicHuffmanTree(StreamData* stream, HuffmanTree* treeOut, HuffmanTree* distTreeOut)
-{
- unsigned int nLitCodes = nextBits(stream, 5) + 257;
- uint16_t litCodes[nLitCodes];
+ void ZLibInflator::buildDynamicHuffmanTree(StreamData* stream, HuffmanTree* treeOut, HuffmanTree* distTreeOut)
+ {
+ unsigned int nLitCodes = nextBits(stream, 5) + 257;
+ uint16_t litCodes[nLitCodes];
- unsigned int nDistCodes = nextBits(stream, 5) + 1;
- uint16_t distCodes[nDistCodes];
+ unsigned int nDistCodes = nextBits(stream, 5) + 1;
+ uint16_t distCodes[nDistCodes];
- uint8_t codeLens[nLitCodes + nDistCodes];
+ uint8_t codeLens[nLitCodes + nDistCodes];
- uint8_t nLenCodes = nextBits(stream, 4) + 4;
- uint8_t lenCodeLens[19];
- memset(lenCodeLens, 0, sizeof(uint8_t)*19);
- uint16_t lenCodes[19];
+ uint8_t nLenCodes = nextBits(stream, 4) + 4;
+ uint8_t lenCodeLens[19];
+ memset(lenCodeLens, 0, sizeof(uint8_t)*19);
+ uint16_t lenCodes[19];
- const static uint8_t lenCodeOrder[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
+ const static uint8_t lenCodeOrder[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
- for(int i = 0; i < nLenCodes; i++)
- lenCodeLens[lenCodeOrder[i]] = nextBits(stream, 3);
+ for(int i = 0; i < nLenCodes; i++)
+ lenCodeLens[lenCodeOrder[i]] = nextBits(stream, 3);
- calculateCodes(lenCodeLens, lenCodes, 19);
- HuffmanTree lenCodeTree;
- buildHuffmanTree(lenCodeLens, lenCodes, 19, &lenCodeTree);
+ calculateCodes(lenCodeLens, lenCodes, 19);
+ HuffmanTree lenCodeTree;
+ buildHuffmanTree(lenCodeLens, lenCodes, 19, &lenCodeTree);
- int i = 0;
- uint8_t extraBits[] = {2, 3, 7};
- uint8_t repStarts[] = {3, 3, 11};
+ int i = 0;
+ uint8_t extraBits[] = {2, 3, 7};
+ uint8_t repStarts[] = {3, 3, 11};
- while(i < nLitCodes + nDistCodes)
- {
- uint16_t code = getNextCode(stream, &lenCodeTree);
- if(code < 16)
- codeLens[i++] = (uint8_t)code;
- else if(code < 19)
+ while(i < nLitCodes + nDistCodes)
{
- code -= 16;
- int reps = repStarts[code] + nextBits(stream, extraBits[code]);
- uint8_t len = 0;
- if(code == 0)
+ uint16_t code = getNextCode(stream, &lenCodeTree);
+ if(code < 16)
+ codeLens[i++] = (uint8_t)code;
+ else if(code < 19)
{
- if(i == 0)
- cout << "Trying to repeat non existent value in dynamic huffman code creation" << endl;
- else
- len = codeLens[i - 1];
+ code -= 16;
+ int reps = repStarts[code] + nextBits(stream, extraBits[code]);
+ uint8_t len = 0;
+ if(code == 0)
+ {
+ if(i == 0)
+ cout << "Trying to repeat non existent value in dynamic huffman code creation" << endl;
+ else
+ len = codeLens[i - 1];
+ }
+ if(i + reps > nLitCodes + nDistCodes)
+ cout << "other big errror oh no " << i << " " << 0+reps << endl;
+ for(int j = 0; j < reps; j++)
+ {
+ codeLens[i++] = len;
+ }
}
- if(i + reps > nLitCodes + nDistCodes)
- cout << "other big errror oh no " << i << " " << 0+reps << endl;
- for(int j = 0; j < reps; j++)
+ else
{
- codeLens[i++] = len;
+ cout << "big error oh no" << endl;
}
}
- else
- {
- cout << "big error oh no" << endl;
- }
- }
- calculateCodes(codeLens, litCodes, nLitCodes);
- buildHuffmanTree(codeLens, litCodes, nLitCodes, treeOut);
+ calculateCodes(codeLens, litCodes, nLitCodes);
+ buildHuffmanTree(codeLens, litCodes, nLitCodes, treeOut);
- calculateCodes(&codeLens[nLitCodes], distCodes, nDistCodes);
- buildHuffmanTree(&codeLens[nLitCodes], distCodes, nDistCodes, distTreeOut);
-}
+ calculateCodes(&codeLens[nLitCodes], distCodes, nDistCodes);
+ buildHuffmanTree(&codeLens[nLitCodes], distCodes, nDistCodes, distTreeOut);
+ }
-void HuffmanTree::free()
-{
- if(left != nullptr)
+ void HuffmanTree::free()
{
- delete left;
- left = nullptr;
+ if(left != nullptr)
+ {
+ delete left;
+ left = nullptr;
+ }
+ if(right != nullptr)
+ {
+ delete right;
+ right = nullptr;
+ }
+ val = 0xFFFF;
}
- if(right != nullptr)
+ HuffmanTree::~HuffmanTree()
{
- delete right;
- right = nullptr;
+ free();
}
- val = 0xFFFF;
-}
-HuffmanTree::~HuffmanTree()
-{
- free();
-}
-uint16_t ZLibInflator::getNextCode(StreamData* stream)
-{
- return getNextCode(stream, &tree);
-}
+ uint16_t ZLibInflator::getNextCode(StreamData* stream)
+ {
+ return getNextCode(stream, &tree);
+ }
-uint16_t ZLibInflator::getNextCode(StreamData* stream, HuffmanTree* tree)
-{
- while(tree->val == 0xFFFF)
+ uint16_t ZLibInflator::getNextCode(StreamData* stream, HuffmanTree* tree)
{
- bool right = nextBit(stream);
+ while(tree->val == 0xFFFF)
+ {
+ bool right = nextBit(stream);
- if(tree->left == nullptr && !right)
- cout << "bad left" << endl;
- if(tree->right == nullptr && right)
- cout << "bad right" << endl;
- tree = (right)?tree->right:tree->left;
+ if(tree->left == nullptr && !right)
+ cout << "bad left" << endl;
+ if(tree->right == nullptr && right)
+ cout << "bad right" << endl;
+ tree = (right)?tree->right:tree->left;
+ }
+ return tree->val;
}
- return tree->val;
-}
-bool ZLibInflator::nextBit(StreamData* stream)
-{
- long bit = stream->pos % 8;
- long byte = stream->pos / 8;
- if(byte >= stream->length)
+ bool ZLibInflator::nextBit(StreamData* stream)
{
- cout << byte << " " << stream->length << endl;
- throw std::out_of_range("Ran out of compressed data");
+ long bit = stream->pos % 8;
+ long byte = stream->pos / 8;
+ if(byte >= stream->length)
+ {
+ cout << byte << " " << stream->length << endl;
+ throw std::out_of_range("Ran out of compressed data");
+ }
+ stream->pos++;
+ //cout << ((stream->data[byte] & (0b1 << bit))?"1":"0");
+ return (stream->data[byte] & (0b1 << bit))?0b1:0b0;
}
- stream->pos++;
- //cout << ((stream->data[byte] & (0b1 << bit))?"1":"0");
- return (stream->data[byte] & (0b1 << bit))?0b1:0b0;
-}
-uint16_t ZLibInflator::nextBits(StreamData* stream, int bits)
-{
- if(bits > 16)
- cout << "Too many bits(" << bits << ")!!!" << endl;
- uint16_t out = 0;
- for(int i = 0; i < bits; i++)
+ uint16_t ZLibInflator::nextBits(StreamData* stream, int bits)
{
- out |= nextBit(stream) << i;
+ if(bits > 16)
+ cout << "Too many bits(" << bits << ")!!!" << endl;
+ uint16_t out = 0;
+ for(int i = 0; i < bits; i++)
+ {
+ out |= nextBit(stream) << i;
+ }
+ return out;
}
- return out;
-}
-int ZLibInflator::decodeData(uint8_t* data, unsigned long length, uint8_t* out, unsigned long outLength)
-{
- staticTree = false;
- const unsigned int lenStart[] = { /* Size base for length codes 257..285 */
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
- 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258};
- const unsigned int lenExtra[] = { /* Extra bits for length codes 257..285 */
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
- 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0};
+ int ZLibInflator::decodeData(uint8_t* data, unsigned long length, uint8_t* out, unsigned long outLength)
+ {
+ staticTree = false;
+ const unsigned int lenStart[] = { /* Size base for length codes 257..285 */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258};
+ const unsigned int lenExtra[] = { /* Extra bits for length codes 257..285 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0};
- const unsigned int distStart[] = { /* Offset base for distance codes 0..29 */
- 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
- 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
- 8193, 12289, 16385, 24577};
- const unsigned int distExtra[] = { /* Extra bits for distance codes 0..29 */
- 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
- 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
- 12, 12, 13, 13};
+ const unsigned int distStart[] = { /* Offset base for distance codes 0..29 */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577};
+ const unsigned int distExtra[] = { /* Extra bits for distance codes 0..29 */
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13};
- StreamData stream = { data, length, 0};
- long outPos = 0;
+ StreamData stream = { data, length, 0};
+ long outPos = 0;
- bool final;
- do
- {
+ bool final;
+ do
+ {
- final = nextBit(&stream);
- int method = nextBits(&stream, 2);
+ final = nextBit(&stream);
+ int method = nextBits(&stream, 2);
- //cout << (final?"Final chunk!\n":"") << "Compression method: " << method << endl;
+ //cout << (final?"Final chunk!\n":"") << "Compression method: " << method << endl;
- //cout << outPos << " " << outLength << endl;
+ //cout << outPos << " " << outLength << endl;
- if(method == 1)
- buildStaticHuffmanTree();
- else if(method == 2)
- buildDynamicHuffmanTree(&stream);
- else if(method == 0)
- {
- while(stream.pos%8 != 0)
- stream.pos++;
- uint16_t LEN = nextBits(&stream, 16);
- uint16_t NLEN = nextBits(&stream, 16);
- NLEN++;
- if(LEN + NLEN != 0)
- throw std::invalid_argument("NLEN and LEN don't match");
- for(int i = 0; i < LEN; i++)
- out[outPos++] = nextBits(&stream, 8);
- continue;
- }
- else
- {
- cout << "Reserved???" << endl;
- return -1;
- }
-
- uint16_t code;
- do
- {
- code = getNextCode(&stream);
- if(outPos > outLength && code != 256)
+ if(method == 1)
+ buildStaticHuffmanTree();
+ else if(method == 2)
+ buildDynamicHuffmanTree(&stream);
+ else if(method == 0)
{
- throw std::out_of_range("No more space left in image (normal)");
+ while(stream.pos%8 != 0)
+ stream.pos++;
+ uint16_t LEN = nextBits(&stream, 16);
+ uint16_t NLEN = nextBits(&stream, 16);
+ NLEN++;
+ if(LEN + NLEN != 0)
+ throw std::invalid_argument("NLEN and LEN don't match");
+ for(int i = 0; i < LEN; i++)
+ out[outPos++] = nextBits(&stream, 8);
+ continue;
}
- if(code < 256)
- out[outPos++] = (uint8_t)code;
- else if(code > 256)
+ else
{
- unsigned int len = lenStart[code-257] + (int)nextBits(&stream, lenExtra[code-257]);
- unsigned int distCode = getNextCode(&stream, &distTree);
-
- unsigned int dist = distStart[distCode] + (int)nextBits(&stream, distExtra[distCode]);
- if(outPos + len > outLength)
+ cout << "Reserved???" << endl;
+ return -1;
+ }
+
+ uint16_t code;
+ do
+ {
+ code = getNextCode(&stream);
+ if(outPos > outLength && code != 256)
{
- throw std::out_of_range("No more space left in image (RLE error)");
+ throw std::out_of_range("No more space left in image (normal)");
}
- for(int i = 0; i < len; i++)
+ if(code < 256)
+ out[outPos++] = (uint8_t)code;
+ else if(code > 256)
{
- out[outPos] = out[outPos - dist];
- outPos++;
+ unsigned int len = lenStart[code-257] + (int)nextBits(&stream, lenExtra[code-257]);
+ unsigned int distCode = getNextCode(&stream, &distTree);
+
+ unsigned int dist = distStart[distCode] + (int)nextBits(&stream, distExtra[distCode]);
+ if(outPos + len > outLength)
+ {
+ throw std::out_of_range("No more space left in image (RLE error)");
+ }
+ for(int i = 0; i < len; i++)
+ {
+ out[outPos] = out[outPos - dist];
+ outPos++;
+ }
}
}
+ while(code != 256);
}
- while(code != 256);
+ while(!final);
+
+ return 0;
}
- while(!final);
- return 0;
}
diff --git a/src/zlib.h b/src/zlib.h
index d9d6b44..fc6a1c3 100644
--- a/src/zlib.h
+++ b/src/zlib.h
@@ -3,50 +3,55 @@
#include <cstdint>
#include <string>
-struct HuffmanTree
+namespace TehImage
{
- uint16_t val = 0xFFFF;
- HuffmanTree* left = nullptr; // 0
- HuffmanTree* right = nullptr; // 1
- HuffmanTree() = default;
- ~HuffmanTree();
- void free();
-};
-
-struct StreamData
-{
- uint8_t* data;
- unsigned long length;
- unsigned long pos;
-};
-
-class ZLibInflator
-{
-private:
- HuffmanTree tree;
- HuffmanTree distTree;
- bool staticTree = false;
- bool haveTree = false;
-public:
- ZLibInflator() = default;
- ~ZLibInflator() = default;
-
- static bool nextBit(StreamData* stream);
- static uint16_t nextBits(StreamData* stream, int bits); // Max 16 bits
-
- void calculateCodes(uint8_t* lengths, uint16_t* codesOut, int codeCount);
-
- void buildHuffmanTree(uint8_t* lengths, uint16_t* codes, int codeCount);
- void buildHuffmanTree(uint8_t* lengths, uint16_t* codes, int codeCount, HuffmanTree* treeOut);
-
- void buildStaticHuffmanTree();
- void buildStaticHuffmanTree(HuffmanTree* treeOut, HuffmanTree* distTreeOut);
-
- void buildDynamicHuffmanTree(StreamData* stream);
- void buildDynamicHuffmanTree(StreamData* stream, HuffmanTree* treeOut, HuffmanTree* distTreeOut);
-
- uint16_t getNextCode(StreamData* stream);
- uint16_t getNextCode(StreamData* stream, HuffmanTree* tree);
- int decodeData(uint8_t* data, unsigned long length, uint8_t* out, unsigned long outLength);
-};
+ struct HuffmanTree
+ {
+ uint16_t val = 0xFFFF;
+ HuffmanTree* left = nullptr; // 0
+ HuffmanTree* right = nullptr; // 1
+ HuffmanTree() = default;
+ ~HuffmanTree();
+ void free();
+ };
+
+ struct StreamData
+ {
+ uint8_t* data;
+ unsigned long length;
+ unsigned long pos;
+ };
+
+ class ZLibInflator
+ {
+ private:
+ HuffmanTree tree;
+ HuffmanTree distTree;
+ bool staticTree = false;
+ bool haveTree = false;
+ public:
+ ZLibInflator() = default;
+ ~ZLibInflator() = default;
+
+ static bool nextBit(StreamData* stream);
+ static uint16_t nextBits(StreamData* stream, int bits); // Max 16 bits
+
+ void calculateCodes(uint8_t* lengths, uint16_t* codesOut, int codeCount);
+
+ void buildHuffmanTree(uint8_t* lengths, uint16_t* codes, int codeCount);
+ void buildHuffmanTree(uint8_t* lengths, uint16_t* codes, int codeCount, HuffmanTree* treeOut);
+
+ void buildStaticHuffmanTree();
+ void buildStaticHuffmanTree(HuffmanTree* treeOut, HuffmanTree* distTreeOut);
+
+ void buildDynamicHuffmanTree(StreamData* stream);
+ void buildDynamicHuffmanTree(StreamData* stream, HuffmanTree* treeOut, HuffmanTree* distTreeOut);
+
+ uint16_t getNextCode(StreamData* stream);
+ uint16_t getNextCode(StreamData* stream, HuffmanTree* tree);
+
+ int decodeData(uint8_t* data, unsigned long length, uint8_t* out, unsigned long outLength);
+ };
+
+}
diff --git a/test/main.cpp b/test/main.cpp
index c020526..d4c2e64 100644
--- a/test/main.cpp
+++ b/test/main.cpp
@@ -21,9 +21,9 @@ int main(int argc, char* argv[])
std::string outfile = argv[2];
- PNGImage png;
+ TehImage::PNGImage png;
png.readFromFile(infile);
- BMPImage bmp(png);
+ TehImage::BMPImage bmp(png);
bmp.writeToFile(outfile);
}