[gthumb/ext: 2/20] load the images and draw the pages following the settings



commit 827a2cbfc2f266ddbeadc689b085e1619e91e675
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Thu Nov 19 01:32:25 2009 +0100

    load the images and draw the pages following the settings

 extensions/image_print/Makefile.am                |    4 +
 extensions/image_print/actions.c                  |   20 +-
 extensions/image_print/gth-image-info.c           |  130 +++++++
 extensions/image_print/gth-image-info.h           |   59 ++++
 extensions/image_print/gth-image-print-job.c      |  372 ++++++++++++++++-----
 extensions/image_print/gth-image-print-job.h      |    5 +-
 extensions/image_print/gth-load-image-info-task.c |  211 ++++++++++++
 extensions/image_print/gth-load-image-info-task.h |   58 ++++
 gthumb/pixbuf-utils.c                             |   43 +++
 gthumb/pixbuf-utils.h                             |    3 +
 10 files changed, 813 insertions(+), 92 deletions(-)
---
diff --git a/extensions/image_print/Makefile.am b/extensions/image_print/Makefile.am
index a0f5a18..39641c1 100644
--- a/extensions/image_print/Makefile.am
+++ b/extensions/image_print/Makefile.am
@@ -8,8 +8,12 @@ libimage_print_la_SOURCES = 		\
 	actions.h			\
 	callbacks.c			\
 	callbacks.h			\
+	gth-image-info.c		\
+	gth-image-info.h		\
 	gth-image-print-job.c		\
 	gth-image-print-job.h		\
+	gth-load-image-info-task.c	\
+	gth-load-image-info-task.h	\
 	main.c
 
 libimage_print_la_CPPFLAGS = $(GTHUMB_CFLAGS) $(DISABLE_DEPRECATED) $(WARNINGS) -I$(top_srcdir) -I$(top_builddir)/gthumb 
diff --git a/extensions/image_print/actions.c b/extensions/image_print/actions.c
index 07aa398..6747733 100644
--- a/extensions/image_print/actions.c
+++ b/extensions/image_print/actions.c
@@ -31,10 +31,20 @@ void
 gth_browser_activate_action_file_print (GtkAction  *action,
 					GthBrowser *browser)
 {
-	GthImagePrintJob *print_job;
+	GList *items;
+	GList *file_list;
 
-	print_job = gth_image_print_job_new (/* FIXME: pass the selected files */);
-	gth_image_print_job_run (print_job,
-				 GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
-				 GTK_WINDOW (browser));
+	items = gth_file_selection_get_selected (GTH_FILE_SELECTION (gth_browser_get_file_list_view (browser)));
+	file_list = gth_file_list_get_files (GTH_FILE_LIST (gth_browser_get_file_list (browser)), items);
+	if (file_list != NULL) {
+		GthImagePrintJob *print_job;
+
+		print_job = gth_image_print_job_new (file_list);
+		gth_image_print_job_run (print_job,
+					 GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
+					 browser);
+	}
+
+	_g_object_list_unref (file_list);
+	_gtk_tree_path_list_free (items);
 }
