aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--GNUmakefile15
-rw-r--r--src/BMPImage.cpp49
-rw-r--r--src/BMPImage.h15
-rw-r--r--src/PNGImage.cpp148
-rw-r--r--src/PNGImage.h12
-rw-r--r--src/image.cpp3
-rw-r--r--src/image.h43
-rw-r--r--test/main.cpp17
8 files changed, 199 insertions, 103 deletions
diff --git a/GNUmakefile b/GNUmakefile
index d42f0cf..af8403a 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -7,9 +7,9 @@ TEST_SRC_DIR := ./test
# Flags
CXX := g++
-CXXFLAGS := -fsanitize=address -g
+CXXFLAGS := -std=c++20 -fsanitize=address -g
LINKFLAGS := -static-libasan
-TEST_CXXFLAGS := -I$(INCLUDE_DIR) -fsanitize=address -g
+TEST_CXXFLAGS := -std=c++20 -I$(INCLUDE_DIR) -fsanitize=address -g
TEST_LINKFLAGS := -L$(LIB_DIR) -ltehimage -static-libasan
# Outputs
@@ -29,7 +29,7 @@ TEST_OBJS = $(subst $(TEST_SRC_DIR),$(OBJS_DIR), $(patsubst %.cpp,%.o,$(TEST_SOU
$(LIB): $(INCLUDE_HEADERS) $(OBJS)
$(CXX) $(OBJS) $(CXXFLAGS) $(LINKFLAGS) -shared -o $(LIB)
-$(OBJS_DIR)/%.o: $(SOURCE_DIR)/%.cpp
+$(OBJS_DIR)/%.o: $(SOURCE_DIR)/%.cpp $(SOURCE_DIR)/%.h
$(CXX) $(CXXFLAGS) -c $< -o $@
$(INCLUDE_DIR)/%.h: $(SOURCE_DIR)/%.h lib
@@ -52,7 +52,8 @@ clean:
test: $(TEST)
-$(OBJS_DIR)/reader.o: $(SOURCE_DIR)/reader.cpp $(SOURCE_DIR)/reader.h $(SOURCE_DIR)/debug.h
-$(OBJS_DIR)/image.o: $(SOURCE_DIR)/image.cpp $(SOURCE_DIR)/image.h
-$(OBJS_DIR)/PNGImage.o: $(SOURCE_DIR)/PNGImage.cpp $(SOURCE_DIR)/PNGImage.h $(SOURCE_DIR)/debug.h $(SOURCE_DIR)/image.h $(SOURCE_DIR)/puff.h
-$(OBJS_DIR)/zlib.o: $(SOURCE_DIR)/zlib.cpp $(SOURCE_DIR)/zlib.h
+$(OBJS_DIR)/reader.o: $(SOURCE_DIR)/debug.h
+$(OBJS_DIR)/image.o:
+$(OBJS_DIR)/PNGImage.o: $(SOURCE_DIR)/debug.h $(SOURCE_DIR)/image.h
+$(OBJS_DIR)/BMPImage.o: $(SOURCE_DIR)/image.h
+$(OBJS_DIR)/zlib.o:
diff --git a/src/BMPImage.cpp b/src/BMPImage.cpp
new file mode 100644
index 0000000..71e5317
--- /dev/null
+++ b/src/BMPImage.cpp
@@ -0,0 +1,49 @@
+#include "BMPImage.h"
+
+#include <iostream>
+
+using std::cout, std::endl;
+
+int BMPImage::readFromFile(std::string filename)
+{
+ cout << "Not implemented" << endl;
+ return 2;
+};
+
+int BMPImage::writeToFile(std::string filename)
+{
+ FILE* fd = fopen(filename.c_str(), "w");
+ char magic[] = "BM";
+ fwrite(magic, sizeof(char), 2, fd);
+ uint32_t fileSize = 14 + 12 + width*height*/*(bitDepth/8)*/8*3;
+ fwrite(&fileSize, sizeof(uint32_t), 1, fd);
+ char zero[] = "\0\0\0\0";
+ fwrite(zero, sizeof(char), 4, fd);
+ uint32_t offset = 26;
+ fwrite(&offset, sizeof(uint32_t), 1, fd);
+ uint32_t headerSize = 12;
+ fwrite(&headerSize, sizeof(uint32_t), 1, fd);
+ uint16_t width = this->width;
+ uint16_t height = this->height;
+ uint16_t colorPlanes = 1;
+ uint16_t bitsPerPixel = /*bitDepth*/8*3;
+ fwrite(&width, sizeof(uint16_t), 1, fd);
+ fwrite(&height, sizeof(uint16_t), 1, fd);
+ fwrite(&colorPlanes, sizeof(uint16_t), 1, fd);
+ fwrite(&bitsPerPixel, sizeof(uint16_t), 1, fd);
+
+ for(int y = height-1; y >= 0; y--)
+ {
+ for(int x = 0; x < width; x++)
+ {
+ Pixel<uint8_t> pixel = getPixel<uint8_t>(x, y);
+ fwrite(&pixel.b, bitDepth/8, 1, fd);
+ fwrite(&pixel.g, bitDepth/8, 1, fd);
+ fwrite(&pixel.r, bitDepth/8, 1, fd);
+ }
+ }
+
+ fclose(fd);
+
+ return 0;
+};
diff --git a/src/BMPImage.h b/src/BMPImage.h
new file mode 100644
index 0000000..697c72d
--- /dev/null
+++ b/src/BMPImage.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "image.h"
+#include <cstdint>
+#include <cstring>
+
+class BMPImage : public Image
+{
+private:
+public:
+ template<std::derived_from<Image> T> BMPImage(const T& other) : Image(other) { }
+
+ int readFromFile(std::string filename) override;
+ int writeToFile(std::string filename) override;
+};
diff --git a/src/PNGImage.cpp b/src/PNGImage.cpp
index b7f28ce..50df7c6 100644
--- a/src/PNGImage.cpp
+++ b/src/PNGImage.cpp
@@ -14,9 +14,7 @@
using std::cout, std::endl;
-PNGImage::PNGImage(std::string filename)
- :reader(filename)
- ,idatData()
+PNGImage::PNGImage()
{
//cout << "Reader good" << endl;
REGISTER_CHUNK_READER(IHDR);
@@ -32,11 +30,6 @@ PNGImage::PNGImage(std::string filename)
//cout << "Chunk readers loaded" << endl;
- char signature[8];
- uint8_t expected[] = {137, 80, 78, 71, 13, 10, 26, 10};
- reader.readBytes(signature, 8);
- if(strncmp(signature, (char*)expected, 8) != 0)
- cout << "UH OH" << endl;
idatData = nullptr;
idatDataSize = 0;
@@ -50,14 +43,39 @@ PNGImage::~PNGImage()
idatDataSize = 0;
}
+int PNGImage::readFromFile(std::string filename)
+{
+ std::unique_ptr<Reader> readerMem(new Reader(filename));
+ reader = readerMem.get();
+
+ char signature[8];
+ uint8_t expected[] = {137, 80, 78, 71, 13, 10, 26, 10};
+ reader->readBytes(signature, 8);
+ if(strncmp(signature, (char*)expected, 8) != 0)
+ {
+ cout << "Not a PNG" << endl;
+ return 1;
+ }
+
+ while (readNextChunk()) {}
+
+ return 0;
+};
+
+int PNGImage::writeToFile(std::string filename)
+{
+ cout << "Not implemented" << endl;
+ return 2;
+};
+
bool PNGImage::readNextChunk()
{
if(end)
return false;
- uint32_t chunkSize = reader.readData<uint32_t>();
+ uint32_t chunkSize = reader->readData<uint32_t>();
char chunkType[4];
- reader.readBytes(chunkType, 4);
+ reader->readBytes(chunkType, 4);
std::string chunkName(chunkType, 4);
cout << "-------------" << endl;
cout << "|Chunk: " << chunkName << "|" << endl;
@@ -66,7 +84,7 @@ bool PNGImage::readNextChunk()
if(chunkReaders.count(chunkName) == 0)
{
cout << "Chunk reader not found!!!" << endl;
- reader.skipBytes(chunkSize + 4);
+ reader->skipBytes(chunkSize + 4);
if(islower(chunkType[0]))
{
cout << "\tAble to skip chunk" << endl;
@@ -79,20 +97,20 @@ bool PNGImage::readNextChunk()
void(PNGImage::*chunkReader)(uint32_t chunkSize) = chunkReaders.find(chunkName)->second;
(this->*chunkReader)(chunkSize);
- reader.skipBytes(4); // CRC
+ reader->skipBytes(4); // CRC
return true;
}
DEFINE_CHUNK_READER(IHDR)
{
- width = reader.readData<uint32_t>();
- height = reader.readData<uint32_t>();
- bitDepth = reader.readData<uint8_t>();
- colorType = reader.readData<uint8_t>();
- compressionMethod = reader.readData<uint8_t>();
- filterMethod = reader.readData<uint8_t>();
- interlaceMethod = reader.readData<uint8_t>();
+ width = reader->readData<uint32_t>();
+ height = reader->readData<uint32_t>();
+ bitDepth = reader->readData<uint8_t>();
+ colorType = reader->readData<uint8_t>();
+ compressionMethod = reader->readData<uint8_t>();
+ filterMethod = reader->readData<uint8_t>();
+ interlaceMethod = reader->readData<uint8_t>();
cout << "Width: " << width << ", Height: " << height << ", Bit depth: " << 0+bitDepth << ", Color type: " << 0+colorType << ", Compression method: " << 0+compressionMethod << ", Filter method: " << 0+filterMethod << ", Interlace method: " << 0+interlaceMethod << endl;
if(colorType != 2 && colorType != 6)
@@ -108,6 +126,7 @@ DEFINE_CHUNK_READER(IHDR)
bpp = colorValues * (bitDepth/8);
unsigned long imageDataSize = width * height * bpp;
+ //imageDataSize = imageDataSize;
cout << "Assigning " << imageDataSize << " bytes for image" << endl;
@@ -127,48 +146,48 @@ DEFINE_CHUNK_READER(iCCP)
{
cout << "!!! iCCP chunk reader not finished !!!" << endl;
std::string profileName;
- char c = reader.readByte();
+ char c = reader->readByte();
chunkSize--;
while(c != 0)
{
profileName.push_back(c);
- c = reader.readByte();
+ c = reader->readByte();
chunkSize--;
}
cout << profileName << endl;
- uint8_t compresssionMethod = reader.readByte();
+ uint8_t compresssionMethod = reader->readByte();
chunkSize--;
cout << 0+compresssionMethod << endl;
- uint8_t CMF = reader.readByte();
+ uint8_t CMF = reader->readByte();
uint8_t CM = CMF & 0b00001111;
uint8_t CINFO = (CMF & 0b11110000) >> 4;
chunkSize--;
- uint8_t FLG = reader.readByte();
+ uint8_t FLG = reader->readByte();
bool check = (CMF * 256 + FLG)%31 == 0;
bool FDICT = FLG & 0b00100000;
uint8_t FLEVEL = FLG & 0b11000000;
chunkSize--;
cout << std::bitset<4>(CM) << ", " << std::bitset<4>(CINFO) << ", " << (check?"Valid":"Failed checksum") << ", " << (FDICT?"Dict is present":"No dict present") << ", " << std::bitset<2>(FLEVEL) << endl;
char compressedData[chunkSize - 4];
- reader.readBytes(compressedData, chunkSize - 4);
+ reader->readBytes(compressedData, chunkSize - 4);
const int compressedSize = chunkSize - 4;
- uint32_t checkValue = reader.readData<uint32_t>();
+ uint32_t checkValue = reader->readData<uint32_t>();
//end = true;
}
DEFINE_CHUNK_READER(sRGB)
{
- renderingIntent = reader.readData<uint8_t>();
+ renderingIntent = reader->readData<uint8_t>();
cout << "Rendering intent: " << 0+renderingIntent << endl;
}
DEFINE_CHUNK_READER(eXIf)
{
char endian[4];
- reader.readBytes(endian, 4);
+ reader->readBytes(endian, 4);
for(int i = 0; i < 2; i++)
{
cout << endian[i];
@@ -179,7 +198,7 @@ DEFINE_CHUNK_READER(eXIf)
}
cout << endl;
char rest[chunkSize - 4];
- reader.readBytes(rest, chunkSize - 4);
+ reader->readBytes(rest, chunkSize - 4);
cout << std::hex;
for(int i = 0; i < chunkSize - 4; i++)
{
@@ -191,25 +210,25 @@ DEFINE_CHUNK_READER(eXIf)
DEFINE_CHUNK_READER(iDOT)
{
cout << "!!! Ignoring iDOT !!!" << endl;
- reader.skipBytes(chunkSize);
+ reader->skipBytes(chunkSize);
}
DEFINE_CHUNK_READER(pHYs)
{
- pixelsPerX = reader.readData<uint32_t>();
- pixelsPerY = reader.readData<uint32_t>();
- unit = reader.readData<uint8_t>();
+ pixelsPerX = reader->readData<uint32_t>();
+ pixelsPerY = reader->readData<uint32_t>();
+ unit = reader->readData<uint8_t>();
cout << "Pixels per unit (x): " << pixelsPerX << ", Pixels per unit (y): " << pixelsPerY << ", unit: " << 0+unit << endl;
}
DEFINE_CHUNK_READER(tIME)
{
- year = reader.readData<uint16_t>();
- month = reader.readData<uint8_t>();
- day = reader.readData<uint8_t>();
- hour = reader.readData<uint8_t>();
- minute = reader.readData<uint8_t>();
- second = reader.readData<uint8_t>();
+ year = reader->readData<uint16_t>();
+ month = reader->readData<uint8_t>();
+ day = reader->readData<uint8_t>();
+ hour = reader->readData<uint8_t>();
+ minute = reader->readData<uint8_t>();
+ second = reader->readData<uint8_t>();
cout << "Image last modified: " << 0+hour << ":" << 0+minute << ":" << 0+second << " " << 0+day << "-" << 0+month << "-" << 0+year << endl;
}
@@ -217,22 +236,22 @@ DEFINE_CHUNK_READER(tEXt)
{
std::string keyword;
- char c = reader.readByte();
+ char c = reader->readByte();
chunkSize--;
while(c != 0)
{
keyword.push_back(c);
- c = reader.readByte();
+ c = reader->readByte();
chunkSize--;
}
cout << keyword << endl;
std::string textString;
- c = reader.readByte();
+ c = reader->readByte();
chunkSize--;
while(chunkSize > 0)
{
textString.push_back(c);
- c = reader.readByte();
+ c = reader->readByte();
chunkSize--;
}
textString.push_back(c);
@@ -243,11 +262,11 @@ DEFINE_CHUNK_READER(IDAT)
{
if(idatDataSize == 0)
{
- uint8_t CMF = reader.readByte();
+ uint8_t CMF = reader->readByte();
uint8_t CM = (CMF & 0b11110000) >> 4;
uint8_t CINFO = CMF & 0b00001111;
chunkSize--;
- uint8_t FLG = reader.readByte();
+ uint8_t FLG = reader->readByte();
bool check = (CMF * 256 + FLG)%31 == 0;
bool FDICT = FLG & 0b00000100;
uint8_t FLEVEL = FLG & 0b00000011;
@@ -257,7 +276,7 @@ DEFINE_CHUNK_READER(IDAT)
}
idatData = (uint8_t *)realloc(idatData, idatDataSize + chunkSize);
- reader.readBytes((char *)&idatData[idatDataSize], chunkSize);
+ reader->readBytes((char *)&idatData[idatDataSize], chunkSize);
idatDataSize += chunkSize;
/*
@@ -268,7 +287,7 @@ DEFINE_CHUNK_READER(IDAT)
//cout << (int)puff((unsigned char*)imageData, &imageDataSize, (const unsigned char*)compressedData, &compressedSize) << endl;
*/
- //uint32_t checkValue = reader.readData<uint32_t>();
+ //uint32_t checkValue = reader->readData<uint32_t>();
//end = true;
}
@@ -293,28 +312,7 @@ DEFINE_CHUNK_READER(IEND)
uint8_t* pngImageData = new uint8_t[imageDataSize];
cout << "My inflate " << zlib.decodeData(idatData, idatDataSize, pngImageData, imageDataSize) << endl;
end = true;
- reader.close();
-
-
- FILE* fd = fopen("tmp.bmp", "w");
- char magic[] = "BM";
- fwrite(magic, sizeof(char), 2, fd);
- uint32_t fileSize = 14 + 12 + width*height*/*(bitDepth/8)*/8*3;
- fwrite(&fileSize, sizeof(uint32_t), 1, fd);
- char zero[] = "\0\0\0\0";
- fwrite(zero, sizeof(char), 4, fd);
- uint32_t offset = 26;
- fwrite(&offset, sizeof(uint32_t), 1, fd);
- uint32_t headerSize = 12;
- fwrite(&headerSize, sizeof(uint32_t), 1, fd);
- uint16_t width = this->width;
- uint16_t height = this->height;
- uint16_t colorPlanes = 1;
- uint16_t bitsPerPixel = /*bitDepth*/8*3;
- fwrite(&width, sizeof(uint16_t), 1, fd);
- fwrite(&height, sizeof(uint16_t), 1, fd);
- fwrite(&colorPlanes, sizeof(uint16_t), 1, fd);
- fwrite(&bitsPerPixel, sizeof(uint16_t), 1, fd);
+ reader->close();
#define imageDataIndex(x, y) imageData[y*width*bpp + x]
#define pngImageDataIndex(x, y) pngImageData[y*(width*bpp + 1) + x + 1]
@@ -361,17 +359,5 @@ DEFINE_CHUNK_READER(IEND)
#undef pngImageDataIndex
#undef filterByte
- for(int y = height-1; y >= 0; y--)
- {
- for(int x = 0; x < width; x++)
- {
- Pixel<uint8_t> pixel = getPixel<uint8_t>(x, y);
- fwrite(&pixel.b, bitDepth/8, 1, fd);
- fwrite(&pixel.g, bitDepth/8, 1, fd);
- fwrite(&pixel.r, bitDepth/8, 1, fd);
- }
- }
-
delete [] pngImageData;
- fclose(fd);
}
diff --git a/src/PNGImage.h b/src/PNGImage.h
index 23c32a0..e937212 100644
--- a/src/PNGImage.h
+++ b/src/PNGImage.h
@@ -6,6 +6,7 @@
#include <cstddef>
#include <cstdint>
#include <map>
+#include <memory>
#include <string>
#include <vector>
@@ -13,15 +14,20 @@
#define REGISTER_CHUNK_READER(X) chunkReaders.insert({#X, &PNGImage::X})
#define DEFINE_CHUNK_READER(X) void PNGImage::X(uint32_t chunkSize)
-class PNGImage : Image
+class PNGImage : public Image
{
private:
ZLibInflator zlib;
uint8_t* idatData;
unsigned long idatDataSize;
public:
- PNGImage(std::string filename);
+ PNGImage();
~PNGImage();
+
+ template<std::derived_from<Image> T> PNGImage(const T& other) : Image(other) { }
+
+ int readFromFile(std::string filename) override;
+ int writeToFile(std::string filename) override;
// sRGB
uint8_t renderingIntent;
@@ -56,5 +62,5 @@ private:
bool end = false;
- Reader reader;
+ Reader *reader;
};
diff --git a/src/image.cpp b/src/image.cpp
index 35941e5..f819b94 100644
--- a/src/image.cpp
+++ b/src/image.cpp
@@ -2,9 +2,8 @@
Image::~Image()
{
- if(width != 0 && height != 0)
+ if(width != 0)
{
delete[] imageData;
}
}
-
diff --git a/src/image.h b/src/image.h
index f4071ea..52f4279 100644
--- a/src/image.h
+++ b/src/image.h
@@ -1,7 +1,8 @@
#pragma once
-#include <cstddef>
#include <cstdint>
+#include <cstring>
+#include <string>
template <typename T>
struct Pixel
@@ -9,6 +10,14 @@ struct Pixel
T r, g, b, a;
};
+struct ImageData
+{
+
+
+
+
+ //unsigned long imageDataSize = 0;
+};
class Image
{
@@ -19,7 +28,16 @@ protected:
public:
Image() = default;
~Image();
+
+ template<std::derived_from<Image> T>
+ Image(const T& other);
+
+ virtual int readFromFile(std::string filename) = 0;
+ virtual int writeToFile(std::string filename) = 0;
+ template <typename T>
+ Pixel<T> getPixel(unsigned int x, unsigned int y);
+
uint32_t width = 0;
uint32_t height = 0;
uint8_t bitDepth;
@@ -27,12 +45,29 @@ public:
uint8_t compressionMethod;
uint8_t filterMethod;
uint8_t interlaceMethod;
-
- template <typename T>
- Pixel<T> getPixel(unsigned int x, unsigned int y);
};
+
+template<std::derived_from<Image> T> Image::Image(const T& other)
+{
+ this->colorValues = other.colorValues;
+ this->bpp = other.bpp;
+
+ this->width = other.width;
+ this->height = other.height;
+ this->bitDepth = other.bitDepth;
+ this->colorType = other.colorType;
+ this->compressionMethod = other.compressionMethod;
+ this->filterMethod = other.filterMethod;
+ this->interlaceMethod = other.interlaceMethod;
+
+ unsigned long imageDataSize = width * height * bpp;
+ imageData = new uint8_t[imageDataSize];
+ mempcpy(imageData, other.imageData, imageDataSize);
+}
+
+
template <typename T>
Pixel<T> Image::getPixel(unsigned int x, unsigned int y)
{
diff --git a/test/main.cpp b/test/main.cpp
index f60017e..c020526 100644
--- a/test/main.cpp
+++ b/test/main.cpp
@@ -1,6 +1,7 @@
#include <reader.h>
#include <debug.h>
#include <PNGImage.h>
+#include <BMPImage.h>
#include <zlib.h>
#include <cstdint>
#include <cstring>
@@ -10,15 +11,19 @@ using std::cout, std::endl;
int main(int argc, char* argv[])
{
- if(argc < 2)
+ if(argc < 3)
{
- cout << "usage: " << argv[0] << " <image>" << endl;
+ cout << "usage: " << argv[0] << " <in file> <out file>" << endl;
return 1;
}
- std::string filename = argv[1];
-
- PNGImage image(filename);
+ std::string infile = argv[1];
+ std::string outfile = argv[2];
+
- while(image.readNextChunk()){}
+ PNGImage png;
+ png.readFromFile(infile);
+
+ BMPImage bmp(png);
+ bmp.writeToFile(outfile);
}