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 }