First commit.
Some checks failed
Build & Release / Linux-x86_64-Build (push) Successful in 40s
Build & Release / Linux-AARCH64-Build (push) Has been cancelled

This commit is contained in:
2024-01-31 22:28:19 -08:00
commit 1a4a1ecd9c
246 changed files with 42404 additions and 0 deletions

1488
src/io/img/Img.cpp Normal file

File diff suppressed because it is too large Load Diff

110
src/io/img/ImgCodec.cpp Normal file
View File

@@ -0,0 +1,110 @@
#include "ehs/io/img/ImgCodec.h"
#include "ehs/io/img/Img.h"
namespace ehs
{
ImgCodec::ImgCodec()
: hashExt(0), endianness(Endianness::LE), encodeCb(nullptr), decodeCb(nullptr)
{
}
ImgCodec::ImgCodec(Str_8 id, Str_8 ext, const Endianness end,
bool (* encodeCb)(const ImgCodec* const, Serializer<UInt_64>&, const Img*),
bool (* decodeCb)(const ImgCodec* const, Serializer<UInt_64>&, Img*))
: id(std::move(id)), hashExt(ext.Hash_64()), ext(std::move(ext)), endianness(end), encodeCb(encodeCb), decodeCb(decodeCb)
{
}
ImgCodec::ImgCodec(ImgCodec&& codec) noexcept
: id(std::move(codec.id)), hashExt(codec.hashExt), ext(std::move(codec.ext)), endianness(codec.endianness),
encodeCb(codec.encodeCb), decodeCb(codec.decodeCb)
{
codec.hashExt = 0;
codec.endianness = Endianness::LE;
codec.encodeCb = nullptr;
codec.decodeCb = nullptr;
}
ImgCodec::ImgCodec(const ImgCodec& codec)
: id(codec.id), hashExt(codec.hashExt), ext(codec.ext), endianness(codec.endianness), encodeCb(codec.encodeCb),
decodeCb(codec.decodeCb)
{
}
ImgCodec& ImgCodec::operator=(ImgCodec&& codec) noexcept
{
if (this == &codec)
return *this;
id = std::move(codec.id);
hashExt = codec.hashExt;
ext = std::move(codec.ext);
endianness = codec.endianness;
encodeCb = codec.encodeCb;
decodeCb = codec.decodeCb;
codec.hashExt = 0;
codec.endianness = Endianness::LE;
codec.encodeCb = nullptr;
codec.decodeCb = nullptr;
return *this;
}
ImgCodec& ImgCodec::operator=(const ImgCodec& codec)
{
if (this == &codec)
return *this;
id = codec.id;
hashExt = codec.hashExt;
ext = codec.ext;
endianness = codec.endianness;
encodeCb = codec.encodeCb;
decodeCb = codec.decodeCb;
return *this;
}
Str_8 ImgCodec::GetId() const
{
return id;
}
UInt_64 ImgCodec::GetHashExt() const
{
return hashExt;
}
Str_8 ImgCodec::GetExt() const
{
return ext;
}
Endianness ImgCodec::GetEndianness() const
{
return endianness;
}
bool ImgCodec::Encode(Serializer<UInt_64>& out, const Img* in) const
{
if (!encodeCb)
{
EHS_LOG_INT("Error", 0, "Encoding is not supported for the " + id + " format.");
return false;
}
return encodeCb(this, out, in);
}
bool ImgCodec::Decode(Serializer<UInt_64>& in, Img* out) const
{
if (!decodeCb)
{
EHS_LOG_INT("Error", 0, "Decoding is not supported for the " + id + " format.");
return false;
}
return decodeCb(this, in, out);
}
}

232
src/io/img/PNG.cpp Normal file
View File

