在C(libpng)中读取和写入png文件而不更改文件大小

时间:2017-05-29 06:18:07

标签: image-processing png libpng deflate

我想阅读 png 文件,请参阅图像数据并重新编写,文件大小没有任何变化。基于 libpng 文档,png是无损的,并使用 deflate lz77 进行压缩。 libpng中有一个示例项目声称可以读取和写入图像而不会丢失,它在像素值中是正确的,但是更改文件的结构(例如IDAT的数量,可选的块等)png文件大小。

我的明确问题: 如何从压缩流(libpng中的Zstream)中提取编码参数(例如deflate params或lz77 params)并使用此参数对原始图像进行编码以创建与输入文件相同的图像文件而不做任何更改?

这是我的代码。我尝试在 info_ptr 中保留params来写图像,但不起作用。怎么做?

int main(int argc, char *argv[])
{
inname = argv[1];
outname = argv[2];

png_structrp read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
png_infop info_ptr = png_create_info_struct(read_ptr);



if (!info_ptr)
{
    png_destroy_read_struct(&read_ptr, (png_infopp)NULL, (png_infopp)NULL);
}

png_FILE_p imageFile, imageFile2, imageFileW;
    imageFile=fopen(inname, "rb");  imageFileW = fopen(outname, "wb"); imageFile2 = fopen(inname, "rb");

int fileSize=fsize(imageFile2);
unsigned char* bufImWrite = malloc(sizeof(char)*fileSize);
fread(bufImWrite, 1, fileSize, imageFile2);

png_init_io(read_ptr, imageFile);

png_read_info(read_ptr, info_ptr);


png_uint_32 height;
height = info_ptr->height;


png_bytep * row_pointers;

row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height);
for (int y = 0; y < height; y++)
    row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(read_ptr, info_ptr));


png_read_image(read_ptr, row_pointers);


png_read_end(read_ptr, info_ptr);


png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);;
png_init_io(png_ptr, imageFileW);
png_write_info(png_ptr, info_ptr);
//png_set_compression_level(png_ptr, 9);
//png_set_compression_window_bits(png_ptr, 15);
//png_set_compression_strategy(png_ptr, 3);
//png_set_compression_mem_level(png_ptr, 8);

png_write_image(png_ptr, row_pointers);
png_write_end(png_ptr, info_ptr);


}

2 个答案:

答案 0 :(得分:6)

PNG文件不包含用于压缩的确切deflate / zlib参数的记录,因此您无法实现所需。如果您需要保留原始编码,则应保留原始PNG文件的副本,而不是破坏性地阅读它。

如果要在不更改图像数据的情况下更改辅助PNG块,请使用某些应用程序(如tweakpng)将原始PNG文件中的IHDR,PLTE,IDAT和IEND块复制到新文件中。 / p>

如评论所示,如果您想在不更改压缩数据流的情况下添加水印,那么这是不可能的,因为图像数据不同。如果您确实需要可移动水印,请使用某些可编辑格式(如SVG)以保持水印分离,或使用APNG等格式将水印存储在单独的部分中。这样做的缺点是任何人都可以从他们的副本中删除水印。

答案 1 :(得分:4)

除了Glenn的正确响应之外,即使您以某种方式使用了用于压缩的参数,压缩也可能是由不再可用的代码完成的,或者是由专有且无法使用的代码完成的。在任何一种情况下,都无法复制精确的压缩数据。 如果您不打算弄乱图片,请保留原始压缩数据。