Initial fixed huffman coding for png.

This commit is contained in:
James Grogan 2022-11-28 10:16:04 +00:00
parent e4f9393ee7
commit 7f5009fb5e
39 changed files with 1294 additions and 440 deletions

View file

@ -26,7 +26,20 @@ unsigned char ByteUtils::getByteN(uint32_t input, unsigned n)
return (input << 8*n) >> 24;
}
unsigned char ByteUtils::getLowerNBits(unsigned char input, unsigned num)
unsigned char ByteUtils::mirror(unsigned char byte, unsigned length)
{
unsigned char ret{0};
for(unsigned idx=0; idx<length; idx++)
{
if (getBitN(byte, length - 1 - idx))
{
ret |= (0x01 << idx);
}
}
return ret;
}
unsigned char ByteUtils::getLowerNBits(uint32_t input, unsigned num)
{
switch (num)
{
@ -81,7 +94,7 @@ unsigned char ByteUtils::getMBitsAtN(unsigned char input, unsigned m, unsigned n
}
}
unsigned char ByteUtils::getBitN(unsigned char input, unsigned n)
bool ByteUtils::getBitN(uint32_t input, unsigned n)
{
return input & (1 << n);
}
@ -105,12 +118,34 @@ unsigned char ByteUtils::getFromString(const std::string& string)
return ret;
}
std::string ByteUtils::toString(unsigned char c)
std::string ByteUtils::toString(uint32_t input, unsigned length)
{
std::string ret;
for(unsigned idx=0; idx<8; idx++)
std::string working;
for(unsigned idx=0; idx<length; idx++)
{
ret += getBitN(c, 7 - idx) ? '1' : '0';
if (idx > 0 && idx % 8 == 0)
{
if (ret.empty())
{
ret = working;
}
else
{
ret = working + '-' + ret;
}
working = "";
}
working += getBitN(input, 7 - idx) ? '1' : '0';
}
if (length <= 8)
{
ret = working;
}
else if(!working.empty())
{
ret = working + '-' + ret;
}
return ret;
}

View file

@ -21,17 +21,19 @@ public:
static unsigned char getHigherNBits(unsigned char input, unsigned num);
static unsigned char getLowerNBits(unsigned char input, unsigned num);
static unsigned char getLowerNBits(uint32_t input, unsigned num);
static unsigned char getTwoBitsAtN(unsigned char input, unsigned n);
static unsigned char getMBitsAtN(unsigned char input, unsigned m, unsigned n);
static unsigned char getBitN(unsigned char input, unsigned n);
static bool getBitN(uint32_t input, unsigned n);
static unsigned char getFromString(const std::string& string);
static std::string toString(unsigned char c);
static std::string toString(uint32_t input, unsigned length = 8);
static unsigned char mirror(unsigned char byte, unsigned length=0);
static void ReverseBuffer(char* buffer, char* reverse, unsigned size, unsigned targetSize);

View file

