gimp/plug-ins/rcm/rcm.c

279 lines
8.0 KiB
C

/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for the GIMP.
*
* Colormap-Rotation plug-in. Exchanges two color ranges.
*
* Copyright (C) 1999 Sven Anders (anderss@fmi.uni-passau.de)
* Based on code from Pavel Grinfeld (pavel@ml.com)
*
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*-----------------------------------------------------------------------------------
* Change log:
*
* Version 2.0, 04 April 1999.
* Nearly complete rewrite, made plug-in stable.
* (Works with GIMP 1.1 and GTK+ 1.2)
*
* Version 1.0, 27 March 1997.
* Initial (unstable) release by Pavel Grinfeld
*
*-----------------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <gtk/gtk.h>
#include <libgimp/gimp.h>
#include <libgimp/gimpintl.h>
#include "rcm.h"
#include "rcm_misc.h"
#include "rcm_dialog.h"
#include "rcm_callback.h"
/*-----------------------------------------------------------------------------------*/
/* Forward declarations */
/*-----------------------------------------------------------------------------------*/
void query(void);
void run(char *name, int nparams, GParam *param, int *nreturn_vals, GParam **return_vals);
/*-----------------------------------------------------------------------------------*/
/* Global variables */
/*-----------------------------------------------------------------------------------*/
RcmParams Current =
{
SELECTION, /* SELECTION ONLY */
TRUE, /* REAL TIME */
FALSE, /* SUCCESS */
RADIANS_OVER_PI, /* START IN RADIANS OVER PI */
GRAY_TO
};
/*-----------------------------------------------------------------------------------*/
/* Local variables */
/*-----------------------------------------------------------------------------------*/
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
/*-----------------------------------------------------------------------------------*/
/* Dummy function */
/*-----------------------------------------------------------------------------------*/
MAIN()
/*-----------------------------------------------------------------------------------*/
/* Query plug-in */
/*-----------------------------------------------------------------------------------*/
void query(void)
{
GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image (used for indexed images)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
};
GParamDef *return_vals = NULL;
int nargs = sizeof (args) / sizeof (args[0]);
int nreturn_vals = 0;
gimp_install_procedure ("plug-in-rotate-colormap",
"Colormap rotation as in xv",
"Exchanges two color ranges. "\
"Based on code from Pavel Grinfeld (pavel@ml.com). "\
"This version written by Sven Anders (anderss@fmi.uni-passau.de).",
"Sven Anders (anderss@fmi.uni-passau.de) and Pavel Grinfeld (pavel@ml.com)",
"Sven Anders (anderss@fmi.uni-passau.de)",
"04th April 1999",
"<Image>/Filters/Darkroom/Colormap Rotation",
"RGB*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
/*-----------------------------------------------------------------------------------*/
/* Rotate colormap of a single row */
/*-----------------------------------------------------------------------------------*/
void rcm_row(const guchar *src_row, guchar *dest_row,
gint row, gint row_width, gint bytes)
{
gint col, bytenum, skip;
hsv H,S,V,R,G,B;
for (col=0; col < row_width; col++)
{
skip = 0;
R = (float)src_row[col*bytes + 0]/255.0;
G = (float)src_row[col*bytes + 1]/255.0;
B = (float)src_row[col*bytes + 2]/255.0;
rgb_to_hsv(R,G,B, &H,&S,&V);
if (rcm_is_gray(S))
{
if (Current.Gray_to_from == GRAY_FROM)
{
if (rcm_angle_inside_slice(Current.Gray->hue,Current.From->angle) <= 1)
{
H = Current.Gray->hue / TP;
S = Current.Gray->satur;
}
else
{
skip = 1;
}
}
else
{
skip = 1;
hsv_to_rgb(Current.Gray->hue/TP, Current.Gray->satur, V, &R, &G, &B);
}
}
if (!skip)
{
H = rcm_linear(rcm_left_end(Current.From->angle),
rcm_right_end(Current.From->angle),
rcm_left_end(Current.To->angle),
rcm_right_end(Current.To->angle),
H*TP);
H = angle_mod_2PI(H) / TP;
hsv_to_rgb(H,S,V, &R,&G,&B);
}
dest_row[col*bytes +0] = R * 255;
dest_row[col*bytes +1] = G * 255;
dest_row[col*bytes +2] = B * 255;
if (bytes > 3)
{
for (bytenum=3; bytenum<bytes; bytenum++)
dest_row[col*bytes+bytenum] = src_row[col*bytes+bytenum];
}
}
}
/*-----------------------------------------------------------------------------------*/
/* Rotate colormap row by row ... */
/*-----------------------------------------------------------------------------------*/
void rcm(GDrawable *drawable)
{
GPixelRgn srcPR, destPR;
gint width, height;
gint bytes;
guchar *src_row, *dest_row;
gint row;
gint x1, y1, x2, y2;
gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
width = drawable->width;
height = drawable->height;
bytes = drawable->bpp;
src_row = (guchar *) malloc ((x2 - x1) * bytes);
dest_row = (guchar *) malloc ((x2 - x1) * bytes);
gimp_pixel_rgn_init(&srcPR, drawable, 0, 0, width, height, FALSE, FALSE);
gimp_pixel_rgn_init(&destPR, drawable, 0, 0, width, height, TRUE, TRUE);
for (row=y1; row < y2; row++)
{
gimp_pixel_rgn_get_row(&srcPR, src_row, x1, row, (x2 - x1));
rcm_row(src_row, dest_row, row, (x2 - x1), bytes);
gimp_pixel_rgn_set_row(&destPR, dest_row, x1, row, (x2 - x1));
if ((row % 10) == 0)
gimp_progress_update((double) row / (double) (y2 - y1));
}
/* update the processed region */
gimp_drawable_flush(drawable);
gimp_drawable_merge_shadow(drawable->id, TRUE);
gimp_drawable_update(drawable->id, x1, y1, (x2 - x1), (y2 - y1));
free (src_row);
free (dest_row);
}
/*-----------------------------------------------------------------------------------*/
/* STANDARD RUN */
/*-----------------------------------------------------------------------------------*/
void run(char *name, int nparams, GParam *param, int *nreturn_vals, GParam **return_vals)
{
GParam values[1];
GStatusType status = STATUS_SUCCESS;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
Current.drawable = gimp_drawable_get(param[2].data.d_drawable);
Current.mask = gimp_drawable_get(gimp_image_get_selection(param[1].data.d_image));
/* works not on INDEXED images */
if (gimp_drawable_indexed (Current.drawable->id) ||
gimp_drawable_gray (Current.drawable->id) )
{
status = STATUS_EXECUTION_ERROR;
}
else
{
/* call dialog and rotate the colormap */
if (gimp_drawable_color(Current.drawable->id) && rcm_dialog())
{
gimp_progress_init(_("Rotating the colormap..."));
gimp_tile_cache_ntiles(2 * (Current.drawable->width / gimp_tile_width() + 1));
rcm(Current.drawable);
gimp_displays_flush();
}
else
status = STATUS_EXECUTION_ERROR;
}
values[0].data.d_status = status;
if (status == STATUS_SUCCESS)
gimp_drawable_detach(Current.drawable);
}