【问题标题】:Read and Write png file without change file size in C (libpng)在 C (libpng) 中读取和写入 png 文件而不更改文件大小
【发布时间】:2017-10-29 08:45:53
【问题描述】:

我想读取 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);


}

【问题讨论】:

  • 这是一个奇怪的请求。如果您不想更改文件,只需复制它即可。如果要更改图像内容,很可能无法达到完全相同的压缩率。如果你想改变一些标签,就地改变它们。
  • 这个问题是正确的@YvesDaoust(否决票?)。他需要获取原始图像数据,并再次压缩此数据以生成相同的文件。它不同于复制(在压缩科学中)。您对这个问题的解决方案是什么?

标签: image-processing png libpng deflate


【解决方案1】:

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

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

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

【讨论】:

  • 感谢@Glenn Randers-Pehrson,根据您的说明,我无法解码和编码 png 文件并生成相同的文件。我正在研究图像水印,我的方法仅限于文件大小。也就是说,我想在 png 的压缩数据流中嵌入水印位,还要考虑数据操作后 adlercrc 的变化。你能告诉我压缩zlib流的最佳位置在哪里可以保存数据结构和图像质量吗?
  • 如果你是加水印,那你就是在改变图片数据,绝对不可能保持相同的压缩数据流,因为压缩的是不同的图片。
  • 我想可以使用 APNG 格式添加水印作为第二帧叠加在第一帧上,但这可能超出了这个问题的范围。我建议你干脆放弃这个想法并接受重新压缩的图像数据。
  • 再次感谢@Glenn Randers-Pehrson 的关注,我知道水印图像与输入图像不同,但第一步是生成相同的图像。因为如果我无法生成相同的图像,我就无法在另一侧提取水印。所以我的想法是改变压缩数据并生成与输入几乎相似的图像。我在 jpeg 中通过更改压缩数据中的 DCT 系数并寻找一种在 PNG 中执行此操作的方法(更改放气结果)。无论如何,谢谢你。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 2021-04-11
    • 2012-04-18
    • 1970-01-01
    • 2012-02-12
    • 2020-04-16
    • 2014-03-20
    • 2016-10-10
    • 1970-01-01
    相关资源
    最近更新 更多