@@ -0,0 +1,232 @@
#include "ehs/io/img/PNG.h"
namespace ehs
{
Array<Byte, UInt_64> pngSeq = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
PNG::PNG()
: hashId(0)
{
}
PNG::PNG(const Str_8& filePath)
{
id = File::ParseName_8(filePath);
hashId = id.Hash_64();
File file(filePath, Mode::READ, Disposition::OPEN);
Serializer<UInt_64> data = file.ReadSerializer_64(Endianness::BE, file.Size());
file.Release();
Array<Byte, UInt_64> seq = data.ReadArray<Byte, UInt_64>(8);
if (seq != pngSeq)
{
EHS_LOG_INT("Error", 0, "File at file path, \"" + filePath + "\", is not a valid PNG file.");
return;
}
while (data.GetOffset() < data.Size())
{
UInt_32 length = data.Read<UInt_32>();
Str_8 id = data.ReadStr<Char_8, UInt_64>(4);
Serializer<UInt_64> chunkData(Endianness::BE, &data[data.GetOffset()], length);
data.SetOffset(data.GetOffset() + length);
Byte crc[4];
UInt_64 crcSize = 4;
data.ReadArray(crc, &crcSize);
PNG_Chunk* chunk = GetChunk(id);
if (chunk)
{
chunk->GetData()->SetOffset(chunk->GetData()->Size());
chunk->GetData()->WriteSer(chunkData);
chunk->GetData()->SetOffset(0);
}
else
chunks.Push(PNG_Chunk(id, chunkData, crc));
}
}
PNG::PNG(const Str_8& id, Serializer<UInt_64>& data)
: id(id), hashId(id.Hash_64())
{
Array<Byte, UInt_64> seq = data.ReadArray<Byte, UInt_64>(8);
if (seq != pngSeq)
return;
while (data.GetOffset() < data.Size())
{
UInt_32 length = data.Read<UInt_32>();
Str_8 id = data.ReadStr<Char_8, UInt_64>(4);
Serializer<UInt_64> chunkData(Endianness::BE, &data[data.GetOffset()], length);
data.SetOffset(data.GetOffset() + length);
Byte crc[4];
UInt_64 crcSize = 4;
data.ReadArray(crc, &crcSize);
PNG_Chunk* chunk = GetChunk(id);
if (chunk)
{
chunk->GetData()->SetOffset(chunk->GetData()->Size());
chunk->GetData()->WriteSer(chunkData);
chunk->GetData()->SetOffset(0);
}
else
chunks.Push(PNG_Chunk(id, chunkData, crc));
}
}
PNG::PNG(const PNG& png)
: id(png.id), hashId(png.hashId), chunks(png.chunks)
{
}
PNG& PNG::operator=(const PNG& png)
{
if (this == &png)
return *this;
id = png.id;
hashId = png.hashId;
chunks = png.chunks;
return *this;
}
bool PNG::HasChunk(const UInt_64 hashId) const
{
for (UInt_64 i = 0; i < chunks.Size(); ++i)
if (chunks[i].GetHashId() == hashId)
return true;
return false;
}
bool PNG::HasChunk(const Str_8& id) const
{
return HasChunk(id.Hash_64());
}
PNG_Chunk* PNG::GetChunk(const UInt_64 hashId)
{
for (UInt_64 i = 0; i < chunks.Size(); ++i)
if (chunks[i].GetHashId() == hashId)
return &chunks[i];
return nullptr;
}
PNG_Chunk* PNG::GetChunk(const Str_8& id)
{
return GetChunk(id.Hash_64());
}
bool PNG::IsPNG(Serializer<UInt_32>& data)
{
UInt_32 oldOffset = data.GetOffset();
data.SetOffset(0);
Array<Byte, UInt_32> seq = data.ReadArray<Byte, UInt_32>(8);
if (seq != pngSeq)
return false;
data.SetOffset(oldOffset);
return true;
}
void PNG::FilterNone(const Byte* const in, Byte* const out, const UInt_8 bitDepth, const UInt_8 channels, const UInt_32 scanline)
{
UInt_8 bytes = bitDepth / 8;
for (UInt_32 i = 0; i < scanline; i += bytes)
for (UInt_8 b = 0; b < bytes; ++b)
out[i + b] = in[i + bytes - 1 - b];
}
void PNG::FilterSub(const Byte* const in, Byte* const out, const UInt_8 bitDepth, const UInt_8 channels, const UInt_32 scanline)
{
UInt_8 bytes = bitDepth / 8;
UInt_8 pxSize = bytes * channels;
for (UInt_32 i = 0; i < scanline; i += bytes)
{
for (UInt_8 b = 0; b < bytes; ++b)
{
if (i >= pxSize)
out[i + b] = in[i + bytes - 1 - b] + out[i - pxSize + b];
else
out[i + b] = in[i + bytes - 1 - b];
}
}
}
void PNG::FilterUp(const Byte* const in, Byte* const out, const UInt_8 bitDepth, const UInt_8 channels, const UInt_32 scanline)
{
UInt_8 bytes = bitDepth / 8;
for (UInt_32 i = 0; i < scanline; i += bytes)
for (UInt_8 b = 0; b < bytes; ++b)
out[scanline + i + b] = in[i + bytes - 1 - b] + out[i + b];
}
void PNG::FilterAverage(const Byte* const in, Byte* const out, const UInt_8 bitDepth, const UInt_8 channels, const UInt_32 scanline)
{
UInt_8 bytes = bitDepth / 8;
UInt_8 pxSize = bytes * channels;
for (UInt_32 i = 0; i < scanline; i += bytes)
{
for (UInt_8 b = 0; b < bytes; ++b)
{
Byte prevPx = 0;
if (i >= pxSize)
prevPx = out[scanline + i - pxSize + b];
out[scanline + i + b] = in[i + bytes - 1 - b] + (Byte)Math::Floor(((float)prevPx + (float)out[i + b]) / 2.0f);
}
}
}
void PNG::FilterPaeth(const Byte* const in, Byte* const out, const UInt_8 bitDepth, const UInt_8 channels, const UInt_32 scanline)
{
UInt_8 bytes = bitDepth / 8;
UInt_8 pxSize = bytes * channels;
for (UInt_32 i = 0; i < scanline; i += bytes)
{
for (UInt_8 b = 0; b < bytes; ++b)
{
if (i >= pxSize)
out[scanline + i + b] = in[i + bytes - 1 - b] + PaethPredictor(out[scanline + i - pxSize + b], out[i + b], out[i - pxSize + b]);
else
out[scanline + i + b] = in[i + bytes - 1 - b] + out[i + b];
}
}
}
Byte PNG::PaethPredictor(const Byte a, const Byte b, const Byte c)
{
SInt_16 p = a + b - c;
SInt_16 pa = Math::Abs(p - a);
SInt_16 pb = Math::Abs(p - b);
SInt_16 pc = Math::Abs(p - c);
if (pa <= pb && pa <= pc)
return a;
else if (pb <= pc)
return b;
else
return c;
}
}