diff --git a/extensions/image_print/gth-image-info.c b/extensions/image_print/gth-image-info.c
new file mode 100644
index 0000000..35dc099
--- /dev/null
+++ b/extensions/image_print/gth-image-info.c
@@ -0,0 +1,130 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2009 The Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+
+#include <config.h>
+#include "gth-image-info.h"
+
+
+GthImageInfo *
+gth_image_info_new (GthFileData *file_data)
+{
+	GthImageInfo *image_info;
+
+	image_info = g_new0 (GthImageInfo, 1);
+	image_info->ref_count = 1;
+	image_info->file_data = g_object_ref (file_data);
+	image_info->pixbuf = NULL;
+	image_info->thumbnail = NULL;
+	image_info->thumbnail_active = NULL;
+	image_info->width = 0.0;
+	image_info->height = 0.0;
+	image_info->scale_x = 0.0;
+	image_info->scale_y = 0.0;
+	image_info->trans_x = 0.0;
+	image_info->trans_y = 0.0;
+	image_info->rotate = 0;
+	image_info->zoom = 0.0;
+	image_info->min_x = 0.0;
+	image_info->min_y = 0.0;
+	image_info->max_x = 0.0;
+	image_info->max_y = 0.0;
+	image_info->comment_height = 0.0;
+	image_info->print_comment = FALSE;
+
+	return image_info;
+}
+
+
+GthImageInfo *
+gth_image_info_ref (GthImageInfo *image_info)
+{
+	image_info->ref_count++;
+	return image_info;
+}
+
+
+void
+gth_image_info_unref (GthImageInfo *image_info)
+{
+	image_info->ref_count--;
+	if (image_info->ref_count > 0)
+		return;
+
+	_g_object_unref (image_info->file_data);
+	_g_object_unref (image_info->pixbuf);
+	_g_object_unref (image_info->thumbnail);
+	_g_object_unref (image_info->thumbnail_active);
+	g_free (image_info);
+}
+
+
+void
+gth_image_info_rotate (GthImageInfo *image_info,
+		       int           angle)
+{
+	GdkPixbuf    *tmp_pixbuf;
+	GthTransform  transform;
+
+	transform = GTH_TRANSFORM_NONE;
+	switch (angle) {
+	case 90:
+		transform = GTH_TRANSFORM_ROTATE_90;
+		break;
+	case 180:
+		transform = GTH_TRANSFORM_ROTATE_180;
+		break;
+	case 270:
+		transform = GTH_TRANSFORM_ROTATE_270;
+		break;
+	default:
+		break;
+	}
+
+	if (transform == GTH_TRANSFORM_NONE)
+		return;
+
+	tmp_pixbuf = image_info->pixbuf;
+	if (tmp_pixbuf != NULL) {
+		image_info->pixbuf = _gdk_pixbuf_transform (tmp_pixbuf, transform);
+		g_object_unref (tmp_pixbuf);
+	}
+
+	tmp_pixbuf = image_info->thumbnail;
+	if (tmp_pixbuf != NULL) {
+		image_info->thumbnail = _gdk_pixbuf_transform (tmp_pixbuf, transform);
+		g_object_unref (tmp_pixbuf);
+	}
+
+	tmp_pixbuf = image_info->thumbnail_active;
+	if (tmp_pixbuf != NULL) {
+		image_info->thumbnail_active = _gdk_pixbuf_transform (tmp_pixbuf, transform);
+		g_object_unref (tmp_pixbuf);
+	}
+
+	image_info->rotate = (image_info->rotate + angle) % 360;
+	if ((angle == 90) || (angle == 270)) {
+		int tmp = image_info->pixbuf_width;
+		image_info->pixbuf_width = image_info->pixbuf_height;
+		image_info->pixbuf_height = tmp;
+	}
+}
diff --git a/extensions/image_print/gth-image-info.h b/extensions/image_print/gth-image-info.h
new file mode 100644
index 0000000..07dacb4
--- /dev/null
+++ b/extensions/image_print/gth-image-info.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2009 The Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GTH_IMAGE_INFO_H
+#define GTH_IMAGE_INFO_H
+
+#include <gtk/gtk.h>
+#include <gthumb.h>
+
+G_BEGIN_DECLS
+
+typedef struct {
+	int           ref_count;
+	GthFileData  *file_data;
+	int           pixbuf_width;
+	int           pixbuf_height;
+	GdkPixbuf    *pixbuf;
+	GdkPixbuf    *thumbnail;
+	GdkPixbuf    *thumbnail_active;
+	int           n_page;
+	double        width, height;
+	double        scale_x, scale_y;
+	double        trans_x, trans_y;
+	int           rotate;
+	double        zoom;
+	double        min_x, min_y;
+	double        max_x, max_y;
+	double        comment_height;
+	gboolean      print_comment;
+} GthImageInfo;
+
+GthImageInfo *  gth_image_info_new    (GthFileData  *file_data);
+GthImageInfo *  gth_image_info_ref    (GthImageInfo *image_info);
+void            gth_image_info_unref  (GthImageInfo *image_info);
+void            gth_image_info_rotate (GthImageInfo *image_info,
+				       int           angle);
+
+G_END_DECLS
+
+#endif /* GTH_IMAGE_INFO_H */
diff --git a/extensions/image_print/gth-image-print-job.c b/extensions/image_print/gth-image-print-job.c
index 83adf52..b60fad7 100644
--- a/extensions/image_print/gth-image-print-job.c
+++ b/extensions/image_print/gth-image-print-job.c
@@ -21,10 +21,13 @@
  */
 
 #include <config.h>
+#include <math.h>
 #include <stdlib.h>
 #include <gtk/gtk.h>
 #include <gthumb.h>
+#include "gth-image-info.h"
 #include "gth-image-print-job.h"
+#include "gth-load-image-info-task.h"
 
 
 #define GET_WIDGET(name) _gtk_builder_get_widget (self->priv->builder, (name))
@@ -33,77 +36,29 @@
 static gpointer parent_class = NULL;
 
 
