mirror of
https://github.com/gryf/wmaker.git
synced 2026-03-20 18:33:31 +01:00
WRaster: add function to save image in memory
This patch adds the RSaveRawImage() function to the WRaster lib to be able to save image structure in memory. The WRaster lib version is bumped.
This commit is contained in:
committed by
Carlos R. Mafra
parent
72942267aa
commit
7cfdf6bd68
130
wrlib/save_png.c
130
wrlib/save_png.c
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* Raster graphics library
|
||||
*
|
||||
* Copyright (c) 2023 Window Maker Team
|
||||
* Copyright (c) 2023-2025 Window Maker Team
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
@@ -33,12 +33,51 @@
|
||||
#include "imgformat.h"
|
||||
#include "wr_i18n.h"
|
||||
|
||||
/*
|
||||
* Save RImage to PNG image
|
||||
*/
|
||||
Bool RSavePNG(RImage *img, const char *filename, char *title)
|
||||
/* Structure to hold PNG data in memory */
|
||||
struct png_mem_data {
|
||||
unsigned char *buffer;
|
||||
size_t size;
|
||||
size_t capacity;
|
||||
};
|
||||
|
||||
/* Callback function to write PNG data to memory buffer */
|
||||
static void png_write_to_memory(png_structp png_ptr, png_bytep data, png_size_t length)
|
||||
{
|
||||
struct png_mem_data *p = (struct png_mem_data *)png_get_io_ptr(png_ptr);
|
||||
size_t new_size = p->size + length;
|
||||
|
||||
/* Expand buffer if necessary */
|
||||
if (new_size > p->capacity) {
|
||||
size_t new_capacity = p->capacity ? p->capacity * 2 : 8192;
|
||||
while (new_capacity < new_size)
|
||||
new_capacity *= 2;
|
||||
|
||||
unsigned char *new_buffer = realloc(p->buffer, new_capacity);
|
||||
if (!new_buffer) {
|
||||
png_error(png_ptr, "Out of memory");
|
||||
return;
|
||||
}
|
||||
p->buffer = new_buffer;
|
||||
p->capacity = new_capacity;
|
||||
}
|
||||
|
||||
/* Copy data to buffer */
|
||||
memcpy(p->buffer + p->size, data, length);
|
||||
p->size += length;
|
||||
}
|
||||
|
||||
/* Dummy flush function for memory I/O */
|
||||
static void png_flush_memory(png_structp png_ptr)
|
||||
{
|
||||
/* No-op for memory I/O */
|
||||
(void)png_ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save RImage to PNG data in memory
|
||||
*/
|
||||
Bool RSaveRawPNG(RImage *img, char *title, unsigned char **out_buf, size_t *out_size)
|
||||
{
|
||||
FILE *file;
|
||||
png_structp png_ptr;
|
||||
png_infop png_info_ptr;
|
||||
png_bytep png_row;
|
||||
@@ -46,17 +85,14 @@ Bool RSavePNG(RImage *img, const char *filename, char *title)
|
||||
int x, y;
|
||||
int width = img->width;
|
||||
int height = img->height;
|
||||
struct png_mem_data png_data = {NULL, 0, 0};
|
||||
|
||||
file = fopen(filename, "wb");
|
||||
if (file == NULL) {
|
||||
RErrorCode = RERR_OPEN;
|
||||
return False;
|
||||
}
|
||||
*out_buf = NULL;
|
||||
*out_size = 0;
|
||||
|
||||
/* Initialize write structure */
|
||||
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if (png_ptr == NULL) {
|
||||
fclose(file);
|
||||
RErrorCode = RERR_NOMEMORY;
|
||||
return False;
|
||||
}
|
||||
@@ -64,19 +100,22 @@ Bool RSavePNG(RImage *img, const char *filename, char *title)
|
||||
/* Initialize info structure */
|
||||
png_info_ptr = png_create_info_struct(png_ptr);
|
||||
if (png_info_ptr == NULL) {
|
||||
fclose(file);
|
||||
png_destroy_write_struct(&png_ptr, NULL);
|
||||
RErrorCode = RERR_NOMEMORY;
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Setup Exception handling */
|
||||
if (setjmp(png_jmpbuf (png_ptr))) {
|
||||
fclose(file);
|
||||
if (setjmp(png_jmpbuf(png_ptr))) {
|
||||
if (png_data.buffer)
|
||||
free(png_data.buffer);
|
||||
png_destroy_write_struct(&png_ptr, &png_info_ptr);
|
||||
RErrorCode = RERR_INTERNAL;
|
||||
return False;
|
||||
}
|
||||
|
||||
png_init_io(png_ptr, file);
|
||||
/* Set up memory I/O */
|
||||
png_set_write_fn(png_ptr, &png_data, png_write_to_memory, png_flush_memory);
|
||||
|
||||
/* Write header (8 bit colour depth) */
|
||||
png_set_IHDR(png_ptr, png_info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB,
|
||||
@@ -96,6 +135,13 @@ Bool RSavePNG(RImage *img, const char *filename, char *title)
|
||||
|
||||
/* Allocate memory for one row (3 bytes per pixel - RGB) */
|
||||
png_row = (png_bytep) malloc(3 * width * sizeof(png_byte));
|
||||
if (!png_row) {
|
||||
if (png_data.buffer)
|
||||
free(png_data.buffer);
|
||||
png_destroy_write_struct(&png_ptr, &png_info_ptr);
|
||||
RErrorCode = RERR_NOMEMORY;
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Write image data */
|
||||
for (y = 0; y < height; y++) {
|
||||
@@ -114,8 +160,7 @@ Bool RSavePNG(RImage *img, const char *filename, char *title)
|
||||
/* End write */
|
||||
png_write_end(png_ptr, NULL);
|
||||
|
||||
/* Clean */
|
||||
fclose(file);
|
||||
/* Clean up structures */
|
||||
if (png_info_ptr != NULL)
|
||||
png_free_data(png_ptr, png_info_ptr, PNG_FREE_ALL, -1);
|
||||
if (png_ptr != NULL)
|
||||
@@ -123,5 +168,54 @@ Bool RSavePNG(RImage *img, const char *filename, char *title)
|
||||
if (png_row != NULL)
|
||||
free(png_row);
|
||||
|
||||
/* Return the buffer */
|
||||
*out_buf = png_data.buffer;
|
||||
*out_size = png_data.size;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save RImage to PNG image
|
||||
*/
|
||||
Bool RSavePNG(RImage *img, const char *filename, char *title)
|
||||
{
|
||||
FILE *file;
|
||||
unsigned char *png_data = NULL;
|
||||
size_t png_size = 0;
|
||||
size_t written;
|
||||
|
||||
if (!img || !filename) {
|
||||
RErrorCode = RERR_BADIMAGEFILE;
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Use RSaveRawPNG to generate PNG data in memory */
|
||||
if (!RSaveRawPNG(img, title, &png_data, &png_size)) {
|
||||
/* Error code already set by RSaveRawPNG */
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Open file for writing */
|
||||
file = fopen(filename, "wb");
|
||||
if (file == NULL) {
|
||||
free(png_data);
|
||||
RErrorCode = RERR_OPEN;
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Write PNG data to file */
|
||||
written = fwrite(png_data, 1, png_size, file);
|
||||
fclose(file);
|
||||
|
||||
/* Check if all data was written */
|
||||
if (written != png_size) {
|
||||
free(png_data);
|
||||
RErrorCode = RERR_WRITE;
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Clean up */
|
||||
free(png_data);
|
||||
return True;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user