aboutsummaryrefslogtreecommitdiff
path: root/src/PNGImage.cpp
diff options
context:
space:
mode:
authorDylan <boss@tehbox.org>2026-05-06 13:39:47 +1200
committerDylan <boss@tehbox.org>2026-05-06 13:39:47 +1200
commitd60976a70e68e1cd312b0e56fe6fbe6c7428cbaa (patch)
tree00bc987a6d935ca26e4d4c2d61ad70d7aa3c2f4c /src/PNGImage.cpp
parenta75bdd0e167140eeb4afb091c9dedd84474c8531 (diff)
downloadtehimage-d60976a70e68e1cd312b0e56fe6fbe6c7428cbaa.tar.gz
tehimage-d60976a70e68e1cd312b0e56fe6fbe6c7428cbaa.zip
feat: Started on PNG writing implementation
Currently writes IHDR and IEND chunks correctly CRC implementation is borrowed from the specification Writer class now also has a buffer for the CRC calculation
Diffstat (limited to 'src/PNGImage.cpp')
-rw-r--r--src/PNGImage.cpp86
1 files changed, 85 insertions, 1 deletions
diff --git a/src/PNGImage.cpp b/src/PNGImage.cpp
index b9f956f..1e46f22 100644
--- a/src/PNGImage.cpp
+++ b/src/PNGImage.cpp
@@ -70,7 +70,15 @@ namespace TehImage
int PNGImage::writeToFile(std::string filename)
{
- cout << "Not implemented" << endl;
+ std::unique_ptr<Writer> writerMem(new Writer(filename, FileEndianness::BIG));
+ writer = writerMem.get();
+
+ uint8_t signature[] = {137, 80, 78, 71, 13, 10, 26, 10};
+ writer->writeBytes((char*)signature, 8);
+
+ writeIHDR();
+ writeIEND();
+
return 2;
};
@@ -403,4 +411,80 @@ namespace TehImage
delete [] rawImage;
}
+ static uint32_t CRCTable[256];
+ static bool CRCComputed = false;
+
+ static void generateCRC()
+ {
+ for(uint32_t i = 0; i < 256; i++)
+ {
+ uint32_t c = i;
+ for(int bit = 0; bit < 8; bit++)
+ {
+ if(c & 1)
+ c = 0xEDB88320 ^ (c >> 1);
+ else
+ c >>= 1;
+ }
+ CRCTable[i] = c;
+ }
+ CRCComputed = true;
+ }
+
+ uint32_t PNGImage::calculateCRC(uint8_t* buffer, std::size_t bufflen)
+ {
+ uint32_t reg = 0xFFFFFFFF;
+ if (!CRCComputed)
+ generateCRC();
+ for (int i = 0; i < bufflen; i++) {
+ reg = CRCTable[(reg ^ buffer[i]) & 0xff] ^ (reg >> 8);
+ }
+ return reg^0xFFFFFFFF;
+ }
+
+
+ DEFINE_CHUNK_WRITER(IHDR)
+ {
+ uint32_t chunkSize = 13;
+ writer->writeData(chunkSize);
+ writer->flushBuffer();
+ char header[] = "IHDR";
+ writer->writeBytes(header, 4);
+
+ writer->writeData(width);
+ writer->writeData(height);
+ writer->writeData(bpp);
+ writer->writeData<uint8_t>(ColorTypes::TRUECOLOR | ColorTypes::ALPHA);
+ writer->writeData<uint8_t>(0); // Compression method
+ writer->writeData<uint8_t>(0); // Filter method
+ writer->writeData<uint8_t>(0); // Interlace method
+
+ uint32_t CRC = calculateCRC((uint8_t*)writer->buffer, writer->pos);
+ // cout << CRC << endl;
+ writer->writeData(CRC);
+ }
+
+ DEFINE_CHUNK_WRITER(IDAT)
+ {
+ uint32_t chunkSize = 0;
+ writer->writeData(chunkSize);
+ writer->flushBuffer();
+
+ char header[] = "IDAT";
+ writer->writeBytes(header, 4);
+ }
+
+ DEFINE_CHUNK_WRITER(IEND)
+ {
+ uint32_t chunkSize = 0;
+ writer->writeData(chunkSize);
+ writer->flushBuffer();
+
+ char header[] = "IEND";
+ writer->writeBytes(header, 4);
+
+ uint32_t CRC = calculateCRC((uint8_t*)writer->buffer, writer->pos);
+ // cout << CRC << endl;
+ writer->writeData(CRC);
+ }
}