Some encode/decode practice.

This commit is contained in:
James Grogan 2022-11-21 17:45:12 +00:00
parent 8a41337e2d
commit ff962a6b16
29 changed files with 727 additions and 305 deletions

View file

@ -2,6 +2,8 @@
list(APPEND compression_LIB_INCLUDES list(APPEND compression_LIB_INCLUDES
StreamCompressor.cpp StreamCompressor.cpp
HuffmanEncoder.cpp HuffmanEncoder.cpp
RunLengthEncoder.cpp
ZlibData.cpp
) )
add_library(compression SHARED ${compression_LIB_INCLUDES}) add_library(compression SHARED ${compression_LIB_INCLUDES})

View file

@ -1,77 +1,100 @@
#include "HuffmanEncoder.h" #include "HuffmanEncoder.h"
#include "Tree.h" #include "RawTree.h"
#include <unordered_map> #include <unordered_map>
#include <queue> #include <queue>
#include <tuple> #include <tuple>
#include <iostream> #include <iostream>
void HuffmanEncoder::dumpNode(RawNode<CountPair>* node, unsigned depth) const
{
if (!node)
{
return;
}
auto data = node->getData();
std::string prefix(depth, '_');
if (node->isLeaf())
{
std::cout << prefix << "Leaf with value: " << data.first << " and sum " << data.second << std::endl;
}
else
{
std::cout << prefix << "Intermediate with sum " << data.second << std::endl;
std::cout << prefix << "Doing Left.." << std::endl;
dumpNode(node->getLeftChild(), depth+1);
std::cout << prefix << "Doing Right.." << std::endl;
dumpNode(node->getRightChild(), depth+1);
std::cout << prefix << "*****" << std::endl;
}
}
void HuffmanEncoder::dumpTree(const RawTree<CountPair>& tree) const
{
dumpNode(tree.getRootNode(), 0);
}
void HuffmanEncoder::encode(const HuffmanEncoder::DataStream& stream) void HuffmanEncoder::encode(const HuffmanEncoder::DataStream& stream)
{ {
std::unordered_map<unsigned char, unsigned> counts; std::unordered_map<unsigned char, unsigned> counts;
for (auto c : stream) for (auto c : stream)
{ {
counts[c]++; counts[c]++;
} }
encode(counts);
using CountPair = std::pair<unsigned char, unsigned>; }
auto cmp = [](CountPair left, CountPair right)
{ void HuffmanEncoder::encode(const std::unordered_map<unsigned char, unsigned>& counts)
return left.second > right.second; {
}; std::cout << "Counts" << std::endl;
std::priority_queue<CountPair, std::vector<CountPair>, decltype(cmp)> q(cmp); for (const auto& data: counts)
for (const auto& entry : counts) {
{ std::cout << data.first << " | " << data.second << std::endl;
q.push({entry.first, entry.second}); }
} std::cout << "*******" << std::endl;
NodePtr<CountPair> lastNode; auto cmp = [](RawNode<CountPair>* left, RawNode<CountPair>* right)
while(!q.empty()) {
{ return left->getData().second > right->getData().second;
const auto charData = q.top(); };
auto characterNode = std::make_unique<Node<CountPair> >(charData);
q.pop(); std::priority_queue<RawNode<CountPair>*, std::vector<RawNode<CountPair>* >, decltype(cmp)> q(cmp);
for (const auto& entry : counts)
if (!lastNode) {
{ q.push(new RawNode<CountPair>(entry));
const auto rightCharData = q.top(); }
auto rightCharacterNode = std::make_unique<Node<CountPair> >(rightCharData);
q.pop(); while(q.size() > 1)
{
const auto sum = charData.second + rightCharData.second; auto node0 = q.top();
CountPair data{0, sum}; q.pop();
auto midNode = std::make_unique<Node<CountPair> >(data);
auto node1 = q.top();
midNode->addChild(std::move(characterNode)); q.pop();
midNode->addChild(std::move(rightCharacterNode));
lastNode = std::move(midNode); const auto sum = node0->getData().second + node1->getData().second;
} auto new_node = new RawNode<CountPair>(CountPair{0, sum});
else
{ new_node->addChild(node0);
const auto sum = lastNode->getData().second; new_node->addChild(node1);
CountPair data{0, sum}; q.push(new_node);
auto midNode = std::make_unique<Node<CountPair> >(data); }
if (charData.second < lastNode->getData().second) auto root = q.top();
{ q.pop();
midNode->addChild(std::move(lastNode));
midNode->addChild(std::move(characterNode)); RawTree<CountPair> tree;
} tree.addRootNode(root);
else
{ //using TableEntry = std::tuple<>
midNode->addChild(std::move(characterNode));
midNode->addChild(std::move(lastNode)); dumpTree(tree);
}
lastNode = std::move(midNode); std::cout << "********" << std::endl;
}
}
Tree<CountPair> tree;
tree.addRootNode(std::move(lastNode));
//using TableEntry = std::tuple<>
std::cout << "********" << std::endl;
} }

