Initial fixed huffman coding for png.
This commit is contained in:
parent
e4f9393ee7
commit
7f5009fb5e
39 changed files with 1294 additions and 440 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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};
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -29,7 +29,7 @@ std::optional<unsigned char> InputBitStream::readNextByte()
|
|||
}
|
||||
}
|
||||
|
||||
void InputBitStream::writeByte(unsigned char data)
|
||||
void InputBitStream::writeByte(unsigned char data, bool checkOverflow )
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue