diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/BMPImage.cpp | 81 | ||||
| -rw-r--r-- | src/BMPImage.h | 21 | ||||
| -rw-r--r-- | src/PNGImage.cpp | 613 | ||||
| -rw-r--r-- | src/PNGImage.h | 87 | ||||
| -rw-r--r-- | src/image.cpp | 39 | ||||
| -rw-r--r-- | src/image.h | 61 | ||||
| -rw-r--r-- | src/reader.cpp | 149 | ||||
| -rw-r--r-- | src/reader.h | 41 | ||||
| -rw-r--r-- | src/zlib.cpp | 519 | ||||
| -rw-r--r-- | src/zlib.h | 95 |
10 files changed, 878 insertions, 828 deletions
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; } @@ -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); + }; + +} |
