ImCvt is a image format converter which includes lightweight encoders/decoders of several image formats:
format | file suffix | supported color type | convert from | convert to | source code |
---|---|---|---|---|---|
PNM | .pnm | ✅ | ✅ | 150 lines of C | |
PNG | .png | ☑️ | ☑️ | uPNG library | |
BMP | .bmp | ☑️ | ☑️ | 180 lines of C | |
QOI | .qoi | ✅ | ✅ | 240 lines of C | |
JPEG-LS | .jls | ❎ | ☑️ | 480 lines of C | |
H.265 | .h265 | ❎ | ☑️ | 1650 lines of C |
✅ = fully supported
☑️ = partially supported
❎ = unsupported
Illustration:
- PNM (Portable Any Map), PGM (Portable Gray Map), and PPM (Portable Pix Map) are simple uncompressed image formats which store raw pixels.
- PNG (Portable Network Graph) is the most popular lossless image compression format. This repo uses uPNG library to decode PNG.
- BMP (Bitmap Image File) is a popular uncompressed image formats which store raw pixels.
- QOI (Quite OK Image) is a simple, fast lossless RGB image compression format. This repo implements a simple QOI encoder/decoder in only 240 lines of C.
- JPEG-LS is a lossless/lossy image compression standard which can get better grayscale compression ratio compared to PNG and Lossless-WEBP. JPEG-LS uses the maximum difference between the pixels before and after compression (NEAR value) to control distortion, NEAR=0 is the lossless mode; NEAR>0 is the lossy mode. The specification of JPEG-LS is ITU-T T.87 [1]. Another reference JPEG-LS encoder/decoder implementation can be found in UBC's website. This repo implements a simpler JPEG-LS encoder in only 480 lines of C.
- H.265/HEVC is a video coding standard. This repo implements a lightweight grayscale 8-bit H.265/HEVC intra-frame image compressor in only 1650 lines of C, which may be the simplest H.265 implementation.
If you installed MinGW, run following compiling command in CMD:
gcc src\*.c src\HEVCe\HEVCe.c src\uPNG\uPNG.c -static -O3 -Wall -Wno-array-bounds -o ImCvt.exe
which will get executable file ImCvt.exe
Also, you can use MSVC to compile. If you added MSVC (cl.exe) to your environment, run following compiling command in CMD:
cl src\*.c src\HEVCe\HEVCe.c src\uPNG\uPNG.c /MT /Ox /FeImCvt.exe
which will get executable file ImCvt.exe
gcc src/*.c src/HEVCe/HEVCe.c src/uPNG/uPNG.c -static -O3 -Wall -Wno-array-bounds -o ImCvt
which will get Linux binary file ImCvt
Run the program without any parameters to display usage:
> .\ImCvt.exe
|------------------------------------------------------------------------------------|
| ImageConverter (v0.5) by https://github.com/WangXuan95/ |
|------------------------------------------------------------------------------------|
| Usage: |
| ImCvt [-switches] <in1> -o <out1> [<in2> -o <out2] ... |
| |
| Where <in> and <out> can be: |
| .pnm (Portable Any Map) : gray 8-bit or RGB 24-bit |
| .pgm (Portable Gray Map) : gray 8-bit |
| .ppm (Portable Pix Map) : RGB 24-bit |
| .png (Portable Network Graphics) : gray 8-bit or RGB 24-bit |
| .bmp (Bitmap Image File) : gray 8-bit or RGB 24-bit |
| .qoi (Quite OK Image) : RGB 24-bit |
| .jls (JPEG-LS Image) : gray 8-bit or RGB 24-bit, can be <out> only! |
| .h265 (H.265/HEVC Image) : gray 8-bit , can be <out> only! |
| |
| switches: -f : force overwrite of output file |
| -0, -1, -2, -3, -4 : JPEG-LS near value or H.265 (qp-4)/6 value |
|------------------------------------------------------------------------------------|
convert a PNG to a PNM:
ImCvt.exe image\1.png -o image\1.pnm
convert a PNM to a QOI:
ImCvt.exe image\1.pnm -o image\1.qoi
convert a QOI to a BMP:
ImCvt.exe image\1.qoi -o image\1.bmp
convert a BMP to a JPEG-LS, with near=1 (lossy):
ImCvt.exe image\1.bmp -o image\1.jls -1
convert a BMP to a H.265 image file, with (qp-4)/6=2 (lossy):
ImCvt.exe image\1.bmp -o image\1.h265
convert multiple files by a single command:
ImCvt.exe -f image\1.png -o image\1.qoi image\2.png -o image\2.jls image\3.png -o image\3.bmp
This repo only offers JPEG-LS compressor instead of decompressor. We show two ways to decompress a .jls file.
The most convenient way is to use this website to view .jls image online (but it may not work sometimes).
Another way is to use python pillow
and pillow_jpls
library [4]. You should firstly install them use pip
:
python -m pip install pillow pillow_jpls
Then use the following python script to decompress a .jls file to a .png file:
from PIL import Image
import pillow_jpls
Image.open("2.jls").save("2d.png") # decompress 2.jls to 2d.png
This repo implements a lightweight grayscale 8-bit H.265/HEVC intra-frame image compressor in only 1650 lines of C, which may be the simplest H.265 implementation.
- This code (HEVCe.c) is highly portable:
- Only use two data types:
unsigned char
andint
; - Do not include any headers;
- Do not use dynamic memory.
- Only use two data types:
- Supported H.265/HEVC features:
- Quality parameter can be 0~4, corresponds to Quantize Parameter (QP) = 4, 10, 16, 22, 28.
- CTU : 32x32
- CU : 32x32, 16x16, 8x8
- TU : 32x32, 16x16, 8x8, 4x4
- The maximum depth of CU splitting into TUs is 1 (each CU is treated as a TU, or divided into 4 small TUs, while the small TUs are not divided into smaller TUs).
- part_mode: The 8x8 CU is treated as a PU (
PART_2Nx2N
), or divided into 4 PUs (PART_NxN
) - Supports all 35 prediction modes
- Simplified RDOQ (Rate Distortion Optimized Quantize)
For more knowledge about H.265, see H.265/HEVC 帧内编码详解:CU层次结构、预测、变换、量化、编码 [10]
The source code is in src/HEVCe/ , includes two files:
The users can call the HEVCImageEncoder
function in HEVCe.h :
int HEVCImageEncoder ( // return the length of encoded stream (unit: bytes)
unsigned char *pbuffer, // encoded stream will be stored here
const unsigned char *img, // The original grayscale pixels of the image need to be input here, with each pixel occupying 8-bit (i.e. an unsigned char), in the order of left to right and top to bottom.
unsigned char *img_rcon, // The pixel buffer of the reconstructed image, with each pixel occupying 8-bit (i.e. an unsigned char), in the order of left to right and top to bottom. Note: Even if you don't care about the reconstructed image, you must pass in an array space of the same size as the input image here, otherwise the image encoder will not work.
int *ysz, // Enter the height of the image here. For values that are not multiples of 32, they will be supplemented with multiples of 32, so this is a pointer and the function will modify the value internally.
int *xsz, // Enter the width of the image here. For values that are not multiples of 32, they will be supplemented with multiples of 32, so this is a pointer and the function will modify the value internally.
const int qpd6 // Quality parameter, can be 0~4, corresponds to Quantize Parameter (QP) = 4, 10, 16, 22, 28.
);
This repo only offers H.265/HEVC compressor instead of decompressor. You can use File Viewer Plus or Elecard HEVC Analyzer to view the compressed .h265 image file.
[1] Official website of QOI : https://qoiformat.org/
[2] ITU-T T.87 : JPEG-LS baseline specification : https://www.itu.int/rec/T-REC-T.87/en
[3] UBC's JPEG-LS baseline Public Domain Code : http://www.stat.columbia.edu/~jakulin/jpeg-ls/mirror.htm
[4] pillow-jpls library for Python : https://pypi.org/project/pillow-jpls
[5] PNM Image File Specification : https://netpbm.sourceforge.net/doc/pnm.html
[6] uPNG: a simple PNG decoder: https://github.com/elanthis/upng
[7] FPGA-based Verilog QOI compressor/decompressor: https://github.com/WangXuan95/FPGA-QOI
[8] FPGA-based Verilog JPEG-LS encoder (basic version which support 8-bit gray lossless and lossy compression) : https://github.com/WangXuan95/FPGA-JPEG-LS-encoder
[9] FPGA-based Verilog JPEG-LS encoder (ultra high performance version which support 8-bit gray lossless compression) : https://github.com/WangXuan95/UH-JLS
[10] H.265/HEVC 帧内编码详解:CU层次结构、预测、变换、量化、编码:https://zhuanlan.zhihu.com/p/607679114
[11] The H.265/HEVC reference software HM: https://github.com/listenlink/HM