View file

@ -1,11 +1,21 @@
#pragma once #pragma once
#include "RawTree.h"
#include <vector> #include <vector>
#include <unordered_map>
class HuffmanEncoder class HuffmanEncoder
{ {
using DataStream = std::vector<unsigned char>; using DataStream = std::vector<unsigned char>;
using CountPair = std::pair<unsigned char, unsigned>;
public: public:
void encode(const DataStream& stream); void encode(const DataStream& stream);
void encode(const std::unordered_map<unsigned char, unsigned>& counts);
private:
void dumpTree(const RawTree<CountPair>& tree) const;
void dumpNode(RawNode<CountPair>* node, unsigned depth) const;
}; };

View file

@ -0,0 +1,110 @@
#pragma once
#include "StringUtils.h"
#include <vector>
#include <string>
class RunLengthEncoder
{
public:
std::string encode(const std::string& string)
{
std::string ret;
if (string.empty())
{
return ret;
}
char working_char{0};
unsigned count = 1;
for(unsigned idx=0; idx<string.size(); idx++)
{
auto c = string[idx];
if (idx == 0)
{
working_char = c;
continue;
}
if (c == working_char)
{
count++;
}
else
{
insertCharacter(ret, working_char, count);
working_char = c;
count = 1;
}
}
insertCharacter(ret, working_char, count);
return ret;
}
std::string decode(const std::string& string)
{
std::string ret;
if (string.empty())
{
return ret;
}
unsigned count{0};
while(count < string.size())
{
auto c = string[count];
if (c == mDelimiter)
{
count++;
std::string reps;
char working_char{0};
while(count < string.size())
{
auto rep_char = string[count];
count++;
if (StringUtils::IsAlphabetical(rep_char))
{
working_char = rep_char;
break;
}
else
{
reps += rep_char;
}
}
for (unsigned idx=0; idx<std::stoul(reps); idx++)
{
ret += working_char;
}
}
else
{
ret += c;
count++;
}
}
return ret;
}
private:
void insertCharacter(std::string& output, char c, unsigned count)
{
if (count >= 3)
{
output += mDelimiter + std::to_string(count) + c;
}
else
{
for (unsigned jdx=0;jdx<count; jdx++)
{
output += c;
}
}
}
char mDelimiter {'@'};
};

View file