-typedef struct {
-	GthFileData *file_data;
-	char        *comment;
-	int          pixbuf_width;
-	int          pixbuf_height;
-	GdkPixbuf   *thumbnail;
-	GdkPixbuf   *thumbnail_active;
-	double       width, height;
-	double       scale_x, scale_y;
-	double       trans_x, trans_y;
-	int          rotate;
-	double       zoom;
-	double       min_x, min_y;
-	double       max_x, max_y;
-	double       comment_height;
-	gboolean     print_comment;
-} ImageInfo;
-
-
-static ImageInfo *
-image_info_new (GthFileData *file_data)
-{
-	ImageInfo *image = g_new0 (ImageInfo, 1);
-
-	image->file_data = g_object_ref (file_data);
-	image->comment = NULL;
-	image->thumbnail = NULL;
-	image->thumbnail_active = NULL;
-	image->width = 0.0;
-	image->height = 0.0;
-	image->scale_x = 0.0;
-	image->scale_y = 0.0;
-	image->trans_x = 0.0;
-	image->trans_y = 0.0;
-	image->rotate = 0;
-	image->zoom = 0.0;
-	image->min_x = 0.0;
-	image->min_y = 0.0;
-	image->max_x = 0.0;
-	image->max_y = 0.0;
-	image->comment_height = 0.0;
-	image->print_comment = FALSE;
-
-	return image;
-}
-
-
-static void
-image_info_free (ImageInfo *image)
-{
-	g_return_if_fail (image != NULL);
-
-	g_object_unref (image->file_data);
-	g_free (image->comment);
-	_g_object_unref (image->thumbnail);
-	_g_object_unref (image->thumbnail_active);
-	g_free (image);
-}
-
-
-
 struct _GthImagePrintJobPrivate {
-	GtkWindow          *parent;
+	GtkPrintOperationAction  action;
+	GthBrowser         *browser;
 	GtkPrintOperation  *print_operation;
 	GtkBuilder         *builder;
-	ImageInfo         **images;
+
+	/* settings */
+
+	GthImageInfo      **images;
 	int                 n_images;
-	int                 images_per_page;
+	int                 requested_images_per_page;
 	gboolean	    auto_sizing;
+	int                 image_width;
+	int                 image_height;
+	GtkPageSetup       *page_setup;
+
+	/* layout info */
+
+	GthTask            *task;
+	int                 real_images_per_page;
 	double              max_image_width;
 	double		    max_image_height;
+	int                 n_pages;
 };
 
 
@@ -115,11 +70,13 @@ gth_image_print_job_finalize (GObject *base)
 
 	self = GTH_IMAGE_PRINT_JOB (base);
 
+	_g_object_unref (self->priv->task);
 	_g_object_unref (self->priv->print_operation);
 	_g_object_unref (self->priv->builder);
 	for (i = 0; i < self->priv->n_images; i++)
-		image_info_free (self->priv->images[i]);
+		gth_image_info_unref (self->priv->images[i]);
 	g_free (self->priv->images);
+	_g_object_unref (self->priv->page_setup);
 
 	G_OBJECT_CLASS (parent_class)->finalize (base);
 }
@@ -143,6 +100,8 @@ gth_image_print_job_init (GthImagePrintJob *self)
 {
 	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_IMAGE_PRINT_JOB, GthImagePrintJobPrivate);
 	self->priv->builder = NULL;
+	self->priv->task = NULL;
+	self->priv->page_setup = NULL;
 }
 
 
