/**
* rot.c
* A pixel-oriented GIMP plugin, attached to images, that does
* something or other.
*
* Copyright (c) 2013 Samuel A. Rebelsky. All rights reserved.
*
* This file is part of The Glimmer Guide to GIMP Plugins (aka GGGP).
*
* GGGP is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GGGP is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GGGP. If not, see .
*/
// +---------+---------------------------------------------------------
// | Headers |
// +---------+
#include
#include
// +--------+----------------------------------------------------------
// | Macros |
// +--------+
/**
* Print a string (somewhere). Right now, this prints to stderr, which
* means it only works when the program is run from the terminal.
*/
#define REPORT(str) fprintf (stderr, "*** %s ***\n", str)
/**
* Print an integer.
*/
#define REPORT_INT(i) fprintf (stderr, "*** %s: %d ***\n", #i, i)
// +-------+-----------------------------------------------------------
// | Types |
// +-------+
typedef void (*PixelFunRGB) (guchar sr, guchar sg, guchar sb,
guchar *tr, guchar *tg, guchar *tb);
// +--------------------------+----------------------------------------
// | Function Predeclarations |
// +--------------------------+
static void query (void);
static void run (const gchar *name,
gint nparams,
const GimpParam *params,
gint *nreturn_vals,
GimpParam **return_vals);
// +-------------+-----------------------------------------------------
// | Pixel Stuff |
// +-------------+
guchar
bite (int i)
{
if (i < 0) return 0;
if (i > 255) return 255;
return (guchar) i;
} // bite
/**
* The real work
*/
void
transform (guchar sr, guchar sg, guchar sb,
guchar *tr, guchar *tg, guchar *tb)
{
int ave = (sr + sg + sb) / 3;
*tr = bite (sr + (sr - ave) / 8);
*tg = bite (sr + (sr - ave) / 8);
*tb = bite (sb + (sb - ave) / 8);
} // transform
/**
* Process a drawable using a function.
*/
int
process_rgb_drawable (int image, int drawable, PixelFunRGB pixelfun)
{
// Sanity check
if (! gimp_image_is_valid (image))
{
return GIMP_PDB_CALLING_ERROR;
}
if (! gimp_drawable_is_valid (drawable))
{
return GIMP_PDB_CALLING_ERROR;
}
// Grab detailed info on the drawables
GimpDrawable *source, *target;
source = gimp_drawable_get (drawable);
target = gimp_drawable_get (drawable);
if ((source == NULL) || (target == NULL))
{
if (source != NULL) gimp_drawable_detach (source);
if (target != NULL) gimp_drawable_detach (target);
return GIMP_PDB_EXECUTION_ERROR;
}
// Gather some information on the region to process. (Right now, we
// don't pay attention to the drawables. We should.)
int left = 0;
int top = 0;
int width = gimp_image_width (image);
int height = gimp_image_height (image);
// Prepare our regions
GimpPixelRgn source_region;
GimpPixelRgn target_region;
gimp_pixel_rgn_init (&source_region, source,
left, top, width, height, FALSE, FALSE); // read only
gimp_pixel_rgn_init (&target_region, target,
left, top, width, height, TRUE, TRUE); // shadow write
// Iterate through tiles
gpointer pr;
pr = gimp_pixel_rgns_register (2, &source_region, &target_region);
while (pr != NULL)
{
guchar *source_data = source_region.data;
guchar *target_data = target_region.data;
// Do each row
int r;
for (r = 0; r < source_region.h; r++)
{
// Grab pointers to the start of the data
guchar *s = source_data;
guchar *t = target_data;
// Do each column in the row
int c;
for (c = 0; c < source_region.w; c++)
{
// Process the pixel
pixelfun (s[0], s[1], s[2], t, t+1, t+2);
// Advance to the next pixel
s += source_region.bpp;
t += target_region.bpp;
} // for each column
// Advance to the next row
source_data = source_data + source_region.rowstride;
target_data = target_data + target_region.rowstride;
} // for each row
// Advance to the next tile
pr = gimp_pixel_rgns_process (pr);
} // while
// Clean up
gimp_drawable_flush (target);
gimp_drawable_merge_shadow (drawable, TRUE);
gimp_drawable_update (drawable, left, top, width, height);
gimp_displays_flush ();
gimp_drawable_detach (source);
gimp_drawable_detach (target);
// And we're done
return GIMP_PDB_SUCCESS;
} // process_rgb_drawable
// +-------------+-----------------------------------------------------
// | Boilerplate |
// +-------------+
/**
* The four key functions. This structure *must* be called PLUG_IN_INFO.
*/
GimpPlugInInfo PLUG_IN_INFO =
{
NULL,
NULL,
query,
run
};
/**
* Indicate that we're ready to begin the main part of the code.
*/
MAIN ()
// +-------------------------+-----------------------------------------
// | Standard GIMP Functions |
// +-------------------------+
static void
init (void)
{
} // init
static void
quit (void)
{
} // quit
static void
query (void)
{
// Build the description of the parameters that the function expects.
// Each parameter has a type, a name, and a description
// All plug-ins must take a run-mode. Plug-ins associated with an
// image
static GimpParamDef args[] =
{
{ GIMP_PDB_INT32, "run-mode", "Run mode" },
{ GIMP_PDB_IMAGE, "image", "Input image" },
{ GIMP_PDB_DRAWABLE, "drawable", "Input layer or other drawable" }
}; // args
// Tell the GIMP about our plugin.
gimp_install_procedure (
"gggp/rot", // Name
"Blurb", // Blurb
"Help", // Help
"Samuel A. Rebelsky", // Author
"Copyright (c) Samuel A. Rebelsky. All rights reserved.",
// Copyright
"2013", // Year
"/GGGP/Rot", // Path
"RGB", // Image types
GIMP_PLUGIN, // Type
3, // Number of params
0, // Number of return vals
args, // Param descriptions
NULL // Return descriptions
);
} // query
static void
run (const gchar *name,
gint nparams,
const GimpParam *params,
gint *nreturn_vals,
GimpParam **return_vals)
{
// Prepare return values
static GimpParam results[1];
results[0].type = GIMP_PDB_STATUS;
results[0].data.d_status = GIMP_PDB_SUCCESS;
*nreturn_vals = 1;
*return_vals = results;
// Get parameters
int image = params[1].data.d_image;
int drawable = params[2].data.d_drawable;
// And do the work
results[0].data.d_status = process_rgb_drawable (image, drawable, transform);
} // run