@ -0,0 +1,97 @@
#pragma once
#include "ByteUtils.h"
#include <vector>
#include <iostream>
class ZlibData
{
public:
void setByte(unsigned idx, unsigned char data)
{
mData[idx] = data;
}
void setDataSize(std::size_t size)
{
mData = std::vector<unsigned char>(size);
}
void setCompressionMethod(unsigned char method)
{
std::cout << "Got compression input " << static_cast<int>(method) << std::endl;
mCmf = method;
mCompressionMethod = ByteUtils::getLowerNBits(method, 4);
mCompressionInfo = ByteUtils::getHigherNBits(method, 4);
std::cout << "Got compression method " << static_cast<int>(mCompressionMethod) << " and info " << static_cast<int>(mCompressionInfo) << std::endl;
}
void setExtraFlags(unsigned char extraFlags)
{
std::cout << "Got flags " << static_cast<int>(extraFlags) << std::endl;
mFlg = extraFlags;
mFlagCheck = ByteUtils::getLowerNBits(extraFlags, 5);
mFlagDict = ByteUtils::getBitN(extraFlags, 5);
mFlagLevel = ByteUtils::getHigherNBits(extraFlags, 2);
std::cout << "Got flag check " << static_cast<int>(mFlagCheck) << " and dict " << static_cast<int>(mFlagDict) << " and level " << static_cast<int>(mFlagLevel) << std::endl;
}
void processData()
{
unsigned char NO_COMPRESSION = 0x00;
unsigned char FIXED_HUFFMAN = 0x01;
unsigned char DYNAMIC_HUFFMAN = 0x02;
unsigned char ERROR = 0x03;
bool in_final_block = false;
unsigned working_byte_id = 0;
for (unsigned idx=0; idx<mData.size(); idx++)
{
auto working_byte = mData[working_byte_id];
std::cout << "Into process data, byte is: " << static_cast<int>(working_byte) << std::endl;
auto final_block = ByteUtils::getBitN(working_byte, 0);
if (final_block)
{
std::cout << "Got final block" << std::endl;
in_final_block = true;
}
auto compress_type = ByteUtils::getTwoBitsAtN(working_byte, 1);
std::cout << "Compress type byte is: " << static_cast<int>(compress_type) << std::endl;
if (compress_type == NO_COMPRESSION)
{
std::cout << "Got NO_COMPRESSION" << std::endl;
}
else if (compress_type == FIXED_HUFFMAN)
{
std::cout << "Got FIXED_HUFFMAN" << std::endl;
}
else if (compress_type == DYNAMIC_HUFFMAN)
{
std::cout << "Got DYNAMIC_HUFFMAN" << std::endl;
}
else if (compress_type == ERROR)
{
std::cout << "Got ERROR" << std::endl;
}
break;
}
}
private:
std::vector<unsigned char> mData;
unsigned char mCmf{0};
unsigned char mFlg{0};
unsigned char mCompressionMethod{0};
unsigned char mCompressionInfo{0};
unsigned char mFlagCheck{0};
unsigned char mFlagDict{0};
unsigned char mFlagLevel{0};
unsigned char mCheckValue{0};
};

View file