@@ -202,22 +161,180 @@ operation_update_custom_widget_cb (GtkPrintOperation *operation,
 				   GtkPrintSettings  *settings,
 				   gpointer           user_data)
 {
-	/* FIXME */
+}
+
+
+enum {
+	IMAGES_PER_PAGE_1,
+	IMAGES_PER_PAGE_2,
+	IMAGES_PER_PAGE_4,
+	IMAGES_PER_PAGE_8,
+	IMAGES_PER_PAGE_16,
+	N_IMAGES_PER_PAGE
+};
+static int n_rows_for_ipp[N_IMAGES_PER_PAGE] = { 1, 2, 2, 4, 4 };
+static int n_cols_for_ipp[N_IMAGES_PER_PAGE] = { 1, 1, 2, 2, 4 };
+#define DEFAULT_PADDING 20.0
+
+
+static double
+_log2 (double x)
+{
+	return log (x) / log (2);
 }
 
 
 static void
 print_operation_begin_print_cb (GtkPrintOperation *operation,
 				GtkPrintContext   *context,
-				GthImagePrintJob  *self)
+				gpointer           user_data)
 {
-	gtk_print_operation_set_n_pages (operation, 1);
+	GthImagePrintJob *self = user_data;
+	GtkPageSetup     *setup;
+	gdouble           page_width;
+	gdouble           page_height;
+	double            x_padding;
+	double            y_padding;
+	int               rows;
+	int               cols;
+	int               current_page;
+	int               current_row;
+	int               current_col;
+	int               i;
 
-	/* FIXME
-	gtk_print_operation_set_n_pages (operation, (pci->n_images + pci->images_per_page - 1) / pci->images_per_page);
-	gtk_print_operation_set_default_page_setup (operation, pci->page_setup);
-	gtk_print_operation_set_show_progress (operation, TRUE);
-	*/
+	setup = gtk_print_context_get_page_setup (context);
+	page_width = gtk_print_context_get_width (context);
+	page_height = gtk_print_context_get_height (context);
+	x_padding = DEFAULT_PADDING;
+	y_padding = DEFAULT_PADDING;
+
+	if (self->priv->auto_sizing) {
+		int idx;
+
+		self->priv->real_images_per_page = self->priv->requested_images_per_page;
+
+		idx = (int) floor (_log2 (self->priv->real_images_per_page) + 0.5);
+		rows = n_rows_for_ipp[idx];
+		cols = n_cols_for_ipp[idx];
+		if ((gtk_page_setup_get_orientation (setup) == GTK_PAGE_ORIENTATION_LANDSCAPE)
+		    || (gtk_page_setup_get_orientation (setup) == GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE))
+		{
+			int tmp = rows;
+			rows = cols;
+			cols = tmp;
+		}
+
+		self->priv->max_image_width = (page_width - ((cols - 1) * x_padding)) / cols;
+		self->priv->max_image_height = (page_height - ((rows - 1) * y_padding)) / rows;
+	}
+	else {
+		double image_width;
+		double image_height;
+		double tmp_cols;
+		double tmp_rows;
+
+		image_width = self->priv->image_width;
+		image_height = self->priv->image_height;
+		tmp_cols = (int) floor ((page_width + x_padding) / (image_height + x_padding));
+		tmp_rows = (int) floor ((page_height + y_padding) / (image_width + y_padding));
+		cols = (int) floor ((page_width + x_padding) / (image_width + x_padding));
+		rows = (int) floor ((page_height + y_padding) / (image_height + y_padding));
+
+		if ((tmp_rows * tmp_cols > cols * rows)
+		    && (image_height <= page_width)
+		    && (image_width <= page_width))
+		{
+			double tmp = image_width;
+			image_width = image_height;
+			image_height = tmp;
+			rows = tmp_rows;
+			cols = tmp_cols;
+		}
+
+		if (rows == 0) {
+			rows = 1;
+			image_height = page_height - y_padding;
+		}
+
+		if (cols == 0) {
+			cols = 1;
+			image_width = page_width - x_padding;
+		}
+
+		self->priv->real_images_per_page = rows * cols;
+
+		if (cols > 1)
+			x_padding = (page_width - (cols * image_width)) / (cols - 1);
+		else
+			x_padding = page_width - image_width;
+
+		if (rows > 1)
+			y_padding = (page_height - (rows * image_height)) / (rows - 1);
+		else
+			y_padding = page_height - image_height;
+
+		self->priv->max_image_width = image_width;
+		self->priv->max_image_height = image_height;
+	}
+
+	self->priv->n_pages = MAX ((int) ceil ((double) self->priv->n_images / self->priv->real_images_per_page), 1);
+	gtk_print_operation_set_n_pages (operation, self->priv->n_pages);
+
+	current_page = 0;
+	current_row = 1;
+	current_col = 1;
+	for (i = 0; i < self->priv->n_images; i++) {
+		GthImageInfo *image_info = self->priv->images[i];
+		double        max_image_width;
+		double        max_image_height;
+		double        image_width;
+		double        image_height;
+		double        factor;
+
+		image_info->n_page = current_page;
+
+		gth_image_info_rotate (image_info, (360 - image_info->rotate) % 360);
+		if (((self->priv->max_image_width > self->priv->max_image_height)
+		     && (image_info->pixbuf_width < image_info->pixbuf_height))
+		    || ((self->priv->max_image_width < self->priv->max_image_height)
+			&& (image_info->pixbuf_width > image_info->pixbuf_height)))
+		{
+			gth_image_info_rotate (image_info, 270);
+		}
+
+		image_info->zoom = 1.0;
+		image_info->min_x = (current_col - 1) * (self->priv->max_image_width + x_padding);
+		image_info->min_y = (current_row - 1) * (self->priv->max_image_height + y_padding);
+		image_info->max_x = image_info->min_x + self->priv->max_image_width;
+		image_info->max_y = image_info->min_y + self->priv->max_image_height;
+
+		current_col++;
+		if (current_col > cols) {
+			current_row++;
+			current_col = 1;
+		}
+
+		max_image_width = self->priv->max_image_width;
+		max_image_height = self->priv->max_image_height;
+
+		/* FIXME: change max_image_width/max_image_height to make space to the comment */
+
+		image_width = (double) image_info->pixbuf_width;
+		image_height = (double) image_info->pixbuf_height;
+		factor = MIN (max_image_width / image_width, max_image_height / image_height);
+		image_info->width = image_width * factor;
+		image_info->height = image_height * factor;
+		image_info->trans_x = image_info->min_x + ((max_image_width - image_info->width) / 2);
+		image_info->trans_y = image_info->min_y + ((max_image_height - image_info->height) / 2);
+		image_info->scale_x = image_info->width * image_info->zoom;
+		image_info->scale_y = image_info->height * image_info->zoom;
+
+		if ((i + 1 < self->priv->n_images) && ((i + 1) % self->priv->real_images_per_page == 0)) {
+			current_page++;
+			current_col = 1;
+			current_row = 1;
+		}
+	}
 }
 
 
