Allow loading window background images from memory

This commit is contained in:
Kovid Goyal 2023-03-01 16:11:38 +05:30
parent bf79940a13
commit 1bf180f354
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 34 additions and 14 deletions

View File

@ -609,6 +609,7 @@ def set_background_image(
os_window_ids: Tuple[int, ...], os_window_ids: Tuple[int, ...],
configured: bool = True, configured: bool = True,
layout_name: Optional[str] = None, layout_name: Optional[str] = None,
png_data: bytes = b''
) -> None: ) -> None:
pass pass

View File

@ -297,41 +297,34 @@ add_trim_predicate(Image *img) {
} }
bool bool
png_path_to_bitmap(const char* path, uint8_t** data, unsigned int* width, unsigned int* height, size_t* sz) { png_from_file_pointer(FILE *fp, const char *path_for_error_messages, uint8_t** data, unsigned int* width, unsigned int* height, size_t* sz) {
FILE* fp = fopen(path, "r");
if (fp == NULL) {
log_error("The PNG image: %s could not be opened with error: %s", path, strerror(errno));
return false;
}
size_t capacity = 16*1024, pos = 0; size_t capacity = 16*1024, pos = 0;
unsigned char *buf = malloc(capacity); unsigned char *buf = malloc(capacity);
if (!buf) { log_error("Out of memory reading PNG file at: %s", path); fclose(fp); return false; } if (!buf) { log_error("Out of memory reading PNG file at: %s", path_for_error_messages); fclose(fp); return false; }
while (!feof(fp)) { while (!feof(fp)) {
if (capacity - pos < 1024) { if (capacity - pos < 1024) {
capacity *= 2; capacity *= 2;
unsigned char *new_buf = realloc(buf, capacity); unsigned char *new_buf = realloc(buf, capacity);
if (!new_buf) { if (!new_buf) {
free(buf); free(buf);
log_error("Out of memory reading PNG file at: %s", path); fclose(fp); return false; log_error("Out of memory reading PNG file at: %s", path_for_error_messages); fclose(fp); return false;
} }
buf = new_buf; buf = new_buf;
} }
pos += fread(buf + pos, sizeof(char), capacity - pos, fp); pos += fread(buf + pos, sizeof(char), capacity - pos, fp);
int saved_errno = errno; int saved_errno = errno;
if (ferror(fp) && saved_errno != EINTR) { if (ferror(fp) && saved_errno != EINTR) {
log_error("Failed while reading from file: %s with error: %s", path, strerror(saved_errno)); log_error("Failed while reading from file: %s with error: %s", path_for_error_messages, strerror(saved_errno));
fclose(fp);
free(buf); free(buf);
return false; return false;
} }
} }
fclose(fp); fp = NULL;
png_read_data d = {0}; png_read_data d = {0};
inflate_png_inner(&d, buf, pos); inflate_png_inner(&d, buf, pos);
free(buf); free(buf);
if (!d.ok) { if (!d.ok) {
free(d.decompressed); free(d.row_pointers); free(d.decompressed); free(d.row_pointers);
log_error("Failed to decode PNG image at: %s", path); log_error("Failed to decode PNG image at: %s", path_for_error_messages);
return false; return false;
} }
*data = d.decompressed; *data = d.decompressed;
@ -341,6 +334,18 @@ png_path_to_bitmap(const char* path, uint8_t** data, unsigned int* width, unsign
return true; return true;
} }
bool
png_path_to_bitmap(const char* path, uint8_t** data, unsigned int* width, unsigned int* height, size_t* sz) {
FILE* fp = fopen(path, "r");
if (fp == NULL) {
log_error("The PNG image: %s could not be opened with error: %s", path, strerror(errno));
return false;
}
bool ret = png_from_file_pointer(fp, path, data, width, height, sz);
fclose(fp); fp = NULL;
return ret;
}
static Image* static Image*
find_or_create_image(GraphicsManager *self, uint32_t id, bool *existing) { find_or_create_image(GraphicsManager *self, uint32_t id, bool *existing) {

View File

@ -160,5 +160,6 @@ void grman_resize(GraphicsManager*, index_type, index_type, index_type, index_ty
void grman_rescale(GraphicsManager *self, CellPixelSize fg); void grman_rescale(GraphicsManager *self, CellPixelSize fg);
void gpu_data_for_image(ImageRenderData *ans, float left, float top, float right, float bottom); void gpu_data_for_image(ImageRenderData *ans, float left, float top, float right, float bottom);
void gpu_data_for_centered_image(ImageRenderData *ans, unsigned int screen_width_px, unsigned int screen_height_px, unsigned int width, unsigned int height); void gpu_data_for_centered_image(ImageRenderData *ans, unsigned int screen_width_px, unsigned int screen_height_px, unsigned int width, unsigned int height);
bool png_from_file_pointer(FILE* fp, const char *path, uint8_t** data, unsigned int* width, unsigned int* height, size_t* sz);
bool png_path_to_bitmap(const char *path, uint8_t** data, unsigned int* width, unsigned int* height, size_t* sz); bool png_path_to_bitmap(const char *path, uint8_t** data, unsigned int* width, unsigned int* height, size_t* sz);
bool scan_active_animations(GraphicsManager *self, const monotonic_t now, monotonic_t *minimum_gap, bool os_window_context_set); bool scan_active_animations(GraphicsManager *self, const monotonic_t now, monotonic_t *minimum_gap, bool os_window_context_set);

View File

@ -1152,14 +1152,27 @@ pyset_background_image(PyObject *self UNUSED, PyObject *args) {
PyObject *layout_name = NULL; PyObject *layout_name = NULL;
PyObject *os_window_ids; PyObject *os_window_ids;
int configured = 0; int configured = 0;
PA("zO!|pO", &path, &PyTuple_Type, &os_window_ids, &configured, &layout_name); char *png_data = NULL; Py_ssize_t png_data_size = 0;
PA("zO!|pOy#", &path, &PyTuple_Type, &os_window_ids, &configured, &layout_name, &png_data, png_data_size);
size_t size; size_t size;
BackgroundImageLayout layout = PyUnicode_Check(layout_name) ? bglayout(layout_name) : OPT(background_image_layout); BackgroundImageLayout layout = PyUnicode_Check(layout_name) ? bglayout(layout_name) : OPT(background_image_layout);
BackgroundImage *bgimage = NULL; BackgroundImage *bgimage = NULL;
if (path) { if (path) {
bgimage = calloc(1, sizeof(BackgroundImage)); bgimage = calloc(1, sizeof(BackgroundImage));
if (!bgimage) return PyErr_NoMemory(); if (!bgimage) return PyErr_NoMemory();
if (!png_path_to_bitmap(path, &bgimage->bitmap, &bgimage->width, &bgimage->height, &size)) { bool ok;
if (png_data) {
FILE *fp = fmemopen(png_data, png_data_size, "r");
if (fp == NULL) {
PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
free(bgimage);
return NULL;
}
ok = png_from_file_pointer(fp, path, &bgimage->bitmap, &bgimage->width, &bgimage->height, &size);
} else {
ok = png_path_to_bitmap(path, &bgimage->bitmap, &bgimage->width, &bgimage->height, &size);
}
if (!ok) {
PyErr_Format(PyExc_ValueError, "Failed to load image from: %s", path); PyErr_Format(PyExc_ValueError, "Failed to load image from: %s", path);
free(bgimage); free(bgimage);
return NULL; return NULL;