From c8883fdbb0ac99d04bc1ffe48efe2ad3a5faaa5c Mon Sep 17 00:00:00 2001 From: David Maciejak Date: Wed, 1 Mar 2023 20:36:09 +0800 Subject: [PATCH] WRaster: add functions to save image on disk This patch adds the RSaveTitledImage() function to the WRaster lib to be able to save file on disk either as a PNG or a JPEG file. Those two formats depends on optional external libs. The function can take an optional title/comment which will be save inside the file. The WRaster lib and header versions are bumped. --- configure.ac | 4 +- wrlib/ChangeLog | 2 + wrlib/Makefile.am | 2 + wrlib/NEWS | 15 +++++- wrlib/imgformat.h | 10 +++- wrlib/save.c | 31 ++++++++--- wrlib/save_jpeg.c | 104 +++++++++++++++++++++++++++++++++++++ wrlib/save_png.c | 127 +++++++++++++++++++++++++++++++++++++++++++++ wrlib/save_xpm.c | 2 +- wrlib/wraster.h.in | 5 +- 10 files changed, 286 insertions(+), 16 deletions(-) create mode 100644 wrlib/save_jpeg.c create mode 100644 wrlib/save_png.c diff --git a/configure.ac b/configure.ac index 3054cc6a..f5567ac1 100644 --- a/configure.ac +++ b/configure.ac @@ -71,9 +71,9 @@ dnl 6. If any interfaces have been removed or changed since the last dnl public release, then set age to 0. dnl dnl libwraster -WRASTER_CURRENT=6 +WRASTER_CURRENT=7 WRASTER_REVISION=0 -WRASTER_AGE=0 +WRASTER_AGE=1 WRASTER_VERSION=$WRASTER_CURRENT:$WRASTER_REVISION:$WRASTER_AGE AC_SUBST(WRASTER_VERSION) dnl diff --git a/wrlib/ChangeLog b/wrlib/ChangeLog index f9ac7a1c..d6d99681 100644 --- a/wrlib/ChangeLog +++ b/wrlib/ChangeLog @@ -1,3 +1,5 @@ +- added RSaveTitledImage() + - removed obsoleted RDestroyImage() - removed Hermes code. - Put back asm/mmx optimized code. diff --git a/wrlib/Makefile.am b/wrlib/Makefile.am index 37c8e37a..a82bb9a0 100644 --- a/wrlib/Makefile.am +++ b/wrlib/Makefile.am @@ -55,10 +55,12 @@ endif if USE_JPEG libwraster_la_SOURCES += load_jpeg.c +libwraster_la_SOURCES += save_jpeg.c endif if USE_PNG libwraster_la_SOURCES += load_png.c +libwraster_la_SOURCES += save_png.c endif if USE_TIFF diff --git a/wrlib/NEWS b/wrlib/NEWS index 75047a8a..a7432d24 100644 --- a/wrlib/NEWS +++ b/wrlib/NEWS @@ -1,8 +1,19 @@ -** API and ABI modifications since wmaker 0.92.0 +** API and ABI modifications +---------------------------------------------------- + +Sat 25 Feb 2023 + +RSaveImage: Improved +Able to save image on disk as PNG or JPEG file + +RSaveTitledImage: Added +Image title can be set on the image to be saved + +---------------------------------------------------- +Since wmaker 0.92.0 RLightImage: ADDED - ---------------------------------------------------- Sat Apr 21 09:12:09 EEST 2001 -Dan diff --git a/wrlib/imgformat.h b/wrlib/imgformat.h index 6bb0610a..52aa93df 100644 --- a/wrlib/imgformat.h +++ b/wrlib/imgformat.h @@ -29,7 +29,6 @@ #ifndef IMGFORMAT_INTERNAL_H #define IMGFORMAT_INTERNAL_H - typedef enum { IM_ERROR = -1, IM_UNKNOWN = 0, @@ -82,8 +81,15 @@ void RReleaseMagick(void); /* * Function for Saving in a specific format */ -Bool RSaveXPM(RImage *image, const char *file); +Bool RSaveXPM(RImage *image, const char *filename); +#ifdef USE_PNG +Bool RSavePNG(RImage *image, const char *filename, char *title); +#endif + +#ifdef USE_JPEG +Bool RSaveJPEG(RImage *image, const char *filename, char *title); +#endif /* * Function to terminate properly diff --git a/wrlib/save.c b/wrlib/save.c index 351ec9c3..eee8ce54 100644 --- a/wrlib/save.c +++ b/wrlib/save.c @@ -3,6 +3,7 @@ * Raster graphics library * * Copyright (c) 1998-2003 Alfredo K. Kojima + * Copyright (c) 2013-2023 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 @@ -29,18 +30,32 @@ #include #include #include -#include #include "wraster.h" #include "imgformat.h" #include "wr_i18n.h" - -Bool RSaveImage(RImage * image, const char *filename, const char *format) +Bool RSaveImage(RImage *image, const char *filename, const char *format) { - if (strcmp(format, "XPM") != 0) { - RErrorCode = RERR_BADFORMAT; - return False; - } - return RSaveXPM(image, filename); + return RSaveTitledImage(image, filename, format, NULL); +} + +Bool RSaveTitledImage(RImage *image, const char *filename, const char *format, char *title) +{ +#ifdef USE_PNG + if (strcasecmp(format, "PNG") == 0) + return RSavePNG(image, filename, title); +#endif +#ifdef USE_JPEG + if (strcasecmp(format, "JPG") == 0) + return RSaveJPEG(image, filename, title); + + if (strcasecmp(format, "JPEG") == 0) + return RSaveJPEG(image, filename, title); +#endif + if (strcasecmp(format, "XPM") == 0) + return RSaveXPM(image, filename); + + RErrorCode = RERR_BADFORMAT; + return False; } diff --git a/wrlib/save_jpeg.c b/wrlib/save_jpeg.c new file mode 100644 index 00000000..5320ba47 --- /dev/null +++ b/wrlib/save_jpeg.c @@ -0,0 +1,104 @@ +/* save_jpeg.c - save JPEG image + * + * Raster graphics library + * + * Copyright (c) 2023 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 + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "wraster.h" +#include "imgformat.h" +#include "wr_i18n.h" + +/* + * Save RImage to JPEG image + */ + +Bool RSaveJPEG(RImage *img, const char *filename, char *title) +{ + FILE *file; + int x, y, img_depth; + char *buffer; + RColor pixel; + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + JSAMPROW row_pointer; + + file = fopen(filename, "wb"); + if (!file) { + RErrorCode = RERR_OPEN; + return False; + } + + if (img->format == RRGBAFormat) + img_depth = 4; + else + img_depth = 3; + + /* collect separate RGB values to a buffer */ + buffer = malloc(sizeof(char) * 3 * img->width * img->height); + for (y = 0; y < img->height; y++) { + for (x = 0; x < img->width; x++) { + RGetPixel(img, x, y, &pixel); + buffer[y*img->width*3+x*3+0] = (char)(pixel.red); + buffer[y*img->width*3+x*3+1] = (char)(pixel.green); + buffer[y*img->width*3+x*3+2] = (char)(pixel.blue); + } + } + + /* Setup Exception handling */ + cinfo.err = jpeg_std_error(&jerr); + + /* Initialize cinfo structure */ + jpeg_create_compress(&cinfo); + jpeg_stdio_dest(&cinfo, file); + + cinfo.image_width = img->width; + cinfo.image_height = img->height; + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, 85, TRUE); + jpeg_start_compress(&cinfo, TRUE); + + /* Set title if any */ + if (title) + jpeg_write_marker(&cinfo, JPEG_COM, (const JOCTET*)title, strlen(title)); + + while (cinfo.next_scanline < cinfo.image_height) { + row_pointer = (JSAMPROW) &buffer[cinfo.next_scanline * img_depth * img->width]; + jpeg_write_scanlines(&cinfo, &row_pointer, 1); + } + + jpeg_finish_compress(&cinfo); + + /* Clean */ + free(buffer); + fclose(file); + + return True; +} diff --git a/wrlib/save_png.c b/wrlib/save_png.c new file mode 100644 index 00000000..40d3b996 --- /dev/null +++ b/wrlib/save_png.c @@ -0,0 +1,127 @@ +/* save_png.c - save PNG image + * + * Raster graphics library + * + * Copyright (c) 2023 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 + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "wraster.h" +#include "imgformat.h" +#include "wr_i18n.h" + +/* + * Save RImage to PNG image + */ +Bool RSavePNG(RImage *img, const char *filename, char *title) +{ + FILE *file; + png_structp png_ptr; + png_infop png_info_ptr; + png_bytep png_row; + RColor pixel; + int x, y; + int width = img->width; + int height = img->height; + + file = fopen(filename, "wb"); + if (file == NULL) { + RErrorCode = RERR_OPEN; + return False; + } + + /* 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; + } + + /* Initialize info structure */ + png_info_ptr = png_create_info_struct(png_ptr); + if (png_info_ptr == NULL) { + fclose(file); + RErrorCode = RERR_NOMEMORY; + return False; + } + + /* Setup Exception handling */ + if (setjmp(png_jmpbuf (png_ptr))) { + fclose(file); + RErrorCode = RERR_INTERNAL; + return False; + } + + png_init_io(png_ptr, file); + + /* Write header (8 bit colour depth) */ + png_set_IHDR(png_ptr, png_info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, + PNG_FILTER_TYPE_BASE); + + /* Set title if any */ + if (title) { + png_text title_text; + title_text.compression = PNG_TEXT_COMPRESSION_NONE; + title_text.key = "Title"; + title_text.text = title; + png_set_text(png_ptr, png_info_ptr, &title_text, 1); + } + + png_write_info(png_ptr, png_info_ptr); + + /* Allocate memory for one row (3 bytes per pixel - RGB) */ + png_row = (png_bytep) malloc(3 * width * sizeof(png_byte)); + + /* Write image data */ + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + png_byte *ptr; + + RGetPixel(img, x, y, &pixel); + ptr = &(png_row[x * 3]); + ptr[0] = pixel.red; + ptr[1] = pixel.green; + ptr[2] = pixel.blue; + } + png_write_row(png_ptr, png_row); + } + + /* End write */ + png_write_end(png_ptr, NULL); + + /* Clean */ + fclose(file); + if (png_info_ptr != NULL) + png_free_data(png_ptr, png_info_ptr, PNG_FREE_ALL, -1); + if (png_ptr != NULL) + png_destroy_write_struct(&png_ptr, (png_infopp) NULL); + if (png_row != NULL) + free(png_row); + + return True; +} diff --git a/wrlib/save_xpm.c b/wrlib/save_xpm.c index 4be7be5e..243f9506 100644 --- a/wrlib/save_xpm.c +++ b/wrlib/save_xpm.c @@ -1,4 +1,4 @@ -/* nxpm.c - load "normalized" XPM image +/* save_xpm.c - save "normalized" XPM image * * Raster graphics library * diff --git a/wrlib/wraster.h.in b/wrlib/wraster.h.in index 62d369f8..6f6e5df4 100644 --- a/wrlib/wraster.h.in +++ b/wrlib/wraster.h.in @@ -41,7 +41,7 @@ /* version of the header for the library */ -#define WRASTER_HEADER_VERSION 24 +#define WRASTER_HEADER_VERSION 25 #include @@ -391,6 +391,9 @@ RImage *RGetImageFromXPMData(RContext *context, char **xpmData) Bool RSaveImage(RImage *image, const char *filename, const char *format) __wrlib_nonnull(1, 2, 3); +Bool RSaveTitledImage(RImage *image, const char *filename, const char *format, char *title) + __wrlib_nonnull(1, 2, 3); + /* * Area manipulation */