summaryrefslogtreecommitdiff
path: root/src/feh_png.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/feh_png.c')
-rw-r--r--src/feh_png.c214
1 files changed, 214 insertions, 0 deletions
diff --git a/src/feh_png.c b/src/feh_png.c
new file mode 100644
index 0000000..7654880
--- /dev/null
+++ b/src/feh_png.c
@@ -0,0 +1,214 @@
+/* feh_png.c
+
+Copyright (C) 2004 Tom Gilbert.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies of the Software and its documentation and acknowledgment shall be
+given in the documentation and software packages that this Software was
+used.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include "feh_png.h"
+
+#include <png.h>
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#define FEH_PNG_COMPRESSION 3
+#define FEH_PNG_NUM_COMMENTS 2 /* only Thumb::URI and Thumb::MTime for now */
+
+gib_hash*
+feh_png_read_comments(char *file)
+{
+ gib_hash *hash = NULL;
+
+ FILE *fp;
+ int i, sig_bytes, comments = 0;
+
+ png_structp png_ptr;
+ png_infop info_ptr;
+ png_textp text_ptr;
+
+ if (!(fp = fopen(file, "rb")))
+ return hash;
+
+ if (!(sig_bytes = feh_png_file_is_png(fp))) {
+ fclose(fp);
+ return hash;
+ }
+
+ /* initialize data structures */
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png_ptr)
+ {
+ fclose(fp);
+ return hash;
+ }
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr) {
+ png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
+ fclose(fp);
+ return hash;
+ }
+
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ fclose(fp);
+ return hash;
+ }
+
+ /* initialize reading */
+ png_init_io(png_ptr, fp);
+ png_set_sig_bytes(png_ptr, sig_bytes);
+
+ png_read_info(png_ptr, info_ptr);
+
+#ifdef PNG_TEXT_SUPPORTED
+ png_get_text(png_ptr, info_ptr, &text_ptr, &comments);
+ if (comments > 0) {
+ hash = gib_hash_new();
+ for (i = 0; i < comments; i++)
+ gib_hash_set(hash, text_ptr[i].key, estrdup(text_ptr[i].text));
+ }
+#endif /* PNG_TEXT_SUPPORTED */
+
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ fclose(fp);
+
+ return hash;
+}
+
+/* grab image data from image and write info file with comments ... */
+int
+feh_png_write_png(Imlib_Image image, char *file, ...)
+{
+ FILE *fp;
+ int i, w, h;
+
+ png_structp png_ptr;
+ png_infop info_ptr;
+ png_color_8 sig_bit;
+
+ DATA32 *ptr;
+
+#ifdef PNG_TEXT_SUPPORTED
+ va_list args;
+ png_text text[FEH_PNG_NUM_COMMENTS];
+ char *pair_key, *pair_text;
+#endif /* PNG_TEXT_SUPPORTED */
+
+ if (!(fp = fopen(file, "wb")))
+ return 0;
+
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png_ptr)
+ return 0;
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
+ return 0;
+ }
+
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ fclose(fp);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ png_destroy_info_struct(png_ptr, &info_ptr);
+ return 0;
+ }
+
+ w = gib_imlib_image_get_width(image);
+ h = gib_imlib_image_get_height(image);
+
+ png_init_io(png_ptr, fp);
+
+ png_set_IHDR(png_ptr, info_ptr, w, h, 8, PNG_COLOR_TYPE_RGB_ALPHA,
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
+ PNG_FILTER_TYPE_DEFAULT);
+
+#ifdef WORDS_BIGENDIAN
+ png_set_swap_alpha(png_ptr);
+#else /* !WORDS_BIGENDIAN */
+ png_set_bgr(png_ptr);
+#endif /* WORDS_BIGENDIAN */
+
+ sig_bit.red = 8;
+ sig_bit.green = 8;
+ sig_bit.blue = 8;
+ sig_bit.alpha = 8;
+ png_set_sBIT(png_ptr, info_ptr, &sig_bit);
+
+#ifdef PNG_TEXT_SUPPORTED
+ va_start(args, file);
+ for (i = 0; i < FEH_PNG_NUM_COMMENTS; i++)
+ {
+ if ((pair_key = va_arg(args, char *)) &&
+ (pair_text = va_arg(args, char *)))
+ {
+ /* got a complete pair, add to info structure */
+ text[i].key = pair_key;
+ text[i].text = pair_text;
+ text[i].compression = PNG_TEXT_COMPRESSION_NONE;
+ }
+ else
+ break;
+ }
+ va_end(args);
+
+ if (i > 0)
+ png_set_text(png_ptr, info_ptr, text, i);
+#endif /* PNG_TEXT_SUPPORTED */
+
+ png_set_compression_level(png_ptr, FEH_PNG_COMPRESSION);
+ png_write_info(png_ptr, info_ptr);
+ png_set_shift(png_ptr, &sig_bit);
+ png_set_packing(png_ptr);
+
+ /* write image data */
+ imlib_context_set_image(image);
+ ptr = imlib_image_get_data();
+ for (i = 0; i < h; i++, ptr += w)
+ png_write_row(png_ptr, (png_bytep) ptr);
+
+ png_write_end(png_ptr, info_ptr);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ png_destroy_info_struct(png_ptr, &info_ptr);
+
+ fclose(fp);
+
+ return 0;
+}
+
+/* check PNG signature */
+int
+feh_png_file_is_png(FILE *fp)
+{
+ unsigned char buf[8];
+
+ fread(buf, 1, 8, fp);
+ if (png_sig_cmp(buf, 0, 8)) {
+ return 0;
+ }
+
+ return 8;
+}