* Support image width less than 4000, height unlimited.
* **Supports all color types** : Grayscale, Grayscale+A, RGB, Indexed RGB, and RGB+A.
* Only 8bit depth is supported (actually most png images are 8bit depth).
| ![diagram](./figures/diagram.png) |
| :---------------------------------------: |
| **Figure1** : Hard-PNG schematic diagram. |
# Background
**png** is the second most common compressed image format after **jpg** . png supports transparency channel (A channel), lossless compression, and indexed RGB (palette-based lossy compression). In colorful digital photos, png can only get 1 to 4 times the lossless compression ratio. In synthetic images (such as graphic design), png can achieve more than 10 times the lossless compression ratio.
png image files have the **.png** suffix name. Take [SIM/test_image/img01.png](./SIM/test_image) in this repository as an example, it contains 98 bytes, which are called png stream. We can use [WinHex software](http://www.x-ways.net/winhex/) to view these bytes:
After the png stream is decompressed, the original pixels will be generated. This is a small image with only 4 columns and 2 rows, and a total of 8 pixels. The hexadecimal representation of these pixels is as follows. where R, G, B, A represent the red, green, blue and transparent channels of the pixel, respectively.
[hard_png.sv](./RTL) in [RTL](./RTL) directory is a module that can input png stream and output decompressed original pixels. Its interface is shown in **Figure2**.
| ![接口图](./figures/interface.png) |
| :----------------------------------: |
| **Figure2** : interface of hard_png. |
## Input png stream
It's easy to use hard_png module. Take the image [SIM/test_image/img01.png](./SIM/test_image) as an example again, such as **Figure3**, before inputting the png stream, a high level pulse must be generated on `istart` (with a width of at least one clock cycle), and then input the png stream through `ivalid` and `ibyte` signals (the png stream of this image has 98 bytes, these 98 bytes must be input to hard_png one by one), among which `ivalid` and `iready` constitutes handshake signals: `ivalid=1` indicates that the user wants to send a byte to hard_png. `iready=1` indicates that hard_png is ready to accept a byte. Only when `ivalid` and `iready` both = 1 at the same time, the handshake is successful, and `ibyte` is successfully input into hard_png.
| ![输入时序图](./figures/wave1.png) |
| :---------------------------------------: |
| **Figure3** : input waveform of hard_png. |
When it finish to input one png image, the next png image can be input immediately or later (that is, pulse the `istart` again, and then input the next png stream).
## Output image information and pixels
At the same time of inputting the png stream, the decompression result of this image (including the basic information of this image and the original pixels) will be output from the module, as shown in **Figure4**, first of all, `ostart` signal will appear A high-level pulse for one cycle, and `colortype`, `width`, and `height` will be valid simutinously, where:
-`width`, `height` are the width and height of the image.
-`colortype` is the color type of the png image, with the meaning in the table below.
Then, `ovalid=1` means that there is a pixel output in this cycle, meanwhile, the R, G, B, A channels of this pixel will appear on `opixelr`, `opixelg`, `opixelb`, and `opixela` signals respectively.
| ![输出时序图](./figures/wave2.png) |
| :----------------------------------------: |
| **Figure4** : output waveform of hard_png. |
# RTL Simulation
Simulation related files are in the [SIM](./SIM) folder, where:
- 14 png image files of different sizes and different color types are provided in [test_image](./SIM/test_image) folder.
- tb_hard_png.sv is the testbench code that compresses these images in sequence and writes the result (raw pixels) to txt files.
- tb_hard_png_run_iverilog.bat is the command script to run iverilog simulation.
- validation.py (Python code) compares the simulation output with the result of the software png decoding to verify the correctness.
Before using iverilog for simulation, you need to install iverilog , see: [iverilog_usage](https://github.com/WangXuan95/WangXuan95/blob/main/iverilog_usage/iverilog_usage.md)
Then double-click tb_hard_png_run_iverilog.bat to run the simulation, which will run for about 30 minutes (it can be forced to close halfway, but the generated simulation waveform is incomplete).
After the simulation runs, you can open the generated dump.vcd file to view the waveform.
In addition, each png image will generate a corresponding .txt file, which contains the decoding result. For example, img01.png generates out01.txt, which contains the decoded 8 pixel values:
In order to verify that the decompression results are correct, I provide a Python program [validation.py](./SIM), which can decompress the .png file and compares it with each pixel in the .txt file generated by the simulation. If the comparison results are the same, the validation passed.
In order to run validation.py , you need to install Python3 and its [numpy](https://pypi.org/project/numpy/) and [PIL](https://pypi.org/project/Pillow/) libraries.
The meaning of this command is: Compare each pixel in [out03.txt]() to see if it matches [test_image/img03.png](). The print is as follows (indicating that the verification passed):
I deploy hard_png on Altera Cyclone IV EP4CE40F23C6 and get clock frequency = 50MHz (just reach timing closure). According to the number of clock cycles consumed by each image during simulation, we can calculate the performance as shown in the following table.
| png file | color type | image size | pixel count | png stream size | cycle count | time |