@@ -227,14 +344,65 @@ print_operation_draw_page_cb (GtkPrintOperation *operation,
 			      int                page_nr,
 			      GthImagePrintJob  *self)
 {
+	cairo_t *cr;
+	int      i;
+
+	cr = gtk_print_context_get_cairo_context (context);
+
+	for (i = 0; i < self->priv->n_images; i++) {
+		GthImageInfo    *image_info = self->priv->images[i];
+		double           scale_factor;
+		GdkPixbuf       *pixbuf;
+
+		if (image_info->n_page != page_nr)
+			continue;
+
+#if 0
+		cairo_set_source_rgb (cr, 0, 0, 0);
+		cairo_rectangle (cr,
+				 image_info->trans_x,
+				 image_info->trans_y,
+				 image_info->width,
+				 image_info->height);
+		cairo_stroke (cr);
+#endif
+
+		/* For higher-resolution images, cairo will render the bitmaps at a miserable
+		 * 72 dpi unless we apply a scaling factor. This scaling boosts the output
+		 * to 300 dpi (if required). */
+
+		scale_factor = MIN (image_info->pixbuf_width / image_info->scale_x, gtk_print_context_get_dpi_x (context) / 72.0);
+		pixbuf = gdk_pixbuf_scale_simple (image_info->pixbuf,
+						  image_info->scale_x * scale_factor,
+						  image_info->scale_y * scale_factor,
+						  GDK_INTERP_BILINEAR);
+		cairo_save (cr);
+		gdk_cairo_set_source_pixbuf (cr, pixbuf, image_info->trans_x, image_info->trans_y);
+		cairo_rectangle (cr,
+				 image_info->trans_x,
+				 image_info->trans_y,
+				 gdk_pixbuf_get_width (pixbuf),
+				 gdk_pixbuf_get_height (pixbuf));
+		cairo_clip (cr);
+		cairo_paint (cr);
+		cairo_restore (cr);
+
+		g_object_unref (pixbuf);
+	}
+
+#if 0
 	cairo_t        *cr;
 	PangoLayout    *layout;
 	int             y;
 	PangoRectangle  rect;
 
+
 	cr = gtk_print_context_get_cairo_context (context);
 	cairo_set_source_rgb (cr, 0, 0, 0);
-	cairo_rectangle (cr, 0, 0, gtk_print_context_get_width (context), gtk_print_context_get_height (context));
+	cairo_rectangle (cr,
+			 0, 0,
+			 gtk_print_context_get_width (context),
+			 gtk_print_context_get_height (context));
 	cairo_stroke (cr);
 
 	layout = gtk_print_context_create_pango_layout (context);
@@ -273,6 +441,7 @@ print_operation_draw_page_cb (GtkPrintOperation *operation,
 	cairo_fill (cr);
 
 	g_object_unref (layout);
+#endif
 }
 
 
@@ -287,7 +456,7 @@ print_operation_done_cb (GtkPrintOperation       *operation,
 		GError *error = NULL;
 
 		gtk_print_operation_get_error (self->priv->print_operation, &error);
-		_gtk_error_dialog_from_gerror_show (self->priv->parent, _("Could not print"), &error);
+		_gtk_error_dialog_from_gerror_show (GTK_WINDOW (self->priv->browser), _("Could not print"), &error);
 		return;
 	}
 
@@ -296,12 +465,24 @@ print_operation_done_cb (GtkPrintOperation       *operation,
 
 
 GthImagePrintJob *
-gth_image_print_job_new (void)
+gth_image_print_job_new (GList *file_data_list)
 {
 	GthImagePrintJob *self;
+	GList            *scan;
+	int               n;
 
 	self = g_object_new (GTH_TYPE_IMAGE_PRINT_JOB, NULL);
 
+	self->priv->n_images = g_list_length (file_data_list);
+	self->priv->images = g_new (GthImageInfo *, self->priv->n_images + 1);
+	for (scan = file_data_list, n = 0; scan; scan = scan->next)
+		self->priv->images[n++] = gth_image_info_new ((GthFileData *) scan->data);
+	self->priv->images[n] = NULL;
+	self->priv->requested_images_per_page = 4; /* FIXME: set correct default values */
+	self->priv->auto_sizing = TRUE;
+	self->priv->image_width = 0;
+	self->priv->image_height = 0;
+
 	self->priv->print_operation = gtk_print_operation_new ();
 	gtk_print_operation_set_allow_async (self->priv->print_operation, TRUE);
 	gtk_print_operation_set_custom_tab_label (self->priv->print_operation, _("Layout"));
@@ -337,22 +518,43 @@ gth_image_print_job_new (void)
 }
 
 
-void
-gth_image_print_job_run (GthImagePrintJob        *self,
-			 GtkPrintOperationAction  action,
-			 GtkWindow               *parent)
+static void
+load_image_info_task_completed_cb (GthTask  *task,
+				   GError   *error,
+				   gpointer  user_data)
 {
+	GthImagePrintJob        *self = user_data;
 	GtkPrintOperationResult  result;
-	GError                  *error = NULL;
 
-	self->priv->parent = parent;
+	if (error != NULL) {
+		_gtk_error_dialog_from_gerror_show (GTK_WINDOW (self->priv->browser), _("Could not print"), &error);
+		return;
+	}
+
 	result = gtk_print_operation_run (self->priv->print_operation,
-					  action,
-					  parent,
+					  self->priv->action,
+					  GTK_WINDOW (self->priv->browser),
 					  &error);
 	if (result == GTK_PRINT_OPERATION_RESULT_ERROR) {
-		_gtk_error_dialog_from_gerror_show (parent, _("Could not print"), &error);
+		_gtk_error_dialog_from_gerror_show (GTK_WINDOW (self->priv->browser), _("Could not print"), &error);
 		return;
 	}
 }
 
+
+void
+gth_image_print_job_run (GthImagePrintJob        *self,
+			 GtkPrintOperationAction  action,
+			 GthBrowser              *browser)
+{
+	g_return_if_fail (self->priv->task == NULL);
+
+	self->priv->action = action;
+	self->priv->browser = browser;
+	self->priv->task = gth_load_image_info_task_new (self->priv->images, self->priv->n_images);
+	g_signal_connect (self->priv->task,
+			  "completed",
+			  G_CALLBACK (load_image_info_task_completed_cb),
+			  self);
+	gth_browser_exec_task (browser, self->priv->task, FALSE);
+}
diff --git a/extensions/image_print/gth-image-print-job.h b/extensions/image_print/gth-image-print-job.h
index b762254..ffe198d 100644
--- a/extensions/image_print/gth-image-print-job.h
+++ b/extensions/image_print/gth-image-print-job.h
@@ -24,6 +24,7 @@
 #define GTH_IMAGE_PRINT_JOB_H
 
 #include <gtk/gtk.h>
+#include <gthumb.h>
 
 G_BEGIN_DECLS
 
@@ -48,10 +49,10 @@ struct _GthImagePrintJobClass {
 };
 
 GType              gth_image_print_job_get_type (void);
-GthImagePrintJob * gth_image_print_job_new      (void);
+GthImagePrintJob * gth_image_print_job_new      (GList                   *file_data_list);
 void               gth_image_print_job_run      (GthImagePrintJob        *self,
 						 GtkPrintOperationAction  action,
-						 GtkWindow               *parent);
+						 GthBrowser              *browser);
 
 G_END_DECLS
 
diff --git a/extensions/image_print/gth-load-image-info-task.c b/extensions/image_print/gth-load-image-info-task.c
new file mode 100644
index 0000000..2e6b8cd
--- /dev/null
+++ b/extensions/image_print/gth-load-image-info-task.c
@@ -0,0 +1,211 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include "gth-load-image-info-task.h"
+
+
+struct _GthLoadImageInfoTaskPrivate {
+	GthImageInfo   **images;
+	int              n_images;
+	int              current;
+	GthImageLoader  *loader;
+};
+
+
+static gpointer parent_class = NULL;
+
+
+static void
+gth_load_image_info_task_finalize (GObject *object)
+{
+	GthLoadImageInfoTask *self;
+	int                   i;
+
+	self = GTH_LOAD_IMAGE_INFO_TASK (object);
+
+	for (i = 0; i < self->priv->n_images; i++)
+		gth_image_info_unref (self->priv->images[i]);
+	g_free (self->priv->images);
+	g_object_unref (self->priv->loader);
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void load_current_image (GthLoadImageInfoTask *self);
+
+
+static void
+image_loader_ready_cb (GthImageLoader *loader,
+		       GError         *error,
+		       gpointer        user_data)
+{
+	GthLoadImageInfoTask *self = user_data;
+	GdkPixbuf            *pixbuf;
+
+	if (error != NULL) {
+		gth_task_completed (GTH_TASK (self), error);
+		return;
+	}
+
+	pixbuf = gth_image_loader_get_pixbuf (loader);
+	if (pixbuf != NULL) {
+		GthImageInfo *image_info;
+		int           thumb_w, thumb_h;
+
+		image_info = self->priv->images[self->priv->current];
+		image_info->pixbuf = g_object_ref (pixbuf);
+
+		thumb_w = image_info->pixbuf_width = gdk_pixbuf_get_width (pixbuf);
+		thumb_h = image_info->pixbuf_height = gdk_pixbuf_get_height (pixbuf);
+		if (scale_keeping_ratio (&thumb_w, &thumb_h, 128, 128, FALSE))
+			image_info->thumbnail = gdk_pixbuf_scale_simple (pixbuf,
+									 thumb_w,
+									 thumb_h,
+									 GDK_INTERP_BILINEAR);
+		else
+			image_info->thumbnail = g_object_ref (image_info->pixbuf);
+
+		if (image_info->thumbnail != NULL) {
+			image_info->thumbnail_active = gdk_pixbuf_copy (image_info->thumbnail);
+			_gdk_pixbuf_colorshift (image_info->thumbnail_active, image_info->thumbnail_active, 30);
+		}
+	}
+
+	self->priv->current++;
+	load_current_image (self);
+}
+
+
+static void
+load_current_image (GthLoadImageInfoTask *self)
+{
+	GthImageInfo *image_info;
+
+	if (self->priv->current >= self->priv->n_images) {
+		/* FIXME: read the required metadata as well */
+		gth_task_completed (GTH_TASK (self), NULL);
+		return;
+	}
+
+	image_info = self->priv->images[self->priv->current];
+	gth_image_loader_set_file_data (self->priv->loader, image_info->file_data);
+	gth_image_loader_load (self->priv->loader);
+}
+
+
+static void
+gth_load_image_info_task_exec (GthTask *task)
+{
+	GthLoadImageInfoTask *self;
+
+	g_return_if_fail (GTH_IS_LOAD_IMAGE_INFO_TASK (task));
+
+	self = GTH_LOAD_IMAGE_INFO_TASK (task);
+
+	load_current_image (self);
+}
+
+
+static void
+gth_load_image_info_task_cancelled (GthTask *task)
+{
+	/* FIXME */
+}
+
+
+static void
+gth_load_image_info_task_class_init (GthLoadImageInfoTaskClass *klass)
+{
+	GObjectClass *object_class;
+	GthTaskClass *task_class;
+
+	parent_class = g_type_class_peek_parent (klass);
+	g_type_class_add_private (klass, sizeof (GthLoadImageInfoTaskPrivate));
+
+	object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gth_load_image_info_task_finalize;
+
+	task_class = GTH_TASK_CLASS (klass);
+	task_class->exec = gth_load_image_info_task_exec;
+	task_class->cancelled = gth_load_image_info_task_cancelled;
+}
+
+
+static void
+gth_load_image_info_task_init (GthLoadImageInfoTask *self)
+{
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_LOAD_IMAGE_INFO_TASK, GthLoadImageInfoTaskPrivate);
+	self->priv->loader = gth_image_loader_new (FALSE);
+	g_signal_connect (self->priv->loader,
+			  "ready",
+			  G_CALLBACK (image_loader_ready_cb),
+			  self);
+}
+
+
+GType
+gth_load_image_info_task_get_type (void)
+{
+	static GType type = 0;
+
+	if (! type) {
+		GTypeInfo type_info = {
+			sizeof (GthLoadImageInfoTaskClass),
+			NULL,
+			NULL,
+			(GClassInitFunc) gth_load_image_info_task_class_init,
+			NULL,
+			NULL,
+			sizeof (GthLoadImageInfoTask),
+			0,
+			(GInstanceInitFunc) gth_load_image_info_task_init
+		};
+
+		type = g_type_register_static (GTH_TYPE_TASK,
+					       "GthLoadImageInfoTask",
+					       &type_info,
+					       0);
+	}
+
+	return type;
+}
+
+
+GthTask *
+gth_load_image_info_task_new (GthImageInfo **images,
+			      int            n_images)
+{
+	GthLoadImageInfoTask *self;
+	int                   n;
+
+	self = (GthLoadImageInfoTask *) g_object_new (GTH_TYPE_LOAD_IMAGE_INFO_TASK, NULL);
+	self->priv->images = g_new0 (GthImageInfo *, n_images + 1);
+	for (n = 0; n < n_images; n++)
+		self->priv->images[n] = gth_image_info_ref (images[n]);
+	self->priv->images[n] = NULL;
+	self->priv->n_images = n;
+	self->priv->current = 0;
+
+	return (GthTask *) self;
+}
diff --git a/extensions/image_print/gth-load-image-info-task.h b/extensions/image_print/gth-load-image-info-task.h
new file mode 100644
index 0000000..4a47e9b
--- /dev/null
+++ b/extensions/image_print/gth-load-image-info-task.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2009 The Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GTH_LOAD_IMAGE_INFO_TASK_H
+#define GTH_LOAD_IMAGE_INFO_TASK_H
+
+#include <glib.h>
+#include <gthumb.h>
+#include "gth-image-info.h"
+
+G_BEGIN_DECLS
+
+#define GTH_TYPE_LOAD_IMAGE_INFO_TASK            (gth_load_image_info_task_get_type ())
+#define GTH_LOAD_IMAGE_INFO_TASK(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTH_TYPE_LOAD_IMAGE_INFO_TASK, GthLoadImageInfoTask))
+#define GTH_LOAD_IMAGE_INFO_TASK_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GTH_TYPE_LOAD_IMAGE_INFO_TASK, GthLoadImageInfoTaskClass))
+#define GTH_IS_LOAD_IMAGE_INFO_TASK(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTH_TYPE_LOAD_IMAGE_INFO_TASK))
+#define GTH_IS_LOAD_IMAGE_INFO_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTH_TYPE_LOAD_IMAGE_INFO_TASK))
+#define GTH_LOAD_IMAGE_INFO_TASK_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), GTH_TYPE_LOAD_IMAGE_INFO_TASK, GthLoadImageInfoTaskClass))
+
+typedef struct _GthLoadImageInfoTask        GthLoadImageInfoTask;
+typedef struct _GthLoadImageInfoTaskClass   GthLoadImageInfoTaskClass;
+typedef struct _GthLoadImageInfoTaskPrivate GthLoadImageInfoTaskPrivate;
+
+struct _GthLoadImageInfoTask {
+	GthTask __parent;
+	GthLoadImageInfoTaskPrivate *priv;
+};
+
+struct _GthLoadImageInfoTaskClass {
+	GthTaskClass __parent;
+};
+
+GType       gth_load_image_info_task_get_type  (void);
+GthTask *   gth_load_image_info_task_new       (GthImageInfo **images,
+					        int            n_images);
+
+G_END_DECLS
+
+#endif /* GTH_LOAD_IMAGE_INFO_TASK_H */
diff --git a/gthumb/pixbuf-utils.c b/gthumb/pixbuf-utils.c
index bb16c8d..cbe0d1a 100644
--- a/gthumb/pixbuf-utils.c
+++ b/gthumb/pixbuf-utils.c
@@ -81,6 +81,49 @@ _gdk_pixbuf_transform (GdkPixbuf    *src,
 
 
 void
+_gdk_pixbuf_colorshift (GdkPixbuf *dest,
+			GdkPixbuf *src,
+			int        shift)
+{
+	int     i, j;
+	int     width, height, has_alpha, srcrowstride, destrowstride;
+	guchar *target_pixels;
+	guchar *original_pixels;
+	guchar *pixsrc;
+	guchar *pixdest;
+	int     val;
+	guchar  r,g,b;
+
+	has_alpha       = gdk_pixbuf_get_has_alpha (src);
+	width           = gdk_pixbuf_get_width (src);
+	height          = gdk_pixbuf_get_height (src);
+	srcrowstride    = gdk_pixbuf_get_rowstride (src);
+	destrowstride   = gdk_pixbuf_get_rowstride (dest);
+	target_pixels   = gdk_pixbuf_get_pixels (dest);
+	original_pixels = gdk_pixbuf_get_pixels (src);
+
+	for (i = 0; i < height; i++) {
+		pixdest = target_pixels + i*destrowstride;
+		pixsrc  = original_pixels + i*srcrowstride;
+		for (j = 0; j < width; j++) {
+			r            = *(pixsrc++);
+			g            = *(pixsrc++);
+			b            = *(pixsrc++);
+			val          = r + shift;
+			*(pixdest++) = CLAMP (val, 0, 255);
+			val          = g + shift;
+			*(pixdest++) = CLAMP (val, 0, 255);
+			val          = b + shift;
+			*(pixdest++) = CLAMP (val, 0, 255);
+
+			if (has_alpha)
+				*(pixdest++) = *(pixsrc++);
+		}
+	}
+}
+
+
+void
 pixmap_from_xpm (const char **data,
 		 GdkPixmap **pixmap,
 		 GdkBitmap **mask)
diff --git a/gthumb/pixbuf-utils.h b/gthumb/pixbuf-utils.h
index e1d5efb..6cac12a 100644
--- a/gthumb/pixbuf-utils.h
+++ b/gthumb/pixbuf-utils.h
@@ -46,6 +46,9 @@ void        _gdk_pixbuf_hv_gradient           (GdkPixbuf       *pixbuf,
 					       guint32          vcolor2);
 GdkPixbuf * _gdk_pixbuf_transform             (GdkPixbuf       *src,
 					       GthTransform     transform);
+void        _gdk_pixbuf_colorshift            (GdkPixbuf       *dest,
+					       GdkPixbuf       *src,
+					       int              shift);
 gboolean    scale_keeping_ratio_min           (int             *width,
 					       int             *height,
 					       int              min_width,



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]