c-PNG文件被截断,不能被每个应用程序显示



我有一个生成PNG文件的代码(使用libpng(。我可以用EOG(Gnome之眼(打开这些文件,但用GIMP、imagemagic和其他文件我会出错。Exiftool告诉我png文件被截断了,但我不知道在哪里。EOG上一切正常。

代码:

int savepng(const char *name, fits *fit, uint32_t bytes_per_sample,
gboolean is_colour) {
int32_t ret = -1;
png_structp png_ptr;
png_infop info_ptr;
const uint32_t width = fit->rx;
const uint32_t height = fit->ry;
char *filename = strdup(name);
if (!ends_with(filename, ".png")) {
filename = str_append(&filename, ".png");
}
FILE *p_png_file = g_fopen(name, "wb");
if (p_png_file == NULL) {
return ret;
}
/* Create and initialize the png_struct with the desired error handler
* functions.  If you want to use the default stderr and longjump method,
* you can supply NULL for the last three parameters.  We also check that
* the library version is compatible with the one used at compile time,
* in case we are using dynamically linked libraries.  REQUIRED.
*/
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) {
fclose(p_png_file);
return ret;
}
/* Allocate/initialize the image information data.  REQUIRED */
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
fclose(p_png_file);
png_destroy_write_struct(&png_ptr, NULL);
return ret;
}
/* Set error handling.  REQUIRED if you aren't supplying your own
* error handling functions in the png_create_write_struct() call.
*/
if (setjmp(png_jmpbuf(png_ptr))) {
/* If we get here, we had a problem writing the file */
fclose(p_png_file);
png_destroy_write_struct(&png_ptr, &info_ptr);
return ret;
}
/* Set up the output control if you are using standard C streams */
png_init_io(png_ptr, p_png_file);
/* Set the image information here.  Width and height are up to 2^31,
* bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
* the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
* PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
* or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
* PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
* currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
*/
if (is_colour) {
png_set_IHDR(png_ptr, info_ptr, width, height, bytes_per_sample * 8,
PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
PNG_FILTER_TYPE_DEFAULT);
uint32_t profile_len;
const unsigned char *profile = get_sRGB_profile_data(&profile_len);
if (profile_len > 0) {
png_set_iCCP(png_ptr, info_ptr, *name ? name : "icc", 0, (png_const_bytep) profile, profile_len);
}
} else {
png_set_IHDR(png_ptr, info_ptr, width, height, bytes_per_sample * 8,
PNG_COLOR_TYPE_GRAY,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
PNG_FILTER_TYPE_DEFAULT);
}
/* Write the file header information.  REQUIRED */
png_write_info(png_ptr, info_ptr);
png_bytep *row_pointers = malloc((size_t) height * sizeof(png_bytep));
int samples_per_pixel;
if (is_colour) {
samples_per_pixel = 3;
} else {
samples_per_pixel = 1;
}
if (bytes_per_sample == 2) {
/* swap bytes of 16 bit files to most significant bit first */
png_set_swap(png_ptr);
WORD *data = convert_data(fit);
for (unsigned i = 0, j = height - 1; i < height; i++)
row_pointers[j--] = (png_bytep) ((uint16_t*) data + (size_t) samples_per_pixel * i * width);
} else {
uint8_t *data = convert_data8(fit);
for (unsigned i = 0, j = height - 1; i < height; i++)
row_pointers[j--] = (uint8_t*) data + (size_t) samples_per_pixel * i * width;
}
png_write_image(png_ptr, row_pointers);
/* Clean up after the write, and free any memory allocated */
png_destroy_write_struct(&png_ptr, &info_ptr);

/* Close the file */
fclose(p_png_file);
free(row_pointers);
free(filename);
return 0;
}

有人能指出我的错误吗?无法读取图像的软件只会显示一个错误对话框。仅此而已。所以我很难知道错误在哪里。

根据@MarkSetchell的建议,缺少一行:

/* Clean up after the write, and free any memory allocated */
png_write_end(png_ptr, info_ptr); // this line was missing
png_destroy_write_struct(&png_ptr, &info_ptr);

仅此而已。

谢谢。

我认为png_write_image()只写入图像行数据,因此元数据的各种标头或元素都丢失了。我通常使用png_write_png()来编写整个文件。

我附上了一些对我来说绝对有效的代码,因为输出可以由Gimp等读取。我不认为这是生产质量;(

int bitmap_write_png (const bitmap_t *bitmap, const char *path)
{
int ret = -1;
size_t x, y;
int pixel_size = 3;
int depth = 8;
FILE *fp = fopen (path, "wb");
if (fp)
{
ret = 0;
png_structp png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
NULL, NULL, NULL); 
png_infop info_ptr = info_ptr = png_create_info_struct (png_ptr);
png_set_IHDR (png_ptr,
info_ptr,
bitmap->width,
bitmap->height,
depth,
PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
png_byte ** row_pointers = png_malloc (png_ptr,
bitmap->height * sizeof (png_byte *));
for (y = 0; y < bitmap->height; y++)
{
png_byte *row =  
png_malloc (png_ptr, sizeof (uint8_t) * bitmap->width * pixel_size);
row_pointers[y] = row;
for (x = 0; x < bitmap->width; x++)
{
pixel_t *pixel = pixel_at_const (bitmap, x, y);
*row++ = pixel->red * 255;
*row++ = pixel->green * 255;
*row++ = pixel->blue * 255;
}
}
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);
for (y = 0; y < bitmap->height; y++)
{
png_free (png_ptr, row_pointers[y]);
}
png_free (png_ptr, row_pointers);
close (fp);
}
else
{
ret = errno;
}
return ret;
}

相关内容

最新更新