{"id":21028270,"url":"https://github.com/vladislav0art/png-decoder","last_synced_at":"2025-03-13T19:14:05.902Z","repository":{"id":178067790,"uuid":"637034303","full_name":"Vladislav0Art/png-decoder","owner":"Vladislav0Art","description":"PNG Decoder written in C++ that conforms to the standard specification and transforms PNG images into RGB pixels based image structures","archived":false,"fork":false,"pushed_at":"2023-05-06T11:28:17.000Z","size":9180,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-20T14:50:45.795Z","etag":null,"topics":["boost","cmake","cpp20","decoder","png","png-decoder","png-images","zlib"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Vladislav0Art.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-05-06T09:54:08.000Z","updated_at":"2023-07-02T12:32:56.000Z","dependencies_parsed_at":null,"dependency_job_id":"2b416073-2b3e-4dd6-b7fe-8fef2777e9f7","html_url":"https://github.com/Vladislav0Art/png-decoder","commit_stats":null,"previous_names":["vladislav0art/png-decoder"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vladislav0Art%2Fpng-decoder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vladislav0Art%2Fpng-decoder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vladislav0Art%2Fpng-decoder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vladislav0Art%2Fpng-decoder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Vladislav0Art","download_url":"https://codeload.github.com/Vladislav0Art/png-decoder/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243467024,"owners_count":20295309,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["boost","cmake","cpp20","decoder","png","png-decoder","png-images","zlib"],"created_at":"2024-11-19T11:54:39.117Z","updated_at":"2025-03-13T19:14:05.878Z","avatar_url":"https://github.com/Vladislav0Art.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PNG Decoder\n\n\n## Demonstration:\n\n---\n\n### Transmitting PNG images into JPG images:\n\nIn 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.\n\n\u003cimg src=\"./assets/transform-png-to-jpg.gif\" style=\"width:900px;display:block;margin:auto;margin-top:20px;\"/\u003e\n\n## Supported features:\n\n---\n\nThe decoder conforms to the requirements of decoders mentioned in [standard PNG specification](http://www.libpng.org/pub/png/spec/1.2/PNG-Contents.html) supporting all the required **chunks** of the PNG format (i.e. `IHDR Image header`, `PLTE Palette`, `IDAT Image data`, and `IEND Image trailer`).\n\n### Supported images:\n\n- Grayscale images\n- Regular RGB images\n- Indexed images (i.e. with a fixed palette of colors)\n- Images containing alpha-channel (transparency)\n\n**Note:** `bit depth \u003c= 8` supported. The entry point is `Image ReadPng(std::string_view filename)` function in `png_decoder.h`.\n\n\n\n## Project details:\n\n---\n\n### The pipeline of decoding:\n\n1. Read signature bytes and validate it.\n1. Read chunks and validate its `CRC` until `IEND` chunk encountered.\n1. Save the information provided by `IHDR` and `PLTE` chunks for future decoding use.\n1. Concatenate the content of all `IDAT` chunks into a single byte vector (lets call it `V`).\n1. Once `IEND` chunk reached, decoding of `V` starts: deflate to decompress `V` into another byte vector `D`.\n1. Process `D` by **scanlines**, applying specified **filters**.\n1. In case of interlaced image use [**Adam7 algorithm**](http://www.libpng.org/pub/png/spec/1.2/PNG-DataRep.html#DR.Image-layout) to decode the image.\n\n### External libraries:\n\n1. **zlib1g-dev (zlib)** - deflate algorithm for decompressing the image data.\n1. **Boost** - CRC calculation.\n\n### Implementation details:\n\n1. Decoder is implemented as a class, receiving `std::istream\u0026` (assuming binary mode) in it's constructor.\n1. Deflate logic is completely separated from the decoder. Since **zlib1g-dev (zlib)** is a C libraries, there is a **RAII wrapper** written\naround the library functionality (see [`Inflate`](./src/inflate/inflate.h)).\n1. Error handling:\n    1. CRC validation for ancillary chunks.\n    1. Checking of EOF when reading from the input stream.\n    1. Exceptions throwing for invalid png images.\n1. 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.\n\n\n\n## Implementation:\n\n---\n\n### Defiltering data scanlines:\n\nThere are 3 main classes that are responsible for decoding the image after deflate algorithm is used: `ScanlineReader`, `Defilter`, and `PixelStrategy`.\n\n`ScanlineReader` applies [defilters]((http://www.libpng.org/pub/png/spec/1.2/PNG-Filters.html)) 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.\n\n[Defilters](./src/defilter/defilter.h) 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`:\n\n```cpp\n// ScanlineReader workflow:\nfor (const auto\u0026 defilter : m_defilters) {\n    if (defilter-\u003eapplicable(scanline)) {\n        defilter-\u003eapply(scanline, m_previousScanline, bpp);\n    }\n}\n```\n\n\n### Pixel recovery:\n\nPNG 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.\n\nIn order to uniformly treat all the image formats the **Strategy Design Pattern** is applied: factory method [`PixelStrategy::create`](./src/scanline-reader/strategy/strategy.h) 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`:\n\n```cpp\nstd::unique_ptr\u003cPixelStrategy\u003e PixelStrategy::create(uint8_t colorType, uint8_t bitDepth, PLTE plte) {\n    if (colorType == PIXEL_GRAYSCALE_COLOR_TYPE) {\n        return std::make_unique\u003cPixelGrayscaleStrategy\u003e(bitDepth, std::move(plte));\n    }\n    else if (colorType == PIXEL_RGB_COLOR_TYPE) {\n        return std::make_unique\u003cPixelRGBStrategy\u003e(bitDepth, std::move(plte));\n    }\n    else if (colorType == PIXEL_PALETTE_INDEX_COLOR_TYPE) {\n        return std::make_unique\u003cPixelPaletteIndexStrategy\u003e(bitDepth, std::move(plte));\n    }\n    else if (colorType == PIXEL_GRAYSCALE_ALPHA_COLOR_TYPE) {\n        return std::make_unique\u003cPixelGrayscaleAlphaStrategy\u003e(bitDepth, std::move(plte));\n    }\n    else if (colorType == PIXEL_RGB_ALPHA_COLOR_TYPE) {\n        return std::make_unique\u003cPixelRGBAlphaStrategy\u003e(bitDepth, std::move(plte));\n    }\n\n    throw exceptions::InvalidColorTypeChunkException(\n        PNG_DECODER_ERROR_MESSAGE(\"Unsupported color type in IHDR: \" + std::to_string(colorType)));\n}\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvladislav0art%2Fpng-decoder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvladislav0art%2Fpng-decoder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvladislav0art%2Fpng-decoder/lists"}