如何简单地编写未压缩的JPEG或PNG图像?

8

我有一个原始图像存储在内存中,以32位RGB值的数组形式组织。我想尽快将其写入图像文件中,以便释放内存。是否有一种方法可以按照以下方式编写未压缩的JPEG、PNG或TIFF图像?或者,我应该说,什么图像格式与这种写入原始像素数据的方法兼容?请注意,左上角像素位于像素数据的前4个字节。

void write_image(uint32_t *pixels, int width, int height) {
 FILE *file=fopen("file.jpg","wb");
 write_header (file, width, height);
 fwrite (pixels,1,width*height*4,file); // write raw pixel data
 write_end (file);
 fclose(file);
}

1
看看 BMP 格式。 - user3386109
4
JPEG和PNG是压缩格式,其中JPEG的压缩并不简单。BMP是一种常见且有充分文档支持的无压缩格式,尽管它可以使用RLE(行程长度编码)进行压缩。 - Weather Vane
1
如果可以是任何格式,那么为什么不像这里一样编写原始像素数据,而不是作为JPEG? - user253751
1
BMP应该可以很好地工作,未压缩的TIFF也可以,但是TIFF格式更复杂。我可能会选择像PPM或PAM这样更简单的格式。 - Harald K
你如何将RGB存储在32位中?每通道10.66位?通常,RGB每像素24位(即8位红色,8位绿色和8位蓝色),RGBA每像素32位。 - Mark Setchell
显示剩余2条评论
4个回答

3

你似乎有两个不同的问题或动机。

首先,你想要以某种未压缩的格式编写图像,以(可能)提高速度。PNG和JPEG是压缩格式,尽管你可以指示编码器(至少在某些PNG实现中)使用“无压缩”设置。

但是:a)很少有情况下这种“优化”会产生关键的差异,通常的压缩程序非常快。

b)即使使用一些compression_level=0设置进行编码,仍然会将图像编码为特定格式(通常是头部)。这导致了我们的第二个动机。

其次,看起来您想避免的不仅是压缩,而且是编码。也就是说,您想以未编码(“原始”)格式写入像素。在这种情况下,当然不能编写PNG或JPEG图像。您可以使用自己的或某些标准的原始格式,或准原始的BMP格式。但是您仍然需要注意像素在内存中的组织方式(例如每个通道一个字节?RGB?BGR?RGBA?),以及可能的其他问题(例如,BMP要求每行字节数是4的倍数)。

3

未压缩的JPEG和PNG格式并不简单,结果可能存在可移植性问题。你最简单的选择可能是使用TGA格式:

TGA格式设计用于存储栅格图像,可以快速加载到帧缓冲区中进行显示。它有一个非常简单的18字节头,然后是原始像素数据。它是可流式的,这意味着可以按生成的顺序写入图像数据,只要它是栅格化的即可。没有长度/偏移/CRC表的要求。最大的限制是样品必须以栅格化的BGR顺序排列,并具有第四个通道(通常为alpha,但可以是任何东西)。页眉中的宽度/高度字段必须为16位小端。TGA格式的支持范围不如GIF/JPEG/PNG广泛,但你应该能够找到一些能够渲染它的查看器。

对于BGR数据,页眉可能是(十六进制值): 0x00 0x00 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 (width%256) (width/256) (height%256) (height/256) 0x18 0x20

对于BGRA数据,页眉可能是: 0x00 0x00 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 (width%256) (width/256) (height%256) (height/256) 0x20 0x28

如果你的数据不是以BGR/BGRA顺序排列,而你不能或不想将其转换,我的第二个建议是使用TIFF格式:

TIFF格式设计重点在于存储栅格化文档扫描,并使用更复杂的TTLV式页眉。它不太可流式且需要偏移表,但你可以通过粗暴的预计算和将整个图像定义为单个条带来解决这个问题。一旦完成页眉,就可以按生成的栅格化RGB或RGBA顺序流式传输原始像素数据。TIFF还可以支持大端或小端和每样本最高16位。它通常是扫描仪的输出格式,因此查看器/编辑器支持相对较广泛。

前四个字节是魔数(字节顺序和TIFF文件版本),后跟图像文件目录(IFD)的4字节偏移量。通常,此偏移量只需位于文件中的前8个字节即可立即放置IFD。IFD是一个计数值(N),后跟N个12字节条目的表单,形式为标签、类型、计数和值/偏移量。其余的细节在此不便描述,但你可以阅读规范以获取更多信息。


1

1
我建议在调试时使用svpng。

https://github.com/miloyip/svpng

一种简约的C函数,用于将RGB / RGBA图像保存为未压缩的PNG格式。

特点

  • RGB或RGBA颜色格式
  • 单个功能
  • 32行ANSI C代码
  • 无依赖性
  • 可定制的输出流(默认为C文件描述符)

示例

void test_rgba(void) {
    unsigned char rgba[256 * 256 * 4], *p = rgba;
    unsigned x, y;
    FILE* fp = fopen("rgba.png", "wb");
    for (y = 0; y < 256; y++)
        for (x = 0; x < 256; x++) {
            *p++ = (unsigned char)x;                /* R */
            *p++ = (unsigned char)y;                /* G */
            *p++ = 128;                             /* B */
            *p++ = (unsigned char)((x + y) / 2);    /* A */
        }
    svpng(fp, 256, 256, rgba, 1);
    fclose(fp);
}

result


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接