#include <libgimp/gimp.h>
#include <libgimp/gimpcompat.h>

/*************************************************************
*       Even though it's not a full fledged grayscale to
*       RGB convertor.. This is my first try.. :-)
*  TO COMPILE THIS plugin (Against GIMP 2.2) use 
   # gimptool-2.0  --install bw2rgb.c 

   Refer http://wiki.gimp.org/gimp/HowToCompileGimp/MicrosoftWindows
   for installing the msys build setup.
   - To access this plugin from GIMP. 
   1) Open a RGB Black and white file
   2) Use the menu option
      Filters -> Colors -> bw2color
*
**************************************************************/


/* Declare local functions.
 */
static void      query  (void);
static void      run    (gchar      *name,
                         gint        nparams,
                         GimpParam  *param,
                         gint       *nreturn_vals,
                         GimpParam **return_vals);

static void      grayscale_to_rgb         (GimpDrawable *drawable);

GimpPlugInInfo PLUG_IN_INFO =
{
  NULL,  /* init_proc  */
  NULL,  /* quit_proc  */
  query, /* query_proc */
  run,   /* run_proc   */
};
gint32 image_ID;
MAIN ()

static void
query (void)
{
  static GimpParamDef args[] =
  {
    { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
    { GIMP_PDB_IMAGE, "image", "Input image" },
    { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" }
  };
  //static gint nargs = sizeof (args) / sizeof (args[0]);

  gimp_install_procedure ("black_and_white_to_color",
                          "bw2color",
                          "Help",
                          "William Durairaj <sheela.william@gmail.com",
                          "William Durairaj <sheela.william@gmail.com",
                          "2000-2004",
                          "Black & White to Color",
                          "RGB*, GRAY*, INDEXED*",
                          GIMP_PLUGIN,
                          G_N_ELEMENTS (args), 0,
                          args, NULL);

   gimp_plugin_menu_register("black_and_white_to_color",
                             "<Image>/Filters/Colors/bw2color");
}

static void
run (gchar      *name,
     gint        nparams,
     GimpParam  *param,
     gint       *nreturn_vals,
     GimpParam **return_vals)
{
  static GimpParam values[1];
  GimpDrawable *drawable;
  GimpRunModeType run_mode;
  GimpPDBStatusType status = GIMP_PDB_SUCCESS;

  //gint32 image_ID;

  run_mode = param[0].data.d_int32;

  /*  Get the specified drawable  */
  drawable = gimp_drawable_get (param[2].data.d_drawable);
  image_ID = param[1].data.d_image;

  /*  Make sure that the drawable is RGB color  */
  if (gimp_drawable_is_rgb (drawable->drawable_id) ||
      gimp_drawable_is_gray(drawable->drawable_id) != 0 )
    {
      gimp_progress_init ("Starting conversion ...");
      gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1));
      grayscale_to_rgb (drawable);

      if (run_mode != GIMP_RUN_NONINTERACTIVE)
        gimp_displays_flush ();
    }
  else
    {
      status = GIMP_PDB_EXECUTION_ERROR;
    }

  *nreturn_vals = 1;
  *return_vals = values;

  values[0].type = GIMP_PDB_STATUS;
  values[0].data.d_status = status;

  gimp_drawable_detach (drawable);
}


static void
grayscale_to_rgb (GimpDrawable *drawable)
{
  GimpPixelRgn src_rgn, dest_rgn;
  guchar *src, *s;
  guchar *dest, *d;
  gint    progress, max_progress;
  gint    has_alpha, red, green, blue, alpha;
  gint    x1, y1, x2, y2;
  gint    x, y;
  gpointer pr;
  /*------------------------- */ 
  static int color_matrix[256][3];
  static int color_matrix_rgb_count[256][3];
  
  int gray_scale_value,gray_scale_avg = 0;
  int i;
  
  for(red = 0 ; red < 256; red++)
	for(green = 0 ; green < 256; green++)
  	  for(blue  = 0 ; blue < 256; blue++)
	  {
				gray_scale_value = (int)( red * 30.0/100.0 + green * 59.0/100.0 + blue * 11.0/100.0); 
				
				color_matrix[gray_scale_value][0] += red;
				color_matrix_rgb_count[gray_scale_value][0] ++;
				
				
				color_matrix[gray_scale_value][1] += green;
				color_matrix_rgb_count[gray_scale_value][1] ++;
				
				
				color_matrix[gray_scale_value][2] += blue;
				color_matrix_rgb_count[gray_scale_value][2] ++;
   	  }
    for(i = 0 ; i < 256 ; i++)
    {
    color_matrix[i][0] /= color_matrix_rgb_count[i][0];
    color_matrix[i][1] /= color_matrix_rgb_count[i][1];
    color_matrix[i][2] /= color_matrix_rgb_count[i][2];
    }

  /* Get selection area */
  gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2);
  has_alpha = gimp_drawable_has_alpha (drawable->drawable_id);

  red = 0; green = 1; blue = 2;

  alpha = (has_alpha) ? drawable->bpp - 1 : drawable->bpp;

  /* Initialize progress */
  progress = 0;
  max_progress = (x2 - x1) * (y2 - y1);

  /* substitute pixel vales */
  //gimp_image_convert_rgb(image_ID);
  gimp_pixel_rgn_init (&src_rgn, drawable,
                       x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE);
  gimp_pixel_rgn_init (&dest_rgn, drawable,
                       x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE);

  for (pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn);
       pr != NULL;
       pr = gimp_pixel_rgns_process (pr))
    {
      src = src_rgn.data;
      dest = dest_rgn.data;

      for (y = 0; y < src_rgn.h; y++)
        {
          s = src;
          d = dest;

          for (x = 0; x < src_rgn.w; x++)
            {

              gray_scale_avg = (guchar)( (s[0] +s[1] + s[2])/3);

              d[0] = (guchar)color_matrix[gray_scale_avg][0]; // color_matrix[s[0]][0];
              d[1] = (guchar)color_matrix[gray_scale_avg][1];
              d[2] = (guchar)color_matrix[gray_scale_avg][2];


              if (has_alpha)
                d[alpha] = s[alpha];

              s += src_rgn.bpp; 
              d += dest_rgn.bpp;
            }

          src  += src_rgn.rowstride;
          dest += dest_rgn.rowstride;
        }

      /* Update progress */
      progress += src_rgn.w * src_rgn.h;

      gimp_progress_update ((double) progress / (double) max_progress);
    }

  /*  update the region  */
  //gimp_image_convert_rgb(image_ID);
  gimp_drawable_flush (drawable);
  gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
  gimp_drawable_update (drawable->drawable_id, x1, y1, (x2 - x1), (y2 - y1));
}

     
