Author: post
Date: 2010-04-04 18:43:00 +0200 (Sun, 04 Apr 2010)
New Revision: 3333
Modified:
trunk/plugins/output-pngfile/output-pngfile.c
Log:
Add 16 bit output in PNG, allow output color profile selection.
Modified: trunk/plugins/output-pngfile/output-pngfile.c
===================================================================
--- trunk/plugins/output-pngfile/output-pngfile.c 2010-04-04 15:56:54 UTC
(rev 3332)
+++ trunk/plugins/output-pngfile/output-pngfile.c 2010-04-04 16:43:00 UTC
(rev 3333)
@@ -22,6 +22,7 @@
#include <rawstudio.h>
#include <gettext.h>
#include "config.h"
+#include <png.h>
#define RS_TYPE_PNGFILE (rs_pngfile_type)
#define RS_PNGFILE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), RS_TYPE_PNGFILE,
RSPngfile))
@@ -36,6 +37,8 @@
gchar *filename;
gint quality;
+ RSColorSpace *color_space;
+ gboolean save16bit;
};
struct _RSPngfileClass {
@@ -46,7 +49,9 @@
enum {
PROP_0,
- PROP_FILENAME
+ PROP_FILENAME,
+ PROP_16BIT,
+ PROP_COLORSPACE
};
static void get_property (GObject *object, guint property_id, GValue *value,
GParamSpec *pspec);
@@ -73,6 +78,16 @@
"filename", "filename", "Full export path",
NULL, G_PARAM_READWRITE)
);
+ g_object_class_install_property(object_class,
+ PROP_COLORSPACE, g_param_spec_object(
+ "colorspace", "Output colorspace", "Color space used
for saving",
+ RS_TYPE_COLOR_SPACE, G_PARAM_READWRITE)
+ );
+ g_object_class_install_property(object_class,
+ PROP_16BIT, g_param_spec_boolean(
+ "save16bit", "16 bit PNG", _("Save 16 bit linear PNG"),
+ FALSE, G_PARAM_READWRITE)
+ );
output_class->execute = execute;
output_class->extension = "png";
@@ -83,6 +98,8 @@
rs_pngfile_init(RSPngfile *pngfile)
{
pngfile->filename = NULL;
+ pngfile->color_space = rs_color_space_new_singleton("RSSrgb");
+ pngfile->save16bit = FALSE;
}
static void
@@ -95,6 +112,12 @@
case PROP_FILENAME:
g_value_set_string(value, pngfile->filename);
break;
+ case PROP_COLORSPACE:
+ g_value_set_object(value, pngfile->color_space);
+ break;
+ case PROP_16BIT:
+ g_value_set_boolean(value, pngfile->save16bit);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id,
pspec);
}
@@ -110,6 +133,14 @@
case PROP_FILENAME:
pngfile->filename = g_value_dup_string(value);
break;
+ case PROP_COLORSPACE:
+ if (pngfile->color_space)
+ g_object_unref(pngfile->color_space);
+ pngfile->color_space = g_value_get_object(value);
+ break;
+ case PROP_16BIT:
+ pngfile->save16bit = g_value_get_boolean(value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id,
pspec);
}
@@ -118,21 +149,121 @@
static gboolean
execute(RSOutput *output, RSFilter *filter)
{
- gboolean ret;
- RSFilterResponse *response;
RSPngfile *pngfile = RS_PNGFILE(output);
- response = rs_filter_get_image8(filter, NULL);
- GdkPixbuf *pixbuf = rs_filter_response_get_image8(response);
+ png_bytep *row_pointers;
+ FILE *fp = fopen(pngfile->filename, "wb");
+ if (!fp)
+ return FALSE;
- ret = gdk_pixbuf_save(pixbuf, pngfile->filename, "png", NULL, NULL);
+ png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
(png_voidp)NULL, NULL, NULL);
+ if (!png_ptr)
+ return FALSE;
+
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_write_struct(&png_ptr,(png_infopp)NULL);
+ return FALSE;
+ }
+
+ png_init_io(png_ptr, fp);
+ /* set the zlib compression level */
+ png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION);
+
+
+ if (pngfile->color_space == rs_color_space_new_singleton("RSSrgb"))
+ {
+ png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr,
PNG_sRGB_INTENT_PERCEPTUAL);
+ if (pngfile->save16bit)
+ png_set_gAMA(png_ptr, info_ptr, 1.0);
+ }
+ else
+ {
+ gchar *data;
+ gsize data_length;
+ const RSIccProfile *profile =
rs_color_space_get_icc_profile(pngfile->color_space);
+ rs_icc_profile_get_data(profile, &data, &data_length);
+
+ // FIXME:
+ png_set_iCCP(png_ptr, info_ptr, "Profile name",
PNG_COMPRESSION_TYPE_BASE, data, data_length);
+ if (pngfile->save16bit)
+ png_set_gAMA(png_ptr, info_ptr, 1.0);
+ }
+
+ RSFilterResponse *response;
+ RSFilterRequest *request = rs_filter_request_new();
+ rs_filter_request_set_quick(RS_FILTER_REQUEST(request), FALSE);
+ rs_filter_param_set_object(RS_FILTER_PARAM(request), "colorspace",
pngfile->color_space);
+
+ if (pngfile->save16bit)
+ {
+ response = rs_filter_get_image(filter, request);
+ RS_IMAGE16 *image = rs_filter_response_get_image(response);
+
+ gint n_channels = image->pixelsize;
+ gint width = image->w;
+ gint height = image->h;
+
+ png_set_IHDR(png_ptr, info_ptr, width, height,
+ 16, PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
+
+ png_write_info(png_ptr, info_ptr);
+
+ row_pointers = g_malloc(sizeof(png_bytep*)*height);
+ gint i;
+ for( i = 0; i < height; i++)
+ row_pointers[i] = (png_bytep)GET_PIXEL(image, 0, i);
+
+ if (n_channels == 4)
+ png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
+#ifdef G_BIG_ENDIAN
+ png_set_swap(png_ptr);
+#endif
+ png_write_image(png_ptr, row_pointers);
+ g_object_unref(image);
+ }
+ else // 8 bit
+ {
+ response = rs_filter_get_image8(filter, request);
+ GdkPixbuf *pixbuf = rs_filter_response_get_image8(response);
+
+ gint n_channels = gdk_pixbuf_get_n_channels (pixbuf);
+ gint width = gdk_pixbuf_get_width (pixbuf);
+ gint height = gdk_pixbuf_get_height (pixbuf);
+ gint rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ guchar* pixels = gdk_pixbuf_get_pixels (pixbuf);
+
+ png_set_IHDR(png_ptr, info_ptr, width, height,
+ 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+
+ png_write_info(png_ptr, info_ptr);
+
+ row_pointers = g_malloc(sizeof(png_bytep*)*height);
+ gint i;
+ for( i = 0; i < height; i++)
+ row_pointers[i] = (png_bytep)(pixels + i * rowstride);
+
+ if (n_channels == 4)
+ png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
+
+ png_write_image(png_ptr, row_pointers);
+ g_object_unref(pixbuf);
+ }
+
+ png_write_end(png_ptr, NULL);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ fclose(fp);
+ g_object_unref(request);
g_object_unref(response);
- g_object_unref(pixbuf);
+ g_free(row_pointers);
gchar *input_filename = NULL;
rs_filter_get_recursive(filter, "filename", &input_filename, NULL);
rs_exif_copy(input_filename, pngfile->filename);
g_free(input_filename);
- return ret;
+ return TRUE;
}
_______________________________________________
Rawstudio-commit mailing list
[email protected]
http://rawstudio.org/cgi-bin/mailman/listinfo/rawstudio-commit