diff --git a/kitty/graphics.c b/kitty/graphics.c index 8e6b80929..fbd2292ac 100644 --- a/kitty/graphics.c +++ b/kitty/graphics.c @@ -305,7 +305,7 @@ err: } static void -png_error_handler(const char *code, const char *msg) { +png_error_handler(png_read_data *d UNUSED, const char *code, const char *msg) { set_command_failed_response(code, "%s", msg); } @@ -333,6 +333,17 @@ add_trim_predicate(Image *img) { return !img->root_frame_data_loaded || (!img->client_id && !img->refs); } +static void +print_png_read_error(png_read_data *d, const char *code, const char* msg) { + if (d->error.used >= d->error.capacity) { + size_t cap = MAX(2 * d->error.capacity, 1024 + d->error.used); + d->error.buf = realloc(d->error.buf, cap); + if (!d->error.buf) return; + d->error.capacity = cap; + } + d->error.used += snprintf(d->error.buf + d->error.used, d->error.capacity - d->error.used, "%s: %s ", code, msg); +} + bool png_from_file_pointer(FILE *fp, const char *path_for_error_messages, uint8_t** data, unsigned int* width, unsigned int* height, size_t* sz) { size_t capacity = 16*1024, pos = 0; @@ -356,16 +367,16 @@ png_from_file_pointer(FILE *fp, const char *path_for_error_messages, uint8_t** d return false; } } - png_read_data d = {0}; + png_read_data d = {.err_handler=print_png_read_error}; inflate_png_inner(&d, buf, pos); free(buf); if (!d.ok) { - free(d.decompressed); free(d.row_pointers); - log_error("Failed to decode PNG image at: %s", path_for_error_messages); + log_error("Failed to decode PNG image at: %s with error: %s", path_for_error_messages, d.error.used > 0 ? d.error.buf : ""); + free(d.decompressed); free(d.row_pointers); free(d.error.buf); return false; } *data = d.decompressed; - free(d.row_pointers); + free(d.row_pointers); free(d.error.buf); *sz = d.sz; *height = d.height; *width = d.width; return true; diff --git a/kitty/png-reader.c b/kitty/png-reader.c index 13bf7db6b..73f9e39aa 100644 --- a/kitty/png-reader.c +++ b/kitty/png-reader.c @@ -5,6 +5,7 @@ * Distributed under terms of the GPL3 license. */ +#include "data-types.h" #include "png-reader.h" #include "cleanup.h" #include "state.h" @@ -26,7 +27,7 @@ read_png_from_buffer(png_structp png, png_bytep out, png_size_t length) { struct custom_error_handler { jmp_buf jb; - png_error_handler_func err_handler; + png_read_data *d; }; static void @@ -34,7 +35,7 @@ read_png_error_handler(png_structp png_ptr, png_const_charp msg) { struct custom_error_handler *eh; eh = png_get_error_ptr(png_ptr); if (eh == NULL) fatal("read_png_error_handler: could not retrieve error handler"); - if(eh->err_handler) eh->err_handler("EBADPNG", msg); + if(eh->d->err_handler) eh->d->err_handler(eh->d, "EBADPNG", msg); longjmp(eh->jb, 1); } @@ -43,14 +44,14 @@ read_png_warn_handler(png_structp UNUSED png_ptr, png_const_charp msg) { if (global_state.debug_rendering) log_error("libpng WARNING: %s", msg); } -#define ABRT(code, msg) { if(d->err_handler) d->err_handler(#code, msg); goto err; } +#define ABRT(code, msg) { if(d->err_handler) d->err_handler(d, #code, msg); goto err; } void inflate_png_inner(png_read_data *d, const uint8_t *buf, size_t bufsz) { struct fake_file f = {.buf = buf, .sz = bufsz}; png_structp png = NULL; png_infop info = NULL; - struct custom_error_handler eh = {.err_handler = d->err_handler}; + struct custom_error_handler eh = {.d = d}; png = png_create_read_struct(PNG_LIBPNG_VER_STRING, &eh, read_png_error_handler, read_png_warn_handler); if (!png) ABRT(ENOMEM, "Failed to create PNG read structure"); info = png_create_info_struct(png); @@ -131,8 +132,8 @@ err: } static void -png_error_handler(const char *code, const char *msg) { - PyErr_Format(PyExc_ValueError, "[%s] %s", code, msg); +png_error_handler(png_read_data *d UNUSED, const char *code, const char *msg) { + if (!PyErr_Occurred()) PyErr_Format(PyExc_ValueError, "[%s] %s", code, msg); } static PyObject* diff --git a/kitty/png-reader.h b/kitty/png-reader.h index 493216af8..451055a66 100644 --- a/kitty/png-reader.h +++ b/kitty/png-reader.h @@ -6,16 +6,25 @@ #pragma once -#include "data-types.h" +#include +#include #include -typedef void(*png_error_handler_func)(const char*, const char*); -typedef struct { + +typedef struct png_read_data png_read_data; + +typedef void(*png_error_handler_func)(png_read_data *d, const char*, const char*); + +typedef struct png_read_data { uint8_t *decompressed; bool ok; png_bytep *row_pointers; int width, height; size_t sz; png_error_handler_func err_handler; + struct { + char *buf; + size_t used, capacity; + } error; } png_read_data; void inflate_png_inner(png_read_data *d, const uint8_t *buf, size_t bufsz);