1 /*
2 * frei0r_cairo.h
3 * Copyright 2012 Janne Liljeblad
4 *
5 * This file is part of Frei0r.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22
23 #include <cairo.h>
24 #include <string.h>
25 #include "frei0r_math.h"
26
27 /**
28 * String identifiers for gradient types available using Cairo.
29 */
30 #define GRADIENT_LINEAR "gradient_linear"
31 #define GRADIENT_RADIAL "gradient_radial"
32
33 /**
34 * String identifiers for blend modes available using Cairo.
35 */
36 #define NORMAL "normal"
37 #define ADD "add"
38 #define SATURATE "saturate"
39 #define MULTIPLY "multiply"
40 #define SCREEN "screen"
41 #define OVERLAY "overlay"
42 #define DARKEN "darken"
43 #define LIGHTEN "lighten"
44 #define COLORDODGE "colordodge"
45 #define COLORBURN "colorburn"
46 #define HARDLIGHT "hardlight"
47 #define SOFTLIGHT "softlight"
48 #define DIFFERENCE "difference"
49 #define EXCLUSION "exclusion"
50 #define HSLHUE "hslhue"
51 #define HSLSATURATION "hslsaturation"
52 #define HSLCOLOR "hslcolor"
53 #define HSLLUMINOSITY "hslluminosity"
54
55
56 /**
57 * frei0r_cairo_set_operator
58 * @cr: Cairo context
59 * @op: String identifier for a blend mode
60 *
61 * Sets cairo context to use the defined blend mode for all paint operations.
62 */
frei0r_cairo_set_operator(cairo_t * cr,char * op)63 void frei0r_cairo_set_operator(cairo_t *cr, char *op)
64 {
65 if(strcmp(op, NORMAL) == 0)
66 {
67 cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
68 }
69 else if(strcmp(op, ADD) == 0)
70 {
71 cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
72 }
73 else if(strcmp(op, SATURATE) == 0)
74 {
75 cairo_set_operator (cr, CAIRO_OPERATOR_SATURATE);
76 }
77 else if(strcmp(op, MULTIPLY) == 0)
78 {
79 cairo_set_operator (cr, CAIRO_OPERATOR_MULTIPLY);
80 }
81 else if(strcmp(op, SCREEN) == 0)
82 {
83 cairo_set_operator (cr, CAIRO_OPERATOR_SCREEN);
84 }
85 else if(strcmp(op, OVERLAY) == 0)
86 {
87 cairo_set_operator (cr, CAIRO_OPERATOR_OVERLAY);
88 }
89 else if(strcmp(op, DARKEN) == 0)
90 {
91 cairo_set_operator (cr, CAIRO_OPERATOR_DARKEN);
92 }
93 else if(strcmp(op, LIGHTEN) == 0)
94 {
95 cairo_set_operator (cr, CAIRO_OPERATOR_LIGHTEN);
96 }
97 else if(strcmp(op, COLORDODGE) == 0)
98 {
99 cairo_set_operator (cr, CAIRO_OPERATOR_COLOR_DODGE);
100 }
101 else if(strcmp(op, COLORBURN) == 0)
102 {
103 cairo_set_operator (cr, CAIRO_OPERATOR_COLOR_BURN);
104 }
105 else if(strcmp(op, HARDLIGHT) == 0)
106 {
107 cairo_set_operator (cr, CAIRO_OPERATOR_HARD_LIGHT);
108 }
109 else if(strcmp(op, SOFTLIGHT) == 0)
110 {
111 cairo_set_operator (cr, CAIRO_OPERATOR_SOFT_LIGHT);
112 }
113 else if(strcmp(op, DIFFERENCE) == 0)
114 {
115 cairo_set_operator (cr, CAIRO_OPERATOR_DIFFERENCE);
116 }
117 else if(strcmp(op, EXCLUSION) == 0)
118 {
119 cairo_set_operator (cr, CAIRO_OPERATOR_EXCLUSION);
120 }
121 else if(strcmp(op, HSLHUE) == 0)
122 {
123 cairo_set_operator (cr, CAIRO_OPERATOR_HSL_HUE);
124 }
125 else if(strcmp(op, HSLSATURATION) == 0)
126 {
127 cairo_set_operator (cr, CAIRO_OPERATOR_HSL_SATURATION);
128 }
129 else if(strcmp(op, HSLCOLOR) == 0)
130 {
131 cairo_set_operator (cr, CAIRO_OPERATOR_HSL_COLOR);
132 }
133 else if(strcmp(op, HSLLUMINOSITY ) == 0)
134 {
135 cairo_set_operator (cr, CAIRO_OPERATOR_HSL_LUMINOSITY);
136 }
137 else
138 {
139 cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
140 }
141 }
142
143
144 /**
145 * frei0r_cairo_set_rgba_LITTLE_ENDIAN
146 * @cr: Cairo context
147 * @red: red component, 0 - 1
148 * @green: green component, 0 - 1
149 * @blue: blue component, 0 - 1
150 * @alpha: opacity of color, 0 -1
151 *
152 * Sets cairo context to use the defined color paint operations.
153 * Switches red and blue channels to get correct color on little endian machines.
154 * This method only works correctly on little endian machines.
155 */
frei0r_cairo_set_rgba_LITTLE_ENDIAN(cairo_t * cr,double red,double green,double blue,double alpha)156 void frei0r_cairo_set_rgba_LITTLE_ENDIAN(cairo_t* cr, double red, double green, double blue, double alpha)
157 {
158 cairo_set_source_rgba (cr, blue, green, red, alpha);
159 }
160
161 /**
162 * frei0r_cairo_set_rgb_LITTLE_ENDIAN
163 * @cr: Cairo context
164 * @red: red component, 0 - 1
165 * @green: green component, 0 - 1
166 * @blue: blue component, 0 - 1
167 *
168 * Sets cairo context to use the defined color paint operations.
169 * Switches red and blue channels to get correct color on little endian machines.
170 * This method only works correctly on little endian machines.
171 */
frei0r_cairo_set_rgb_LITTLE_ENDIAN(cairo_t * cr,double red,double green,double blue)172 void frei0r_cairo_set_rgb_LITTLE_ENDIAN(cairo_t* cr, double red, double green, double blue)
173 {
174 cairo_set_source_rgb (cr, blue, green, red);
175 }
176
177 /**
178 * freior_cairo_set_color_stop_rgba_LITTLE_ENDIAN(
179 * @pat: Cairo pattern
180 * @offset: offset of color position in pattern space, 0 - 1
181 * @red: red component, 0 - 1
182 * @green: green component, 0 - 1
183 * @blue: blue component, 0 - 1
184 * @alpha: opacity of color, 0 -1
185 *
186 * Sets color stop for cairo patterns.
187 * Switches red and blue channels to get correct color on little endian machines.
188 * This method only works correctly on little endian machines.
189 */
freior_cairo_set_color_stop_rgba_LITTLE_ENDIAN(cairo_pattern_t * pat,double offset,double red,double green,double blue,double alpha)190 void freior_cairo_set_color_stop_rgba_LITTLE_ENDIAN(cairo_pattern_t *pat, double offset,
191 double red, double green, double blue, double alpha)
192 {
193 cairo_pattern_add_color_stop_rgba (pat, offset, blue, green, red, alpha);
194 }
195
196 /**
197 * frei0r_cairo_get_pixel_position
198 * @norm_pos: position in range 0 - 1, either x or y
199 * @dim: dimension, either witdh or height
200 *
201 * Converts double range [0 -> 1] to pixel range [-2*dim -> 3*dim]. Input 0.4 gives position 0.
202 *
203 * Returns: position in pixels
204 */
frei0r_cairo_get_pixel_position(double norm_pos,int dim)205 double frei0r_cairo_get_pixel_position (double norm_pos, int dim)
206 {
207 double pos_o = -(dim * 2.0);
208 return pos_o + norm_pos * dim * 5.0;
209 }
210
211 /**
212 * frei0r_cairo_get_scale
213 * @norm_scale: scale in range 0 - 1
214 *
215 * Converts double range [0 -> 1] to scale range [0 -> 5]. Input 0.2 gives scale 1.0.
216 *
217 * Returns: scale
218 */
frei0r_cairo_get_scale(double norm_scale)219 double frei0r_cairo_get_scale (double norm_scale)
220 {
221 return norm_scale * 5.0;
222 }
223
224 /**
225 * Convert frei0r RGBA to pre-multiplied alpha as needed by Cairo.
226 *
227 * \param rgba the image buffer with format F0R_COLOR_MODEL_RGBA8888
228 * \param pixels the size of the image buffer in number of pixels
229 * \param alpha if >= 0, the alpha channel will be set to this value
230 * \see frei0r_cairo_unpremultiply_rgba
231 */
frei0r_cairo_premultiply_rgba(unsigned char * rgba,int pixels,int alpha)232 void frei0r_cairo_premultiply_rgba (unsigned char *rgba, int pixels, int alpha)
233 {
234 int i = pixels + 1;
235 while ( --i ) {
236 register unsigned char a = rgba[3];
237 if (a == 0) {
238 *((uint32_t *)rgba) = 0;
239 } else if (a < 0xff) {
240 rgba[0] = ( rgba[0] * a ) >> 8;
241 rgba[1] = ( rgba[1] * a ) >> 8;
242 rgba[2] = ( rgba[2] * a ) >> 8;
243 }
244 if (alpha >= 0) rgba[3] = alpha;
245 rgba += 4;
246 }
247 }
248
249 /**
250 * Convert Cairo ARGB pre-multiplied alpha to frei0r straight RGBA.
251 *
252 * \param rgba the image buffer with format CAIRO_FORMAT_ARGB32
253 * \param pixels the size of the image buffer in number of pixels
254 * \see frei0r_cairo_premultiply_rgba
255 */
frei0r_cairo_unpremultiply_rgba(unsigned char * rgba,int pixels)256 void frei0r_cairo_unpremultiply_rgba (unsigned char *rgba, int pixels)
257 {
258 int i = pixels + 1;
259 while ( --i ) {
260 register unsigned char a = rgba[3];
261 if (a > 0 && a < 0xff) {
262 rgba[0] = MIN(( rgba[0] << 8 ) / a, 255);
263 rgba[1] = MIN(( rgba[1] << 8 ) / a, 255);
264 rgba[2] = MIN(( rgba[2] << 8 ) / a, 255);
265 }
266 rgba += 4;
267 }
268 }
269
270 /**
271 * Convert frei0r RGBA to pre-multiplied alpha as needed by Cairo.
272 *
273 * \param rgba the image buffer with format F0R_COLOR_MODEL_RGBA8888
274 * \param pixels the size of the image buffer in number of pixels
275 * \param alpha if >= 0, the alpha channel will be set to this value
276 * \see frei0r_cairo_premultiply_rgba
277 *
278 * This is the same as frei0r_cairo_premultiply_rgba but it writes the
279 * output to a different buffer.
280 */
frei0r_cairo_premultiply_rgba2(unsigned char * in,unsigned char * out,int pixels,int alpha)281 void frei0r_cairo_premultiply_rgba2 (unsigned char *in, unsigned char *out,
282 int pixels, int alpha)
283 {
284 int i = pixels + 1;
285 while ( --i ) {
286 register unsigned char a = in[3];
287 if (a == 0) {
288 *((uint32_t *)out) = 0;
289 } else if (a == 0xff) {
290 memcpy(out, in, 4);
291 } else {
292 out[0] = ( in[0] * a ) >> 8;
293 out[1] = ( in[1] * a ) >> 8;
294 out[2] = ( in[2] * a ) >> 8;
295 }
296 if (alpha >= 0)
297 out[3] = alpha;
298 in += 4;
299 out += 4;
300 }
301 }
302