55
src/io/img/PNG_Chunk.cpp Normal file
View File

@@ -0,0 +1,55 @@
#include "ehs/io/img/PNG_Chunk.h"
namespace ehs
{
PNG_Chunk::PNG_Chunk()
: hashId(0), crc{0x0, 0x0, 0x0, 0x0}
{
}
PNG_Chunk::PNG_Chunk(const Str_8& id, const Serializer<UInt_64>& data, const Byte crc[4])
: id(id), hashId(id.Hash_64()), data(data), crc{crc[0], crc[1], crc[2], crc[3]}
{
}
PNG_Chunk::PNG_Chunk(const PNG_Chunk& chunk)
: id(chunk.id), hashId(chunk.hashId), data(chunk.data), crc{chunk.crc[0], chunk.crc[1], chunk.crc[2], chunk.crc[3]}
{
}
PNG_Chunk& PNG_Chunk::operator=(const PNG_Chunk& chunk)
{
if (this == &chunk)
return *this;
id = chunk.id;
hashId = chunk.hashId;
data = chunk.data;
crc[0] = chunk.crc[0];
crc[1] = chunk.crc[1];
crc[2] = chunk.crc[2];
crc[3] = chunk.crc[3];
return *this;
}
Str_8 PNG_Chunk::GetId() const
{
return id;
}
UInt_64 PNG_Chunk::GetHashId() const
{
return hashId;
}
Serializer<UInt_64>* PNG_Chunk::GetData()
{
return &data;
}
const unsigned char* PNG_Chunk::GetCRC() const
{
return crc;
}
}