Evince
Evince is a document viewer capable of displaying multiple and single page document formats like PDF and Postscript.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ev-utils.c
Go to the documentation of this file.
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
2 /*
3  * Copyright (C) 2004 Anders Carlsson <andersca@gnome.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  *
19  */
20 
21 #include <config.h>
22 
23 #include "ev-utils.h"
24 #include "ev-file-helpers.h"
25 
26 #include <string.h>
27 #include <math.h>
28 #include <glib/gi18n.h>
29 
30 typedef struct
31 {
32  int size;
33  double *data;
34 } ConvFilter;
35 
36 static double
37 gaussian (double x, double y, double r)
38 {
39  return ((1 / (2 * M_PI * r)) *
40  exp ((- (x * x + y * y)) / (2 * r * r)));
41 }
42 
43 static ConvFilter *
44 create_blur_filter (int radius)
45 {
46  ConvFilter *filter;
47  int x, y;
48  double sum;
49 
50  filter = g_new0 (ConvFilter, 1);
51  filter->size = radius * 2 + 1;
52  filter->data = g_new (double, filter->size * filter->size);
53 
54  sum = 0.0;
55 
56  for (y = 0 ; y < filter->size; y++)
57  {
58  for (x = 0 ; x < filter->size; x++)
59  {
60  sum += filter->data[y * filter->size + x] = gaussian (x - (filter->size >> 1),
61  y - (filter->size >> 1),
62  radius);
63  }
64  }
65 
66  for (y = 0; y < filter->size; y++)
67  {
68  for (x = 0; x < filter->size; x++)
69  {
70  filter->data[y * filter->size + x] /= sum;
71  }
72  }
73 
74  return filter;
75 
76 }
77 
78 static GdkPixbuf *
79 create_shadow (GdkPixbuf *src, int blur_radius,
80  int x_offset, int y_offset, double opacity)
81 {
82  int x, y, i, j;
83  int width, height;
84  GdkPixbuf *dest;
85  static ConvFilter *filter = NULL;
86  int src_rowstride, dest_rowstride;
87  int src_bpp, dest_bpp;
88 
89  guchar *src_pixels, *dest_pixels;
90 
91  if (!filter)
92  filter = create_blur_filter (blur_radius);
93 
94  if (x_offset < 0)
95  x_offset = (blur_radius * 4) / 5;
96 
97  if (y_offset < 0)
98  y_offset = (blur_radius * 4) / 5;
99 
100 
101  width = gdk_pixbuf_get_width (src) + blur_radius * 2 + x_offset;
102  height = gdk_pixbuf_get_height (src) + blur_radius * 2 + y_offset;
103 
104  dest = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (src), TRUE,
105  gdk_pixbuf_get_bits_per_sample (src),
106  width, height);
107  gdk_pixbuf_fill (dest, 0);
108  src_pixels = gdk_pixbuf_get_pixels (src);
109  src_rowstride = gdk_pixbuf_get_rowstride (src);
110  src_bpp = gdk_pixbuf_get_has_alpha (src) ? 4 : 3;
111 
112  dest_pixels = gdk_pixbuf_get_pixels (dest);
113  dest_rowstride = gdk_pixbuf_get_rowstride (dest);
114  dest_bpp = gdk_pixbuf_get_has_alpha (dest) ? 4 : 3;
115 
116  for (y = 0; y < height; y++)
117  {
118  for (x = 0; x < width; x++)
119  {
120  int sumr = 0, sumg = 0, sumb = 0, suma = 0;
121 
122  for (i = 0; i < filter->size; i++)
123  {
124  for (j = 0; j < filter->size; j++)
125  {
126  int src_x, src_y;
127 
128  src_y = -(blur_radius + x_offset) + y - (filter->size >> 1) + i;
129  src_x = -(blur_radius + y_offset) + x - (filter->size >> 1) + j;
130 
131  if (src_y < 0 || src_y > gdk_pixbuf_get_height (src) ||
132  src_x < 0 || src_x > gdk_pixbuf_get_width (src))
133  continue;
134 
135  sumr += src_pixels [src_y * src_rowstride +
136  src_x * src_bpp + 0] *
137  filter->data [i * filter->size + j];
138  sumg += src_pixels [src_y * src_rowstride +
139  src_x * src_bpp + 1] *
140  filter->data [i * filter->size + j];
141 
142  sumb += src_pixels [src_y * src_rowstride +
143  src_x * src_bpp + 2] *
144  filter->data [i * filter->size + j];
145 
146  if (src_bpp == 4)
147  suma += src_pixels [src_y * src_rowstride +
148  src_x * src_bpp + 3] *
149  filter->data [i * filter->size + j];
150  else
151  suma += 0xff;
152 
153  }
154  }
155 
156  if (dest_bpp == 4)
157  dest_pixels [y * dest_rowstride +
158  x * dest_bpp + 3] = (suma * opacity) / (filter->size * filter->size);
159 
160  }
161  }
162 
163  return dest;
164 }
165 
166 GdkPixbuf *
167 ev_pixbuf_add_shadow (GdkPixbuf *src, int size,
168  int x_offset, int y_offset, double opacity)
169 {
170  GdkPixbuf *dest;
171 
172  dest = create_shadow (src, size, x_offset, y_offset, opacity);
173 
174  gdk_pixbuf_composite (src, dest,
175  size, size,
176  gdk_pixbuf_get_width (src),
177  gdk_pixbuf_get_height (src),
178  size, size,
179  1.0, 1.0,
180  GDK_INTERP_NEAREST, 255);
181 
182  return dest;
183 }
184 
185 
186 /* Simple function to output the contents of a region. Used solely for testing
187  * the region code.
188  */
189 void
190 ev_print_region_contents (cairo_region_t *region)
191 {
192  gint n_rectangles, i;
193 
194  if (region == NULL) {
195  g_print ("<empty region>\n");
196  return;
197  }
198 
199  g_print ("<region %p>\n", region);
200  n_rectangles = cairo_region_num_rectangles (region);
201  for (i = 0; i < n_rectangles; i++) {
202  GdkRectangle rect;
203 
204  cairo_region_get_rectangle (region, i, &rect);
205  g_print ("\t(%d %d, %d %d) [%dx%d]\n",
206  rect.x,
207  rect.y,
208  rect.x + rect.width,
209  rect.y + rect.height,
210  rect.width,
211  rect.height);
212  }
213 }
214 
215 static void
217  GtkWidget *widget,
218  gint *x,
219  gint *y)
220 {
221  GdkScreen *screen = gtk_widget_get_screen (widget);
222  gint monitor_num;
223  GdkRectangle monitor;
224  GtkRequisition req;
225 
226  g_return_if_fail (widget != NULL);
227 
228  gtk_widget_get_preferred_size (GTK_WIDGET (menu), &req, NULL);
229 
230  monitor_num = gdk_screen_get_monitor_at_point (screen, *x, *y);
231  gtk_menu_set_monitor (menu, monitor_num);
232  gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
233 
234  *x = CLAMP (*x, monitor.x, monitor.x + MAX (0, monitor.width - req.width));
235  *y = CLAMP (*y, monitor.y, monitor.y + MAX (0, monitor.height - req.height));
236 }
237 
238 void
240  gint *x,
241  gint *y,
242  gboolean *push_in,
243  gpointer user_data)
244 {
245  GtkTreeSelection *selection;
246  GList *selected_rows;
247  GtkTreeModel *model;
248  GtkTreeView *tree_view = GTK_TREE_VIEW (user_data);
249  GtkWidget *widget = GTK_WIDGET (user_data);
250  GtkRequisition req;
251  GtkAllocation allocation;
252  GdkRectangle visible;
253 
254  gtk_widget_get_preferred_size (GTK_WIDGET (menu), &req, NULL);
255  gdk_window_get_origin (gtk_widget_get_window (widget), x, y);
256  gtk_widget_get_allocation (widget, &allocation);
257 
258  *x += (allocation.width - req.width) / 2;
259 
260  /* Add on height for the treeview title */
261  gtk_tree_view_get_visible_rect (tree_view, &visible);
262  *y += allocation.height - visible.height;
263 
264  selection = gtk_tree_view_get_selection (tree_view);
265  selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
266  if (selected_rows)
267  {
268  GdkRectangle cell_rect;
269 
270  gtk_tree_view_get_cell_area (tree_view, selected_rows->data,
271  NULL, &cell_rect);
272 
273  *y += CLAMP (cell_rect.y + cell_rect.height, 0, visible.height);
274 
275  g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
276  g_list_free (selected_rows);
277  }
278 
279  ev_gui_sanitise_popup_position (menu, widget, x, y);
280 }
281 
282 static void
283 file_filter_add_mime_types (GdkPixbufFormat *format, GtkFileFilter *filter,
284  GtkFileFilter *supported_filter)
285 {
286  gchar **mime_types;
287  gint i;
288 
289  mime_types = gdk_pixbuf_format_get_mime_types (format);
290  for (i = 0; mime_types[i] != 0; i++) {
291  gtk_file_filter_add_mime_type (filter, mime_types[i]);
292  gtk_file_filter_add_mime_type (supported_filter, mime_types[i]);
293  }
294  g_strfreev (mime_types);
295 }
296 
297 void
299 {
300  GSList *pixbuf_formats = NULL;
301  GSList *iter;
302  GtkFileFilter *filter, *supported_filter;
303 
304  supported_filter = gtk_file_filter_new ();
305  gtk_file_filter_set_name (supported_filter, _("Supported Image Files"));
306  gtk_file_chooser_add_filter (chooser, supported_filter);
307 
308  filter = gtk_file_filter_new ();
309  gtk_file_filter_set_name (filter, _("All Files"));
310  gtk_file_filter_add_pattern (filter, "*");
311  gtk_file_chooser_add_filter (chooser, filter);
312 
313  pixbuf_formats = gdk_pixbuf_get_formats ();
314 
315  for (iter = pixbuf_formats; iter; iter = iter->next) {
316  GdkPixbufFormat *format = iter->data;
317  gchar *name;
318 
319  if (gdk_pixbuf_format_is_disabled (format) ||
320  !gdk_pixbuf_format_is_writable (format))
321  continue;
322 
323  filter = gtk_file_filter_new ();
324  name = gdk_pixbuf_format_get_description (format);
325  gtk_file_filter_set_name (filter, name);
326 
327  file_filter_add_mime_types (format, filter, supported_filter);
328  g_object_set_data (G_OBJECT(filter), "pixbuf-format", format);
329  gtk_file_chooser_add_filter (chooser, filter);
330  }
331 
332  g_slist_free (pixbuf_formats);
333 }
334 
335 GdkPixbufFormat*
337 {
338  GSList *pixbuf_formats = NULL;
339  GSList *iter;
340  int i;
341 
342  pixbuf_formats = gdk_pixbuf_get_formats ();
343 
344  for (iter = pixbuf_formats; iter; iter = iter->next) {
345  gchar **extension_list;
346  GdkPixbufFormat *format = iter->data;
347 
348  if (gdk_pixbuf_format_is_disabled (format) ||
349  !gdk_pixbuf_format_is_writable (format))
350  continue;
351 
352  extension_list = gdk_pixbuf_format_get_extensions (format);
353 
354  for (i = 0; extension_list[i] != 0; i++) {
355  if (g_str_has_suffix (uri, extension_list[i])) {
356  g_slist_free (pixbuf_formats);
357  g_strfreev (extension_list);
358  return format;
359  }
360  }
361  g_strfreev (extension_list);
362  }
363 
364  g_slist_free (pixbuf_formats);
365  return NULL;
366 }