/*
* Tiny PNG Output (C++)
*
* Copyright (c) 2021 Project Nayuki
* https://www.nayuki.io/page/tiny-png-output
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program (see COPYING.txt and COPYING.LESSER.txt).
* If not, see .
*/
#pragma once
#include
#include
#include
/*
* Takes image pixel data in raw RGB8.8.8 format and writes a PNG file to a byte output stream.
*/
class TinyPngOut final {
/*---- Fields ----*/
// Immutable configuration
private: std::uint32_t width; // Measured in pixels
private: std::uint32_t height; // Measured in pixels
private: std::uint32_t lineSize; // Measured in bytes, equal to (width * 3 + 1)
// Running state
private: std::ostream &output;
private: std::uint32_t positionX; // Next byte index in current line
private: std::uint32_t positionY; // Line index of next byte
private: std::uint32_t uncompRemain; // Number of uncompressed bytes remaining
private: std::uint16_t deflateFilled; // Bytes filled in the current block (0 <= n < DEFLATE_MAX_BLOCK_SIZE)
private: std::uint32_t crc; // Primarily for IDAT chunk
private: std::uint32_t adler; // For DEFLATE data within IDAT
/*---- Public constructor and method ----*/
/*
* Creates a PNG writer with the given width and height (both non-zero) and byte output stream.
* TinyPngOut will leave the output stream still open once it finishes writing the PNG file data.
* Throws an exception if the dimensions exceed certain limits (e.g. w * h > 700 million).
*/
public: explicit TinyPngOut(std::uint32_t w, std::uint32_t h, std::ostream &out);
private: TinyPngOut(const TinyPngOut &other) = delete;
public: TinyPngOut(TinyPngOut &&other) = default;
/*
* Writes 'count' pixels from the given array to the output stream. This reads count*3
* bytes from the array. Pixels are presented from top to bottom, left to right, and with
* subpixels in RGB order. This object keeps track of how many pixels were written and
* various position variables. It is an error to write more pixels in total than width*height.
* Once exactly width*height pixels have been written with this TinyPngOut object,
* there are no more valid operations on the object and it should be discarded.
*/
public: void write(const std::uint8_t pixels[], std::size_t count);
/*---- Private checksum methods ----*/
// Reads the 'crc' field and updates its value based on the given array of new data.
private: void crc32(const std::uint8_t data[], std::size_t len);
// Reads the 'adler' field and updates its value based on the given array of new data.
private: void adler32(const std::uint8_t data[], std::size_t len);
/*---- Private utility members ----*/
private: template
void write(const std::uint8_t (&data)[N]) {
output.write(reinterpret_cast(data), sizeof(data));
}
private: static void putBigUint32(std::uint32_t val, std::uint8_t array[4]);
private: static constexpr std::uint16_t DEFLATE_MAX_BLOCK_SIZE = UINT16_C(65535);
};