@ -24,6 +24,7 @@ void BitStream::write(uint32_t data)
unsigned num_bytes = sizeof(uint32_t);
for(unsigned idx=0; idx<num_bytes;idx++)
{
std::cout << "Writing byte " << idx << " for multibyte" << std::endl;
writeByte(ByteUtils::getByteN(data, idx));
}
}
@ -46,18 +47,70 @@ unsigned BitStream::getCurrentBitOffset() const
return mBitOffset;
}
std::string BitStream::logLocation()
{
std::stringstream sstr;
sstr << "Byte offset " << mByteOffset<< " | Bit offset " << mBitOffset;
sstr << " | Working byte " << ByteUtils::toString(getCurrentByte()) << '\n';
return sstr.str();
}
std::string BitStream::logNextNBytes(unsigned n) const
{
std::stringstream sstr;
unsigned count{0};
for(auto byte : peekNextNBytes(n))
{
sstr << count << " | " << ByteUtils::toString(byte) + '\n';
sstr << mByteOffset + count << " | " << ByteUtils::toString(byte) + '\n';
count++;
}
return sstr.str();
}
void BitStream::writeNBits(uint32_t data, unsigned length)
{
const auto num_left = 8 - mBitOffset;
const int overshoot = length - num_left;
if (overshoot > 0)
{
unsigned char lower_bits = ByteUtils::getLowerNBits(data, num_left);
mCurrentByte |= lower_bits << mBitOffset;
writeByte(mCurrentByte, false);
auto num_bytes = overshoot / 8;
for (unsigned idx=0; idx< num_bytes; idx++)
{
mCurrentByte = ByteUtils::getMBitsAtN(data, overshoot, idx*8 + num_left);
writeByte(mCurrentByte, false);
}
if (const auto remainder = overshoot % 8; remainder > 0)
{
mCurrentByte = ByteUtils::getMBitsAtN(data, remainder, num_bytes*8 + num_left);
mBitOffset = remainder;
}
else
{
mCurrentByte = 0;
mBitOffset = 0;
}
}
else
{
mCurrentByte |= (static_cast<unsigned char>(data) << mBitOffset);
mBitOffset += length;
if (mBitOffset == 8)
{
writeByte(mCurrentByte, false);
mCurrentByte = 0;
mBitOffset = 0;
}
}
}
bool BitStream::readNextNBits(unsigned n, unsigned char& buffer)
{
if (mByteOffset < 0)

View file

@ -21,13 +21,17 @@ public:
std::string logNextNBytes(unsigned n) const;
std::string logLocation();
virtual std::vector<unsigned char> peekNextNBytes(unsigned n) const = 0;
virtual bool readNextNBits(unsigned n, unsigned char& buffer);
virtual std::optional<unsigned char> readNextByte() = 0;
virtual void writeByte(unsigned char data) = 0;
virtual void writeNBits(uint32_t data, unsigned length);
virtual void writeByte(unsigned char data, bool checkOverflow = true) = 0;
void write(uint32_t data);
@ -37,6 +41,11 @@ public:
void resetOffsets()
{
mEndByteOffset = mByteOffset;
mEndBitOffset = mBitOffset;
mEndByte = mCurrentByte;
mCurrentByte = 0;
mByteOffset = -1;
mBitOffset = 0;
}
@ -47,6 +56,20 @@ public:
mCurrentByte = 0;
}
void flushRemainingBits()
{
if (mBitOffset > 0)
{
writeByte(mCurrentByte, false);
mBitOffset = 0;
}
}
std::pair<unsigned char, unsigned> getRemainingBits() const
{
return {mEndByte, mEndBitOffset};
}
void setChecksumCalculator(AbstractChecksumCalculator* calc)
{
mChecksumCalculator = calc;
@ -60,8 +83,10 @@ public:
protected:
int mByteOffset{-1};
unsigned mBitOffset{0};
unsigned char mCurrentByte{0};
int mEndByteOffset{-1};
unsigned mEndBitOffset{0};
unsigned char mEndByte{0};
AbstractChecksumCalculator* mChecksumCalculator{nullptr};
};

View file

@ -1,5 +1,7 @@
#include "BufferBitStream.h"
#include "ByteUtils.h"
#include <iostream>
bool BufferBitStream::isFinished() const
@ -50,13 +52,27 @@ void BufferBitStream::setBuffer(const std::vector<unsigned char>& data)
mBuffer = data;
}
void BufferBitStream::writeByte(unsigned char data)
void BufferBitStream::writeByte(unsigned char data, bool checkOverflow)
{
unsigned char out_byte{0};
if (checkOverflow && mBitOffset > 0)
{
out_byte = ByteUtils::getLowerNBits(mCurrentByte, mBitOffset);
out_byte |= data << mBitOffset;
mCurrentByte = ByteUtils::getHigherNBits(data, mBitOffset);
}
else
{
out_byte = data;
}
if (mChecksumCalculator)
{
mChecksumCalculator->addValue(data);
mChecksumCalculator->addValue(out_byte);
}
mBuffer.push_back(data);
std::cout << "Writing byte " << ByteUtils::toString(out_byte) << " had bitoffset of " << mBitOffset << std::endl;
mBuffer.push_back(out_byte);
}

View file

@ -15,7 +15,7 @@ public:
void setBuffer(const std::vector<unsigned char>& data);
void writeByte(unsigned char data) override;
void writeByte(unsigned char data, bool checkOverflow = true) override;
void writeBytes(const std::vector<unsigned char> data) override
{

View file

@ -29,7 +29,7 @@ std::optional<unsigned char> InputBitStream::readNextByte()
}
}
void InputBitStream::writeByte(unsigned char data)
void InputBitStream::writeByte(unsigned char data, bool checkOverflow )
{
}

View file

@ -14,7 +14,7 @@ class InputBitStream : public BitStream
std::optional<unsigned char> readNextByte() override;
void writeByte(unsigned char data) override;
void writeByte(unsigned char data, bool checkOverflow = true) override;
void writeBytes(const std::vector<unsigned char> data) override
{

View file

@ -22,7 +22,7 @@ std::optional<unsigned char> OutputBitStream::readNextByte()
return std::nullopt;
}
void OutputBitStream::writeByte(unsigned char data)
void OutputBitStream::writeByte(unsigned char data, bool checkOverflow )
{
(*mStream) << data;
}

View file

@ -15,7 +15,7 @@ public:
std::optional<unsigned char> readNextByte() override;
void writeByte(unsigned char data) override;
void writeByte(unsigned char data, bool checkOverflow = true) override;
void writeBytes(const std::vector<unsigned char> data) override;