Circle buffer and png cleaning.
This commit is contained in:
parent
59cc910d58
commit
5400a232dd
13 changed files with 353 additions and 122 deletions
172
src/image/png/PngWriter.cpp
Normal file
172
src/image/png/PngWriter.cpp
Normal 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();
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue