[gthumb: 112/129] rotate tool: improved crop UI
- From: Paolo Bacchilega <paobac src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gthumb: 112/129] rotate tool: improved crop UI
- Date: Wed, 27 Apr 2011 20:59:47 +0000 (UTC)
commit d71fb97fe6e5bf48813b5489353b6b6be3791bcf
Author: Stefano Pettini <spettini users sourceforge net>
Date: Sun Apr 24 02:11:04 2011 +0100
rotate tool: improved crop UI
extensions/file_tools/data/ui/rotate-options.ui | 88 ++++++++++++--
extensions/file_tools/gdk-pixbuf-rotate.c | 83 ++++++++++++-
extensions/file_tools/gdk-pixbuf-rotate.h | 11 ++-
extensions/file_tools/gth-file-tool-rotate.c | 156 ++++++++++++++++++++---
4 files changed, 302 insertions(+), 36 deletions(-)
---
diff --git a/extensions/file_tools/data/ui/rotate-options.ui b/extensions/file_tools/data/ui/rotate-options.ui
index 019742b..6b539f7 100644
--- a/extensions/file_tools/data/ui/rotate-options.ui
+++ b/extensions/file_tools/data/ui/rotate-options.ui
@@ -207,26 +207,25 @@
</packing>
</child>
<child>
- <object class="GtkFrame" id="frame1">
+ <object class="GtkFrame" id="frame3">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
- <object class="GtkAlignment" id="alignment1">
+ <object class="GtkAlignment" id="alignment3">
<property name="visible">True</property>
<property name="top_padding">6</property>
<property name="left_padding">12</property>
<child>
- <object class="GtkVBox" id="vbox3">
+ <object class="GtkVBox" id="vbox5">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
- <object class="GtkCheckButton" id="high_quality">
- <property name="label" translatable="yes">High _quality</property>
+ <object class="GtkCheckButton" id="auto_crop">
+ <property name="label" translatable="yes">A_uto-crop</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
- <property name="tooltip_text" translatable="yes">Slower but produces better results</property>
<property name="use_underline">True</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
@@ -236,8 +235,8 @@
</packing>
</child>
<child>
- <object class="GtkCheckButton" id="auto_crop">
- <property name="label" translatable="yes">A_uto-crop</property>
+ <object class="GtkCheckButton" id="keep_aspect_ratio">
+ <property name="label" translatable="yes">_Keep aspect ratio</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
@@ -249,6 +248,77 @@
<property name="position">1</property>
</packing>
</child>
+ <child>
+ <object class="GtkHBox" id="crop_p1_hbox">
+ <property name="visible">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="crop_p2_hbox">
+ <property name="visible">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="assisted_crop_label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Assisted crop</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame1">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox3">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="high_quality">
+ <property name="label" translatable="yes">High _quality</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="tooltip_text" translatable="yes">Slower but produces better results</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
</object>
</child>
</object>
@@ -266,7 +336,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">2</property>
+ <property name="position">3</property>
</packing>
</child>
</object>
diff --git a/extensions/file_tools/gdk-pixbuf-rotate.c b/extensions/file_tools/gdk-pixbuf-rotate.c
index aab98b2..43c18bf 100644
--- a/extensions/file_tools/gdk-pixbuf-rotate.c
+++ b/extensions/file_tools/gdk-pixbuf-rotate.c
@@ -24,6 +24,8 @@
#include "gdk-pixbuf-rotate.h"
+#define PI 3.1415926535
+
#define ROUND(x) ((int) floor ((x) + 0.5))
#define INTERPOLATE(v00, v10, v01, v11, fx, fy) ((v00) + ((v10) - (v00)) * (fx) + ((v01) - (v00)) * (fy) + ((v00) - (v10) - (v01) + (v11)) * (fx) * (fy))
@@ -43,23 +45,94 @@
void
+_gdk_pixbuf_rotate_get_cropping_parameters (GdkPixbuf *src_pixbuf,
+ double angle,
+ double *alpha_plus_beta,
+ double *gamma_plus_delta)
+{
+ double angle_rad;
+ double cos_angle, sin_angle;
+ double src_width, src_height;
+ double px, py, pz;
+
+ angle = CLAMP (angle, -90.0, 90.0);
+
+ angle_rad = fabs (angle) / 180.0 * PI;
+
+ cos_angle = cos (angle_rad);
+ sin_angle = sin (angle_rad);
+
+ src_width = gdk_pixbuf_get_width (src_pixbuf) - 1;
+ src_height = gdk_pixbuf_get_height (src_pixbuf) - 1;
+
+ px = cos_angle * src_width - sin_angle * src_height;
+ py = sin_angle * src_width + cos_angle * src_height;
+ pz = - sin_angle * src_width + cos_angle * src_height;
+
+ *alpha_plus_beta = 1.0 + (px * src_height) / (py * src_width);
+ *gamma_plus_delta = 1.0 + (pz * src_width) / (px * src_height);
+}
+
+
+void
_gdk_pixbuf_rotate_get_cropping_region (GdkPixbuf *src_pixbuf,
double angle,
double alpha,
double beta,
+ double gamma,
+ double delta,
int *x1,
- int *x2,
int *y1,
+ int *x2,
int *y2)
{
+ double angle_rad;
+ double cos_angle, sin_angle;
+ double src_width, src_height;
+ double xx1, yy1, xx2, yy2;
+
+ angle = CLAMP (angle, -90.0, 90.0);
+ alpha = CLAMP (alpha, 0.0, 1.0);
+ beta = CLAMP (beta, 0.0, 1.0);
+ gamma = CLAMP (gamma, 0.0, 1.0);
+ delta = CLAMP (delta, 0.0, 1.0);
+
+ angle_rad = fabs (angle) / 180.0 * PI;
+
+ cos_angle = cos (angle_rad);
+ sin_angle = sin (angle_rad);
+
+ src_width = gdk_pixbuf_get_width (src_pixbuf) - 1;
+ src_height = gdk_pixbuf_get_height (src_pixbuf) - 1;
+
+ if (src_width > src_height) {
+ xx1 = alpha * src_width * cos_angle + src_height * sin_angle;
+ yy1 = alpha * src_width * sin_angle;
+
+ xx2 = (1 - beta) * src_width * cos_angle;
+ yy2 = (1 - beta) * src_width * sin_angle + src_height * cos_angle;
+ }
+ else {
+ xx1 = gamma * src_height * sin_angle;
+ yy1 = (1 - gamma) * src_height * cos_angle;
+
+ xx2 = (1 - delta) * src_height * sin_angle + src_width * cos_angle;
+ yy2 = delta * src_height * cos_angle + src_width * sin_angle;
+ }
+
+ *x1 = ROUND (MIN (xx1, xx2));
+ *y1 = ROUND (MIN (yy1, yy2));
+
+ *x2 = ROUND (MAX (xx1, xx2));
+ *y2 = ROUND (MAX (yy1, yy2));
}
static GdkPixbuf*
rotate (GdkPixbuf *src_pixbuf,
double angle,
- gint high_quality)
+ gboolean high_quality)
{
const guchar R0 = 0;
const guchar G0 = 0;
@@ -86,7 +159,9 @@ rotate (GdkPixbuf *src_pixbuf,
guchar g00, g01, g10, g11;
guchar b00, b01, b10, b11;
- angle_rad = angle / 180.0 * 3.1415926535;
+ angle = CLAMP (angle, -90.0, 90.0);
+
+ angle_rad = angle / 180.0 * PI;
cos_angle = cos (angle_rad);
sin_angle = sin (angle_rad);
@@ -168,7 +243,7 @@ rotate (GdkPixbuf *src_pixbuf,
GdkPixbuf*
_gdk_pixbuf_rotate (GdkPixbuf *src_pixbuf,
double angle,
- gint high_quality)
+ gboolean high_quality)
{
GdkPixbuf *new_pixbuf;
diff --git a/extensions/file_tools/gdk-pixbuf-rotate.h b/extensions/file_tools/gdk-pixbuf-rotate.h
index bf1a481..9244a7d 100644
--- a/extensions/file_tools/gdk-pixbuf-rotate.h
+++ b/extensions/file_tools/gdk-pixbuf-rotate.h
@@ -28,18 +28,25 @@
G_BEGIN_DECLS
+void _gdk_pixbuf_rotate_get_cropping_parameters (GdkPixbuf *src_pixbuf,
+ double angle,
+ double *alpha_plus_beta,
+ double *gamma_plus_delta);
+
void _gdk_pixbuf_rotate_get_cropping_region (GdkPixbuf *src_pixbuf,
double angle,
double alpha,
double beta,
+ double gamma,
+ double delta,
int *x1,
- int *x2,
int *y1,
+ int *x2,
int *y2);
GdkPixbuf* _gdk_pixbuf_rotate (GdkPixbuf *src_pixbuf,
double angle,
- gint high_quality);
+ gboolean high_quality);
G_END_DECLS
diff --git a/extensions/file_tools/gth-file-tool-rotate.c b/extensions/file_tools/gth-file-tool-rotate.c
index 7bfb152..fe390e5 100644
--- a/extensions/file_tools/gth-file-tool-rotate.c
+++ b/extensions/file_tools/gth-file-tool-rotate.c
@@ -45,8 +45,12 @@ struct _GthFileToolRotatePrivate {
GtkAdjustment *rotation_angle_adj;
GtkWidget *high_quality;
GtkWidget *auto_crop;
- GthImageSelector *selector;
- guint selector_point;
+ GtkWidget *keep_aspect_ratio;
+ GtkAdjustment *crop_p1_adj;
+ GtkAdjustment *crop_p2_adj;
+ GthImageSelector *selector_crop;
+ GthImageSelector *selector_align;
+ guint selector_align_point;
guint apply_event;
};
@@ -74,13 +78,13 @@ get_1_button_clicked_cb (GtkButton *button,
GtkWidget *viewer_page;
GtkWidget *viewer;
- self->priv->selector_point = 1;
+ self->priv->selector_align_point = 1;
window = gth_file_tool_get_window (GTH_FILE_TOOL (self));
viewer_page = gth_browser_get_viewer_page (GTH_BROWSER (window));
viewer = gth_image_viewer_page_get_image_viewer (GTH_IMAGE_VIEWER_PAGE (viewer_page));
- gth_image_viewer_set_tool (GTH_IMAGE_VIEWER (viewer), (GthImageViewerTool *) self->priv->selector);
+ gth_image_viewer_set_tool (GTH_IMAGE_VIEWER (viewer), (GthImageViewerTool *) self->priv->selector_align);
}
@@ -92,13 +96,13 @@ get_2_button_clicked_cb (GtkButton *button,
GtkWidget *viewer_page;
GtkWidget *viewer;
- self->priv->selector_point = 2;
+ self->priv->selector_align_point = 2;
window = gth_file_tool_get_window (GTH_FILE_TOOL (self));
viewer_page = gth_browser_get_viewer_page (GTH_BROWSER (window));
viewer = gth_image_viewer_page_get_image_viewer (GTH_IMAGE_VIEWER_PAGE (viewer_page));
- gth_image_viewer_set_tool (GTH_IMAGE_VIEWER (viewer), (GthImageViewerTool *) self->priv->selector);
+ gth_image_viewer_set_tool (GTH_IMAGE_VIEWER (viewer), (GthImageViewerTool *) self->priv->selector_align);
}
@@ -155,6 +159,79 @@ cancel_button_clicked_cb (GtkButton *button,
}
+static void
+update_crop_region (gpointer user_data)
+{
+ GthFileToolRotate *self = user_data;
+ GtkWidget *window;
+ GtkWidget *viewer_page;
+ GtkWidget *viewer;
+ double rotation_angle;
+ gboolean auto_crop;
+ gboolean keep_aspect_ratio;
+ double crop_alpha, crop_beta, crop_alpha_plus_beta;
+ double crop_gamma, crop_delta, crop_gamma_plus_delta;
+ int crop_x1, crop_y1;
+ int crop_x2, crop_y2;
+
+ window = gth_file_tool_get_window (GTH_FILE_TOOL (self));
+ viewer_page = gth_browser_get_viewer_page (GTH_BROWSER (window));
+ viewer = gth_image_viewer_page_get_image_viewer (GTH_IMAGE_VIEWER_PAGE (viewer_page));
+
+ auto_crop = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->priv->auto_crop));
+
+ if (auto_crop) {
+
+ gtk_widget_set_sensitive (GTK_WIDGET (self->priv->keep_aspect_ratio), TRUE);
+
+ rotation_angle = gtk_adjustment_get_value (self->priv->rotation_angle_adj);
+ keep_aspect_ratio = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->priv->keep_aspect_ratio));
+
+ if (keep_aspect_ratio) {
+
+ gtk_widget_set_sensitive (GET_WIDGET ("crop_p1_hbox"), FALSE);
+ gtk_widget_set_sensitive (GET_WIDGET ("crop_p2_hbox"), FALSE);
+
+ _gdk_pixbuf_rotate_get_cropping_parameters (self->priv->src_pixbuf, rotation_angle,
+ &crop_alpha_plus_beta, &crop_gamma_plus_delta);
+
+ crop_alpha = crop_alpha_plus_beta / 2.0;
+ crop_beta = crop_alpha_plus_beta / 2.0;
+ crop_gamma = crop_gamma_plus_delta / 2.0;
+ crop_delta = crop_gamma_plus_delta / 2.0;
+
+ printf("%f, %f\n", crop_alpha_plus_beta, crop_gamma_plus_delta);
+ }
+ else {
+ gtk_widget_set_sensitive (GET_WIDGET ("crop_p1_hbox"), TRUE);
+ gtk_widget_set_sensitive (GET_WIDGET ("crop_p2_hbox"), TRUE);
+
+ crop_alpha = gtk_adjustment_get_value (self->priv->crop_p1_adj);
+ crop_beta = gtk_adjustment_get_value (self->priv->crop_p2_adj);
+ crop_gamma = crop_alpha;
+ crop_delta = crop_beta;
+ }
+
+ _gdk_pixbuf_rotate_get_cropping_region (self->priv->src_pixbuf, rotation_angle,
+ crop_alpha, crop_beta, crop_gamma, crop_delta,
+ &crop_x1, &crop_y1, &crop_x2, &crop_y2);
+
+ gth_image_viewer_set_tool (GTH_IMAGE_VIEWER (viewer), (GthImageViewerTool *) self->priv->selector_crop);
+
+ gth_image_selector_set_selection_pos (self->priv->selector_crop, crop_x1, crop_y1);
+ gth_image_selector_set_selection_width (self->priv->selector_crop, crop_x2 - crop_x1);
+ gth_image_selector_set_selection_height (self->priv->selector_crop, crop_y2 - crop_y1);
+ }
+ else {
+ gth_image_viewer_set_tool (GTH_IMAGE_VIEWER (viewer), NULL);
+
+ gtk_widget_set_sensitive (GTK_WIDGET (self->priv->keep_aspect_ratio), FALSE);
+ gtk_widget_set_sensitive (GET_WIDGET ("crop_p1_hbox"), FALSE);
+ gtk_widget_set_sensitive (GET_WIDGET ("crop_p2_hbox"), FALSE);
+ }
+}
+
+
static gboolean
apply_cb (gpointer user_data)
{
@@ -162,9 +239,8 @@ apply_cb (gpointer user_data)
GtkWidget *window;
GtkWidget *viewer_page;
double rotation_angle;
- gint high_quality;
- gint auto_crop;
-
+ gboolean high_quality;
+
if (self->priv->apply_event != 0) {
g_source_remove (self->priv->apply_event);
self->priv->apply_event = 0;
@@ -175,18 +251,27 @@ apply_cb (gpointer user_data)
rotation_angle = gtk_adjustment_get_value (self->priv->rotation_angle_adj);
high_quality = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->priv->high_quality));
- auto_crop = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->priv->auto_crop));
_g_object_unref (self->priv->dest_pixbuf);
self->priv->dest_pixbuf = _gdk_pixbuf_rotate (self->priv->src_pixbuf, rotation_angle, high_quality);
gth_image_viewer_page_set_pixbuf (GTH_IMAGE_VIEWER_PAGE (viewer_page), self->priv->dest_pixbuf, FALSE);
+
+ update_crop_region (user_data);
return FALSE;
}
static void
+crop_parameters_changed_cb (GtkAdjustment *adj,
+ GthFileToolRotate *self)
+{
+ update_crop_region (self);
+}
+
+
+static void
value_changed_cb (GtkAdjustment *adj,
GthFileToolRotate *self)
{
@@ -208,7 +293,7 @@ selector_selected_cb (GthImageSelector *selector,
GtkWidget *viewer_page;
GtkWidget *viewer;
- self->priv->selector_point = 0;
+ self->priv->selector_align_point = 0;
window = gth_file_tool_get_window (GTH_FILE_TOOL (self));
viewer_page = gth_browser_get_viewer_page (GTH_BROWSER (window));
@@ -224,11 +309,11 @@ selector_motion_notify_cb (GthImageSelector *selector,
int y,
GthFileToolRotate *self)
{
- if (self->priv->selector_point == 1) {
+ if (self->priv->selector_align_point == 1) {
gtk_spin_button_set_value (GTK_SPIN_BUTTON (GET_WIDGET ("p1_x_spinbutton")), (double) x);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (GET_WIDGET ("p1_y_spinbutton")), (double) y);
}
- else if (self->priv->selector_point == 2) {
+ else if (self->priv->selector_align_point == 2) {
gtk_spin_button_set_value (GTK_SPIN_BUTTON (GET_WIDGET ("p2_x_spinbutton")), (double) x);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (GET_WIDGET ("p2_y_spinbutton")), (double) y);
}
@@ -277,10 +362,22 @@ gth_file_tool_rotate_get_options (GthFileTool *base)
self->priv->high_quality = _gtk_builder_get_widget (self->priv->builder, "high_quality");
self->priv->auto_crop = _gtk_builder_get_widget (self->priv->builder, "auto_crop");
- self->priv->selector = (GthImageSelector *) gth_image_selector_new (GTH_IMAGE_VIEWER (viewer), GTH_SELECTOR_TYPE_POINT);
+ self->priv->keep_aspect_ratio = _gtk_builder_get_widget (self->priv->builder, "keep_aspect_ratio");
+
+ self->priv->crop_p1_adj = gimp_scale_entry_new (GET_WIDGET ("crop_p1_hbox"),
+ GTK_LABEL (GET_WIDGET ("assisted_crop_label")),
+ 1.0, 0.0, 1.0, 0.01, 0.1, 2);
- gth_image_selector_set_mask_visible (self->priv->selector, TRUE);
- self->priv->selector_point = 0;
+ self->priv->crop_p2_adj = gimp_scale_entry_new (GET_WIDGET ("crop_p2_hbox"),
+ GTK_LABEL (GET_WIDGET ("assisted_crop_label")),
+ 1.0, 0.0, 1.0, 0.01, 0.1, 2);
+
+ self->priv->selector_crop = (GthImageSelector *) gth_image_selector_new (GTH_IMAGE_VIEWER (viewer), GTH_SELECTOR_TYPE_REGION);
+ self->priv->selector_align = (GthImageSelector *) gth_image_selector_new (GTH_IMAGE_VIEWER (viewer), GTH_SELECTOR_TYPE_POINT);
+
+ gth_image_selector_set_mask_visible (self->priv->selector_crop, TRUE);
+ gth_image_selector_set_mask_visible (self->priv->selector_align, TRUE);
+ self->priv->selector_align_point = 0;
g_signal_connect (GET_WIDGET ("apply_button"),
"clicked",
@@ -310,6 +407,14 @@ gth_file_tool_rotate_get_options (GthFileTool *base)
"value-changed",
G_CALLBACK (value_changed_cb),
self);
+ g_signal_connect (G_OBJECT (self->priv->crop_p1_adj),
+ "value-changed",
+ G_CALLBACK (crop_parameters_changed_cb),
+ self);
+ g_signal_connect (G_OBJECT (self->priv->crop_p2_adj),
+ "value-changed",
+ G_CALLBACK (crop_parameters_changed_cb),
+ self);
g_signal_connect (G_OBJECT (self->priv->high_quality),
"toggled",
G_CALLBACK (value_changed_cb),
@@ -318,14 +423,21 @@ gth_file_tool_rotate_get_options (GthFileTool *base)
"toggled",
G_CALLBACK (value_changed_cb),
self);
- g_signal_connect (self->priv->selector,
+ g_signal_connect (G_OBJECT (self->priv->keep_aspect_ratio),
+ "toggled",
+ G_CALLBACK (crop_parameters_changed_cb),
+ self);
+ g_signal_connect (self->priv->selector_align,
"selected",
G_CALLBACK (selector_selected_cb),
self);
- g_signal_connect (self->priv->selector,
+ g_signal_connect (self->priv->selector_align,
"motion_notify",
G_CALLBACK (selector_motion_notify_cb),
self);
+
+ update_crop_region (self);
+
return options;
}
@@ -353,12 +465,14 @@ gth_file_tool_rotate_destroy_options (GthFileTool *base)
_g_object_unref (self->priv->src_pixbuf);
_g_object_unref (self->priv->dest_pixbuf);
_g_object_unref (self->priv->builder);
- _g_object_unref (self->priv->selector);
+ _g_object_unref (self->priv->selector_crop);
+ _g_object_unref (self->priv->selector_align);
self->priv->src_pixbuf = NULL;
self->priv->dest_pixbuf = NULL;
self->priv->builder = NULL;
- self->priv->selector = NULL;
- self->priv->selector_point = 0;
+ self->priv->selector_crop = NULL;
+ self->priv->selector_align = NULL;
+ self->priv->selector_align_point = 0;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]