/** * 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