aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/PNGImage.cpp86
-rw-r--r--src/PNGImage.h35
-rw-r--r--src/files.cpp23
-rw-r--r--src/files.h7
4 files changed, 139 insertions, 12 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);
+ }
}
diff --git a/src/PNGImage.h b/src/PNGImage.h
index 1ed1be5..4bbb4ff 100644
--- a/src/PNGImage.h
+++ b/src/PNGImage.h
@@ -10,16 +10,28 @@
#include <string>
#include <vector>
-#define CHUNK_READER(X) void X(uint32_t chunkSize)
-#define REGISTER_CHUNK_READER(X) chunkReaders.insert({#X, &PNGImage::X})
-#define DEFINE_CHUNK_READER(X) void PNGImage::X(uint32_t chunkSize)
+#define CHUNK_READER(X) void read##X(uint32_t chunkSize)
+#define REGISTER_CHUNK_READER(X) chunkReaders.insert({#X, &PNGImage::read##X})
+#define DEFINE_CHUNK_READER(X) void PNGImage::read##X(uint32_t chunkSize)
+
+#define CHUNK_WRITER(X) void write##X()
+#define DEFINE_CHUNK_WRITER(X) void PNGImage::write##X()
+
+
namespace TehImage
{
-
class PNGImage : public Image
{
public:
+ typedef enum
+ {
+ GRAYSCALE = 0,
+ TRUECOLOR = 2,
+ INDEXED = 3,
+ ALPHA = 4
+ } ColorTypes;
+
PNGImage();
~PNGImage();
@@ -44,8 +56,6 @@ namespace TehImage
uint8_t hour;
uint8_t minute;
uint8_t second;
-
- bool readNextChunk();
private:
std::map<std::string, void(PNGImage::*)(uint32_t chunkSize)> chunkReaders;
@@ -60,6 +70,18 @@ namespace TehImage
CHUNK_READER(IDAT);
CHUNK_READER(IEND);
+ CHUNK_WRITER(IHDR);
+ CHUNK_WRITER(IDAT);
+ CHUNK_WRITER(IEND);
+
+
+
+ bool readNextChunk();
+
+ uint32_t calculateCRC(uint8_t *buffer, std::size_t bufflen);
+
+ const uint64_t PNG_CRC = 0x104C11DB7;
+
ZLib zlib;
uint8_t* idatData;
unsigned long idatDataSize;
@@ -67,6 +89,7 @@ namespace TehImage
bool end = false;
Reader *reader;
+ Writer *writer;
};
}
diff --git a/src/files.cpp b/src/files.cpp
index b757811..20f2672 100644
--- a/src/files.cpp
+++ b/src/files.cpp
@@ -6,6 +6,7 @@
#include <cstdio>
#include <cstring>
#include <iostream>
+#include <stdexcept>
using std::cout, std::endl;
@@ -124,14 +125,17 @@ namespace TehImage
void Writer::writeByte(char toWrite)
{
- fwrite(&toWrite, sizeof(char), 1, file);
+ if(pos == WRITER_BUFFER_SIZE)
+ throw std::out_of_range("Writer buffer ran out single-byte!!!");
+ buffer[pos++] = toWrite;
}
void Writer::writeBytes(char toWrite[], std::size_t len)
{
- // for(int i = 0; i < len; i++)
- // cout << toWrite[i] << endl;
- fwrite(toWrite, sizeof(char), len, file);
+ if(pos + len > WRITER_BUFFER_SIZE)
+ throw std::out_of_range("Writer buffer ran out multi-byte!!!");
+ memcpy(&(buffer[pos]), toWrite, len);
+ pos += len;
}
void Writer::zeroBytes(std::size_t len)
@@ -145,10 +149,21 @@ namespace TehImage
void Writer::close()
{
if(ready)
+ {
+ flushBuffer();
fclose(file);
+ }
ready = false;
}
+ void Writer::flushBuffer()
+ {
+ if(!ready)
+ throw std::logic_error("Cannot flush buffer before opening file");
+ fwrite(buffer, sizeof(char), pos, file);
+ pos = 0;
+ }
+
template <> void Writer::writeData(uint8_t toWrite)
{
writeByte(toWrite);
diff --git a/src/files.h b/src/files.h
index fbbe8b7..ad65ce8 100644
--- a/src/files.h
+++ b/src/files.h
@@ -4,6 +4,7 @@
#include <string>
#define READER_BUFFER_SIZE 4096
+#define WRITER_BUFFER_SIZE 4096
#define DEFINE_INT_READER(TYPE) \
template<> TYPE Reader::readData<TYPE>() \
@@ -78,8 +79,12 @@ namespace TehImage
void zeroBytes(std::size_t len);
void close();
+
+ void flushBuffer();
+
+ char buffer[WRITER_BUFFER_SIZE];
+ std::size_t pos;
private:
- /* std::size_t pos; */
FILE* file;
bool ready = false;
FileEndianness fileEndianness;