Circle buffer and png cleaning.

This commit is contained in:
James Grogan 2022-11-24 09:05:39 +00:00
parent 59cc910d58
commit 5400a232dd
13 changed files with 353 additions and 122 deletions

172
src/image/png/PngWriter.cpp Normal file
View file

@ -0,0 +1,172 @@
#include "PngWriter.h"
#include "Image.h"
#include "File.h"
#include "BufferBitStream.h"
#include "OutputBitStream.h"
#include "ImageBitStream.h"
#include "Lz77Encoder.h"
#include "ZlibEncoder.h"
#include "CyclicRedundancyChecker.h"
#include "ByteUtils.h"
#include <stdio.h>
PngWriter::PngWriter()
{
}
PngWriter::~PngWriter()
{
}
std::unique_ptr<PngWriter> PngWriter::Create()
{
return std::make_unique<PngWriter>();
}
void PngWriter::setPath(const Path& path)
{
mPath = path;
}
void PngWriter::setPngInfo(const PngInfo& info)
{
mPngInfoUserSet = true;
mPngInfo = info;
}
void PngWriter::writeSignature()
{
mOutStream->writeByte(mPngHeader.getHighBitCheck());
mOutStream->writeBytes(StringUtils::toBytes(mPngHeader.getFileName()));
mOutStream->writeBytes(mPngHeader.getSignature());
}
void PngWriter::writeHeader()
{
writeSignature();
if (!mPngInfoUserSet)
{
if (mWorkingImage->getNumChannels() == 1)
{
mPngInfo.mColorType = PngInfo::ColorType::GREYSCALE;
}
else if (mWorkingImage->getNumChannels() == 2)
{
mPngInfo.mColorType = PngInfo::ColorType::GREYSCALE_ALPHA;
}
else if (mWorkingImage->getNumChannels() == 3)
{
mPngInfo.mColorType = PngInfo::ColorType::RGB;
}
else if (mWorkingImage->getNumChannels() == 4)
{
mPngInfo.mColorType = PngInfo::ColorType::RGB_ALPHA;
}
}
mPngHeader.setPngInfo(mPngInfo);
mPngHeader.setImageData(mWorkingImage->getWidth(), mWorkingImage->getHeight(), mWorkingImage->getBitDepth());
auto length = mPngHeader.getLength();
mOutStream->write(length);
mOutStream->writeBytes(StringUtils::toBytes(mPngHeader.getChunkName()));
mPngHeader.updateData();
mOutStream->writeBytes(mPngHeader.getData());
auto crc = mPngHeader.getCrc();
mOutStream->write(crc);
}
void PngWriter::writeEndChunk()
{
unsigned length{0};
mOutStream->write(length);
mOutStream->writeBytes(StringUtils::toBytes("IEND"));
CyclicRedundancyChecker crc_check;
auto crc = crc_check.doCrc(nullptr, 0);
mOutStream->write(crc);
}
void PngWriter::writeDataChunks(const BufferBitStream& buffer)
{
auto num_bytes = buffer.getBuffer().size();
auto max_bytes{32000};
std::vector<unsigned char> crc_buffer(max_bytes, 0);
unsigned num_dat_chunks = num_bytes/max_bytes + 1;
unsigned offset = 0;
for(unsigned idx=0;idx<num_dat_chunks;idx++)
{
auto length = max_bytes;
if (idx == num_dat_chunks - 1)
{
length = num_bytes - num_dat_chunks*num_bytes;
}
mOutStream->write(length);
mOutStream->writeBytes(StringUtils::toBytes("IDAT"));
for(unsigned jdx=0; jdx<length; jdx++)
{
auto val = buffer.getBuffer()[idx*max_bytes + jdx];
crc_buffer[jdx] = val;
mOutStream->writeByte(val);
}
CyclicRedundancyChecker crc_check;
auto crc = crc_check.doCrc(crc_buffer.data(), crc_buffer.size());
mOutStream->write(crc);
}
}
void PngWriter::write(const std::unique_ptr<Image<unsigned char> >& image)
{
if (!mPath.empty())
{
mWorkingFile = std::make_unique<File>(mPath);
mWorkingFile->SetAccessMode(File::AccessMode::Write);
mWorkingFile->Open(true);
mOutStream = std::make_unique<OutputBitStream>(mWorkingFile->GetOutHandle());
}
else
{
mOutStream = std::make_unique<BufferBitStream>();
}
mWorkingImage = image.get();
mInStream = std::make_unique<ImageBitStream>(image.get());
writeHeader();
BufferBitStream lz77_out_stream;
Lz77Encoder lz77_encoder(mInStream.get(), &lz77_out_stream);
lz77_encoder.encode();
lz77_out_stream.resetOffsets();
BufferBitStream zlib_out_stream;
ZlibEncoder zlib_encoder(&lz77_out_stream, &zlib_out_stream);
zlib_encoder.encode();
zlib_out_stream.resetOffsets();
writeDataChunks(zlib_out_stream);
writeEndChunk();
if (mWorkingFile)
{
mWorkingFile->Close();
}
}