Duotone effect in Raster

on 10 Mar 2011 by Mukund (@muks)

It's 3 AM but I've got round to doing the types of things that I started writing Raster for. :) This is a graph of operations for the simple duotone effect. It is based on the algorithm in Alexios Chouchoulas's Simple Duotone script for GIMP.

Raster has a nifty op called RasterOpMap using which you can map one pixel value to any other. This can be used for things such as color curves and any kind of render operations. It's inefficient in the case of color curves, but if you want a custom map function, this is the op. :) Here, we simply map an image to a sine curve. RasterOpMask takes that as a mask for a solid sepia rectangle and then RasterOpOver composites that over the original image.

Duotone graph

The result: (do you notice the effect?) :)

Input Output

The code:

#include <stdio.h>
#include <raster/raster.h>
#include <math.h>

#ifndef M_PI
#define M_PI 3.14159265358979323846

#define CLAMP(x) ((x) > 1.0 ? 1.0 : ((x) < 0.0 ? 0.0 : (x)))

static void
map_cb (void   *ptr,
        size_t  width,
        size_t  height,
        size_t  x,
        size_t  y,
        float   in_r,
        float   in_g,
        float   in_b,
        float   in_a,
        float  *out_r,
        float  *out_g,
        float  *out_b,
        float  *out_a)
  *out_r = sin (CLAMP (in_r) * M_PI) / 3.0;
  *out_g = sin (CLAMP (in_g) * M_PI) / 3.0;
  *out_b = sin (CLAMP (in_b) * M_PI) / 3.0;

main (int argc, char *argv[])
  RasterNode *n1;
  RasterNode *n2;
  RasterNode *n3;
  RasterNode *n4;
  RasterNode *n5;

  n1 = raster_in_ppm ("om.ppm");
  n2 = raster_op_map (n1, map_cb, NULL);
  n3 = raster_op_clear (n1, 162/255.0, 138/255.0, 101/255.0, 1.0);

  n4 = raster_op_mask (n3, n2);
  raster_node_unref (n3);
  raster_node_unref (n2);

  n5 = raster_op_over (n4, n1);
  raster_node_unref (n4);
  raster_node_unref (n1);

  raster_out_ppm (n5, "out6.ppm");

  printf ("exp: %s\n", raster_node_get_expr (n5));

  raster_node_unref (n5);

  return 0;