Skip to content

PNG Decoder written in C++ that conforms to the standard specification and transforms PNG images into RGB pixels based image structures

Notifications You must be signed in to change notification settings

Vladislav0Art/png-decoder

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PNG Decoder

Demonstration:


Transmitting PNG images into JPG images:

In the video the png images are being transformed into jpg images by first being decoded into a pixel based image structure using the PNG decoder and then transformed into jpg images using external library.

Supported features:


The decoder conforms to the requirements of decoders mentioned in standard PNG specification supporting all the required chunks of the PNG format (i.e. IHDR Image header, PLTE Palette, IDAT Image data, and IEND Image trailer).

Supported images:

  • Grayscale images
  • Regular RGB images
  • Indexed images (i.e. with a fixed palette of colors)
  • Images containing alpha-channel (transparency)

Note: bit depth <= 8 supported. The entry point is Image ReadPng(std::string_view filename) function in png_decoder.h.

Project details:


The pipeline of decoding:

  1. Read signature bytes and validate it.
  2. Read chunks and validate its CRC until IEND chunk encountered.
  3. Save the information provided by IHDR and PLTE chunks for future decoding use.
  4. Concatenate the content of all IDAT chunks into a single byte vector (lets call it V).
  5. Once IEND chunk reached, decoding of V starts: deflate to decompress V into another byte vector D.
  6. Process D by scanlines, applying specified filters.
  7. In case of interlaced image use Adam7 algorithm to decode the image.

External libraries:

  1. zlib1g-dev (zlib) - deflate algorithm for decompressing the image data.
  2. Boost - CRC calculation.

Implementation details:

  1. Decoder is implemented as a class, receiving std::istream& (assuming binary mode) in it's constructor.
  2. Deflate logic is completely separated from the decoder. Since zlib1g-dev (zlib) is a C libraries, there is a RAII wrapper written around the library functionality (see Inflate).
  3. Error handling:
    1. CRC validation for ancillary chunks.
    2. Checking of EOF when reading from the input stream.
    3. Exceptions throwing for invalid png images.
  4. In case of bit depth being less than 8 bits bits reading functionality is used which takes a sequence of bytes and reads it bitwise.

Implementation:


Defiltering data scanlines:

There are 3 main classes that are responsible for decoding the image after deflate algorithm is used: ScanlineReader, Defilter, and PixelStrategy.

ScanlineReader applies defilters to the scanlines to remove additional encoding layer from the actual image data, after that depending on the pixel storing format (which is stored inside IHDR chunk) a concrete implementation of abstract PixelStrategy used to convert scanline bytes into image pixels.

Defilters are concrete implementations of abstact class Defilter that comform to Applicable Design Pattern: the caller (i.e. ScanlineReader) provides every scanline to the method Defilter::applicable which tells whether the currect defilter can be used in order to apply defiltering (it can be determined by a header stored in scanlines), in case of success the caller invokes Defilter::apply:

// ScanlineReader workflow:
for (const auto& defilter : m_defilters) {
    if (defilter->applicable(scanline)) {
        defilter->apply(scanline, m_previousScanline, bpp);
    }
}

Pixel recovery:

PNG format supports 3 main image formats: grayscale, RGB, and color pallete images, where the former two may also contain alpha-channel, which leads to having 5 completely different image formats.

In order to uniformly treat all the image formats the Strategy Design Pattern is applied: factory method PixelStrategy::create determines which image format is used in the current image and returns the concrete implementor of the image format, i.e. one of PixelGrayscaleStrategy, PixelRGBStrategy, PixelPaletteIndexStrategy, PixelGrayscaleAlphaStrategy, and PixelRGBAlphaStrategy:

std::unique_ptr<PixelStrategy> PixelStrategy::create(uint8_t colorType, uint8_t bitDepth, PLTE plte) {
    if (colorType == PIXEL_GRAYSCALE_COLOR_TYPE) {
        return std::make_unique<PixelGrayscaleStrategy>(bitDepth, std::move(plte));
    }
    else if (colorType == PIXEL_RGB_COLOR_TYPE) {
        return std::make_unique<PixelRGBStrategy>(bitDepth, std::move(plte));
    }
    else if (colorType == PIXEL_PALETTE_INDEX_COLOR_TYPE) {
        return std::make_unique<PixelPaletteIndexStrategy>(bitDepth, std::move(plte));
    }
    else if (colorType == PIXEL_GRAYSCALE_ALPHA_COLOR_TYPE) {
        return std::make_unique<PixelGrayscaleAlphaStrategy>(bitDepth, std::move(plte));
    }
    else if (colorType == PIXEL_RGB_ALPHA_COLOR_TYPE) {
        return std::make_unique<PixelRGBAlphaStrategy>(bitDepth, std::move(plte));
    }

    throw exceptions::InvalidColorTypeChunkException(
        PNG_DECODER_ERROR_MESSAGE("Unsupported color type in IHDR: " + std::to_string(colorType)));
}

About

PNG Decoder written in C++ that conforms to the standard specification and transforms PNG images into RGB pixels based image structures

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published