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

Read and Write png file without change file size in C (libpng)

我想读取 png 文件,查看图像数据并在不改变文件大小的情况下再次写入。基于libpng文档,png是无损的,使用deflatelz77进行压缩。 libpng中有一个示例项目声称可以无损读写图像,它的像素值是正确的,但是改变了文件的结构(例如IDAT的数量,可选块等)png文件大小。

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

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

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);


}

PNG 文件不包含用于压缩的确切 deflate/zlib 参数的记录,因此您想要的实际上是不可能的。如果您需要保留原始编码,您应该保留原始 PNG 文件的副本,而不是破坏性地读取它。

如果您想在不更改图像数据的情况下更改辅助 PNG 块,请使用 tweakpng 等应用程序将原始 PNG 文件中的 IHDR、PLTE、IDAT 和 IEND 块复制到新文件中.

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

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