aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDylan <boss@tehbox.org>2026-05-04 18:36:15 +1200
committerDylan <boss@tehbox.org>2026-05-04 18:36:15 +1200
commita75bdd0e167140eeb4afb091c9dedd84474c8531 (patch)
tree9c94262edc1c1eea4bd4977f76c7cd8ec6a43da1
parent500151be4794923cee6034c26881effeb1bb056d (diff)
downloadtehimage-a75bdd0e167140eeb4afb091c9dedd84474c8531.tar.gz
tehimage-a75bdd0e167140eeb4afb091c9dedd84474c8531.zip
feat: Added a writer class
Also moved both the reader and writer class to the same files, named files.{cpp,h}
-rw-r--r--GNUmakefile7
-rw-r--r--src/BMPImage.cpp38
-rw-r--r--src/PNGImage.cpp2
-rw-r--r--src/PNGImage.h2
-rw-r--r--src/files.cpp160
-rw-r--r--src/files.h87
-rw-r--r--src/reader.cpp137
-rw-r--r--src/reader.h53
-rw-r--r--test/main.cpp1
9 files changed, 272 insertions, 215 deletions
diff --git a/GNUmakefile b/GNUmakefile
index 0353f28..819d70d 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -58,9 +58,10 @@ install: $(LIB)
test: $(TEST)
-$(OBJS_DIR)/reader.o: $(SOURCE_DIR)/debug.h
+# $(OBJS_DIR)/reader.o: $(SOURCE_DIR)/debug.h
+$(OBJS_DIR)/files.o:
$(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)/PNGImage.o: $(SOURCE_DIR)/debug.h $(SOURCE_DIR)/image.h $(SOURCE_DIR)/files.h
+$(OBJS_DIR)/BMPImage.o: $(SOURCE_DIR)/image.h $(SOURCE_DIR)/files.h
$(OBJS_DIR)/zlib.o: $(SOURCE_DIR)/HashTable.h
$(OBJS_DIR)/HashTable.o:
diff --git a/src/BMPImage.cpp b/src/BMPImage.cpp
index b79bc0c..a22e65d 100644
--- a/src/BMPImage.cpp
+++ b/src/BMPImage.cpp
@@ -1,5 +1,5 @@
#include "BMPImage.h"
-#include "reader.h"
+#include "files.h"
#include <cstdint>
#include <iostream>
@@ -92,42 +92,42 @@ namespace TehImage
int BMPImage::writeToFile(std::string filename)
{
- FILE* fd = fopen(filename.c_str(), "w");
+ Writer writer(filename, LITTLE);
char magic[] = "BM";
uint32_t rowSize = (bpp * width + 31)/32;
uint32_t fileSize = 14 + 12 + rowSize*height*/*(bitDepth/8)*/8*3;
- char zero[] = "\0\0\0\0";
+ // 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);
+ uint16_t bitsPerPixel = /*bpp*/8*3;
+
+ writer.writeBytes(magic, 2);
+ writer.writeData(fileSize);
+ writer.zeroBytes(4);
+ writer.writeData(offset);
+ writer.writeData(headerSize);
- 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);
+ writer.writeData(width);
+ writer.writeData(height);
+ writer.writeData(colorPlanes);
+ writer.writeData(bitsPerPixel);
for(int y = height-1; y >= 0; y--)
{
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);
+ writer.writeData(pixel.b);
+ writer.writeData(pixel.g);
+ writer.writeData(pixel.r);
}
- fwrite(zero, sizeof(char), (4-((width * 3)%4))%4, fd);
+ writer.zeroBytes((4-((width * 3)%4))%4);
}
- fclose(fd);
+ writer.close();
return 0;
};
diff --git a/src/PNGImage.cpp b/src/PNGImage.cpp
index 677c811..b9f956f 100644
--- a/src/PNGImage.cpp
+++ b/src/PNGImage.cpp
@@ -1,5 +1,5 @@
#include "PNGImage.h"
-#include "reader.h"
+#include "files.h"
#include "zlib.h"
#include "debug.h"
diff --git a/src/PNGImage.h b/src/PNGImage.h
index fa78e0e..1ed1be5 100644
--- a/src/PNGImage.h
+++ b/src/PNGImage.h
@@ -1,6 +1,6 @@
#pragma once
-#include "reader.h"
+#include "files.h"
#include "image.h"
#include "zlib.h"
#include <cstddef>
diff --git a/src/files.cpp b/src/files.cpp
new file mode 100644
index 0000000..b757811
--- /dev/null
+++ b/src/files.cpp
@@ -0,0 +1,160 @@
+#include "files.h"
+
+#include <bit>
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <cstring>
+#include <iostream>
+
+
+using std::cout, std::endl;
+
+namespace TehImage
+{
+ // HELPERS
+ void convertEndian(uint8_t* in, uint8_t* out, std::size_t bytes, FileEndianness target)
+ {
+ constexpr bool LE = std::endian::native == std::endian::little;
+ constexpr bool BE = !LE;
+ if(target == NO_CONVERT || (target == BIG && BE) || (target == LITTLE && LE))
+ {
+ for(int i = 0; i < bytes; i++)
+ {
+ out[i] = in[i];
+ }
+ return;
+ }
+ // std::cout << "Converting" << std::endl;
+ for(int i = 0; i < bytes; i++)
+ {
+ out[bytes - 1 - i] = in[i];
+ }
+ }
+
+
+ // READER
+ Reader::Reader(std::string filename, FileEndianness fileEndianness)
+ :fileEndianness(fileEndianness)
+ {
+ file = fopen(filename.c_str(), "rb");
+ refreshBuffer();
+ ready = true;
+ }
+ Reader::~Reader()
+ {
+ if(ready)
+ fclose(file);
+ }
+
+ char Reader::readByte()
+ {
+ if(pos == READER_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();
+ }
+
+ DEFINE_INT_READER(uint16_t);
+ DEFINE_INT_READER(uint32_t);
+ DEFINE_INT_READER(uint64_t);
+
+
+ void Reader::readBytes(char* out, size_t len)
+ {
+ while(len > 0)
+ {
+ size_t bytesToRead = std::min(len, READER_BUFFER_SIZE - pos);
+ if(bytesToRead == 0)
+ {
+ refreshBuffer();
+ continue;
+ }
+ memcpy(out, buffer + pos, bytesToRead);
+ out += bytesToRead;
+ len -= bytesToRead;
+ pos += bytesToRead;
+ }
+ }
+
+ void Reader::skipBytes(size_t len)
+ {
+ while(len > 0)
+ {
+ size_t bytesToRead = std::min(len, READER_BUFFER_SIZE - pos);
+ if(bytesToRead == 0)
+ {
+ refreshBuffer();
+ continue;
+ }
+ len -= bytesToRead;
+ pos += bytesToRead;
+ }
+ }
+
+ void Reader::close()
+ {
+ fclose(file);
+ ready = false;
+ }
+
+
+ // WRITER
+ Writer::Writer(std::string filename, FileEndianness fileEndianness)
+ :fileEndianness(fileEndianness)
+ {
+ file = fopen(filename.c_str(), "w");
+ ready = true;
+ }
+
+ Writer::~Writer()
+ {
+ close();
+ }
+
+ void Writer::writeByte(char toWrite)
+ {
+ fwrite(&toWrite, sizeof(char), 1, file);
+ }
+
+ 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);
+ }
+
+ void Writer::zeroBytes(std::size_t len)
+ {
+ char *zeroes = new char[len];
+ memset(zeroes, 0, len);
+ writeBytes(zeroes, len);
+ delete[] zeroes;
+ }
+
+ void Writer::close()
+ {
+ if(ready)
+ fclose(file);
+ ready = false;
+ }
+
+ template <> void Writer::writeData(uint8_t toWrite)
+ {
+ writeByte(toWrite);
+ }
+
+ DEFINE_INT_WRITER(uint16_t);
+ DEFINE_INT_WRITER(uint32_t);
+ DEFINE_INT_WRITER(uint64_t);
+}
diff --git a/src/files.h b/src/files.h
new file mode 100644
index 0000000..fbbe8b7
--- /dev/null
+++ b/src/files.h
@@ -0,0 +1,87 @@
+#pragma once
+
+#include <cstdint>
+#include <string>
+
+#define READER_BUFFER_SIZE 4096
+
+#define DEFINE_INT_READER(TYPE) \
+ template<> TYPE Reader::readData<TYPE>() \
+ { \
+ TYPE in, out; \
+ readBytes((char*)&in, sizeof(TYPE)); \
+ convertEndian((uint8_t*)&in, (uint8_t*)&out, sizeof(TYPE), fileEndianness); \
+ return out; \
+ } \
+
+
+#define DEFINE_INT_WRITER(TYPE) \
+ template <> void Writer::writeData(TYPE toWrite) \
+ { \
+ TYPE converted; \
+ convertEndian((uint8_t*)&toWrite, (uint8_t*)&converted, sizeof(TYPE), fileEndianness); \
+ writeBytes((char*)&converted, sizeof(TYPE)); \
+ } \
+
+namespace TehImage
+{
+ enum FileEndianness
+ {
+ NO_CONVERT,
+ LITTLE,
+ BIG
+ };
+
+ void convertEndian(uint8_t* in, uint8_t* out, std::size_t bytes, FileEndianness target);
+
+ class Reader
+ {
+ public:
+ //Bytes are big endian
+ Reader(std::string file, FileEndianness fileEndianness);
+ ~Reader();
+
+ template <typename T>
+ T readData();
+
+ char readByte();
+
+ void readBytes(char* out, std::size_t len);
+
+ void skipBytes(std::size_t len);
+
+ void close();
+ private:
+ char buffer[READER_BUFFER_SIZE];
+ std::size_t pos;
+ FILE* file;
+ bool ready = false;
+ FileEndianness fileEndianness;
+
+ void refreshBuffer();
+ };
+
+ class Writer
+ {
+ public:
+ //Bytes are big endian
+ Writer(std::string filename, FileEndianness fileEndianness);
+ ~Writer();
+
+ template <typename T>
+ void writeData(T toWrite);
+
+ void writeByte(char toWrite);
+
+ void writeBytes(char toWrite[], std::size_t len);
+
+ void zeroBytes(std::size_t len);
+
+ void close();
+ private:
+ /* std::size_t pos; */
+ FILE* file;
+ bool ready = false;
+ FileEndianness fileEndianness;
+ };
+}
diff --git a/src/reader.cpp b/src/reader.cpp
deleted file mode 100644
index f0b19ae..0000000
--- a/src/reader.cpp
+++ /dev/null
@@ -1,137 +0,0 @@
-#include "reader.h"
-
-#include "debug.h"
-
-#include <algorithm>
-#include <cstddef>
-#include <cstdint>
-#include <cstring>
-#include <iostream>
-
-namespace TehImage
-{
-
- Reader::Reader(std::string filename, FileEndianness fileEndianness)
- {
- file = fopen(filename.c_str(), "rb");
- refreshBuffer();
- ready = true;
- this->fileEndianness = fileEndianness;
- }
- Reader::~Reader()
- {
- if(ready)
- fclose(file);
- }
-
- char Reader::readByte()
- {
- if(pos == BUFFER_SIZE)
- refreshBuffer();
- return buffer[pos++];
- }
-
- void Reader::refreshBuffer()
- {
- fread(buffer, sizeof(buffer), 1, file);
- pos = 0;
- }
-
- void Reader::convertEndian(uint8_t* out, size_t bytes)
- {
- constexpr bool LE = std::endian::native == std::endian::little;
- constexpr bool BE = !LE;
- if(fileEndianness == NO_CONVERT || (fileEndianness == BIG && BE) || (fileEndianness == LITTLE && LE))
- {
- for(int i = 0; i < bytes; i++)
- {
- out[i] = readByte();
- }
- return;
- }
- for(int i = 0; i < bytes; i++)
- {
- out[bytes - 1 - i] = readByte();
- }
- }
-
- template<> uint8_t Reader::readData<uint8_t>()
- {
- return readByte();
- }
-
- template<> uint16_t Reader::readData<uint16_t>()
- {
- uint16_t num = 0;
- convertEndian((uint8_t*)&num, 2);
- // for(int i = 0; i < 2; i++)
- // {
- // num += readByte() << (8 * (1-i));
- // }
- return num;
- }
-
- template<> uint32_t Reader::readData<uint32_t>()
- {
- uint32_t num = 0;
- convertEndian((uint8_t*)&num, 4);
- // for(int i = 0; i < 4; i++)
- // {
- // // uint8_t byte = readByte();
- // // debug(std::cout << std::hex << 0+byte << " ");
- // num += ((uint8_t) readByte()) << (8 * (3-i));
- // }
- // // debug(std::cout << std::dec << std::endl);
- return num;
- }
-
- template<> uint64_t Reader::readData<uint64_t>()
- {
- uint64_t num = 0;
- convertEndian((uint8_t*)&num, 8);
- // for(int i = 0; i < 8; i++)
- // {
- // num += readByte() << (8 * (7-i));
- // }
- return num;
- }
-
- void Reader::readBytes(char* out, size_t len)
- {
- while(len > 0)
- {
- 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;
- }
- }
-
- void Reader::skipBytes(size_t len)
- {
- while(len > 0)
- {
- size_t bytesToRead = std::min(len, BUFFER_SIZE - pos);
- if(bytesToRead == 0)
- {
- refreshBuffer();
- continue;
- }
- len -= bytesToRead;
- pos += bytesToRead;
- }
- }
-
- void Reader::close()
- {
- fclose(file);
- ready = false;
- }
-
-}
diff --git a/src/reader.h b/src/reader.h
deleted file mode 100644
index bb181e6..0000000
--- a/src/reader.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#pragma once
-
-#include <cstddef>
-#include <cstdint>
-#include <cstdio>
-#include <string>
-
-#define BUFFER_SIZE 4096
-
-namespace TehImage
-{
- enum FileEndianness
- {
- NO_CONVERT,
- LITTLE,
- BIG
- };
-
- class Reader
- {
- public:
- //Bytes are big endian
- Reader(std::string file, FileEndianness fileEndianness);
- ~Reader();
-
- template <typename T>
- T readData();
-
- char readByte();
-
- void readBytes(char* out, size_t len);
-
- void skipBytes(size_t len);
-
- void close();
- private:
- char buffer[BUFFER_SIZE];
- size_t pos;
- FILE* file;
- bool ready = false;
- FileEndianness fileEndianness;
-
- void refreshBuffer();
- void convertEndian(uint8_t* out, size_t bytes);
- };
-
- // template <typename T>
- // T Reader::readData()
- // {
- // T num = 0;
- // convertEndian((uint8_t*)&num, sizeof(T));
- // }
-}
diff --git a/test/main.cpp b/test/main.cpp
index 6cd6d74..6e521f3 100644
--- a/test/main.cpp
+++ b/test/main.cpp
@@ -1,5 +1,4 @@
#include <bitset>
-#include <reader.h>
#include <debug.h>
#include <PNGImage.h>
#include <BMPImage.h>