4 // code courtesy http://cocoawithlove.com/2008/09/drawing-gloss-gradients-in-coregraphics.html
5 // adapted to Vala by Hans Baier
9 private static double perceptualGlossFractionForColor(RGBA color
) {
10 double REFLECTION_SCALE_NUMBER
= 0.2;
11 double NTSC_RED_FRACTION
= 0.299;
12 double NTSC_GREEN_FRACTION
= 0.587;
13 double NTSC_BLUE_FRACTION
= 0.114;
16 NTSC_RED_FRACTION
* color
.red
+
17 NTSC_GREEN_FRACTION
* color
.green
+
18 NTSC_BLUE_FRACTION
* color
.blue
;
20 glossScale
= Math
.pow(glossScale
, REFLECTION_SCALE_NUMBER
);
25 private static RGBA
perceptualCausticColorForColor(RGBA input
) {
26 double CAUSTIC_FRACTION
= 0.60;
27 double COSINE_ANGLE_SCALE
= 1.4;
28 double MIN_RED_THRESHOLD
= 0.95;
29 double MAX_BLUE_THRESHOLD
= 0.7;
30 double GRAYSCALE_CAUSTIC_SATURATION
= 0.2;
34 HSV source_hsv
= new
HSV();
35 source_hsv
.from_rgba(source
);
37 double hue
= source_hsv
.hue
;
38 double saturation
= source_hsv
.saturation
;
39 double value
= source_hsv
.value
;
40 double alpha
= input
.alpha
;
42 HSV target_hsv
= new
HSV();
43 target_hsv
.from_rgba(rgba_new(1.0, 1.0, 0.0));
45 double targetHue
= target_hsv
.hue
;
46 double targetSaturation
= target_hsv
.saturation
;
47 double targetValue
= target_hsv
.value
;
49 if (saturation
< 0.0001) {
51 saturation
= GRAYSCALE_CAUSTIC_SATURATION
;
54 if (hue
> MIN_RED_THRESHOLD
) {
56 } else if (hue
> MAX_BLUE_THRESHOLD
) {
57 target_hsv
.from_rgba(rgba_new(1.0, 0.0, 1.0));
59 targetHue
= target_hsv
.hue
;
60 targetSaturation
= target_hsv
.saturation
;
61 targetValue
= target_hsv
.value
;
64 double scaledCaustic
= CAUSTIC_FRACTION
* 0.5 * (1.0 + Math
.cos(COSINE_ANGLE_SCALE
* Math
.PI
* (hue
- targetHue
) / 360.0));
66 target_hsv
.hue
= hue
* (1.0 - scaledCaustic
) + targetHue
* scaledCaustic
;
67 target_hsv
.saturation
= saturation
;
68 target_hsv
.value
= value
* (1.0 - scaledCaustic
) + targetValue
* scaledCaustic
;
70 RGBA target_color
= target_hsv
.to_rgba();
71 target_color
.alpha
= alpha
;
76 private struct GlossParameters
{
79 double expCoefficient
;
86 private static RGBA
glossInterpolation(double progress
, ref GlossParameters params
) {
91 progress
= progress
* 2.0;
94 1.0 - params
.expScale
* (Math
.exp(progress
* (-params
.expCoefficient
)) - params
.expOffset
);
96 double currentWhite
= progress
* (params
.finalWhite
- params
.initialWhite
) + params
.initialWhite
;
98 output
.red
= params
.color
.red
* (1.0 - currentWhite
) + currentWhite
;
99 output
.green
= params
.color
.green
* (1.0 - currentWhite
) + currentWhite
;
100 output
.blue
= params
.color
.blue
* (1.0 - currentWhite
) + currentWhite
;
101 output
.alpha
= params
.color
.alpha
* (1.0 - currentWhite
) + currentWhite
;
105 progress
= (progress
- 0.5) * 2.0;
108 progress
= params
.expScale
*
109 (Math
.exp((1.0 - progress
) * (-params
.expCoefficient
)) - params
.expOffset
);
111 output
.red
= params
.color
.red
* (1.0 - progress
) + params
.caustic
.red
* progress
;
112 output
.green
= params
.color
.green
* (1.0 - progress
) + params
.caustic
.green
* progress
;
113 output
.blue
= params
.color
.blue
* (1.0 - progress
) + params
.caustic
.blue
* progress
;
114 output
.alpha
= params
.color
.alpha
* (1.0 - progress
) + params
.caustic
.alpha
* progress
;
120 public static Cairo
.Pattern
gloss_gradient_pattern(double x0
, double y0
, double x1
, double y1
, RGBA color
, int no_steps
= 100) {
121 double EXP_COEFFICIENT
= 1.2;
122 double REFLECTION_MAX
= 0.60;
123 double REFLECTION_MIN
= 0.20;
125 GlossParameters params
= GlossParameters();
127 params
.expCoefficient
= EXP_COEFFICIENT
;
128 params
.expOffset
= Math
.exp(-params
.expCoefficient
);
129 params
.expScale
= 1.0 / (1.0 - params
.expOffset
);
131 params
.color
= color
;
133 params
.caustic
= perceptualCausticColorForColor(params
.color
);
135 double glossScale
= perceptualGlossFractionForColor(params
.color
);
137 params
.initialWhite
= glossScale
* REFLECTION_MAX
;
138 params
.finalWhite
= glossScale
* REFLECTION_MIN
;
140 Cairo
.Pattern result
= new Cairo
.Pattern
.linear(x0
, y0
, x1
, y1
);
142 for (double offset
= 0; offset
<= 1.0; offset
+= 1.0 / (double) no_steps
) {
143 RGBA stop
= glossInterpolation(offset
, ref params
);
144 result
.add_color_stop_rgba(offset
, stop
.red
, stop
.green
, stop
.blue
, stop
.alpha
);
150 } // namespace Prolooks