1 /* This file is an image processing operation for GEGL
2 *
3 * GEGL is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 3 of the License, or (at your option) any later version.
7 *
8 * GEGL is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with GEGL; if not, see <https://www.gnu.org/licenses/>.
15 *
16 * Copyright 2018 Øyvind Kolås <pippin@gimp.org>
17 */
18
19 #include "config.h"
20 #include <glib/gi18n-lib.h>
21
22
23 #ifdef GEGL_PROPERTIES
24
25 /* no properties */
26
27 #else
28
29 #define GEGL_OP_POINT_FILTER
30 #define GEGL_OP_NAME aces_rrt
31 #define GEGL_OP_C_SOURCE aces-rrt.c
32
33 #include "gegl-op.h"
34
aces_rrt(float x)35 static inline float aces_rrt (float x)
36 {
37 /* source of approximation:
38
39 https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/
40 https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl
41 */
42 float a = x * (x + 0.0245786f) - 0.000090537f;
43 float b = x * (0.983729f * x + 0.4329510f) + 0.238081f;
44 return a / b;
45 }
46
47 #define lerp(a,b,d) ((a) * (1.0-d) + (b) * ((d)))
48
aces_rrt_rgb(float rin,float gin,float bin,float * rout,float * gout,float * bout)49 static inline void aces_rrt_rgb (float rin, float gin, float bin, float *rout, float *gout, float *bout)
50 {
51 float r, g, b;
52
53 r = aces_rrt (rin);
54 g = aces_rrt (gin);
55 b = aces_rrt (bin);
56 r = (rin);
57 g = (gin);
58 b = (bin);
59
60 #if 0
61 /* this is not the proper glow + desaturate used by ACES RRT,
62 but does something similar
63 */
64
65 #define THRESHOLD 0.05
66 #define THRESHOLD2 0.4
67
68
69 {
70 float gray;
71
72 gray = (r+g+b) / 3.0;
73 if (gray > 1.0f) gray = 1.0f;
74
75 if (gray < THRESHOLD)
76 {
77 float saturation = 1.0-(gray)/THRESHOLD;
78 r = lerp (r, gray, saturation);
79 g = lerp (g, gray, saturation);
80 b = lerp (b, gray, saturation);
81 }
82 else if (gray > THRESHOLD2)
83 {
84 float saturation = (gray - THRESHOLD2)/(1.0-THRESHOLD2);
85 r = lerp (r, gray, saturation);
86 g = lerp (g, gray, saturation);
87 b = lerp (b, gray, saturation);
88 }
89 }
90 #endif
91
92 *rout = r;
93 *gout = g;
94 *bout = b;
95 }
96
97 static gboolean
process(GeglOperation * op,void * in_buf,void * out_buf,glong samples,const GeglRectangle * roi,gint level)98 process (GeglOperation *op,
99 void *in_buf,
100 void *out_buf,
101 glong samples,
102 const GeglRectangle *roi,
103 gint level)
104 {
105 gfloat *in = in_buf;
106 gfloat *out = out_buf;
107
108 while (samples--)
109 {
110 aces_rrt_rgb (in[0], in[1], in[2],
111 &out[0], &out[1], &out[2]);
112 out[3] = in[3];
113
114 in += 4;
115 out+= 4;
116 }
117 return TRUE;
118 }
119
120 static void
gegl_op_class_init(GeglOpClass * klass)121 gegl_op_class_init (GeglOpClass *klass)
122 {
123 GeglOperationClass *operation_class;
124 GeglOperationPointFilterClass *point_filter_class;
125
126 operation_class = GEGL_OPERATION_CLASS (klass);
127 point_filter_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass);
128
129 point_filter_class->process = process;
130
131 gegl_operation_class_set_keys (operation_class,
132 "name", "gegl:aces-rrt",
133 "title", _("ACES RRT"),
134 "categories" , "color:tonemapping",
135 "description",
136 _("HDR to SDR proofing filter/mapping curve that is an approximation of the ACES RRT (Reference Rendering Transform). When feeding scene-refereed imagery into this op, the result is suitable for display referred transform to sRGB or output display using regular ICC matric profiles as the ODT. Note that for the time being, this is a luminance only approximation of the ACES RRT; without desaturation of highlights and shadows nor red hue modifications."),
137 NULL);
138 }
139
140 #endif
141