在 C 中使用 libpng 读取和写入 PNG 文件
Read and write a PNG file using libpng in C
我的目标是读取 PNG 文件,更改像素值并使用 libpng 存储更新后的 PNG 文件。
我按照official libpng manual. The example code doesn't change the pixel values, because it's a minimum, reproducible example写了两个函数read_png
和write_png
。它也不会检查输入文件是否实际上是 PNG 文件。
#include <png.h>
png_infop info_ptr;
png_bytepp row_pointers;
void read_png(char *file_name)
{
FILE *fp = fopen(file_name, "rb");
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
png_infop info_ptr = png_create_info_struct(png_ptr);
png_init_io(png_ptr, fp);
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
row_pointers = png_get_rows(png_ptr, info_ptr);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(fp);
}
void write_png(char *file_name)
{
FILE *fp = fopen(file_name, "wb");
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
png_init_io(png_ptr, fp);
png_set_rows(png_ptr, info_ptr, row_pointers);
png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp);
}
int main(int argc, char *argv[])
{
read_png(argv[1]);
write_png(argv[2]);
return 0;
}
代码编译没有任何错误。
$ gcc -o rw_png -lpng rw_png.c
并且程序可以运行带有两个参数。
$ ./rw_png input.png output.png
问题是,虽然创建了 output.png
,但它是一个空文件而不是 PNG 文件。
$ file output.png
output.png: empty
libpng 使用 info_struct
来保存有关像素数据外观的信息。因此,您需要将其保留 write_png
(或重新创建)。
png_infop info_ptr; // <-- Global info_ptr (good)
png_bytepp row_pointers;
void read_png(char *file_name)
{
FILE *fp = fopen(file_name, "rb");
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
png_infop info_ptr = png_create_info_struct(png_ptr); // <-- creating a new, local info_ptr
png_init_io(png_ptr, fp);
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
row_pointers = png_get_rows(png_ptr, info_ptr);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL); // <-- destroying the info_ptr (as well).
fclose(fp);
}
因此,固定的 read_png
将是:
void read_png(char *file_name)
{
FILE *fp = fopen(file_name, "rb");
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
info_ptr = png_create_info_struct(png_ptr);
png_init_io(png_ptr, fp);
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
row_pointers = png_get_rows(png_ptr, info_ptr);
png_destroy_read_struct(&png_ptr, NULL, NULL);
fclose(fp);
}
假设 read_png
/ write_png
,您将在 write_png
中释放 info_ptr
。
我的目标是读取 PNG 文件,更改像素值并使用 libpng 存储更新后的 PNG 文件。
我按照official libpng manual. The example code doesn't change the pixel values, because it's a minimum, reproducible example写了两个函数read_png
和write_png
。它也不会检查输入文件是否实际上是 PNG 文件。
#include <png.h>
png_infop info_ptr;
png_bytepp row_pointers;
void read_png(char *file_name)
{
FILE *fp = fopen(file_name, "rb");
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
png_infop info_ptr = png_create_info_struct(png_ptr);
png_init_io(png_ptr, fp);
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
row_pointers = png_get_rows(png_ptr, info_ptr);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(fp);
}
void write_png(char *file_name)
{
FILE *fp = fopen(file_name, "wb");
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
png_init_io(png_ptr, fp);
png_set_rows(png_ptr, info_ptr, row_pointers);
png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp);
}
int main(int argc, char *argv[])
{
read_png(argv[1]);
write_png(argv[2]);
return 0;
}
代码编译没有任何错误。
$ gcc -o rw_png -lpng rw_png.c
并且程序可以运行带有两个参数。
$ ./rw_png input.png output.png
问题是,虽然创建了 output.png
,但它是一个空文件而不是 PNG 文件。
$ file output.png
output.png: empty
libpng 使用 info_struct
来保存有关像素数据外观的信息。因此,您需要将其保留 write_png
(或重新创建)。
png_infop info_ptr; // <-- Global info_ptr (good)
png_bytepp row_pointers;
void read_png(char *file_name)
{
FILE *fp = fopen(file_name, "rb");
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
png_infop info_ptr = png_create_info_struct(png_ptr); // <-- creating a new, local info_ptr
png_init_io(png_ptr, fp);
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
row_pointers = png_get_rows(png_ptr, info_ptr);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL); // <-- destroying the info_ptr (as well).
fclose(fp);
}
因此,固定的 read_png
将是:
void read_png(char *file_name)
{
FILE *fp = fopen(file_name, "rb");
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
info_ptr = png_create_info_struct(png_ptr);
png_init_io(png_ptr, fp);
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
row_pointers = png_get_rows(png_ptr, info_ptr);
png_destroy_read_struct(&png_ptr, NULL, NULL);
fclose(fp);
}
假设 read_png
/ write_png
,您将在 write_png
中释放 info_ptr
。