nautilus-3.6.3/eel/eel-graphic-effects.c

No issues found

  1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
  2 
  3 /* Eel - pixbuf manipulation routines for graphical effects.
  4  *
  5  * Copyright (C) 2000 Eazel, Inc
  6  *
  7  * Author: Andy Hertzfeld <andy@eazel.com>
  8  *
  9  * This library is free software; you can redistribute it and/or
 10  * modify it under the terms of the GNU Library General Public
 11  * License as published by the Free Software Foundation; either
 12  * version 2 of the License, or (at your option) any later version.
 13  *
 14  * This library is distributed in the hope that it will be useful,
 15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17  * Library General Public License for more details.
 18  *
 19  * You should have received a copy of the GNU Library General Public
 20  * License along with this library; if not, write to the
 21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 22  * Boston, MA 02111-1307, USA.
 23  */
 24 
 25 /* This file contains pixbuf manipulation routines used for graphical effects like pre-lighting
 26    and selection hilighting */
 27 
 28 #include <config.h>
 29 
 30 #include "eel-graphic-effects.h"
 31 #include "eel-glib-extensions.h"
 32 
 33 #include <math.h>
 34 #include <string.h>
 35 
 36 /* shared utility to create a new pixbuf from the passed-in one */
 37 
 38 static GdkPixbuf *
 39 create_new_pixbuf (GdkPixbuf *src)
 40 {
 41 	g_assert (gdk_pixbuf_get_colorspace (src) == GDK_COLORSPACE_RGB);
 42 	g_assert ((!gdk_pixbuf_get_has_alpha (src)
 43 			       && gdk_pixbuf_get_n_channels (src) == 3)
 44 			      || (gdk_pixbuf_get_has_alpha (src)
 45 				  && gdk_pixbuf_get_n_channels (src) == 4));
 46 
 47 	return gdk_pixbuf_new (gdk_pixbuf_get_colorspace (src),
 48 			       gdk_pixbuf_get_has_alpha (src),
 49 			       gdk_pixbuf_get_bits_per_sample (src),
 50 			       gdk_pixbuf_get_width (src),
 51 			       gdk_pixbuf_get_height (src));
 52 }
 53 
 54 /* utility routine to bump the level of a color component with pinning */
 55 
 56 static guchar
 57 lighten_component (guchar cur_value)
 58 {
 59 	int new_value = cur_value;
 60 	new_value += 24 + (new_value >> 3);
 61 	if (new_value > 255) {
 62 		new_value = 255;
 63 	}
 64 	return (guchar) new_value;
 65 }
 66 
 67 GdkPixbuf *
 68 eel_create_spotlight_pixbuf (GdkPixbuf* src)
 69 {
 70 	GdkPixbuf *dest;
 71 	int i, j;
 72 	int width, height, has_alpha, src_row_stride, dst_row_stride;
 73 	guchar *target_pixels, *original_pixels;
 74 	guchar *pixsrc, *pixdest;
 75 
 76 	g_return_val_if_fail (gdk_pixbuf_get_colorspace (src) == GDK_COLORSPACE_RGB, NULL);
 77 	g_return_val_if_fail ((!gdk_pixbuf_get_has_alpha (src)
 78 			       && gdk_pixbuf_get_n_channels (src) == 3)
 79 			      || (gdk_pixbuf_get_has_alpha (src)
 80 				  && gdk_pixbuf_get_n_channels (src) == 4), NULL);
 81 	g_return_val_if_fail (gdk_pixbuf_get_bits_per_sample (src) == 8, NULL);
 82 
 83 	dest = create_new_pixbuf (src);
 84 	
 85 	has_alpha = gdk_pixbuf_get_has_alpha (src);
 86 	width = gdk_pixbuf_get_width (src);
 87 	height = gdk_pixbuf_get_height (src);
 88 	dst_row_stride = gdk_pixbuf_get_rowstride (dest);
 89 	src_row_stride = gdk_pixbuf_get_rowstride (src);
 90 	target_pixels = gdk_pixbuf_get_pixels (dest);
 91 	original_pixels = gdk_pixbuf_get_pixels (src);
 92 
 93 	for (i = 0; i < height; i++) {
 94 		pixdest = target_pixels + i * dst_row_stride;
 95 		pixsrc = original_pixels + i * src_row_stride;
 96 		for (j = 0; j < width; j++) {		
 97 			*pixdest++ = lighten_component (*pixsrc++);
 98 			*pixdest++ = lighten_component (*pixsrc++);
 99 			*pixdest++ = lighten_component (*pixsrc++);
100 			if (has_alpha) {
101 				*pixdest++ = *pixsrc++;
102 			}
103 		}
104 	}
105 	return dest;
106 }
107 
108 /* this routine colorizes the passed-in pixbuf by multiplying each pixel with the passed in color */
109 
110 GdkPixbuf *
111 eel_create_colorized_pixbuf (GdkPixbuf *src,
112 			     GdkRGBA *color)
113 {
114 	int i, j;
115 	int width, height, has_alpha, src_row_stride, dst_row_stride;
116 	guchar *target_pixels;
117 	guchar *original_pixels;
118 	guchar *pixsrc;
119 	guchar *pixdest;
120 	GdkPixbuf *dest;
121 	gint red_value, green_value, blue_value;
122 
123 	g_return_val_if_fail (gdk_pixbuf_get_colorspace (src) == GDK_COLORSPACE_RGB, NULL);
124 	g_return_val_if_fail ((!gdk_pixbuf_get_has_alpha (src)
125 			       && gdk_pixbuf_get_n_channels (src) == 3)
126 			      || (gdk_pixbuf_get_has_alpha (src)
127 				  && gdk_pixbuf_get_n_channels (src) == 4), NULL);
128 	g_return_val_if_fail (gdk_pixbuf_get_bits_per_sample (src) == 8, NULL);
129 
130 	red_value = (gint) floor (color->red * 255);
131 	green_value = (gint) floor (color->green * 255);
132 	blue_value = (gint) floor (color->blue * 255);	
133 
134 	dest = create_new_pixbuf (src);
135 	
136 	has_alpha = gdk_pixbuf_get_has_alpha (src);
137 	width = gdk_pixbuf_get_width (src);
138 	height = gdk_pixbuf_get_height (src);
139 	src_row_stride = gdk_pixbuf_get_rowstride (src);
140 	dst_row_stride = gdk_pixbuf_get_rowstride (dest);
141 	target_pixels = gdk_pixbuf_get_pixels (dest);
142 	original_pixels = gdk_pixbuf_get_pixels (src);
143 
144 	for (i = 0; i < height; i++) {
145 		pixdest = target_pixels + i*dst_row_stride;
146 		pixsrc = original_pixels + i*src_row_stride;
147 		for (j = 0; j < width; j++) {		
148 			*pixdest++ = (*pixsrc++ * red_value) >> 8;
149 			*pixdest++ = (*pixsrc++ * green_value) >> 8;
150 			*pixdest++ = (*pixsrc++ * blue_value) >> 8;
151 			if (has_alpha) {
152 				*pixdest++ = *pixsrc++;
153 			}
154 		}
155 	}
156 	return dest;
157 }
158 
159 /* utility to stretch a frame to the desired size */
160 
161 static void
162 draw_frame_row (GdkPixbuf *frame_image, int target_width, int source_width, int source_v_position, int dest_v_position, GdkPixbuf *result_pixbuf, int left_offset, int height)
163 {
164 	int remaining_width, h_offset, slab_width;
165 	
166 	remaining_width = target_width;
167 	h_offset = 0;
168 	while (remaining_width > 0) {	
169 		slab_width = remaining_width > source_width ? source_width : remaining_width;
170 		gdk_pixbuf_copy_area (frame_image, left_offset, source_v_position, slab_width, height, result_pixbuf, left_offset + h_offset, dest_v_position);
171 		remaining_width -= slab_width;
172 		h_offset += slab_width; 
173 	}
174 }
175 
176 /* utility to draw the middle section of the frame in a loop */
177 static void
178 draw_frame_column (GdkPixbuf *frame_image, int target_height, int source_height, int source_h_position, int dest_h_position, GdkPixbuf *result_pixbuf, int top_offset, int width)
179 {
180 	int remaining_height, v_offset, slab_height;
181 	
182 	remaining_height = target_height;
183 	v_offset = 0;
184 	while (remaining_height > 0) {	
185 		slab_height = remaining_height > source_height ? source_height : remaining_height;
186 		gdk_pixbuf_copy_area (frame_image, source_h_position, top_offset, width, slab_height, result_pixbuf, dest_h_position, top_offset + v_offset);
187 		remaining_height -= slab_height;
188 		v_offset += slab_height; 
189 	}
190 }
191 
192 static GdkPixbuf *
193 eel_stretch_frame_image (GdkPixbuf *frame_image, int left_offset, int top_offset, int right_offset, int bottom_offset,
194 			 int dest_width, int dest_height, gboolean fill_flag)
195 {
196 	GdkPixbuf *result_pixbuf;
197 	guchar *pixels_ptr;
198 	int frame_width, frame_height;
199 	int y, row_stride;
200 	int target_width, target_frame_width;
201 	int target_height, target_frame_height;
202 	
203 	frame_width  = gdk_pixbuf_get_width  (frame_image);
204 	frame_height = gdk_pixbuf_get_height (frame_image );
205 	
206 	if (fill_flag) {
207 		result_pixbuf = gdk_pixbuf_scale_simple (frame_image, dest_width, dest_height, GDK_INTERP_NEAREST);
208 	} else {
209 		result_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, dest_width, dest_height);
210 	}
211 	row_stride = gdk_pixbuf_get_rowstride (result_pixbuf);
212 	pixels_ptr = gdk_pixbuf_get_pixels (result_pixbuf);
213 	
214 	/* clear the new pixbuf */
215 	if (!fill_flag) {
216 		for (y = 0; y < dest_height; y++) {
217 			memset (pixels_ptr, 255, row_stride);
218 			pixels_ptr += row_stride; 
219 		}
220 	}
221 	
222 	target_width  = dest_width - left_offset - right_offset;
223 	target_frame_width = frame_width - left_offset - right_offset;
224 	
225 	target_height  = dest_height - top_offset - bottom_offset;
226 	target_frame_height = frame_height - top_offset - bottom_offset;
227 	
228 	/* draw the left top corner  and top row */
229 	gdk_pixbuf_copy_area (frame_image, 0, 0, left_offset, top_offset, result_pixbuf, 0,  0);
230 	draw_frame_row (frame_image, target_width, target_frame_width, 0, 0, result_pixbuf, left_offset, top_offset);
231 	
232 	/* draw the right top corner and left column */
233 	gdk_pixbuf_copy_area (frame_image, frame_width - right_offset, 0, right_offset, top_offset, result_pixbuf, dest_width - right_offset,  0);
234 	draw_frame_column (frame_image, target_height, target_frame_height, 0, 0, result_pixbuf, top_offset, left_offset);
235 
236 	/* draw the bottom right corner and bottom row */
237 	gdk_pixbuf_copy_area (frame_image, frame_width - right_offset, frame_height - bottom_offset, right_offset, bottom_offset, result_pixbuf, dest_width - right_offset,  dest_height - bottom_offset);
238 	draw_frame_row (frame_image, target_width, target_frame_width, frame_height - bottom_offset, dest_height - bottom_offset, result_pixbuf, left_offset, bottom_offset);
239 		
240 	/* draw the bottom left corner and the right column */
241 	gdk_pixbuf_copy_area (frame_image, 0, frame_height - bottom_offset, left_offset, bottom_offset, result_pixbuf, 0,  dest_height - bottom_offset);
242 	draw_frame_column (frame_image, target_height, target_frame_height, frame_width - right_offset, dest_width - right_offset, result_pixbuf, top_offset, right_offset);
243 	
244 	return result_pixbuf;
245 }
246 
247 
248 /* draw an arbitrary frame around an image, with the result passed back in a newly allocated pixbuf */
249 GdkPixbuf *
250 eel_embed_image_in_frame (GdkPixbuf *source_image, GdkPixbuf *frame_image, int left_offset, int top_offset, int right_offset, int bottom_offset)
251 {
252 	GdkPixbuf *result_pixbuf;
253 	int source_width, source_height;
254 	int dest_width, dest_height;
255 	
256 	source_width  = gdk_pixbuf_get_width  (source_image);
257 	source_height = gdk_pixbuf_get_height (source_image);
258 
259 	dest_width  = source_width  + left_offset + right_offset;
260 	dest_height = source_height + top_offset  + bottom_offset;
261 	
262 	result_pixbuf = eel_stretch_frame_image (frame_image, left_offset, top_offset, right_offset, bottom_offset, 
263 						      dest_width, dest_height, FALSE);
264 		
265 	/* Finally, copy the source image into the framed area */
266 	gdk_pixbuf_copy_area (source_image, 0, 0, source_width, source_height, result_pixbuf, left_offset,  top_offset);
267 
268 	return result_pixbuf;
269 }