#include "PngWriter.h" #include "Image.h" #include "File.h" #include "BufferBitStream.h" #include "OutputBitStream.h" #include "ImageBitStream.h" #include "StringUtils.h" #include "PngFilter.h" #include "Lz77Encoder.h" #include "ZlibEncoder.h" #include "HuffmanEncoder.h" #include "CyclicRedundancyChecker.h" #include "ByteUtils.h" #include PngWriter::PngWriter() { } PngWriter::~PngWriter() { } std::unique_ptr PngWriter::Create() { return std::make_unique(); } void PngWriter::setCompressionMethod(Deflate::CompressionMethod method) { mCompressionMethod = method; } 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(); //std::cout << mPngHeader.toString() << "*********" << std::endl; mOutStream->write(crc); } void PngWriter::writeEndChunk() { //std::cout << "Start writing end chunk" << std::endl; unsigned length{0}; mOutStream->write(length); mOutStream->writeBytes(StringUtils::toBytes("IEND")); std::vector char_data = StringUtils::toBytes("IEND"); CyclicRedundancyChecker crc_check; for (auto c : char_data) { crc_check.addValue(c); } auto crc = crc_check.getChecksum(); mOutStream->write(crc); //std::cout << "Writing end chunk" << std::endl; } void PngWriter::writeDataChunks(const BufferBitStream& buffer) { auto num_bytes = buffer.getBuffer().size(); auto max_bytes{32000}; auto num_dat_chunks = num_bytes/max_bytes + 1; unsigned offset = 0; for(std::size_t idx=0;idxwrite(num_bytes); std::vector char_data = StringUtils::toBytes("IDAT"); mOutStream->writeBytes(char_data); CyclicRedundancyChecker crc_check; for (auto c : char_data) { crc_check.addValue(c); } for(unsigned jdx=0; jdxwriteByte(val); crc_check.addValue(val); } auto crc = crc_check.getChecksum(); //std::cout << "Writing idat crc" << crc << std::endl; mOutStream->write(crc); //std::cout << "Finished Writing idat crc" << crc << std::endl; } } void PngWriter::write(const std::unique_ptr >& image) { if (!mPath.empty()) { mWorkingFile = std::make_unique(mPath); mWorkingFile->open(File::AccessMode::Write); mOutStream = std::make_unique(mWorkingFile->getOutHandle()); } else { mOutStream = std::make_unique(); } mWorkingImage = image.get(); auto image_bit_stream = std::make_unique(image.get()); auto raw_image_stream = image_bit_stream.get(); mInStream = std::move(image_bit_stream); writeHeader(); auto filter_out_stream = std::make_unique(); PngFilter filter(raw_image_stream, filter_out_stream.get()); filter.encode(); filter_out_stream->resetOffsets(); std::unique_ptr lz77_out_stream; if (mCompressionMethod == Deflate::CompressionMethod::NONE) { lz77_out_stream = std::move(filter_out_stream); } else { lz77_out_stream = std::make_unique(); Lz77Encoder lz77_encoder(filter_out_stream.get(), lz77_out_stream.get()); if (mCompressionMethod == Deflate::CompressionMethod::FIXED_HUFFMAN) { auto huffman_encoder = std::make_unique(); huffman_encoder->setUseFixedCode(true); lz77_encoder.setPrefixCodeGenerator(std::move(huffman_encoder)); } lz77_encoder.encode(); lz77_out_stream->resetOffsets(); } BufferBitStream zlib_out_stream; ZlibEncoder zlib_encoder(lz77_out_stream.get(), &zlib_out_stream); zlib_encoder.setDeflateCompressionMethod(mCompressionMethod); zlib_encoder.encode(); zlib_out_stream.resetOffsets(); writeDataChunks(zlib_out_stream); writeEndChunk(); if (mWorkingFile) { mWorkingFile->close(); } }