@ -25,6 +25,46 @@ public:
return word & ByteUtils::WORD_LAST_BYTE; return word & ByteUtils::WORD_LAST_BYTE;
} }
static unsigned char getHigherNBits(unsigned char input, unsigned num)
{
return input >> 8 - num;
}
static unsigned char getLowerNBits(unsigned char input, unsigned num)
{
switch (num)
{
case 1:
return input & 0x01;
case 2:
return input & 0x03;
case 3:
return input & 0x07;
case 4:
return input & 0x0F;
case 5:
return input & 0x1F;
case 6:
return input & 0x3F;
case 7:
return input & 0x7F;
case 8:
return input;
default:
return 0;
}
}
static unsigned char getTwoBitsAtN(unsigned char input, unsigned n)
{
return (input & (0x03 << n)) >> n;
}
static unsigned char getBitN(unsigned char input, unsigned n)
{
return input & (1 << n);
}
static void ReverseBuffer(char* buffer, char* reverse, unsigned size, unsigned targetSize) static void ReverseBuffer(char* buffer, char* reverse, unsigned size, unsigned targetSize)
{ {
for(unsigned idx=0; idx<targetSize; idx++) for(unsigned idx=0; idx<targetSize; idx++)

View file

@ -18,6 +18,7 @@ list(APPEND core_LIB_INCLUDES
Dictionary.cpp Dictionary.cpp
Color.cpp Color.cpp
CommandLineArgs.cpp CommandLineArgs.cpp
data_structures/RawTree.cpp
data_structures/Tree.cpp data_structures/Tree.cpp
loggers/FileLogger.cpp loggers/FileLogger.cpp
file_utilities/Directory.cpp file_utilities/Directory.cpp

View file

@ -20,6 +20,11 @@ bool StringUtils::IsSpace(char c)
return std::isspace(c, loc); return std::isspace(c, loc);
} }
bool StringUtils::IsAlphabetical(char c)
{
return std::isalpha(c);
}
std::vector<std::string> StringUtils::toLines(const std::string& input) std::vector<std::string> StringUtils::toLines(const std::string& input)
{ {
auto result = std::vector<std::string>{}; auto result = std::vector<std::string>{};

View file

@ -17,6 +17,9 @@ public:
static constexpr char COLON = ':'; static constexpr char COLON = ':';
static bool IsAlphaNumeric(char c); static bool IsAlphaNumeric(char c);
static bool IsAlphabetical(char c);
static bool IsSpace(char c); static bool IsSpace(char c);
static std::string ToLower(const std::string& s); static std::string ToLower(const std::string& s);
static std::string convert(const std::wstring& input); static std::string convert(const std::wstring& input);

View file

View file

@ -0,0 +1,97 @@
#pragma once
#include <memory>
template<typename T>
class RawNode
{
public:
RawNode(T data)
: mData(data)
{
}
~RawNode()
{
if(mLeftChild)
{
delete mLeftChild;
}
if(mRightChild)
{
delete mRightChild;
}
}
void addChild(RawNode* child)
{
if(!mLeftChild)
{
mLeftChild = child;
}
else
{
mRightChild = child;
}
}
bool isLeaf() const
{
return !mLeftChild && !mRightChild;
}
T getData() const
{
return mData;
}
RawNode* getLeftChild() const
{
return mLeftChild;
}
RawNode* getRightChild() const
{
return mRightChild;
}
private:
T mData;
unsigned char mTag{0};
RawNode* mLeftChild{nullptr};
RawNode* mRightChild{nullptr};
};
template<typename T>
class RawTree
{
public:
RawTree()
{
}
~RawTree()
{
if (mRootNode)
{
delete mRootNode;
}
}
void addRootNode(RawNode<T>* root)
{
mRootNode = root;
}
RawNode<T>* getRootNode() const
{
return mRootNode;
}
private:
RawNode<T>* mRootNode{nullptr};
};

View file

@ -6,37 +6,47 @@ template<typename T>
class Node class Node
{ {
public: public:
Node(T data) Node(T data)
: mData(data) : mData(data)
{} {}
void addChild(std::unique_ptr<Node> child) void addChild(std::unique_ptr<Node> child)
{ {
if(!mLeftChild) if(!mLeftChild)
{ {
mLeftChild = std::move(child); mLeftChild = std::move(child);
} }
else else
{ {
mRightChild = std::move(child); mRightChild = std::move(child);
} }
} }
bool isLeaf() const bool isLeaf() const
{ {
return !mLeftChild && !mRightChild; return !mLeftChild && !mRightChild;
} }
T getData() const T getData() const
{ {
return mData; return mData;
} }
Node* getLeftChild() const
{
return mLeftChild.get();
}
Node* getRightChild() const
{
return mRightChild.get();
}
private: private:
T mData; T mData;
unsigned char mTag{0}; unsigned char mTag{0};
std::unique_ptr<Node> mLeftChild; std::unique_ptr<Node> mLeftChild;
std::unique_ptr<Node> mRightChild; std::unique_ptr<Node> mRightChild;
}; };
template<typename T> template<typename T>
@ -46,21 +56,21 @@ template<typename T>
class Tree class Tree
{ {
public: public:
Tree() Tree()
{ {
} }
void addRootNode(NodePtr<T> root) void addRootNode(NodePtr<T> root)
{ {
mRootNode = std::move(root); mRootNode = std::move(root);
} }
Node<T>* getRootNode() const Node<T>* getRootNode() const
{ {
return mRootNode.get(); return mRootNode.get();
} }
private: private:
NodePtr<T> mRootNode; NodePtr<T> mRootNode;
}; };

View file

@ -32,6 +32,11 @@ std::ofstream* File::GetOutHandle() const
return mOutHandle.get(); return mOutHandle.get();
} }
unsigned char File::readNextByte()
{
return mInHandle->get();
}
void File::Open(bool asBinary) void File::Open(bool asBinary)
{ {
if(mAccessMode == AccessMode::Read) if(mAccessMode == AccessMode::Read)

View file

@ -48,6 +48,8 @@ public:
void Close(); void Close();
unsigned char readNextByte();
private: private:

View file

@ -1,38 +1,22 @@
list(APPEND image_HEADERS list(APPEND image_HEADERS
Image.h Image.h
PngWriter.h PngWriter.h
PngWriterBasic.h
PngWriterImpl.h
) )
list(APPEND image_LIB_INCLUDES list(APPEND image_LIB_INCLUDES
Image.cpp Image.cpp
PngWriter.cpp PngWriter.cpp
PngWriterBasic.cpp
PngReader.cpp PngReader.cpp
) )
list(APPEND image_LIBS core) list(APPEND image_LIBS core compression)
list(APPEND image_DEFINES "") list(APPEND image_DEFINES "")
find_package(PNG QUIET)
if(PNG_FOUND)
list(APPEND image_LIBS PNG::PNG)
list(APPEND image_LIB_INCLUDES
PngWriterLibPng.cpp
)
list(APPEND image_DEFINES HAS_LIBPNG)
else()
message(STATUS "LIBRARY CHECK: libPNG not found - disabling libPNG based image i/o.")
endif()
add_library(image SHARED ${image_LIB_INCLUDES} ${image_HEADERS}) add_library(image SHARED ${image_LIB_INCLUDES} ${image_HEADERS})
#target_compile_definitions(image PRIVATE ${image_DEFINES}) #target_compile_definitions(image PRIVATE ${image_DEFINES})
target_include_directories(image PUBLIC target_include_directories(image PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
"${CMAKE_CURRENT_SOURCE_DIR}"
)
set_target_properties( image PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON ) set_target_properties( image PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
target_link_libraries( image PUBLIC ${image_LIBS}) target_link_libraries( image PUBLIC ${image_LIBS})

View file

@ -23,4 +23,19 @@ public:
} }
} }
} }
static void drawAlternatingStrips(std::vector<unsigned char>& data, unsigned width, unsigned height, unsigned channels, unsigned bytesPerRow)
{
for(unsigned jdx=0;jdx<height;jdx++)
{
const auto heightOffset = jdx*bytesPerRow;
for(unsigned idx=0;idx<width*channels;idx+=channels)
{
const auto index = heightOffset + idx;
data[index] = (idx%2 == 0) ? 255*jdx/(height+1) : 0;
data[index+1] = 0;
data[index+2] = 0;
}
}
}
}; };

