预测编码像素图像格式
Prediction-Encoded Pixels image format

原始链接: https://github.com/ENDESGA/PEP

## PEP:一种新的像素艺术压缩格式 PEP 是一种实验性的图像压缩格式,专门为低色彩像素艺术(最多 256 色)设计,旨在实现比 GIF、PNG 和 QOI 更小的文件尺寸。它利用“基于部分匹配的预测,2 阶”压缩,优先考虑尺寸而非速度。 虽然比成熟的格式如 GIF/PNG/QOI 慢 2-10 倍,但 PEP 通常能实现比 GIF/PNG 更好的 20-50% 压缩率,并且在尺寸上显著优于 QOI。它的压缩效果介于 GIF 和 WEBP 之间。 PEP 输出一种对游戏开发有用的结构,提供对像素数据的直接访问。它需要现有的颜色字节数据,并提供压缩 (`pep_compress`)、解压缩 (`pep_decompress`)、序列化/反序列化以及文件 I/O (`pep_save`, `pep_load`) 函数。 该库正在积极寻求贡献,以成为像素艺术领域的领先格式。基准测试表明,在有限的颜色调色板下,尺寸缩减显著。

一种名为预测编码像素 (PEP) 的新图像格式在 Hacker News 上分享,引发了关于其潜在优势和劣势的讨论。虽然 PEP 在小尺寸、颜色有限的图像方面表现出色,并提供无损压缩,但对于较大的图像,它在文件大小方面并不总是优于成熟的有损格式,如 lossy-PNG、lossy-WEBP 或 mozcjpeg。 主要问题在于解压缩速度。初步测试表明,PEP 的速度可能比优化的 PNG 慢,但性能因图像而异。作者澄清 PEP 专为特定用例设计,并非通用替代品。 macOS 的 CLI 实现可在 GitHub 上找到 ([https://github.com/gingerbeardman/pepr](https://github.com/gingerbeardman/pepr)),并在 Twitter 上分享了基准测试结果。一位开发者已经将 PEP 支持集成到他们的像素艺术应用程序 Dottie 中,尽管存在局限性,但认为它值得探索。
相关文章

原文

pep_logo

This format is specifically designed to be for low-color pixel art (<=16 colors works best, up to 256 colors is supported).

It uses "Prediction by Partial Matching, Order-2" compression, which is able to compress packed-palette-indices smaller than GIF, PNG, and QOI, while sacrificing a bit of time. It's 2-10x slower than GIF/PNG/QOI (depending on the image), but often compresses the image 20-50% smaller than GIF/PNG (and multiple-times smaller than QOI).

If you care about compressed image size, this is for you. It's somewhere between GIF and WEBP (.webp can compress better at times, but it's painfully slow).


( this is currently in the EXPERIMENTAL phase! )


Use the C header like:

#define PEP_IMPLEMENTATION
#include "PEP.h"

tree1

112x96 : 4 colors

Format Size (bytes) Compression Ratio Compression (ms) Decompression (ms)
PEP 901 0.021x 0.383 0.412
PNG 984 0.023x
GIF 1,047 0.024x
QOI 2,425 0.056x 0.023 0.028
BMP 43,130 1.00x
font

192x144 : 2 colors

Format Size (bytes) Compression Ratio Compression (ms) Decompression (ms)
PNG 1,318 0.368x
PEP 1,357 0.378x 0.419 0.602
GIF 1,919 0.535x
BMP 3,586 1.00x
QOI 6,669 1.860x 0.071 0.078
nz_scene

640x200 : 251 colors

Format Size (bytes) Compression Ratio Compression (ms) Decompression (ms)
PEP 73,542 0.407x 25.652 32.121
PNG 84,657 0.469x
GIF 96,997 0.751x
BMP 129,078 1.00x
QOI 180,533 1.399x 1.03 1.004

PEP is designed for games too, so the compression outputs a structure that has useful elements. The PEP.data pointer ONLY contains the bytes for the pixels. This library doesn't have a BMP loader, so this is specifically designed for setups where the color bytes already exist. You just feed it into pep_compress() with the correct in_format of the bytes, and then you're able to use it however you like! Often you just use pep_save() after compressing, and then pep_load() + pep_decompress() to access the image data.

/*
pep_compress() parameters:
	uint32_t*  PIXEL_BYTES = raw RGBA/BGRA pixels
	uint16_t   WIDTH       = width of the image
	uint16_t   HEIGHT      = height of the image
	pep_format IN_FORMAT   = channel-order of PIXEL_BYTES, either pep_rgba or pep_bgra
	pep_format OUT_FORMAT  = channel-order of the new PEP, either pep_rgba or pep_bgra
returns:
	a pep struct
*/
pep p = pep_compress( PIXEL_BYTES, WIDTH, HEIGHT, IN_FORMAT, OUT_FORMAT );

/*
pep_decompress() parameters:
	pep*       IN_PEP     = pep struct-pointer to decompress
	pep_format OUT_FORMAT = channel-order of the new pixels, either pep_rgba or pep_bgra
returns:
	a uint32_t* with the uncompressed pixel data
*/
uint32_t* pixels = pep_decompress( IN_PEP, OUT_FORMAT );

/*
pep_free() parameters:
	pep* IN_PEP = pep struct-pointer to free
note:
	frees the internal bytes buffer and resets bytes_size to 0
*/
pep_free( IN_PEP );

/*
pep_serialize() parameters:
	pep*      IN_PEP   = pep struct-pointer to serialize
	uint32_t* OUT_SIZE = pointer to store the resulting byte array size
returns:
	a uint8_t* byte array containing the serialized pep data
note:
	caller must free() the returned byte array when done
*/
uint8_t* bytes = pep_serialize( IN_PEP, OUT_SIZE );

/*
pep_deserialize() parameters:
	uint8_t* IN_BYTES = byte array containing serialized pep data
returns:
	a pep struct reconstructed from the byte array
*/
pep p = pep_deserialize( IN_BYTES );

/*
pep_save() parameters:
	pep*  IN_PEP    = pep struct-pointer to save
	char* FILE_PATH = path to save the .pep file (e.g. "image.pep")
returns:
	uint8_t - 1 on success, 0 on failure
*/
uint8_t success = pep_save( IN_PEP, FILE_PATH );

/*
pep_load() parameters:
	char* FILE_PATH = path to the .pep file to load (e.g. "image.pep")
returns:
	a pep struct loaded from the file
note:
	returns an empty pep struct on failure
*/
pep p = pep_load( FILE_PATH );

Though a lot of this was bashed together with love and tweaked with brute-force, many underlying structures were inspired/referenced from these sources:

  1. Wikipedia: Prediction by Partial Matching.
  2. Cleary, J. G., & Witten, I. H. (1984): Data compression using adaptive coding and partial string matching. IEEE Transactions on Communications, 32(4), 396-402.
  3. Moffat, A. (1990): Implementing the PPM data compression scheme. IEEE Transactions on Communications, 38(11), 1917-1921.
  4. Cleary, J. G., Teahan, W. J., & Witten, I. H. (1995): Unbounded length contexts for PPM. Proceedings DCC-95, IEEE Computer Society Press, 52-61.
  5. Shkarin, D. (2002): PPM: One step to practicality. Proceedings of Data Compression Conference 2002, 202-211.

Please contribute to make PEP the best pixel art format there is!

-End :::.

联系我们 contact @ memedata.com