See More

#include "ImageEncoder.hpp" #include "main.hpp" #include "Logger.hpp" #include "utils.hpp" #include "Huffman.hpp" #include /** * @brief dc::Encoder::Encoder * * @param source_file * Path to a raw image file. * @param dest_file * Path to the destination file (path needs to exist, file will be overwritten). * @param width * @param height * @param use_rle * @param quant_m */ dc::ImageEncoder::ImageEncoder(const std::string &source_file, const std::string &dest_file, const uint16_t &width, const uint16_t &height, const bool &use_rle, MatrixReader<> &quant_m) : ImageProcessor(source_file, dest_file, width, height, use_rle, quant_m) { assert(this->width % dc::BlockSize == 0); assert(this->height % dc::BlockSize == 0); assert(this->reader->get_size() == size_t(this->width * this->height)); } /** * @brief Default dtor */ dc::ImageEncoder::~ImageEncoder(void) { // Empty } /** * @brief Process the raw image for encoding. * * 1. Create Blocks * 2. Determine header length * 3. Estimate final stream length (header + size for each Block) * 4. Write header (encoding settings) * For each Block: * 5. Perform DCT and divide with the quant_matrix * 6. Create the RLE sequence * 7. Stream the results to the byte stream, ignoring trailing zeroes if use_rle == true * * @return Returns true on success. */ bool dc::ImageEncoder::process(void) { bool success = true; util::Logger::WriteLn("[ImageEncoder] Processing image..."); // Pre-process image success = ImageProcessor::process(this->reader->get_buffer()); // Write setting header util::Logger::WriteLn("[ImageEncoder] Creating settings header..."); size_t output_length; const uint8_t quant_bit_len = this->quant_m.getMaxBitLength(); output_length = dc::ImageProcessor::RLE_BITS // Bit for RLE setting + dc::ImageProcessor::DIM_BITS * 2u // 2 times bits for image dimension + dc::MatrixReader<>::SIZE_LEN_BITS // Bits to signify size of quant_matrix contents + (quant_bit_len // Size of quantmatrix * dc::BlockSize * dc::BlockSize); util::Logger::WriteLn(std::string_format("[ImageEncoder] Settings header length: %.1f bytes.", float(output_length) / 8.f)); output_length += this->blocks->size() * this->blocks->front()->streamSize(); #ifndef ENABLE_HUFFMAN output_length++; // Add one bit to signal Huffman is not enabled. #endif output_length = util::round_to_byte(output_length); // Padding to next whole byte this->writer = util::allocVar<:bitstreamwriter>(output_length); #ifndef ENABLE_HUFFMAN this->writer->put_bit(0); // '0': No Huffman sequence present. #endif // Write matrix data first this->quant_m.write(*this->writer); // Write other settings this->writer->put(dc::ImageProcessor::RLE_BITS, uint32_t(this->use_rle)); this->writer->put(dc::ImageProcessor::DIM_BITS, this->width); this->writer->put(dc::ImageProcessor::DIM_BITS, this->height); const size_t block_count = this->blocks->size(); size_t blockid = 0u; util::Logger::WriteLn("[ImageEncoder] Processing Blocks..."); util::Logger::WriteProgress(0, block_count); #ifdef LOG_LOCAL for (Block<>* b : *this->blocks) { util::Logger::WriteLn(std::string_format("Block % 3d:", blockid++)); b->printExpanded(); util::Logger::WriteLn("", false); util::Logger::WriteLn("After DCT and quantization:"); b->processDCTDivQ(this->quant_m.getData()); b->printExpanded(); util::Logger::WriteLn("", false); b->printZigzag(); b->createRLESequence(); b->printRLE(); b->streamEncoded(*this->writer, this->use_rle); util::Logger::WriteLn("", false); } #else #ifdef ENABLE_OPENMP #pragma omp parallel for shared(blockid) schedule(dynamic) for (auto it = this->blocks->begin(); it < this->blocks->end(); it++) { Block<> *b = *it; b->processDCTDivQ(this->quant_m.getData()); b->createRLESequence(); #pragma omp atomic ++blockid; #pragma omp critical util::Logger::WriteProgress(blockid, block_count); } // Writing results must happen in sequence for (Block<>* b : *this->blocks) { b->streamEncoded(*this->writer, this->use_rle); } #else for (Block<>* b : *this->blocks) { b->processDCTDivQ(this->quant_m.getData()); b->createRLESequence(); b->streamEncoded(*this->writer, this->use_rle); util::Logger::WriteProgress(++blockid, block_count); } #endif #endif util::Logger::WriteLn("", false); #ifdef ENABLE_HUFFMAN util::BitStreamReader hm_input(this->writer->get_buffer(), this->writer->get_last_byte_position()); algo::Huffman<> hm; util::BitStreamWriter *hm_output = hm.encode(hm_input); #ifdef LOG_LOCAL util::Logger::WriteLn("\n", false); hm.printDict(); // util::Logger::WriteLn("\n", false); // hm.printTree(); util::Logger::WriteLn("\n", false); #endif if (hm_output != nullptr) { util::deallocVar(this->writer); this->writer = hm_output; } util::Logger::WriteLn("", false); #endif return success; } /** * @brief Save the resulting stream to the destination. */ void dc::ImageEncoder::saveResult(void) const { ImageProcessor::saveResult(true); }