33
src/image/PngElements.h Normal file
View file

@ -0,0 +1,33 @@
#pragma once
#include <string>
#include <sstream>
namespace Png
{
struct IHDRChunk
{
unsigned width{0};
unsigned height{0};
char bitDepth{0};
char colorType{0};
char compressionMethod{0};
char filterMethod{0};
char interlaceMethod{0};
std::string toString() const
{
std::stringstream sstr;
sstr << "width: " << width << "\n";
sstr << "height: " << height << "\n";
sstr << "bitDepth: " << (int)bitDepth << "\n";
sstr << "colorType: " << (int)colorType << "\n";
sstr << "compressionMethod: " << (int)compressionMethod << "\n";
sstr << "filterMethod: " << (int)filterMethod << "\n";
sstr << "interlaceMethod: " << (int)interlaceMethod << "\n";
return sstr.str();
}
};
}

View file

@ -1,7 +1,6 @@
#include "PngReader.h" #include "PngReader.h"
#include "BinaryStream.h"
#include "Image.h" #include "BinaryStream.h"
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
@ -11,120 +10,135 @@ PngReader::~PngReader()
} }
void PngReader::setPath(const std::string& path) void PngReader::setPath(const Path& path)
{ {
mPath = path; mPath = path;
} }
bool PngReader::checkSignature() bool PngReader::checkSignature()
{ {
const int highBitCheck = 0x89; const int highBitCheck = 0x89;
const auto firstPos = mFile->GetInHandle()->get(); const auto firstPos = mFile->GetInHandle()->get();
if (firstPos != highBitCheck) if (firstPos != highBitCheck)
{ {
return false; return false;
} }
std::string fileType; std::string fileType;
BinaryStream::getNextString(mFile->GetInHandle(), fileType, 3); BinaryStream::getNextString(mFile->GetInHandle(), fileType, 3);
if (fileType != "PNG") if (fileType != "PNG")
{ {
return false; return false;
} }
std::vector<char> sequence{13, 10, 26, 10}; std::vector<char> sequence{13, 10, 26, 10};
for (auto c : sequence) for (auto c : sequence)
{ {
if (mFile->GetInHandle()->get() != c) if (mFile->GetInHandle()->get() != c)
{ {
return false; return false;
} }
} }
mCurrentOffset += 8; mCurrentOffset += 8;
return true; return true;
} }
bool PngReader::readChunk() bool PngReader::readChunk()
{ {
unsigned length = *BinaryStream::getNextDWord(mFile->GetInHandle()); unsigned length = *BinaryStream::getNextDWord(mFile->GetInHandle());
std::string chunkType; std::string chunkType;
BinaryStream::getNextString(mFile->GetInHandle(), chunkType, 4); BinaryStream::getNextString(mFile->GetInHandle(), chunkType, 4);
mCurrentOffset += 8; mCurrentOffset += 8;
std::cout << "Got chunk with type: " << chunkType << " and length: " << length << std::endl; std::cout << "Got chunk with type: " << chunkType << " and length: " << length << std::endl;
bool lastChunk = false; bool lastChunk = false;
if (chunkType == "IHDR") if (chunkType == "IHDR")
{ {
parseHeader(); readHeaderChunk();
} }
else if(chunkType == "IEND") else if(chunkType == "IEND")
{ {
lastChunk = true; lastChunk = true;
} }
else else if(chunkType == "IDAT")
{ {
for(unsigned idx=0;idx<length;idx++) readIDATChunk(length);
{ }
mFile->GetInHandle()->get(); else
} {
} for(unsigned idx=0;idx<length;idx++)
{
mFile->GetInHandle()->get();
}
}
unsigned crcCheck = *BinaryStream::getNextDWord(mFile->GetInHandle()); unsigned crcCheck = *BinaryStream::getNextDWord(mFile->GetInHandle());
mCurrentOffset += 4; mCurrentOffset += 4;
return !lastChunk; return !lastChunk;
} }
void PngReader::parseHeader() void PngReader::readIDATChunk(unsigned length)
{ {
mIHDRChunk.width = *BinaryStream::getNextDWord(mFile->GetInHandle()); if (mAwaitingDataBlock)
mIHDRChunk.height = *BinaryStream::getNextDWord(mFile->GetInHandle()); {
mIHDRChunk.bitDepth = mFile->GetInHandle()->get(); mImageData.setCompressionMethod(mFile->readNextByte());
mIHDRChunk.colorType = mFile->GetInHandle()->get(); mImageData.setExtraFlags(mFile->readNextByte());
mIHDRChunk.compressionMethod = mFile->GetInHandle()->get(); mImageData.setDataSize(length-2);
mIHDRChunk.filterMethod = mFile->GetInHandle()->get(); for(unsigned idx=0; idx<length-2; idx++)
mIHDRChunk.interlaceMethod = mFile->GetInHandle()->get(); {
mImageData.setByte(idx, mFile->readNextByte());
}
mAwaitingDataBlock = false;
}
else
{
for(unsigned idx=0; idx<length; idx++)
{
mImageData.setByte(idx, mFile->readNextByte());
}
}
}
mCurrentOffset += 13; void PngReader::readHeaderChunk()
{
mIHDRChunk.width = *BinaryStream::getNextDWord(mFile->GetInHandle());
mIHDRChunk.height = *BinaryStream::getNextDWord(mFile->GetInHandle());
mIHDRChunk.bitDepth = mFile->GetInHandle()->get();
mIHDRChunk.colorType = mFile->GetInHandle()->get();
mIHDRChunk.compressionMethod = mFile->GetInHandle()->get();
mIHDRChunk.filterMethod = mFile->GetInHandle()->get();
mIHDRChunk.interlaceMethod = mFile->GetInHandle()->get();
logHeader(); mCurrentOffset += 13;
logHeader();
} }
void PngReader::logHeader() void PngReader::logHeader()
{ {
std::stringstream sstr; std::cout << "IHDR\n" << mIHDRChunk.toString() << "*************\n";
sstr << "IHDR\n";
sstr << "width: " << mIHDRChunk.width << "\n";
sstr << "height: " << mIHDRChunk.height << "\n";
sstr << "bitDepth: " << (int)mIHDRChunk.bitDepth << "\n";
sstr << "colorType: " << (int)mIHDRChunk.colorType << "\n";
sstr << "compressionMethod: " << (int)mIHDRChunk.compressionMethod << "\n";
sstr << "filterMethod: " << (int)mIHDRChunk.filterMethod << "\n";
sstr << "interlaceMethod: " << (int)mIHDRChunk.interlaceMethod << "\n";
sstr << "************\n";
std::cout << sstr.str() << std::endl;
} }
std::unique_ptr<Image<unsigned char> > PngReader::read() std::unique_ptr<Image<unsigned char> > PngReader::read()
{ {
auto image = std::make_unique<Image<unsigned char> >(5, 5); auto image = std::make_unique<Image<unsigned char> >(5, 5);
mFile = std::make_unique<File>(mPath); mFile = std::make_unique<File>(mPath);
mFile->Open(true); mFile->Open(true);
if (!checkSignature()) if (!checkSignature())
{ {
std::cout << "Signature check failed" << std::endl; std::cout << "Signature check failed" << std::endl;
return image; return image;
} }
while(readChunk()) while(readChunk())
{ {
} }
mImageData.processData();
return std::move(image); return std::move(image);
} }

