Evas filters: Implement color curves filter
authorJean-Philippe Andre <jp.andre@samsung.com>
Mon, 9 Dec 2013 07:32:38 +0000 (16:32 +0900)
committerJean-Philippe Andre <jp.andre@samsung.com>
Fri, 7 Feb 2014 08:33:16 +0000 (17:33 +0900)
Color curves are a very simple tool to alter the colors of an image,
on a per-pixel basis. This implementation will simply map each pixel
to a 256 bytes buffer, provided by the application.

NOTE: There are no convenience functions yet for easy curve
generation, but this is the plan (give point A, B, B and interpolate
between them to generate the 256 values array).

src/lib/evas/filters/evas_filter_curve.c [new file with mode: 0644]

diff --git a/src/lib/evas/filters/evas_filter_curve.c b/src/lib/evas/filters/evas_filter_curve.c
new file mode 100644 (file)
index 0000000..a31c333
--- /dev/null
@@ -0,0 +1,125 @@
+#include "evas_filter.h"
+#include "evas_filter_private.h"
+
+
+static Eina_Bool
+_filter_curve_cpu_rgba(Evas_Filter_Command *cmd)
+{
+   RGBA_Image *in, *out;
+   DATA32 *src, *dst, *d, *s;
+   DATA8 *curve;
+   int k, offset = -1, len;
+
+#define C_VAL(p) (((DATA8 *)(p))[offset])
+
+   in = cmd->input->backing;
+   out = cmd->output->backing;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(in, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(out, EINA_FALSE);
+   src = in->image.data;
+   dst = out->image.data;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(src, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(dst, EINA_FALSE);
+   curve = cmd->curve.data;
+   len = in->cache_entry.w * in->cache_entry.h;
+
+   switch (cmd->curve.channel)
+     {
+#ifndef WORDS_BIGENDIAN
+      case EVAS_FILTER_CHANNEL_RED:   offset = 2; break;
+      case EVAS_FILTER_CHANNEL_GREEN: offset = 1; break;
+      case EVAS_FILTER_CHANNEL_BLUE:  offset = 0; break;
+#else
+      case EVAS_FILTER_CHANNEL_RED:   offset = 1; break;
+      case EVAS_FILTER_CHANNEL_GREEN: offset = 2; break;
+      case EVAS_FILTER_CHANNEL_BLUE:  offset = 3; break;
+#endif
+      case EVAS_FILTER_CHANNEL_ALPHA: break;
+      case EVAS_FILTER_CHANNEL_RGB: break;
+      default:
+        ERR("Invalid color channel %d", (int) cmd->curve.channel);
+        return EINA_FALSE;
+     }
+
+   // One channel
+   if (offset >= 0)
+     {
+        for (k = len; k; k--, dst++, src++)
+          C_VAL(dst) = curve[C_VAL(src)];
+        return EINA_TRUE;
+     }
+
+   // RGB
+   if (cmd->curve.channel == EVAS_FILTER_CHANNEL_RGB)
+     {
+#ifndef WORDS_BIGENDIAN
+        for (offset = 0; offset <= 2; offset++)
+#else
+        for (offset = 1; offset <= 3; offset++)
+#endif
+          {
+             for (k = len, s = src, d = dst; k; k--, d++, s++)
+               C_VAL(d) = curve[C_VAL(s)];
+          }
+        return EINA_TRUE;
+     }
+
+   // Alpha
+#ifndef WORDS_BIGENDIAN
+   offset = 3;
+#else
+   offset = 0;
+#endif
+
+   if (src != dst)
+     memcpy(dst, src, len * sizeof(DATA32));
+   evas_data_argb_unpremul(dst, len);
+   for (k = len, d = dst; k; k--, d++, src++)
+     C_VAL(d) = curve[C_VAL(src)];
+   evas_data_argb_premul(dst, len);
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_filter_curve_cpu_alpha(Evas_Filter_Command *cmd)
+{
+   RGBA_Image *in, *out;
+   DATA8 *src, *dst;
+   DATA8 *curve;
+   int k;
+
+   in = cmd->input->backing;
+   out = cmd->output->backing;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(in, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(out, EINA_FALSE);
+   src = in->mask.data;
+   dst = out->mask.data;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(src, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(dst, EINA_FALSE);
+   curve = cmd->curve.data;
+
+   for (k = in->cache_entry.w * in->cache_entry.h; k; k--)
+     *dst++ = curve[*src++];
+
+   return EINA_TRUE;
+}
+
+Evas_Filter_Apply_Func
+evas_filter_curve_cpu_func_get(Evas_Filter_Command *cmd)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(cmd, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->output, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->input, NULL);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL((cmd->input->w == cmd->output->w)
+                                   && (cmd->input->h == cmd->output->h), 0);
+
+   if (!cmd->input->alpha_only && !cmd->output->alpha_only)
+     return _filter_curve_cpu_rgba;
+
+   if (cmd->input->alpha_only && cmd->output->alpha_only)
+     return _filter_curve_cpu_alpha;
+
+   CRIT("Incompatible image formats");
+   return NULL;
+}