View file

@ -1,44 +1,42 @@
#pragma once #pragma once
#include <string>
#include <memory>
#include <vector>
#include "File.h" #include "File.h"
#include "Image.h" #include "Image.h"
#include "PngElements.h"
#include "ZlibData.h"
#include <string>
#include <memory>
#include <filesystem>
using Path = std::filesystem::path;
class PngReader class PngReader
{ {
public: public:
~PngReader(); ~PngReader();
void setPath(const std::string& path); void setPath(const Path& path);
std::unique_ptr<Image<unsigned char> > read(); std::unique_ptr<Image<unsigned char> > read();
private: private:
struct IHDRChunk
{
unsigned width{0};
unsigned height{0};
char bitDepth{0};
char colorType{0};
char compressionMethod{0};
char filterMethod{0};
char interlaceMethod{0};
};
bool readChunk(); bool readChunk();
void parseHeader();
void readHeaderChunk();
void readIDATChunk(unsigned length);
void logHeader(); void logHeader();
bool checkSignature(); bool checkSignature();
unsigned mCurrentOffset{0}; unsigned mCurrentOffset{0};
IHDRChunk mIHDRChunk; Png::IHDRChunk mIHDRChunk;
std::unique_ptr<Image<unsigned char> > mWorkingImage; std::unique_ptr<Image<unsigned char> > mWorkingImage;
std::unique_ptr<File> mFile; std::unique_ptr<File> mFile;
std::string mPath; Path mPath;
ZlibData mImageData;
bool mAwaitingDataBlock{true};
}; };

View file

@ -2,21 +2,11 @@
#include "Image.h" #include "Image.h"
#ifdef HAS_LIBPNG
#include <png.h>
#include "PngWriterLibPng.h"
#else
#include "PngWriterBasic.h"
#endif
#include <stdio.h> #include <stdio.h>
PngWriter::PngWriter() PngWriter::PngWriter()
{ {
#ifdef HAS_LIBPNG
mImpl = std::make_unique<PngWriterLibPng>();
#else
mImpl = std::make_unique<PngWriterBasic>();
#endif
} }
std::unique_ptr<PngWriter> PngWriter::Create() std::unique_ptr<PngWriter> PngWriter::Create()
@ -24,14 +14,14 @@ std::unique_ptr<PngWriter> PngWriter::Create()
return std::make_unique<PngWriter>(); return std::make_unique<PngWriter>();
} }
void PngWriter::SetPath(const std::string& path) void PngWriter::setPath(const Path& path)
{ {
mImpl->setPath(path); mPath = path;
} }
void PngWriter::Write(const std::unique_ptr<Image<unsigned char> >& image) const void PngWriter::write(const std::unique_ptr<Image<unsigned char> >& image) const
{ {
mImpl->write(image); //mImpl->write(image);
//auto fp = fopen(mPath.c_str(), "wb"); //auto fp = fopen(mPath.c_str(), "wb");
//auto png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); //auto png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);

View file

@ -1,11 +1,12 @@
#pragma once #pragma once
#include <memory>
#include <string>
#include "Image.h" #include "Image.h"
class PngWriterImpl; #include <memory>
#include <string>
#include <filesystem>
using Path = std::filesystem::path;
class PngWriter class PngWriter
{ {
@ -14,13 +15,12 @@ public:
static std::unique_ptr<PngWriter> Create(); static std::unique_ptr<PngWriter> Create();
void SetPath(const std::string& path); void setPath(const Path& path);
void Write(const std::unique_ptr<Image<unsigned char> >& image) const; void write(const std::unique_ptr<Image<unsigned char> >& image) const;
private: private:
std::unique_ptr<PngWriterImpl> mImpl; Path mPath;
}; };
using PngWriterPtr = std::unique_ptr<PngWriter>; using PngWriterPtr = std::unique_ptr<PngWriter>;

View file

@ -1,11 +0,0 @@
#include "PngWriterBasic.h"
void PngWriterBasic::setPath(const std::string& path)
{
}
void PngWriterBasic::write(const std::unique_ptr<Image<unsigned char> >& image) const
{
}

View file

@ -1,14 +0,0 @@
#pragma once
#include "PngWriterImpl.h"
class PngWriterBasic : public PngWriterImpl
{
public:
void setPath(const std::string& path) override;
void write(const std::unique_ptr<Image<unsigned char>>& image) const override;
private:
std::string mPath;
};

View file

@ -1,16 +0,0 @@
#pragma once
#include <string>
#include <memory>
#include "Image.h"
class PngWriterImpl
{
public:
virtual ~PngWriterImpl() = default;
virtual void setPath(const std::string& path) = 0;
virtual void write(const std::unique_ptr<Image<unsigned char> >& image) const = 0;
};

View file

@ -1,14 +1,46 @@
#include <iostream> #include <iostream>
#include "HuffmanEncoder.h" #include "HuffmanEncoder.h"
#include "RunLengthEncoder.h"
void test_run_length_encoder()
{
std::string test_data = "BCAAAADDDCCACACAC";
RunLengthEncoder encoder;
auto encoded = encoder.encode(test_data);
std::cout << "Encoded: " << encoded << std::endl;
auto decoded = encoder.decode(encoded);
std::cout << "Decoded: " << decoded << std::endl;
}
void test_huffman_encoder()
{
//std::string testData = "BCAADDDCCACACAC";
//std::vector<unsigned char> stream(testData.begin(), testData.end());
std::unordered_map<unsigned char, unsigned> counts;
counts['A'] = 1;
counts['B'] = 1;
counts['C'] = 1;
counts['D'] = 2;
counts['E'] = 3;
counts['F'] = 5;
counts['G'] = 5;
counts['H'] = 12;
HuffmanEncoder encoder;
encoder.encode(counts);
}
int main() int main()
{ {
std::string testData = "BCAADDDCCACACAC"; test_huffman_encoder();
std::vector<unsigned char> stream(testData.begin(), testData.end());
HuffmanEncoder encoder;
encoder.encode(stream);
//test_run_length_encoder();
return 0; return 0;
} }

View file

@ -5,7 +5,7 @@
int main() int main()
{ {
const auto path = "/home/jmsgrogan/code/MediaTool-build/bin/test.png"; const auto path = "/home/jmsgrogan/Downloads/test.png";
PngReader reader; PngReader reader;
reader.setPath(path); reader.setPath(path);

View file

@ -1,6 +1,7 @@
#include "Image.h" #include "Image.h"
#include "PngWriter.h" #include "PngWriter.h"
#include "PngWriterImpl.h"
#include "ImagePrimitives.h"
#include <iostream> #include <iostream>
@ -13,22 +14,13 @@ int main()
image->setNumChannels(numChannels); image->setNumChannels(numChannels);
std::vector<unsigned char> data(image->getBytesPerRow()*height, 0); std::vector<unsigned char> data(image->getBytesPerRow()*height, 0);
for(unsigned jdx=0;jdx<height;jdx++)
{ ImagePrimitives::drawAlternatingStrips(data, width,height, numChannels, image->getBytesPerRow());
const auto heightOffset = jdx*image->getBytesPerRow();
for(unsigned idx=0;idx<width*numChannels;idx+=numChannels)
{
const auto index = heightOffset + idx;
data[index] = (idx%2 == 0) ? 255*jdx/(height+1) : 0;
data[index+1] = 0;
data[index+2] = 0;
}
}
image->setData(data); image->setData(data);
PngWriter writer; PngWriter writer;
writer.SetPath("test.png"); writer.setPath("test.png");
writer.Write(image); writer.write(image);
return 0; return 0;
} }