mirror of https://github.com/GNOME/gimp.git
build color_cmds, lut_funcs, and pixel_processor feedback in the splash
* app/Makefile.am: build color_cmds, lut_funcs, and pixel_processor * app/app_procs.c: feedback in the splash screen when loading parasites. * app/boundary.c: Optimized find_empty_segs. * app/brightness_contrast.[ch] * app/levels.[ch] * app/posterize.[ch]: moved pdb and lut calculation code. These files now contain only GUI functions. * app/channel.c: Optimized channel_bounds (fewer compares, better use of registers). Use color_region instead of channel_*_segment in channel_combine_rect. Optimized channel_combine_ellipse by skipping pixels inside of the ellipse. Use pixel_region_process_parallel in channel_combine_mask. Use a GimpLut in channel_invert, and channel_sharpen. * app/invert.c * app/equalize.c: moved the lut functions to lut_funcs.c * app/gimpdrawable.c, app/gimpdrawableP.h * app/gimpimage.c, app/gimpimageP.h: removed unused gimpmatrix variables/includes. * app/gimplut.[ch]: added new function gimp_lut_process_inline that operates on a single PixelRegion. * app/gimpparasite.[ch]: new functions to save/load parasiterc * app/parasitelist.[ch]: new functions to save/load ParasiteLists in/from files. * libgimp/parasite.[ch]: new functions to load/save parasites. * app/internal_procs.c: get some procs from new location in color_cmds.h. * app/pixel_region.[ch]: moved pixel_regions_process_parallel related functions to a new file. * app/color_cmds.[ch]: new files for PDB definitions/implementations of color correction functions. * app/lut_funcs.[ch]: new files to hold lut creation functions. * app/pixel_processor.[ch]: new files that contain the pixel_regions_process_parallel routines. Added some new capabilities that are currently unused.
This commit is contained in:
parent
8650675f22
commit
dde3603123
52
ChangeLog
52
ChangeLog
|
@ -1,3 +1,55 @@
|
||||||
|
1999-04-08 Jay Cox <jaycox@earthlink.net>
|
||||||
|
|
||||||
|
* app/Makefile.am: build color_cmds, lut_funcs, and pixel_processor
|
||||||
|
* app/app_procs.c: feedback in the splash screen when loading
|
||||||
|
parasites.
|
||||||
|
* app/boundary.c: Optimized find_empty_segs.
|
||||||
|
|
||||||
|
* app/brightness_contrast.[ch]
|
||||||
|
* app/levels.[ch]
|
||||||
|
* app/posterize.[ch]:
|
||||||
|
moved pdb and lut calculation code. These files now contain only
|
||||||
|
GUI functions.
|
||||||
|
|
||||||
|
* app/channel.c: Optimized channel_bounds (fewer compares, better
|
||||||
|
use of registers). Use color_region instead of channel_*_segment
|
||||||
|
in channel_combine_rect. Optimized channel_combine_ellipse by
|
||||||
|
skipping pixels inside of the ellipse. Use
|
||||||
|
pixel_region_process_parallel in channel_combine_mask. Use a
|
||||||
|
GimpLut in channel_invert, and channel_sharpen.
|
||||||
|
|
||||||
|
* app/invert.c
|
||||||
|
* app/equalize.c: moved the lut functions to lut_funcs.c
|
||||||
|
|
||||||
|
* app/gimpdrawable.c, app/gimpdrawableP.h
|
||||||
|
* app/gimpimage.c, app/gimpimageP.h: removed unused gimpmatrix
|
||||||
|
variables/includes.
|
||||||
|
|
||||||
|
* app/gimplut.[ch]: added new function gimp_lut_process_inline
|
||||||
|
that operates on a single PixelRegion.
|
||||||
|
|
||||||
|
* app/gimpparasite.[ch]: new functions to save/load parasiterc
|
||||||
|
|
||||||
|
* app/parasitelist.[ch]: new functions to save/load ParasiteLists
|
||||||
|
in/from files.
|
||||||
|
|
||||||
|
* libgimp/parasite.[ch]: new functions to load/save parasites.
|
||||||
|
|
||||||
|
* app/internal_procs.c: get some procs from new location in
|
||||||
|
color_cmds.h.
|
||||||
|
|
||||||
|
* app/pixel_region.[ch]: moved pixel_regions_process_parallel
|
||||||
|
related functions to a new file.
|
||||||
|
|
||||||
|
* app/color_cmds.[ch]: new files for PDB
|
||||||
|
definitions/implementations of color correction functions.
|
||||||
|
|
||||||
|
* app/lut_funcs.[ch]: new files to hold lut creation functions.
|
||||||
|
|
||||||
|
* app/pixel_processor.[ch]: new files that contain the
|
||||||
|
pixel_regions_process_parallel routines. Added some new
|
||||||
|
capabilities that are currently unused.
|
||||||
|
|
||||||
Fri Apr 9 01:52:23 MEST 1999 Sven Neumann <sven@gimp.org>
|
Fri Apr 9 01:52:23 MEST 1999 Sven Neumann <sven@gimp.org>
|
||||||
|
|
||||||
* plug-ins/autocrop/autocrop.c: Fixed a Bad Bug(TM).
|
* plug-ins/autocrop/autocrop.c: Fixed a Bad Bug(TM).
|
||||||
|
|
|
@ -77,6 +77,8 @@ gimp_SOURCES = \
|
||||||
color_area.h \
|
color_area.h \
|
||||||
color_balance.c \
|
color_balance.c \
|
||||||
color_balance.h \
|
color_balance.h \
|
||||||
|
color_cmds.c \
|
||||||
|
color_cmds.h \
|
||||||
color_notebook.c \
|
color_notebook.c \
|
||||||
color_notebook.h \
|
color_notebook.h \
|
||||||
color_panel.c \
|
color_panel.c \
|
||||||
|
@ -245,6 +247,8 @@ gimp_SOURCES = \
|
||||||
layers_dialogP.h \
|
layers_dialogP.h \
|
||||||
levels.c \
|
levels.c \
|
||||||
levels.h \
|
levels.h \
|
||||||
|
lut_funcs.c \
|
||||||
|
lut_funcs.h \
|
||||||
magnify.c \
|
magnify.c \
|
||||||
magnify.h \
|
magnify.h \
|
||||||
main.c \
|
main.c \
|
||||||
|
@ -288,6 +292,8 @@ gimp_SOURCES = \
|
||||||
pencil.h \
|
pencil.h \
|
||||||
perspective_tool.c \
|
perspective_tool.c \
|
||||||
perspective_tool.h \
|
perspective_tool.h \
|
||||||
|
pixel_processor.c \
|
||||||
|
pixel_processor.h \
|
||||||
pixel_region.c \
|
pixel_region.c \
|
||||||
pixel_region.h \
|
pixel_region.h \
|
||||||
pixmaps.h \
|
pixmaps.h \
|
||||||
|
|
|
@ -85,6 +85,7 @@
|
||||||
|
|
||||||
#include "color_notebook.h"
|
#include "color_notebook.h"
|
||||||
#include "color_select.h"
|
#include "color_select.h"
|
||||||
|
#include "gimpparasite.h"
|
||||||
|
|
||||||
#include "libgimp/gimpintl.h"
|
#include "libgimp/gimpintl.h"
|
||||||
|
|
||||||
|
@ -535,15 +536,16 @@ app_init (void)
|
||||||
file_ops_pre_init (); /* pre-initialize the file types */
|
file_ops_pre_init (); /* pre-initialize the file types */
|
||||||
RESET_BAR();
|
RESET_BAR();
|
||||||
xcf_init (); /* initialize the xcf file format routines */
|
xcf_init (); /* initialize the xcf file format routines */
|
||||||
gimp_init_parasites (); /* initialize the parasite table */
|
|
||||||
|
|
||||||
app_init_update_status (_("Looking for data files"), _("Brushes"), 0.00);
|
app_init_update_status (_("Looking for data files"), _("Parasites"), 0.00);
|
||||||
|
gimp_init_parasites (); /* initialize the global parasite table */
|
||||||
|
app_init_update_status (NULL, _("Brushes"), 0.20);
|
||||||
brushes_init (no_data); /* initialize the list of gimp brushes */
|
brushes_init (no_data); /* initialize the list of gimp brushes */
|
||||||
app_init_update_status (NULL, _("Patterns"), 0.25);
|
app_init_update_status (NULL, _("Patterns"), 0.40);
|
||||||
patterns_init (no_data); /* initialize the list of gimp patterns */
|
patterns_init (no_data); /* initialize the list of gimp patterns */
|
||||||
app_init_update_status (NULL, _("Palettes"), 0.50);
|
app_init_update_status (NULL, _("Palettes"), 0.60);
|
||||||
palettes_init (no_data); /* initialize the list of gimp palettes */
|
palettes_init (no_data); /* initialize the list of gimp palettes */
|
||||||
app_init_update_status (NULL, _("Gradients"), 0.75);
|
app_init_update_status (NULL, _("Gradients"), 0.80);
|
||||||
gradients_init (no_data); /* initialize the list of gimp gradients */
|
gradients_init (no_data); /* initialize the list of gimp gradients */
|
||||||
app_init_update_status (NULL, NULL, 1.00);
|
app_init_update_status (NULL, NULL, 1.00);
|
||||||
|
|
||||||
|
@ -635,6 +637,7 @@ app_exit_finish (void)
|
||||||
menus_quit ();
|
menus_quit ();
|
||||||
tile_swap_exit ();
|
tile_swap_exit ();
|
||||||
save_unitrc ();
|
save_unitrc ();
|
||||||
|
gimp_parasiterc_save ();
|
||||||
|
|
||||||
/* Things to do only if there is an interface */
|
/* Things to do only if there is an interface */
|
||||||
if (no_interface == FALSE)
|
if (no_interface == FALSE)
|
||||||
|
|
|
@ -83,6 +83,8 @@ find_empty_segs (PixelRegion *maskPR,
|
||||||
int val, last;
|
int val, last;
|
||||||
int tilex;
|
int tilex;
|
||||||
Tile *tile = NULL;
|
Tile *tile = NULL;
|
||||||
|
int endx, l_num_empty, dstep;
|
||||||
|
|
||||||
|
|
||||||
data = NULL;
|
data = NULL;
|
||||||
start = 0;
|
start = 0;
|
||||||
|
@ -121,7 +123,9 @@ find_empty_segs (PixelRegion *maskPR,
|
||||||
empty_segs[(*num_empty)++] = 0;
|
empty_segs[(*num_empty)++] = 0;
|
||||||
last = -1;
|
last = -1;
|
||||||
|
|
||||||
for (x = start; x < end; x++)
|
l_num_empty = *num_empty;
|
||||||
|
|
||||||
|
for (x = start; x < end;)
|
||||||
{
|
{
|
||||||
/* Check to see if we must advance to next tile */
|
/* Check to see if we must advance to next tile */
|
||||||
if ((x / TILE_WIDTH) != tilex)
|
if ((x / TILE_WIDTH) != tilex)
|
||||||
|
@ -132,22 +136,46 @@ find_empty_segs (PixelRegion *maskPR,
|
||||||
data = (unsigned char*)tile_data_pointer (tile, x % TILE_WIDTH, scanline % TILE_HEIGHT) + (tile_bpp(tile) - 1);
|
data = (unsigned char*)tile_data_pointer (tile, x % TILE_WIDTH, scanline % TILE_HEIGHT) + (tile_bpp(tile) - 1);
|
||||||
|
|
||||||
tilex = x / TILE_WIDTH;
|
tilex = x / TILE_WIDTH;
|
||||||
|
dstep = tile_bpp(tile);
|
||||||
|
}
|
||||||
|
endx = x + (TILE_WIDTH - (x%TILE_WIDTH));
|
||||||
|
endx = MINIMUM(end, endx);
|
||||||
|
if (type == IgnoreBounds && (endx > x1 || x < x2))
|
||||||
|
for (; x < endx; x++)
|
||||||
|
{
|
||||||
|
if (*data > HALF_WAY)
|
||||||
|
if (x >= x1 && x < x2)
|
||||||
|
val = -1;
|
||||||
|
else
|
||||||
|
val = 1;
|
||||||
|
else
|
||||||
|
val = -1;
|
||||||
|
|
||||||
|
data += dstep;
|
||||||
|
|
||||||
|
if (last != val)
|
||||||
|
empty_segs[l_num_empty++] = x;
|
||||||
|
|
||||||
|
last = val;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
for (; x < endx; x++)
|
||||||
|
{
|
||||||
|
if (*data > HALF_WAY)
|
||||||
|
val = 1;
|
||||||
|
else
|
||||||
|
val = -1;
|
||||||
|
|
||||||
|
data += dstep;
|
||||||
|
|
||||||
|
if (last != val)
|
||||||
|
empty_segs[l_num_empty++] = x;
|
||||||
|
|
||||||
|
last = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
empty_segs[*num_empty] = x;
|
|
||||||
val = (*data > HALF_WAY) ? 1 : -1;
|
|
||||||
|
|
||||||
/* The IgnoreBounds case */
|
|
||||||
if (val == 1 && type == IgnoreBounds)
|
|
||||||
if (x >= x1 && x < x2)
|
|
||||||
val = -1;
|
|
||||||
|
|
||||||
if (last * val < 0)
|
|
||||||
(*num_empty)++;
|
|
||||||
last = val;
|
|
||||||
|
|
||||||
data += tile_bpp(tile);
|
|
||||||
}
|
}
|
||||||
|
*num_empty = l_num_empty;
|
||||||
|
|
||||||
if (last > 0)
|
if (last > 0)
|
||||||
empty_segs[(*num_empty)++] = x;
|
empty_segs[(*num_empty)++] = x;
|
||||||
|
|
|
@ -160,6 +160,79 @@ gimp_lut_process (GimpLut *lut,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gimp_lut_process_inline (GimpLut *lut,
|
||||||
|
PixelRegion *srcPR)
|
||||||
|
{
|
||||||
|
int h, width, src_r_i;
|
||||||
|
unsigned char *src;
|
||||||
|
unsigned char *lut0 = NULL, *lut1 = NULL, *lut2 = NULL, *lut3 = NULL;
|
||||||
|
|
||||||
|
if (lut->nchannels > 0)
|
||||||
|
lut0 = lut->luts[0];
|
||||||
|
if (lut->nchannels > 1)
|
||||||
|
lut1 = lut->luts[1];
|
||||||
|
if (lut->nchannels > 2)
|
||||||
|
lut2 = lut->luts[2];
|
||||||
|
if (lut->nchannels > 3)
|
||||||
|
lut3 = lut->luts[3];
|
||||||
|
|
||||||
|
h = srcPR->h;
|
||||||
|
src = srcPR->data;
|
||||||
|
width = srcPR->w;
|
||||||
|
src_r_i = srcPR->rowstride - (srcPR->bytes * srcPR->w);
|
||||||
|
|
||||||
|
if (src_r_i == 0)
|
||||||
|
{
|
||||||
|
width *= h;
|
||||||
|
h = 1;
|
||||||
|
}
|
||||||
|
while (h--)
|
||||||
|
{
|
||||||
|
switch (lut->nchannels)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
while (width--)
|
||||||
|
{
|
||||||
|
*src = lut0[*src];
|
||||||
|
src++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
while (width--)
|
||||||
|
{
|
||||||
|
src[0] = lut0[src[0]];
|
||||||
|
src[1] = lut1[src[1]];
|
||||||
|
src += 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
while (width--)
|
||||||
|
{
|
||||||
|
src[0] = lut0[src[0]];
|
||||||
|
src[1] = lut1[src[1]];
|
||||||
|
src[2] = lut2[src[2]];
|
||||||
|
src += 3;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
while (width--)
|
||||||
|
{
|
||||||
|
src[0] = lut0[src[0]];
|
||||||
|
src[1] = lut1[src[1]];
|
||||||
|
src[2] = lut2[src[2]];
|
||||||
|
src[3] = lut3[src[3]];
|
||||||
|
src += 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "gimplut: Error: nchannels = %d\n", lut->nchannels);
|
||||||
|
}
|
||||||
|
width = srcPR->w;
|
||||||
|
src += src_r_i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gimp_lut_process_2 (PixelRegion *srcPR,
|
gimp_lut_process_2 (PixelRegion *srcPR,
|
||||||
PixelRegion *destPR,
|
PixelRegion *destPR,
|
||||||
|
|
|
@ -49,6 +49,11 @@ void gimp_lut_process (GimpLut *lut,
|
||||||
PixelRegion *srcPR,
|
PixelRegion *srcPR,
|
||||||
PixelRegion *destPR);
|
PixelRegion *destPR);
|
||||||
|
|
||||||
|
/* gimp_lut_process_inline is like gimp_lut_process except it uses a
|
||||||
|
single PixelRegion as both the source and destination */
|
||||||
|
void gimp_lut_process_inline(GimpLut *lut,
|
||||||
|
PixelRegion *src_destPR);
|
||||||
|
|
||||||
/* gimp_lut_process_2 is the same as gimp_lut_process but the lut
|
/* gimp_lut_process_2 is the same as gimp_lut_process but the lut
|
||||||
perameter is last instead of first. this is necesary because
|
perameter is last instead of first. this is necesary because
|
||||||
pixel_region_process_paralell sends the user_data as the 1st
|
pixel_region_process_paralell sends the user_data as the 1st
|
||||||
|
|
|
@ -0,0 +1,417 @@
|
||||||
|
/* The GIMP -- an image manipulation program
|
||||||
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "gimplut.h"
|
||||||
|
#include "gimphistogram.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
/* ---------- Brightness/Contrast -----------*/
|
||||||
|
|
||||||
|
typedef struct B_C_struct
|
||||||
|
{
|
||||||
|
double brightness;
|
||||||
|
double contrast;
|
||||||
|
} B_C_struct;
|
||||||
|
|
||||||
|
static float
|
||||||
|
brightness_contrast_lut_func(B_C_struct *data,
|
||||||
|
int nchannels, int channel, float value)
|
||||||
|
{
|
||||||
|
float nvalue;
|
||||||
|
double power;
|
||||||
|
|
||||||
|
/* return the original value for the alpha channel */
|
||||||
|
if ((nchannels == 2 || nchannels == 4) && channel == nchannels -1)
|
||||||
|
return value;
|
||||||
|
|
||||||
|
/* apply brightness */
|
||||||
|
if (data->brightness < 0.0)
|
||||||
|
value = value * (1.0 + data->brightness);
|
||||||
|
else
|
||||||
|
value = value + ((1.0 - value) * data->brightness);
|
||||||
|
|
||||||
|
/* apply contrast */
|
||||||
|
if (data->contrast < 0.0)
|
||||||
|
{
|
||||||
|
if (value > 0.5)
|
||||||
|
nvalue = 1.0 - value;
|
||||||
|
else
|
||||||
|
nvalue = value;
|
||||||
|
if (nvalue < 0.0)
|
||||||
|
nvalue = 0.0;
|
||||||
|
nvalue = 0.5 * pow (nvalue * 2.0 , (double) (1.0 + data->contrast));
|
||||||
|
if (value > 0.5)
|
||||||
|
value = 1.0 - nvalue;
|
||||||
|
else
|
||||||
|
value = nvalue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (value > 0.5)
|
||||||
|
nvalue = 1.0 - value;
|
||||||
|
else
|
||||||
|
nvalue = value;
|
||||||
|
if (nvalue < 0.0)
|
||||||
|
nvalue = 0.0;
|
||||||
|
power = (data->contrast == 1.0) ? 127 : 1.0 / (1.0 - data->contrast);
|
||||||
|
nvalue = 0.5 * pow (2.0 * nvalue, power);
|
||||||
|
if (value > 0.5)
|
||||||
|
value = 1.0 - nvalue;
|
||||||
|
else
|
||||||
|
value = nvalue;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
brightness_contrast_lut_setup(GimpLut *lut, double brightness, double contrast,
|
||||||
|
int nchannels)
|
||||||
|
{
|
||||||
|
B_C_struct data;
|
||||||
|
data.brightness = brightness;
|
||||||
|
data.contrast = contrast;
|
||||||
|
gimp_lut_setup(lut, (GimpLutFunc) brightness_contrast_lut_func,
|
||||||
|
(void *) &data, nchannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
GimpLut *
|
||||||
|
brightness_contrast_lut_new(double brightness, double contrast,
|
||||||
|
int nchannels)
|
||||||
|
{
|
||||||
|
GimpLut *lut;
|
||||||
|
lut = gimp_lut_new();
|
||||||
|
brightness_contrast_lut_setup(lut, brightness, contrast, nchannels);
|
||||||
|
return lut;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------- invert ------------------ */
|
||||||
|
|
||||||
|
static float
|
||||||
|
invert_lut_func(void *unused,
|
||||||
|
int nchannels, int channel, float value)
|
||||||
|
{
|
||||||
|
/* don't invert the alpha channel */
|
||||||
|
if ((nchannels == 2 || nchannels == 4) && channel == nchannels -1)
|
||||||
|
return value;
|
||||||
|
|
||||||
|
return 1.0 - value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
invert_lut_setup(GimpLut *lut, int nchannels)
|
||||||
|
{
|
||||||
|
gimp_lut_setup_exact(lut, (GimpLutFunc) invert_lut_func,
|
||||||
|
NULL , nchannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
GimpLut *
|
||||||
|
invert_lut_new(int nchannels)
|
||||||
|
{
|
||||||
|
GimpLut *lut;
|
||||||
|
lut = gimp_lut_new();
|
||||||
|
invert_lut_setup(lut, nchannels);
|
||||||
|
return lut;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------- add (or subract)------------------ */
|
||||||
|
|
||||||
|
static float
|
||||||
|
add_lut_func(double *ammount,
|
||||||
|
int nchannels, int channel, float value)
|
||||||
|
{
|
||||||
|
/* don't change the alpha channel */
|
||||||
|
if ((nchannels == 2 || nchannels == 4) && channel == nchannels -1)
|
||||||
|
return value;
|
||||||
|
|
||||||
|
return (value + *ammount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
add_lut_setup(GimpLut *lut, double ammount, int nchannels)
|
||||||
|
{
|
||||||
|
gimp_lut_setup(lut, (GimpLutFunc) add_lut_func,
|
||||||
|
(void *) &ammount , nchannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
GimpLut *
|
||||||
|
add_lut_new(double ammount, int nchannels)
|
||||||
|
{
|
||||||
|
GimpLut *lut;
|
||||||
|
lut = gimp_lut_new();
|
||||||
|
add_lut_setup(lut, ammount, nchannels);
|
||||||
|
return lut;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------- intersect (MINIMUM(pixel, value)) ------------------ */
|
||||||
|
|
||||||
|
static float
|
||||||
|
intersect_lut_func(double *min,
|
||||||
|
int nchannels, int channel, float value)
|
||||||
|
{
|
||||||
|
/* don't change the alpha channel */
|
||||||
|
if ((nchannels == 2 || nchannels == 4) && channel == nchannels -1)
|
||||||
|
return value;
|
||||||
|
|
||||||
|
return MIN(value, *min);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
intersect_lut_setup(GimpLut *lut, double value, int nchannels)
|
||||||
|
{
|
||||||
|
gimp_lut_setup_exact(lut, (GimpLutFunc) intersect_lut_func,
|
||||||
|
(void *) &value , nchannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
GimpLut *
|
||||||
|
intersect_lut_new(double value, int nchannels)
|
||||||
|
{
|
||||||
|
GimpLut *lut;
|
||||||
|
lut = gimp_lut_new();
|
||||||
|
intersect_lut_setup(lut, value, nchannels);
|
||||||
|
return lut;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------- Threshold ------------------ */
|
||||||
|
|
||||||
|
static float
|
||||||
|
threshold_lut_func(double *min,
|
||||||
|
int nchannels, int channel, float value)
|
||||||
|
{
|
||||||
|
/* don't change the alpha channel */
|
||||||
|
if ((nchannels == 2 || nchannels == 4) && channel == nchannels -1)
|
||||||
|
return value;
|
||||||
|
if (value < *min)
|
||||||
|
return 0.0;
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
threshold_lut_setup(GimpLut *lut, double value, int nchannels)
|
||||||
|
{
|
||||||
|
gimp_lut_setup_exact(lut, (GimpLutFunc) threshold_lut_func,
|
||||||
|
(void *) &value , nchannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
GimpLut *
|
||||||
|
threshold_lut_new(double value, int nchannels)
|
||||||
|
{
|
||||||
|
GimpLut *lut;
|
||||||
|
lut = gimp_lut_new();
|
||||||
|
threshold_lut_setup(lut, value, nchannels);
|
||||||
|
return lut;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------- levels ------------ */
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
double *gamma;
|
||||||
|
|
||||||
|
int *low_input;
|
||||||
|
int *high_input;
|
||||||
|
|
||||||
|
int *low_output;
|
||||||
|
int *high_output;
|
||||||
|
} levels_struct;
|
||||||
|
|
||||||
|
static float
|
||||||
|
levels_lut_func(levels_struct *data,
|
||||||
|
int nchannels, int channel, float value)
|
||||||
|
{
|
||||||
|
double inten;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
if (nchannels == 1)
|
||||||
|
j = 0;
|
||||||
|
else
|
||||||
|
j = channel + 1;
|
||||||
|
inten = value;
|
||||||
|
/* For color images this runs through the loop with j = channel +1
|
||||||
|
the first time and j = 0 the second time */
|
||||||
|
/* For bw images this runs through the loop with j = 0 the first and
|
||||||
|
only time */
|
||||||
|
for (; j >= 0; j -= (channel + 1))
|
||||||
|
{
|
||||||
|
/* don't apply the overall curve to the alpha channel */
|
||||||
|
if (j == 0 && (nchannels == 2 || nchannels == 4)
|
||||||
|
&& channel == nchannels -1)
|
||||||
|
return inten;
|
||||||
|
|
||||||
|
/* determine input intensity */
|
||||||
|
if (data->high_input[j] != data->low_input[j])
|
||||||
|
inten = (double) (255.0*inten - data->low_input[j]) /
|
||||||
|
(double) (data->high_input[j] - data->low_input[j]);
|
||||||
|
else
|
||||||
|
inten = (double) (255.0*inten - data->low_input[j]);
|
||||||
|
|
||||||
|
if (data->gamma[j] != 0.0)
|
||||||
|
{
|
||||||
|
if (inten >= 0.0)
|
||||||
|
inten = pow ( inten, (1.0 / data->gamma[j]));
|
||||||
|
else
|
||||||
|
inten = -pow (-inten, (1.0 / data->gamma[j]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* determine the output intensity */
|
||||||
|
if (data->high_output[j] >= data->low_output[j])
|
||||||
|
inten = (double) (inten * (data->high_output[j] - data->low_output[j]) +
|
||||||
|
data->low_output[j]);
|
||||||
|
else if (data->high_output[j] < data->low_output[j])
|
||||||
|
inten = (double) (data->low_output[j] - inten *
|
||||||
|
(data->low_output[j] - data->high_output[j]));
|
||||||
|
|
||||||
|
inten /= 255.0;
|
||||||
|
}
|
||||||
|
return inten;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
levels_lut_setup(GimpLut *lut, double *gamma, int *low_input, int *high_input,
|
||||||
|
int *low_output, int *high_output, int nchannels)
|
||||||
|
{
|
||||||
|
levels_struct data;
|
||||||
|
data.gamma = gamma;
|
||||||
|
data.low_input = low_input;
|
||||||
|
data.high_input = high_input;
|
||||||
|
data.low_output = low_output;
|
||||||
|
data.high_output = high_output;
|
||||||
|
gimp_lut_setup(lut, (GimpLutFunc) levels_lut_func,
|
||||||
|
(void *) &data, nchannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
GimpLut *
|
||||||
|
levels_lut_new(double *gamma, int *low_input, int *high_input,
|
||||||
|
int *low_output, int *high_output, int nchannels)
|
||||||
|
{
|
||||||
|
GimpLut *lut;
|
||||||
|
lut = gimp_lut_new();
|
||||||
|
levels_lut_setup(lut, gamma, low_input, high_input,
|
||||||
|
low_output, high_output, nchannels);
|
||||||
|
return lut;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------- posterize ---------------- */
|
||||||
|
|
||||||
|
static float
|
||||||
|
posterize_lut_func(int *ilevels,
|
||||||
|
int nchannels, int channel, float value)
|
||||||
|
{
|
||||||
|
int levels;
|
||||||
|
/* don't posterize the alpha channel */
|
||||||
|
if ((nchannels == 2 || nchannels == 4) && channel == nchannels -1)
|
||||||
|
return value;
|
||||||
|
|
||||||
|
if (*ilevels < 2)
|
||||||
|
levels = 2;
|
||||||
|
else
|
||||||
|
levels = *ilevels;
|
||||||
|
|
||||||
|
value = rint(value * (levels - 1.0)) / (levels - 1.0);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
posterize_lut_setup(GimpLut *lut, int levels, int nchannels)
|
||||||
|
{
|
||||||
|
gimp_lut_setup_exact(lut, (GimpLutFunc) posterize_lut_func,
|
||||||
|
(void *) &levels , nchannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
GimpLut *
|
||||||
|
posterize_lut_new(int levels, int nchannels)
|
||||||
|
{
|
||||||
|
GimpLut *lut;
|
||||||
|
lut = gimp_lut_new();
|
||||||
|
posterize_lut_setup(lut, levels, nchannels);
|
||||||
|
return lut;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------- equalize ------------- */
|
||||||
|
|
||||||
|
struct hist_lut_struct
|
||||||
|
{
|
||||||
|
GimpHistogram *histogram;
|
||||||
|
int part[5][257];
|
||||||
|
};
|
||||||
|
|
||||||
|
static float
|
||||||
|
equalize_lut_func(struct hist_lut_struct *hlut,
|
||||||
|
int nchannels, int channel, float value)
|
||||||
|
{
|
||||||
|
int i = 0, j;
|
||||||
|
j = (int)(value * 255.0 + 0.5);
|
||||||
|
while (hlut->part[channel][i + 1] <= j)
|
||||||
|
i++;
|
||||||
|
return i / 255.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
eq_histogram_lut_setup (GimpLut *lut, GimpHistogram *hist, int bytes)
|
||||||
|
{
|
||||||
|
int i, k, j;
|
||||||
|
struct hist_lut_struct hlut;
|
||||||
|
double pixels_per_value;
|
||||||
|
double desired;
|
||||||
|
double sum, dif;
|
||||||
|
|
||||||
|
/* Find partition points */
|
||||||
|
pixels_per_value = gimp_histogram_get_count(hist, 0, 255) / 256.0;
|
||||||
|
|
||||||
|
for (k = 0; k < bytes; k++)
|
||||||
|
{
|
||||||
|
/* First and last points in partition */
|
||||||
|
hlut.part[k][0] = 0;
|
||||||
|
hlut.part[k][256] = 256;
|
||||||
|
|
||||||
|
/* Find intermediate points */
|
||||||
|
j = 0;
|
||||||
|
sum = gimp_histogram_get_channel(hist, k, 0) +
|
||||||
|
gimp_histogram_get_channel(hist, k, 1);
|
||||||
|
for (i = 1; i < 256; i++)
|
||||||
|
{
|
||||||
|
desired = i * pixels_per_value;
|
||||||
|
while (sum <= desired)
|
||||||
|
{
|
||||||
|
j++;
|
||||||
|
sum += gimp_histogram_get_channel(hist, k, j + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Nearest sum */
|
||||||
|
dif = sum - gimp_histogram_get_channel(hist, k, j);
|
||||||
|
if ((sum - desired) > (dif / 2.0))
|
||||||
|
hlut.part[k][i] = j;
|
||||||
|
else
|
||||||
|
hlut.part[k][i] = j + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gimp_lut_setup(lut, (GimpLutFunc) equalize_lut_func,
|
||||||
|
(void *) &hlut, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
GimpLut *
|
||||||
|
eq_histogram_lut_new(GimpHistogram *h, int nchannels)
|
||||||
|
{
|
||||||
|
GimpLut *lut;
|
||||||
|
lut = gimp_lut_new();
|
||||||
|
eq_histogram_lut_setup(lut, h, nchannels);
|
||||||
|
return lut;
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/* The GIMP -- an image manipulation program
|
||||||
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LUT_FUNCS_H__
|
||||||
|
#define __LUT_FUNCS_H__
|
||||||
|
|
||||||
|
#include "gimplutF.h"
|
||||||
|
#include "gimphistogramF.h"
|
||||||
|
|
||||||
|
/* brightness contrast */
|
||||||
|
void brightness_contrast_lut_setup (GimpLut *lut,
|
||||||
|
double brightness, double contrast,
|
||||||
|
int nchannels);
|
||||||
|
GimpLut *brightness_contrast_lut_new (double brightness, double contrast,
|
||||||
|
int nchannels);
|
||||||
|
|
||||||
|
/* invert */
|
||||||
|
void invert_lut_setup (GimpLut *lut, int nchannels);
|
||||||
|
GimpLut *invert_lut_new (int nchannels);
|
||||||
|
|
||||||
|
/* add (or subtract) */
|
||||||
|
void add_lut_setup (GimpLut *lut, double ammount, int nchannels);
|
||||||
|
GimpLut *add_lut_new (double ammount, int nchannels);
|
||||||
|
|
||||||
|
/* intersect (MINIMUM(pixel, value)) */
|
||||||
|
void intersect_lut_setup (GimpLut *lut, double value, int nchannels);
|
||||||
|
GimpLut *intersect_lut_new (double value, int nchannels);
|
||||||
|
|
||||||
|
/* threshold */
|
||||||
|
void threshold_lut_setup (GimpLut *lut, double value, int nchannels);
|
||||||
|
GimpLut *threshold_lut_new (double value, int nchannels);
|
||||||
|
|
||||||
|
/* levels */
|
||||||
|
void levels_lut_setup (GimpLut *lut, double *gamma,
|
||||||
|
int *low_input, int *high_input,
|
||||||
|
int *low_output, int *high_output, int nchannels);
|
||||||
|
GimpLut *levels_lut_new (double *gamma, int *low_input, int *high_input,
|
||||||
|
int *low_output, int *high_output, int nchannels);
|
||||||
|
/* posterize */
|
||||||
|
void posterize_lut_setup (GimpLut *lut, int levels, int nchannels);
|
||||||
|
GimpLut *posterize_lut_new (int levels, int nchannels);
|
||||||
|
|
||||||
|
/* equalize histogram */
|
||||||
|
void eq_histogram_lut_setup (GimpLut *lut, GimpHistogram *hist, int bytes);
|
||||||
|
GimpLut *eq_histogram_lut_new (GimpHistogram *h, int nchannels);
|
||||||
|
|
||||||
|
#endif /* __LUT_FUNCS_H__ */
|
|
@ -0,0 +1,292 @@
|
||||||
|
/* The GIMP -- an image manipulation program
|
||||||
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||||
|
*
|
||||||
|
* pixel_processor.c: Copyright (C) 1999 Jay Cox <jaycox@earthlink.net>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../config.h"
|
||||||
|
#include "pixel_processor.h"
|
||||||
|
#include "pixel_region.h"
|
||||||
|
#include "gimprc.h"
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifdef ENABLE_MP
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#define IF_THREAD(statement) statement
|
||||||
|
|
||||||
|
#else /* !USE_PTHREADS */
|
||||||
|
|
||||||
|
#define IF_THREAD(statement)
|
||||||
|
|
||||||
|
#endif /* !USE_PTHREADS */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef void (*p1_func)(void *, PixelRegion *);
|
||||||
|
typedef void (*p2_func)(void *, PixelRegion * ,PixelRegion *);
|
||||||
|
typedef void (*p3_func)(void *, PixelRegion * ,PixelRegion *, PixelRegion *);
|
||||||
|
typedef void (*p4_func)(void *, PixelRegion * ,PixelRegion *, PixelRegion *,
|
||||||
|
PixelRegion *);
|
||||||
|
|
||||||
|
typedef struct _PixelRegionIterator PixelRegionIterator;
|
||||||
|
|
||||||
|
struct _PixelProcessor
|
||||||
|
{
|
||||||
|
void *data;
|
||||||
|
p_func f;
|
||||||
|
PixelRegionIterator *PRI;
|
||||||
|
IF_THREAD(pthread_mutex_t mutex;)
|
||||||
|
int nthreads;
|
||||||
|
int n_regions;
|
||||||
|
PixelRegion *r[4];
|
||||||
|
|
||||||
|
void *progress_report_data;
|
||||||
|
ProgressReportFunc progress_report_func;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void *
|
||||||
|
do_parallel_regions(PixelProcessor *p_s)
|
||||||
|
{
|
||||||
|
PixelRegion tr[4];
|
||||||
|
int ntiles = 0;
|
||||||
|
int i;
|
||||||
|
int cont = 1;
|
||||||
|
|
||||||
|
IF_THREAD(pthread_mutex_lock(&p_s->mutex);)
|
||||||
|
if (p_s->nthreads != 0 && p_s->PRI)
|
||||||
|
p_s->PRI = (PixelRegionIterator*)pixel_regions_process(p_s->PRI);
|
||||||
|
if (p_s->PRI == NULL)
|
||||||
|
{
|
||||||
|
IF_THREAD(pthread_mutex_unlock(&p_s->mutex);)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
p_s->nthreads++;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
for (i = 0; i < p_s->n_regions; i++)
|
||||||
|
if (p_s->r[i])
|
||||||
|
memcpy(&tr[i], p_s->r[i], sizeof(PixelRegion));
|
||||||
|
IF_THREAD(pthread_mutex_unlock(&p_s->mutex);)
|
||||||
|
ntiles++;
|
||||||
|
switch(p_s->n_regions)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
((p1_func)p_s->f)(p_s->data,
|
||||||
|
p_s->r[0] ? &tr[0] : NULL);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
((p2_func)p_s->f)(p_s->data,
|
||||||
|
p_s->r[0] ? &tr[0] : NULL,
|
||||||
|
p_s->r[1] ? &tr[1] : NULL);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
((p3_func)p_s->f)(p_s->data,
|
||||||
|
p_s->r[0] ? &tr[0] : NULL,
|
||||||
|
p_s->r[1] ? &tr[1] : NULL,
|
||||||
|
p_s->r[2] ? &tr[2] : NULL);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
((p4_func)p_s->f)(p_s->data,
|
||||||
|
p_s->r[0] ? &tr[0] : NULL,
|
||||||
|
p_s->r[1] ? &tr[1] : NULL,
|
||||||
|
p_s->r[2] ? &tr[2] : NULL,
|
||||||
|
p_s->r[3] ? &tr[3] : NULL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_message("do_parallel_regions: Bad number of regions %d\n",
|
||||||
|
p_s->n_regions);
|
||||||
|
}
|
||||||
|
IF_THREAD(pthread_mutex_lock(&p_s->mutex);)
|
||||||
|
if (p_s->progress_report_func)
|
||||||
|
if (!p_s->progress_report_func(p_s->progress_report_data,
|
||||||
|
p_s->r[0]->x, p_s->r[0]->y,
|
||||||
|
p_s->r[0]->w, p_s->r[0]->h))
|
||||||
|
cont = 0;
|
||||||
|
} while (cont && p_s->PRI &&
|
||||||
|
(p_s->PRI = (PixelRegionIterator*)pixel_regions_process(p_s->PRI)));
|
||||||
|
p_s->nthreads--;
|
||||||
|
/* fprintf(stderr, "processed %d tiles\n", ntiles); */
|
||||||
|
IF_THREAD(pthread_mutex_unlock(&p_s->mutex);)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX_THREADS 30
|
||||||
|
|
||||||
|
static void
|
||||||
|
pixel_regions_do_parallel(PixelProcessor *p_s)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
IF_THREAD(int nthreads;)
|
||||||
|
IF_THREAD(pthread_t threads[MAX_THREADS];)
|
||||||
|
IF_THREAD(pthread_attr_t pthread_attr;)
|
||||||
|
|
||||||
|
/* (p_s->PRI->region_width * p_s->PRI->region_height) /(64*64)); */
|
||||||
|
IF_THREAD(
|
||||||
|
nthreads = MIN(num_processors, 5);
|
||||||
|
if (nthreads > 1)
|
||||||
|
{
|
||||||
|
pthread_attr_init (&pthread_attr);
|
||||||
|
for (i = 0; i < nthreads; i++)
|
||||||
|
{
|
||||||
|
pthread_create (&threads[i], &pthread_attr,
|
||||||
|
(void *(*)(void *)) do_parallel_regions,
|
||||||
|
p_s);
|
||||||
|
}
|
||||||
|
for (i = 0; i < nthreads; i++)
|
||||||
|
{
|
||||||
|
pthread_join(threads[i], NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
)
|
||||||
|
do_parallel_regions(p_s);
|
||||||
|
if (p_s->nthreads != 0)
|
||||||
|
fprintf(stderr, "Ack, we lost a thread\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static PixelProcessor *
|
||||||
|
pixel_regions_real_process_parallel(p_func f, void *data,
|
||||||
|
ProgressReportFunc report_func,
|
||||||
|
void *report_data,
|
||||||
|
int num_regions, va_list ap)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
PixelProcessor *p_s;
|
||||||
|
|
||||||
|
|
||||||
|
p_s = g_new(PixelProcessor, 200);
|
||||||
|
|
||||||
|
|
||||||
|
for (i = 0; i < num_regions; i++)
|
||||||
|
p_s->r[i] = va_arg (ap, PixelRegion *);
|
||||||
|
|
||||||
|
switch(num_regions)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
p_s->PRI = (PixelRegionIterator *) pixel_regions_register(num_regions,
|
||||||
|
p_s->r[0]);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
p_s->PRI = (PixelRegionIterator *) pixel_regions_register(num_regions,
|
||||||
|
p_s->r[0],
|
||||||
|
p_s->r[1]);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
p_s->PRI = (PixelRegionIterator *) pixel_regions_register(num_regions,
|
||||||
|
p_s->r[0],
|
||||||
|
p_s->r[1],
|
||||||
|
p_s->r[2]);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
p_s->PRI = (PixelRegionIterator *) pixel_regions_register(num_regions,
|
||||||
|
p_s->r[0],
|
||||||
|
p_s->r[1],
|
||||||
|
p_s->r[2],
|
||||||
|
p_s->r[3]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_message("pixel_regions_real_process_parallel: Bad number of regions %d\n",
|
||||||
|
p_s->n_regions);
|
||||||
|
}
|
||||||
|
if (!p_s->PRI)
|
||||||
|
{
|
||||||
|
pixel_processor_free(p_s);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
p_s->f = f;
|
||||||
|
p_s->data = data;
|
||||||
|
p_s->n_regions = num_regions;
|
||||||
|
IF_THREAD(pthread_mutex_init(&(p_s->mutex), NULL);)
|
||||||
|
p_s->nthreads = 0;
|
||||||
|
|
||||||
|
p_s->progress_report_data = report_data;
|
||||||
|
p_s->progress_report_func = report_func;
|
||||||
|
|
||||||
|
|
||||||
|
pixel_regions_do_parallel(p_s);
|
||||||
|
|
||||||
|
if (p_s->PRI)
|
||||||
|
return p_s;
|
||||||
|
pixel_processor_free (p_s);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pixel_regions_process_parallel(p_func f, void *data, int num_regions, ...)
|
||||||
|
{
|
||||||
|
va_list va;
|
||||||
|
va_start (va, num_regions);
|
||||||
|
|
||||||
|
pixel_regions_real_process_parallel(f, data, NULL, NULL, num_regions, va);
|
||||||
|
|
||||||
|
va_end (va);
|
||||||
|
}
|
||||||
|
|
||||||
|
PixelProcessor *
|
||||||
|
pixel_regions_process_parallel_progress(p_func f, void *data,
|
||||||
|
ProgressReportFunc progress_func,
|
||||||
|
void *progress_data, int num_regions,
|
||||||
|
...)
|
||||||
|
{
|
||||||
|
PixelProcessor *ret;
|
||||||
|
va_list va;
|
||||||
|
va_start (va, num_regions);
|
||||||
|
|
||||||
|
ret = pixel_regions_real_process_parallel(f, data,
|
||||||
|
progress_func, progress_data,
|
||||||
|
num_regions, va);
|
||||||
|
|
||||||
|
va_end (va);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pixel_processor_stop(PixelProcessor *pp)
|
||||||
|
{
|
||||||
|
if (!pp)
|
||||||
|
return;
|
||||||
|
if (pp->PRI)
|
||||||
|
{
|
||||||
|
pixel_regions_process_stop (pp->PRI);
|
||||||
|
pp->PRI = NULL;
|
||||||
|
}
|
||||||
|
pixel_processor_free(pp);
|
||||||
|
}
|
||||||
|
|
||||||
|
PixelProcessor *
|
||||||
|
pixel_processor_cont(PixelProcessor *pp)
|
||||||
|
{
|
||||||
|
pixel_regions_do_parallel(pp);
|
||||||
|
if (pp->PRI)
|
||||||
|
return pp;
|
||||||
|
pixel_processor_free (pp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pixel_processor_free (PixelProcessor *pp)
|
||||||
|
{
|
||||||
|
if (pp->PRI)
|
||||||
|
pixel_processor_stop(pp);
|
||||||
|
else
|
||||||
|
g_free(pp);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
/* The GIMP -- an image manipulation program
|
||||||
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||||
|
*
|
||||||
|
* pixel_processor.h: Copyright (C) 1999 Jay Cox <jaycox@earthlink.net>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PIXEL_PROCESSOR_H__
|
||||||
|
#define __PIXEL_PROCESSOR_H__
|
||||||
|
|
||||||
|
typedef struct _PixelProcessor PixelProcessor;
|
||||||
|
|
||||||
|
typedef void (*p_func)(void);
|
||||||
|
typedef int (*ProgressReportFunc)(void *, int, int, int, int);
|
||||||
|
|
||||||
|
void pixel_regions_process_parallel (p_func f, void *data, int num_regions,
|
||||||
|
...);
|
||||||
|
PixelProcessor *pixel_process_progress (p_func f, void *data,
|
||||||
|
ProgressReportFunc progress_func,
|
||||||
|
void *progress_data,
|
||||||
|
int num_regions, ...);
|
||||||
|
|
||||||
|
void pixel_processor_free (PixelProcessor *);
|
||||||
|
void pixel_processor_stop (PixelProcessor *);
|
||||||
|
PixelProcessor *pixel_processor_cont (PixelProcessor *);
|
||||||
|
|
||||||
|
#endif /* __PIXEL_PROCESSOR_H__ */
|
|
@ -26,18 +26,6 @@
|
||||||
#include "tile_manager_pvt.h"
|
#include "tile_manager_pvt.h"
|
||||||
#include "tile.h" /* ick. */
|
#include "tile.h" /* ick. */
|
||||||
|
|
||||||
#ifdef ENABLE_MP
|
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
#define IF_THREAD(statement) statement
|
|
||||||
|
|
||||||
#else /* !USE_PTHREADS */
|
|
||||||
|
|
||||||
#define IF_THREAD(statement)
|
|
||||||
|
|
||||||
#endif /* !USE_PTHREADS */
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct _PixelRegionHolder PixelRegionHolder;
|
typedef struct _PixelRegionHolder PixelRegionHolder;
|
||||||
|
|
||||||
|
@ -303,159 +291,6 @@ pixel_region_set_col (PR, x, y, h, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef void (*p1_func)(void *, PixelRegion *);
|
|
||||||
typedef void (*p2_func)(void *, PixelRegion * ,PixelRegion *);
|
|
||||||
typedef void (*p3_func)(void *, PixelRegion * ,PixelRegion *, PixelRegion *);
|
|
||||||
typedef void (*p4_func)(void *, PixelRegion * ,PixelRegion *, PixelRegion *,
|
|
||||||
PixelRegion *);
|
|
||||||
|
|
||||||
struct parallel_struct
|
|
||||||
{
|
|
||||||
void *data;
|
|
||||||
p_func f;
|
|
||||||
PixelRegionIterator *PRI;
|
|
||||||
IF_THREAD(pthread_mutex_t mutex;)
|
|
||||||
int nthreads;
|
|
||||||
int n_regions;
|
|
||||||
PixelRegion *r[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
static void *
|
|
||||||
do_parallel_regions(struct parallel_struct *p_s)
|
|
||||||
{
|
|
||||||
PixelRegion tr[4];
|
|
||||||
int ntiles = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
IF_THREAD(pthread_mutex_lock(&p_s->mutex);)
|
|
||||||
if (p_s->nthreads != 0 && p_s->PRI)
|
|
||||||
p_s->PRI = (PixelRegionIterator*)pixel_regions_process(p_s->PRI);
|
|
||||||
if (p_s->PRI == NULL)
|
|
||||||
{
|
|
||||||
IF_THREAD(pthread_mutex_unlock(&p_s->mutex);)
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
p_s->nthreads++;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
for (i = 0; i < p_s->n_regions; i++)
|
|
||||||
if (p_s->r[i])
|
|
||||||
memcpy(&tr[i], p_s->r[i], sizeof(PixelRegion));
|
|
||||||
IF_THREAD(pthread_mutex_unlock(&p_s->mutex);)
|
|
||||||
ntiles++;
|
|
||||||
switch(p_s->n_regions)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
((p1_func)p_s->f)(p_s->data,
|
|
||||||
p_s->r[0] ? &tr[0] : NULL);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
((p2_func)p_s->f)(p_s->data,
|
|
||||||
p_s->r[0] ? &tr[0] : NULL,
|
|
||||||
p_s->r[1] ? &tr[1] : NULL);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
((p3_func)p_s->f)(p_s->data,
|
|
||||||
p_s->r[0] ? &tr[0] : NULL,
|
|
||||||
p_s->r[1] ? &tr[1] : NULL,
|
|
||||||
p_s->r[2] ? &tr[2] : NULL);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
((p4_func)p_s->f)(p_s->data,
|
|
||||||
p_s->r[0] ? &tr[0] : NULL,
|
|
||||||
p_s->r[1] ? &tr[1] : NULL,
|
|
||||||
p_s->r[2] ? &tr[2] : NULL,
|
|
||||||
p_s->r[3] ? &tr[3] : NULL);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
g_message("do_parallel_regions: Bad number of regions %d\n",
|
|
||||||
p_s->n_regions);
|
|
||||||
}
|
|
||||||
IF_THREAD(pthread_mutex_lock(&p_s->mutex);)
|
|
||||||
} while (p_s->PRI && (p_s->PRI = (PixelRegionIterator*)pixel_regions_process(p_s->PRI)));
|
|
||||||
p_s->nthreads--;
|
|
||||||
/* fprintf(stderr, "processed %d tiles\n", ntiles); */
|
|
||||||
IF_THREAD(pthread_mutex_unlock(&p_s->mutex);)
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MAX_THREADS 30
|
|
||||||
|
|
||||||
void pixel_regions_process_parallel(p_func f, void *data, int num_regions, ...)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
struct parallel_struct p_s;
|
|
||||||
IF_THREAD(pthread_t threads[MAX_THREADS];)
|
|
||||||
IF_THREAD(pthread_attr_t pthread_attr;)
|
|
||||||
IF_THREAD(int nthreads;)
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start (ap, num_regions);
|
|
||||||
for (i = 0; i < num_regions; i++)
|
|
||||||
p_s.r[i] = va_arg (ap, PixelRegion *);
|
|
||||||
va_end (ap);
|
|
||||||
|
|
||||||
switch(num_regions)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
p_s.PRI = (PixelRegionIterator *) pixel_regions_register(num_regions,
|
|
||||||
p_s.r[0]);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
p_s.PRI = (PixelRegionIterator *) pixel_regions_register(num_regions,
|
|
||||||
p_s.r[0],
|
|
||||||
p_s.r[1]);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
p_s.PRI = (PixelRegionIterator *) pixel_regions_register(num_regions,
|
|
||||||
p_s.r[0],
|
|
||||||
p_s.r[1],
|
|
||||||
p_s.r[2]);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
p_s.PRI = (PixelRegionIterator *) pixel_regions_register(num_regions,
|
|
||||||
p_s.r[0],
|
|
||||||
p_s.r[1],
|
|
||||||
p_s.r[2],
|
|
||||||
p_s.r[3]);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
g_message("pixel_regions_process_parallel: Bad number of regions %d\n",
|
|
||||||
p_s.n_regions);
|
|
||||||
}
|
|
||||||
if (!p_s.PRI)
|
|
||||||
return;
|
|
||||||
p_s.f = f;
|
|
||||||
p_s.data = data;
|
|
||||||
p_s.n_regions = num_regions;
|
|
||||||
IF_THREAD(pthread_mutex_init(&p_s.mutex, NULL);)
|
|
||||||
p_s.nthreads = 0;
|
|
||||||
|
|
||||||
IF_THREAD(
|
|
||||||
nthreads = MIN(num_processors,
|
|
||||||
(p_s.PRI->region_width * p_s.PRI->region_height) /(64*64));
|
|
||||||
if (nthreads > 1)
|
|
||||||
{
|
|
||||||
pthread_attr_init (&pthread_attr);
|
|
||||||
for (i = 0; i < nthreads; i++)
|
|
||||||
{
|
|
||||||
pthread_create (&threads[i], &pthread_attr,
|
|
||||||
(void *(*)(void *)) do_parallel_regions,
|
|
||||||
&p_s);
|
|
||||||
}
|
|
||||||
for (i = 0; i < nthreads; i++)
|
|
||||||
{
|
|
||||||
pthread_join(threads[i], NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
)
|
|
||||||
do_parallel_regions(&p_s);
|
|
||||||
if (p_s.nthreads != 0)
|
|
||||||
fprintf(stderr, "Ack, we've lost a thread.");
|
|
||||||
}
|
|
||||||
|
|
||||||
void *
|
void *
|
||||||
pixel_regions_register (int num_regions, ...)
|
pixel_regions_register (int num_regions, ...)
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#define __PIXEL_REGION_H__
|
#define __PIXEL_REGION_H__
|
||||||
|
|
||||||
#include "tile_manager.h"
|
#include "tile_manager.h"
|
||||||
|
#include "pixel_processor.h" /* this is temporary, */
|
||||||
|
|
||||||
typedef struct _PixelRegion PixelRegion;
|
typedef struct _PixelRegion PixelRegion;
|
||||||
|
|
||||||
|
@ -36,7 +37,6 @@ struct _PixelRegion
|
||||||
int process_count; /* used internally */
|
int process_count; /* used internally */
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void (*p_func)(void);
|
|
||||||
|
|
||||||
/* PixelRegion functions */
|
/* PixelRegion functions */
|
||||||
void pixel_region_init (PixelRegion *, TileManager *, int, int, int, int, int);
|
void pixel_region_init (PixelRegion *, TileManager *, int, int, int, int, int);
|
||||||
|
@ -48,8 +48,6 @@ void pixel_region_set_row (PixelRegion *, int, int, int, unsigned char *)
|
||||||
void pixel_region_get_col (PixelRegion *, int, int, int, unsigned char *, int);
|
void pixel_region_get_col (PixelRegion *, int, int, int, unsigned char *, int);
|
||||||
void pixel_region_set_col (PixelRegion *, int, int, int, unsigned char *);
|
void pixel_region_set_col (PixelRegion *, int, int, int, unsigned char *);
|
||||||
void *pixel_regions_register (int, ...);
|
void *pixel_regions_register (int, ...);
|
||||||
void pixel_regions_process_parallel (p_func f, void *data, int num_regions,
|
|
||||||
...);
|
|
||||||
void *pixel_regions_process (void *);
|
void *pixel_regions_process (void *);
|
||||||
void pixel_regions_process_stop (void *);
|
void pixel_regions_process_stop (void *);
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,8 @@ find_empty_segs (PixelRegion *maskPR,
|
||||||
int val, last;
|
int val, last;
|
||||||
int tilex;
|
int tilex;
|
||||||
Tile *tile = NULL;
|
Tile *tile = NULL;
|
||||||
|
int endx, l_num_empty, dstep;
|
||||||
|
|
||||||
|
|
||||||
data = NULL;
|
data = NULL;
|
||||||
start = 0;
|
start = 0;
|
||||||
|
@ -121,7 +123,9 @@ find_empty_segs (PixelRegion *maskPR,
|
||||||
empty_segs[(*num_empty)++] = 0;
|
empty_segs[(*num_empty)++] = 0;
|
||||||
last = -1;
|
last = -1;
|
||||||
|
|
||||||
for (x = start; x < end; x++)
|
l_num_empty = *num_empty;
|
||||||
|
|
||||||
|
for (x = start; x < end;)
|
||||||
{
|
{
|
||||||
/* Check to see if we must advance to next tile */
|
/* Check to see if we must advance to next tile */
|
||||||
if ((x / TILE_WIDTH) != tilex)
|
if ((x / TILE_WIDTH) != tilex)
|
||||||
|
@ -132,22 +136,46 @@ find_empty_segs (PixelRegion *maskPR,
|
||||||
data = (unsigned char*)tile_data_pointer (tile, x % TILE_WIDTH, scanline % TILE_HEIGHT) + (tile_bpp(tile) - 1);
|
data = (unsigned char*)tile_data_pointer (tile, x % TILE_WIDTH, scanline % TILE_HEIGHT) + (tile_bpp(tile) - 1);
|
||||||
|
|
||||||
tilex = x / TILE_WIDTH;
|
tilex = x / TILE_WIDTH;
|
||||||
|
dstep = tile_bpp(tile);
|
||||||
|
}
|
||||||
|
endx = x + (TILE_WIDTH - (x%TILE_WIDTH));
|
||||||
|
endx = MINIMUM(end, endx);
|
||||||
|
if (type == IgnoreBounds && (endx > x1 || x < x2))
|
||||||
|
for (; x < endx; x++)
|
||||||
|
{
|
||||||
|
if (*data > HALF_WAY)
|
||||||
|
if (x >= x1 && x < x2)
|
||||||
|
val = -1;
|
||||||
|
else
|
||||||
|
val = 1;
|
||||||
|
else
|
||||||
|
val = -1;
|
||||||
|
|
||||||
|
data += dstep;
|
||||||
|
|
||||||
|
if (last != val)
|
||||||
|
empty_segs[l_num_empty++] = x;
|
||||||
|
|
||||||
|
last = val;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
for (; x < endx; x++)
|
||||||
|
{
|
||||||
|
if (*data > HALF_WAY)
|
||||||
|
val = 1;
|
||||||
|
else
|
||||||
|
val = -1;
|
||||||
|
|
||||||
|
data += dstep;
|
||||||
|
|
||||||
|
if (last != val)
|
||||||
|
empty_segs[l_num_empty++] = x;
|
||||||
|
|
||||||
|
last = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
empty_segs[*num_empty] = x;
|
|
||||||
val = (*data > HALF_WAY) ? 1 : -1;
|
|
||||||
|
|
||||||
/* The IgnoreBounds case */
|
|
||||||
if (val == 1 && type == IgnoreBounds)
|
|
||||||
if (x >= x1 && x < x2)
|
|
||||||
val = -1;
|
|
||||||
|
|
||||||
if (last * val < 0)
|
|
||||||
(*num_empty)++;
|
|
||||||
last = val;
|
|
||||||
|
|
||||||
data += tile_bpp(tile);
|
|
||||||
}
|
}
|
||||||
|
*num_empty = l_num_empty;
|
||||||
|
|
||||||
if (last > 0)
|
if (last > 0)
|
||||||
empty_segs[(*num_empty)++] = x;
|
empty_segs[(*num_empty)++] = x;
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "image_map.h"
|
#include "image_map.h"
|
||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
#include "gimplut.h"
|
#include "gimplut.h"
|
||||||
|
#include "lut_funcs.h"
|
||||||
|
|
||||||
#include "libgimp/gimpintl.h"
|
#include "libgimp/gimpintl.h"
|
||||||
|
|
||||||
|
@ -94,59 +95,6 @@ static void brightness_contrast_contrast_text_update (GtkWidget *, gpointer
|
||||||
static void *brightness_contrast_options = NULL;
|
static void *brightness_contrast_options = NULL;
|
||||||
static BrightnessContrastDialog *brightness_contrast_dialog = NULL;
|
static BrightnessContrastDialog *brightness_contrast_dialog = NULL;
|
||||||
|
|
||||||
static Argument * brightness_contrast_invoker (Argument *);
|
|
||||||
|
|
||||||
/* brightness contrast machinery */
|
|
||||||
|
|
||||||
static float
|
|
||||||
brightness_contrast_lut_func(BrightnessContrastDialog *bcd,
|
|
||||||
int nchannels, int channel, float value)
|
|
||||||
{
|
|
||||||
float nvalue;
|
|
||||||
double power;
|
|
||||||
|
|
||||||
/* return the original value for the alpha channel */
|
|
||||||
if ((nchannels == 2 || nchannels == 4) && channel == nchannels -1)
|
|
||||||
return value;
|
|
||||||
|
|
||||||
/* apply brightness */
|
|
||||||
if (bcd->brightness < 0)
|
|
||||||
value = value * (1.0 + bcd->brightness/255.0);
|
|
||||||
else
|
|
||||||
value = value + ((1.0 - value) * bcd->brightness/255.0);
|
|
||||||
|
|
||||||
/* apply contrast */
|
|
||||||
if (bcd->contrast < 0)
|
|
||||||
{
|
|
||||||
if (value > 0.5)
|
|
||||||
nvalue = 1.0 - value;
|
|
||||||
else
|
|
||||||
nvalue = value;
|
|
||||||
if (nvalue < 0.0)
|
|
||||||
nvalue = 0.0;
|
|
||||||
nvalue = 0.5 * pow (nvalue * 2.0 , (double) (127 + bcd->contrast) / 127.0);
|
|
||||||
if (value > 0.5)
|
|
||||||
value = 1.0 - nvalue;
|
|
||||||
else
|
|
||||||
value = nvalue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (value > 0.5)
|
|
||||||
nvalue = 1.0 - value;
|
|
||||||
else
|
|
||||||
nvalue = value;
|
|
||||||
if (nvalue < 0.0)
|
|
||||||
nvalue = 0.0;
|
|
||||||
power = (bcd->contrast == 127) ? 127 : 127.0 / (127 - bcd->contrast);
|
|
||||||
nvalue = 0.5 * pow (2.0 * nvalue, power);
|
|
||||||
if (value > 0.5)
|
|
||||||
value = 1.0 - nvalue;
|
|
||||||
else
|
|
||||||
value = nvalue;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* by_color select action functions */
|
/* by_color select action functions */
|
||||||
|
@ -467,8 +415,9 @@ brightness_contrast_preview (BrightnessContrastDialog *bcd)
|
||||||
if (!bcd->image_map)
|
if (!bcd->image_map)
|
||||||
g_message (_("brightness_contrast_preview(): No image map"));
|
g_message (_("brightness_contrast_preview(): No image map"));
|
||||||
active_tool->preserve = TRUE;
|
active_tool->preserve = TRUE;
|
||||||
gimp_lut_setup(bcd->lut, (GimpLutFunc) brightness_contrast_lut_func,
|
brightness_contrast_lut_setup(bcd->lut, bcd->brightness / 255.0,
|
||||||
(void *) bcd, gimp_drawable_bytes(bcd->drawable));
|
bcd->contrast / 127.0,
|
||||||
|
gimp_drawable_bytes(bcd->drawable));
|
||||||
image_map_apply (bcd->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
image_map_apply (bcd->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
||||||
(void *) bcd->lut);
|
(void *) bcd->lut);
|
||||||
active_tool->preserve = FALSE;
|
active_tool->preserve = FALSE;
|
||||||
|
@ -489,8 +438,9 @@ brightness_contrast_ok_callback (GtkWidget *widget,
|
||||||
|
|
||||||
if (!bcd->preview)
|
if (!bcd->preview)
|
||||||
{
|
{
|
||||||
gimp_lut_setup(bcd->lut, (GimpLutFunc) brightness_contrast_lut_func,
|
brightness_contrast_lut_setup(bcd->lut, bcd->brightness / 255.0,
|
||||||
(void *) bcd, gimp_drawable_bytes(bcd->drawable));
|
bcd->contrast / 127.0,
|
||||||
|
gimp_drawable_bytes(bcd->drawable));
|
||||||
image_map_apply (bcd->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
image_map_apply (bcd->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
||||||
(void *) bcd->lut);
|
(void *) bcd->lut);
|
||||||
}
|
}
|
||||||
|
@ -632,119 +582,3 @@ brightness_contrast_contrast_text_update (GtkWidget *w,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* The brightness_contrast procedure definition */
|
|
||||||
ProcArg brightness_contrast_args[] =
|
|
||||||
{
|
|
||||||
{ PDB_DRAWABLE,
|
|
||||||
"drawable",
|
|
||||||
"the drawable"
|
|
||||||
},
|
|
||||||
{ PDB_INT32,
|
|
||||||
"brightness",
|
|
||||||
"brightness adjustment: (-127 <= brightness <= 127)"
|
|
||||||
},
|
|
||||||
{ PDB_INT32,
|
|
||||||
"contrast",
|
|
||||||
"constrast adjustment: (-127 <= contrast <= 127)"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ProcRecord brightness_contrast_proc =
|
|
||||||
{
|
|
||||||
"gimp_brightness_contrast",
|
|
||||||
"Modify brightness/contrast in the specified drawable",
|
|
||||||
"This procedures allows the brightness and contrast of the specified drawable to be modified. Both 'brightness' and 'contrast' parameters are defined between -127 and 127.",
|
|
||||||
"Spencer Kimball & Peter Mattis",
|
|
||||||
"Spencer Kimball & Peter Mattis",
|
|
||||||
"1997",
|
|
||||||
PDB_INTERNAL,
|
|
||||||
|
|
||||||
/* Input arguments */
|
|
||||||
3,
|
|
||||||
brightness_contrast_args,
|
|
||||||
|
|
||||||
/* Output arguments */
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
|
|
||||||
/* Exec method */
|
|
||||||
{ { brightness_contrast_invoker } },
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static Argument *
|
|
||||||
brightness_contrast_invoker (Argument *args)
|
|
||||||
{
|
|
||||||
PixelRegion srcPR, destPR;
|
|
||||||
int success = TRUE;
|
|
||||||
int int_value;
|
|
||||||
BrightnessContrastDialog bcd;
|
|
||||||
GImage *gimage;
|
|
||||||
int brightness;
|
|
||||||
int contrast;
|
|
||||||
int x1, y1, x2, y2;
|
|
||||||
GimpDrawable *drawable;
|
|
||||||
|
|
||||||
drawable = NULL;
|
|
||||||
brightness = 0;
|
|
||||||
contrast = 0;
|
|
||||||
|
|
||||||
/* the drawable */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[0].value.pdb_int;
|
|
||||||
drawable = drawable_get_ID (int_value);
|
|
||||||
if (drawable == NULL)
|
|
||||||
success = FALSE;
|
|
||||||
else
|
|
||||||
gimage = drawable_gimage (drawable);
|
|
||||||
}
|
|
||||||
/* make sure the drawable is not indexed color */
|
|
||||||
if (success)
|
|
||||||
success = ! drawable_indexed (drawable);
|
|
||||||
|
|
||||||
/* brightness */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[1].value.pdb_int;
|
|
||||||
if (int_value < -127 || int_value > 127)
|
|
||||||
success = FALSE;
|
|
||||||
else
|
|
||||||
brightness = int_value;
|
|
||||||
}
|
|
||||||
/* contrast */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[2].value.pdb_int;
|
|
||||||
if (int_value < -127 || int_value > 127)
|
|
||||||
success = FALSE;
|
|
||||||
else
|
|
||||||
contrast = int_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* arrange to modify the brightness/contrast */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
bcd.brightness = brightness;
|
|
||||||
bcd.contrast = contrast;
|
|
||||||
bcd.lut = gimp_lut_new();
|
|
||||||
|
|
||||||
/* The application should occur only within selection bounds */
|
|
||||||
drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
|
|
||||||
|
|
||||||
pixel_region_init (&srcPR, drawable_data (drawable), x1, y1, (x2 - x1), (y2 - y1), FALSE);
|
|
||||||
pixel_region_init (&destPR, drawable_shadow (drawable), x1, y1, (x2 - x1), (y2 - y1), TRUE);
|
|
||||||
|
|
||||||
gimp_lut_setup(bcd.lut, (GimpLutFunc) brightness_contrast_lut_func,
|
|
||||||
(void *) &bcd, gimp_drawable_bytes(drawable));
|
|
||||||
|
|
||||||
pixel_regions_process_parallel((p_func)gimp_lut_process, bcd.lut,
|
|
||||||
2, &srcPR, &destPR);
|
|
||||||
|
|
||||||
gimp_lut_free(bcd.lut);
|
|
||||||
drawable_merge_shadow (drawable, TRUE);
|
|
||||||
drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1));
|
|
||||||
}
|
|
||||||
|
|
||||||
return procedural_db_return_args (&brightness_contrast_proc, success);
|
|
||||||
}
|
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#define __BRIGHTNESS_CONTRAST_H__
|
#define __BRIGHTNESS_CONTRAST_H__
|
||||||
|
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
#include "procedural_db.h"
|
|
||||||
|
|
||||||
/* by_color select functions */
|
/* by_color select functions */
|
||||||
Tool * tools_new_brightness_contrast (void);
|
Tool * tools_new_brightness_contrast (void);
|
||||||
|
@ -27,7 +26,4 @@ void tools_free_brightness_contrast (Tool *);
|
||||||
|
|
||||||
void brightness_contrast_initialize (GDisplay *);
|
void brightness_contrast_initialize (GDisplay *);
|
||||||
|
|
||||||
/* Procedure definition and marshalling function */
|
|
||||||
extern ProcRecord brightness_contrast_proc;
|
|
||||||
|
|
||||||
#endif /* __BRIGHTNESS_CONTRAST_H__ */
|
#endif /* __BRIGHTNESS_CONTRAST_H__ */
|
||||||
|
|
336
app/channel.c
336
app/channel.c
|
@ -36,6 +36,9 @@
|
||||||
#include "channel_pvt.h"
|
#include "channel_pvt.h"
|
||||||
#include "tile.h"
|
#include "tile.h"
|
||||||
|
|
||||||
|
#include "gimplut.h"
|
||||||
|
#include "lut_funcs.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
enum {
|
enum {
|
||||||
LAST_SIGNAL
|
LAST_SIGNAL
|
||||||
|
@ -602,9 +605,9 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2)
|
||||||
unsigned char * data;
|
unsigned char * data;
|
||||||
int x, y;
|
int x, y;
|
||||||
int ex, ey;
|
int ex, ey;
|
||||||
int found;
|
|
||||||
void *pr;
|
void *pr;
|
||||||
|
int tx1, tx2, ty1, ty2;
|
||||||
|
int minx, maxx;
|
||||||
/* if the mask's bounds have already been reliably calculated... */
|
/* if the mask's bounds have already been reliably calculated... */
|
||||||
if (mask->bounds_known)
|
if (mask->bounds_known)
|
||||||
{
|
{
|
||||||
|
@ -617,10 +620,10 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* go through and calculate the bounds */
|
/* go through and calculate the bounds */
|
||||||
*x1 = GIMP_DRAWABLE(mask)->width;
|
tx1 = GIMP_DRAWABLE(mask)->width;
|
||||||
*y1 = GIMP_DRAWABLE(mask)->height;
|
ty1 = GIMP_DRAWABLE(mask)->height;
|
||||||
*x2 = 0;
|
tx2 = 0;
|
||||||
*y2 = 0;
|
ty2 = 0;
|
||||||
|
|
||||||
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, 0, 0, GIMP_DRAWABLE(mask)->width, GIMP_DRAWABLE(mask)->height, FALSE);
|
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, 0, 0, GIMP_DRAWABLE(mask)->width, GIMP_DRAWABLE(mask)->height, FALSE);
|
||||||
for (pr = pixel_regions_register (1, &maskPR); pr != NULL; pr = pixel_regions_process (pr))
|
for (pr = pixel_regions_register (1, &maskPR); pr != NULL; pr = pixel_regions_process (pr))
|
||||||
|
@ -630,36 +633,50 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2)
|
||||||
ey = maskPR.y + maskPR.h;
|
ey = maskPR.y + maskPR.h;
|
||||||
/* only check the pixels if this tile is not fully within the currently
|
/* only check the pixels if this tile is not fully within the currently
|
||||||
computed bounds */
|
computed bounds */
|
||||||
if (maskPR.x < *x1 || ex > *x2 ||
|
if (maskPR.x < tx1 || ex > tx2 ||
|
||||||
maskPR.y < *y1 || ey > *y2)
|
maskPR.y < ty1 || ey > ty2)
|
||||||
{
|
{
|
||||||
for (y = maskPR.y; y < ey; y++)
|
/* Check upper left and lower right corners to see if we can
|
||||||
|
avoid checking the rest of the pixels in this tile */
|
||||||
|
if (data[0] && data[maskPR.rowstride*(maskPR.h - 1) + maskPR.w - 1])
|
||||||
|
{
|
||||||
|
if (maskPR.x < tx1)
|
||||||
|
tx1 = maskPR.x;
|
||||||
|
if (ex > tx2)
|
||||||
|
tx2 = ex;
|
||||||
|
if (maskPR.y < ty1)
|
||||||
|
ty1 = maskPR.y;
|
||||||
|
if (ey > ty2)
|
||||||
|
ty2 = ey;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
for (y = maskPR.y; y < ey; y++)
|
||||||
{
|
{
|
||||||
found = FALSE;
|
|
||||||
for (x = maskPR.x; x < ex; x++, data++)
|
for (x = maskPR.x; x < ex; x++, data++)
|
||||||
if (*data)
|
if (*data)
|
||||||
{
|
{
|
||||||
if (x < *x1)
|
minx = x;
|
||||||
*x1 = x;
|
maxx = x;
|
||||||
if (x > *x2)
|
for (; x < ex; x++, data++)
|
||||||
*x2 = x;
|
if (*data)
|
||||||
found = TRUE;
|
maxx = x;
|
||||||
}
|
if (minx < tx1)
|
||||||
if (found)
|
tx1 = minx;
|
||||||
{
|
if (maxx > tx2)
|
||||||
if (y < *y1)
|
tx2 = maxx;
|
||||||
*y1 = y;
|
if (y < ty1)
|
||||||
if (y > *y2)
|
ty1 = y;
|
||||||
*y2 = y;
|
if (y > ty2)
|
||||||
}
|
ty2 = y;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*x2 = BOUNDS (*x2 + 1, 0, GIMP_DRAWABLE(mask)->width);
|
tx2 = BOUNDS (tx2 + 1, 0, GIMP_DRAWABLE(mask)->width);
|
||||||
*y2 = BOUNDS (*y2 + 1, 0, GIMP_DRAWABLE(mask)->height);
|
ty2 = BOUNDS (ty2 + 1, 0, GIMP_DRAWABLE(mask)->height);
|
||||||
|
|
||||||
if (*x1 == GIMP_DRAWABLE(mask)->width && *y1 == GIMP_DRAWABLE(mask)->height)
|
if (tx1 == GIMP_DRAWABLE(mask)->width && ty1 == GIMP_DRAWABLE(mask)->height)
|
||||||
{
|
{
|
||||||
mask->empty = TRUE;
|
mask->empty = TRUE;
|
||||||
mask->x1 = 0; mask->y1 = 0;
|
mask->x1 = 0; mask->y1 = 0;
|
||||||
|
@ -669,13 +686,18 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mask->empty = FALSE;
|
mask->empty = FALSE;
|
||||||
mask->x1 = *x1;
|
mask->x1 = tx1;
|
||||||
mask->y1 = *y1;
|
mask->y1 = ty1;
|
||||||
mask->x2 = *x2;
|
mask->x2 = tx2;
|
||||||
mask->y2 = *y2;
|
mask->y2 = ty2;
|
||||||
}
|
}
|
||||||
mask->bounds_known = TRUE;
|
mask->bounds_known = TRUE;
|
||||||
|
|
||||||
|
*x1 = tx1;
|
||||||
|
*x2 = tx2;
|
||||||
|
*y1 = ty1;
|
||||||
|
*y2 = ty2;
|
||||||
|
|
||||||
return (mask->empty) ? FALSE : TRUE;
|
return (mask->empty) ? FALSE : TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -800,61 +822,31 @@ channel_sub_segment (Channel *mask, int x, int y, int width, int value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
channel_inter_segment (Channel *mask, int x, int y, int width, int value)
|
|
||||||
{
|
|
||||||
PixelRegion maskPR;
|
|
||||||
unsigned char *data;
|
|
||||||
int val;
|
|
||||||
int x2;
|
|
||||||
void * pr;
|
|
||||||
|
|
||||||
/* check horizontal extents... */
|
|
||||||
x2 = x + width;
|
|
||||||
if (x2 < 0) x2 = 0;
|
|
||||||
if (x2 > GIMP_DRAWABLE(mask)->width) x2 = GIMP_DRAWABLE(mask)->width;
|
|
||||||
if (x < 0) x = 0;
|
|
||||||
if (x > GIMP_DRAWABLE(mask)->width) x = GIMP_DRAWABLE(mask)->width;
|
|
||||||
width = x2 - x;
|
|
||||||
if (!width) return;
|
|
||||||
|
|
||||||
if (y < 0 || y > GIMP_DRAWABLE(mask)->height)
|
|
||||||
return;
|
|
||||||
|
|
||||||
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, x, y, width, 1, TRUE);
|
|
||||||
for (pr = pixel_regions_register (1, &maskPR); pr != NULL; pr = pixel_regions_process (pr))
|
|
||||||
{
|
|
||||||
data = maskPR.data;
|
|
||||||
width = maskPR.w;
|
|
||||||
while (width--)
|
|
||||||
{
|
|
||||||
val = MINIMUM(*data, value);
|
|
||||||
*data++ = val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
channel_combine_rect (Channel *mask, int op, int x, int y, int w, int h)
|
channel_combine_rect (Channel *mask, int op, int x, int y, int w, int h)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
int x2, y2;
|
||||||
|
PixelRegion maskPR;
|
||||||
|
unsigned char color;
|
||||||
|
y2 = y + h;
|
||||||
|
x2 = x + w;
|
||||||
|
|
||||||
for (i = y; i < y + h; i++)
|
x = BOUNDS (x, 0, GIMP_DRAWABLE(mask)->width);
|
||||||
{
|
y = BOUNDS (y, 0, GIMP_DRAWABLE(mask)->height);
|
||||||
if (i >= 0 && i < GIMP_DRAWABLE(mask)->height)
|
x2 = BOUNDS (x2, 0, GIMP_DRAWABLE(mask)->width);
|
||||||
switch (op)
|
y2 = BOUNDS (y2, 0, GIMP_DRAWABLE(mask)->height);
|
||||||
{
|
|
||||||
case ADD: case REPLACE:
|
if (x2 - x <= 0 || y2 - y <= 0)
|
||||||
channel_add_segment (mask, x, i, w, 255);
|
return;
|
||||||
break;
|
|
||||||
case SUB:
|
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, x, y,
|
||||||
channel_sub_segment (mask, x, i, w, 255);
|
x2 - x, y2 - y, TRUE);
|
||||||
break;
|
if (op == ADD || op == REPLACE)
|
||||||
case INTERSECT:
|
color = 255;
|
||||||
channel_inter_segment (mask, x, i, w, 255);
|
else
|
||||||
break;
|
color = 0;
|
||||||
}
|
color_region(&maskPR, &color);
|
||||||
}
|
|
||||||
|
|
||||||
/* Determine new boundary */
|
/* Determine new boundary */
|
||||||
if (mask->bounds_known && (op == ADD) && !mask->empty)
|
if (mask->bounds_known && (op == ADD) && !mask->empty)
|
||||||
|
@ -933,9 +925,6 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h,
|
||||||
case SUB :
|
case SUB :
|
||||||
channel_sub_segment (mask, x1, i, (x2 - x1), 255);
|
channel_sub_segment (mask, x1, i, (x2 - x1), 255);
|
||||||
break;
|
break;
|
||||||
case INTERSECT:
|
|
||||||
channel_inter_segment (mask, x1, i, (x2 - x1), 255);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* antialiasing */
|
/* antialiasing */
|
||||||
|
@ -965,7 +954,7 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h,
|
||||||
val = (int) (255 * (1 - (dist + 0.5)));
|
val = (int) (255 * (1 - (dist + 0.5)));
|
||||||
else
|
else
|
||||||
val = 0;
|
val = 0;
|
||||||
|
|
||||||
if (last != val && last)
|
if (last != val && last)
|
||||||
{
|
{
|
||||||
switch (op)
|
switch (op)
|
||||||
|
@ -976,8 +965,6 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h,
|
||||||
case SUB:
|
case SUB:
|
||||||
channel_sub_segment (mask, x0, i, j - x0, last);
|
channel_sub_segment (mask, x0, i, j - x0, last);
|
||||||
break;
|
break;
|
||||||
case INTERSECT:
|
|
||||||
channel_inter_segment (mask, x0, i, j - x0, last);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -985,6 +972,10 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h,
|
||||||
{
|
{
|
||||||
x0 = j;
|
x0 = j;
|
||||||
last = val;
|
last = val;
|
||||||
|
/* because we are symetric accross the y axis we can
|
||||||
|
skip ahead a bit if we are inside the ellipse*/
|
||||||
|
if (val == 255 && j < cx)
|
||||||
|
j = cx + (cx - j) - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -994,8 +985,6 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h,
|
||||||
channel_add_segment (mask, x0, i, j - x0, last);
|
channel_add_segment (mask, x0, i, j - x0, last);
|
||||||
else if (op == SUB)
|
else if (op == SUB)
|
||||||
channel_sub_segment (mask, x0, i, j - x0, last);
|
channel_sub_segment (mask, x0, i, j - x0, last);
|
||||||
else if (op == INTERSECT)
|
|
||||||
channel_inter_segment (mask, x0, i, j - x0, last);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1032,18 +1021,81 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
channel_combine_sub_region_add (void *unused,
|
||||||
|
PixelRegion *srcPR,
|
||||||
|
PixelRegion *destPR)
|
||||||
|
{
|
||||||
|
unsigned char *src, *dest;
|
||||||
|
int x, y, val;
|
||||||
|
src = srcPR->data;
|
||||||
|
dest = destPR->data;
|
||||||
|
for (y = 0; y < srcPR->h; y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < srcPR->w; x++)
|
||||||
|
{
|
||||||
|
val = dest[x] + src[x];
|
||||||
|
if (val > 255)
|
||||||
|
dest[x] = 255;
|
||||||
|
else
|
||||||
|
dest[x] = val;
|
||||||
|
}
|
||||||
|
src += srcPR->rowstride;
|
||||||
|
dest += destPR->rowstride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
channel_combine_sub_region_sub (void *unused,
|
||||||
|
PixelRegion *srcPR,
|
||||||
|
PixelRegion *destPR)
|
||||||
|
{
|
||||||
|
unsigned char *src, *dest;
|
||||||
|
int x, y;
|
||||||
|
src = srcPR->data;
|
||||||
|
dest = destPR->data;
|
||||||
|
for (y = 0; y < srcPR->h; y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < srcPR->w; x++)
|
||||||
|
{
|
||||||
|
if (src[x] > dest[x])
|
||||||
|
dest[x] = 0;
|
||||||
|
else
|
||||||
|
dest[x]-= src[x];
|
||||||
|
}
|
||||||
|
src += srcPR->rowstride;
|
||||||
|
dest += destPR->rowstride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
channel_combine_sub_region_intersect (void *unused,
|
||||||
|
PixelRegion *srcPR,
|
||||||
|
PixelRegion *destPR)
|
||||||
|
{
|
||||||
|
unsigned char *src, *dest;
|
||||||
|
int x, y;
|
||||||
|
src = srcPR->data;
|
||||||
|
dest = destPR->data;
|
||||||
|
for (y = 0; y < srcPR->h; y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < srcPR->w; x++)
|
||||||
|
{
|
||||||
|
dest[x] = MINIMUM(dest[x], src[x]);
|
||||||
|
}
|
||||||
|
src += srcPR->rowstride;
|
||||||
|
dest += destPR->rowstride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
channel_combine_mask (Channel *mask, Channel *add_on, int op,
|
channel_combine_mask (Channel *mask, Channel *add_on, int op,
|
||||||
int off_x, int off_y)
|
int off_x, int off_y)
|
||||||
{
|
{
|
||||||
PixelRegion srcPR, destPR;
|
PixelRegion srcPR, destPR;
|
||||||
unsigned char *src;
|
|
||||||
unsigned char *dest;
|
|
||||||
int val;
|
|
||||||
int x1, y1, x2, y2;
|
int x1, y1, x2, y2;
|
||||||
int x, y;
|
|
||||||
int w, h;
|
int w, h;
|
||||||
void * pr;
|
|
||||||
|
|
||||||
x1 = BOUNDS (off_x, 0, GIMP_DRAWABLE(mask)->width);
|
x1 = BOUNDS (off_x, 0, GIMP_DRAWABLE(mask)->width);
|
||||||
y1 = BOUNDS (off_y, 0, GIMP_DRAWABLE(mask)->height);
|
y1 = BOUNDS (off_y, 0, GIMP_DRAWABLE(mask)->height);
|
||||||
|
@ -1056,39 +1108,25 @@ channel_combine_mask (Channel *mask, Channel *add_on, int op,
|
||||||
pixel_region_init (&srcPR, GIMP_DRAWABLE(add_on)->tiles, (x1 - off_x), (y1 - off_y), w, h, FALSE);
|
pixel_region_init (&srcPR, GIMP_DRAWABLE(add_on)->tiles, (x1 - off_x), (y1 - off_y), w, h, FALSE);
|
||||||
pixel_region_init (&destPR, GIMP_DRAWABLE(mask)->tiles, x1, y1, w, h, TRUE);
|
pixel_region_init (&destPR, GIMP_DRAWABLE(mask)->tiles, x1, y1, w, h, TRUE);
|
||||||
|
|
||||||
for (pr = pixel_regions_register (2, &srcPR, &destPR); pr != NULL; pr = pixel_regions_process (pr))
|
switch (op)
|
||||||
{
|
{
|
||||||
src = srcPR.data;
|
case ADD: case REPLACE:
|
||||||
dest = destPR.data;
|
pixel_regions_process_parallel ((p_func)channel_combine_sub_region_add,
|
||||||
|
NULL, 2, &srcPR, &destPR);
|
||||||
for (y = 0; y < srcPR.h; y++)
|
break;
|
||||||
{
|
case SUB:
|
||||||
for (x = 0; x < srcPR.w; x++)
|
pixel_regions_process_parallel ((p_func)channel_combine_sub_region_sub,
|
||||||
{
|
NULL, 2, &srcPR, &destPR);
|
||||||
switch (op)
|
break;
|
||||||
{
|
case INTERSECT:
|
||||||
case ADD: case REPLACE:
|
pixel_regions_process_parallel ((p_func)
|
||||||
val = dest[x] + src[x];
|
channel_combine_sub_region_intersect,
|
||||||
if (val > 255) val = 255;
|
NULL, 2, &srcPR, &destPR);
|
||||||
break;
|
break;
|
||||||
case SUB:
|
default:
|
||||||
val = dest[x] - src[x];
|
g_message("Error: unknown opperation type in channel_combine_mask\n");
|
||||||
if (val < 0) val = 0;
|
break;
|
||||||
break;
|
}
|
||||||
case INTERSECT:
|
|
||||||
val = MINIMUM(dest[x], src[x]);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
val = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
dest[x] = val;
|
|
||||||
}
|
|
||||||
src += srcPR.rowstride;
|
|
||||||
dest += destPR.rowstride;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mask->bounds_known = FALSE;
|
mask->bounds_known = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1184,57 +1222,35 @@ void
|
||||||
channel_invert (Channel *mask)
|
channel_invert (Channel *mask)
|
||||||
{
|
{
|
||||||
PixelRegion maskPR;
|
PixelRegion maskPR;
|
||||||
unsigned char *data;
|
GimpLut *lut;
|
||||||
int size;
|
|
||||||
void * pr;
|
|
||||||
|
|
||||||
/* push the current channel onto the undo stack */
|
/* push the current channel onto the undo stack */
|
||||||
channel_push_undo (mask);
|
channel_push_undo (mask);
|
||||||
|
|
||||||
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, 0, 0, GIMP_DRAWABLE(mask)->width, GIMP_DRAWABLE(mask)->height, TRUE);
|
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, 0, 0, GIMP_DRAWABLE(mask)->width, GIMP_DRAWABLE(mask)->height, TRUE);
|
||||||
for (pr = pixel_regions_register (1, &maskPR); pr != NULL; pr = pixel_regions_process (pr))
|
|
||||||
{
|
lut = invert_lut_new(1);
|
||||||
/* subtract each pixel in the mask from 255 */
|
|
||||||
data = maskPR.data;
|
|
||||||
size = maskPR.w * maskPR.h;
|
|
||||||
while (size --)
|
|
||||||
{
|
|
||||||
*data = 255 - *data;
|
|
||||||
data++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
pixel_regions_process_parallel ((p_func)gimp_lut_process_inline,
|
||||||
|
lut, 1, &maskPR);
|
||||||
|
gimp_lut_free(lut);
|
||||||
mask->bounds_known = FALSE;
|
mask->bounds_known = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
channel_sharpen (Channel *mask)
|
channel_sharpen (Channel *mask)
|
||||||
{
|
{
|
||||||
PixelRegion maskPR;
|
PixelRegion maskPR;
|
||||||
unsigned char *data;
|
GimpLut *lut;
|
||||||
int size;
|
|
||||||
void * pr;
|
|
||||||
|
|
||||||
/* push the current channel onto the undo stack */
|
/* push the current channel onto the undo stack */
|
||||||
channel_push_undo (mask);
|
channel_push_undo (mask);
|
||||||
|
|
||||||
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, 0, 0, GIMP_DRAWABLE(mask)->width, GIMP_DRAWABLE(mask)->height, TRUE);
|
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, 0, 0, GIMP_DRAWABLE(mask)->width, GIMP_DRAWABLE(mask)->height, TRUE);
|
||||||
for (pr = pixel_regions_register (1, &maskPR); pr != NULL; pr = pixel_regions_process (pr))
|
lut = threshold_lut_new(0.5, 1);
|
||||||
{
|
|
||||||
/* if a pixel in the mask has a non-zero value, make it 255 */
|
|
||||||
data = maskPR.data;
|
|
||||||
size = maskPR.w * maskPR.h;
|
|
||||||
while (size--)
|
|
||||||
{
|
|
||||||
if (*data > HALF_WAY)
|
|
||||||
*data++ = 255;
|
|
||||||
else
|
|
||||||
*data++ = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mask->bounds_known = FALSE;
|
pixel_regions_process_parallel ((p_func)gimp_lut_process_inline,
|
||||||
|
lut, 1, &maskPR);
|
||||||
|
gimp_lut_free(lut);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,457 @@
|
||||||
|
/* The GIMP -- an image manipulation program
|
||||||
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "color_cmds.h"
|
||||||
|
#include "gimpimage.h"
|
||||||
|
#include "gimpdrawable.h"
|
||||||
|
#include "gimplut.h"
|
||||||
|
#include "lut_funcs.h"
|
||||||
|
|
||||||
|
static Argument * brightness_contrast_invoker (Argument *);
|
||||||
|
static Argument * levels_invoker (Argument *);
|
||||||
|
static Argument * posterize_invoker (Argument *);
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* --------- The brightness_contrast procedure definition ---------- */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
ProcArg brightness_contrast_args[] =
|
||||||
|
{
|
||||||
|
{ PDB_DRAWABLE,
|
||||||
|
"drawable",
|
||||||
|
"the drawable"
|
||||||
|
},
|
||||||
|
{ PDB_INT32,
|
||||||
|
"brightness",
|
||||||
|
"brightness adjustment: (-127 <= brightness <= 127)"
|
||||||
|
},
|
||||||
|
{ PDB_INT32,
|
||||||
|
"contrast",
|
||||||
|
"constrast adjustment: (-127 <= contrast <= 127)"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ProcRecord brightness_contrast_proc =
|
||||||
|
{
|
||||||
|
"gimp_brightness_contrast",
|
||||||
|
"Modify brightness/contrast in the specified drawable",
|
||||||
|
"This procedures allows the brightness and contrast of the specified drawable to be modified. Both 'brightness' and 'contrast' parameters are defined between -127 and 127.",
|
||||||
|
"Spencer Kimball & Peter Mattis",
|
||||||
|
"Spencer Kimball & Peter Mattis",
|
||||||
|
"1997",
|
||||||
|
PDB_INTERNAL,
|
||||||
|
|
||||||
|
/* Input arguments */
|
||||||
|
3,
|
||||||
|
brightness_contrast_args,
|
||||||
|
|
||||||
|
/* Output arguments */
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
|
||||||
|
/* Exec method */
|
||||||
|
{ { brightness_contrast_invoker } },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static Argument *
|
||||||
|
brightness_contrast_invoker (Argument *args)
|
||||||
|
{
|
||||||
|
PixelRegion srcPR, destPR;
|
||||||
|
int success = TRUE;
|
||||||
|
int int_value;
|
||||||
|
GimpImage *gimage;
|
||||||
|
int brightness;
|
||||||
|
int contrast;
|
||||||
|
int x1, y1, x2, y2;
|
||||||
|
GimpDrawable *drawable;
|
||||||
|
|
||||||
|
drawable = NULL;
|
||||||
|
brightness = 0;
|
||||||
|
contrast = 0;
|
||||||
|
|
||||||
|
/* the drawable */
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
int_value = args[0].value.pdb_int;
|
||||||
|
drawable = gimp_drawable_get_ID (int_value);
|
||||||
|
if (drawable == NULL)
|
||||||
|
success = FALSE;
|
||||||
|
else
|
||||||
|
gimage = gimp_drawable_gimage (drawable);
|
||||||
|
}
|
||||||
|
/* make sure the drawable is not indexed color */
|
||||||
|
if (success)
|
||||||
|
success = ! gimp_drawable_indexed (drawable);
|
||||||
|
|
||||||
|
/* brightness */
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
int_value = args[1].value.pdb_int;
|
||||||
|
if (int_value < -127 || int_value > 127)
|
||||||
|
success = FALSE;
|
||||||
|
else
|
||||||
|
brightness = int_value;
|
||||||
|
}
|
||||||
|
/* contrast */
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
int_value = args[2].value.pdb_int;
|
||||||
|
if (int_value < -127 || int_value > 127)
|
||||||
|
success = FALSE;
|
||||||
|
else
|
||||||
|
contrast = int_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* arrange to modify the brightness/contrast */
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
GimpLut *lut;
|
||||||
|
lut = brightness_contrast_lut_new(brightness / 255.0, contrast / 127.0,
|
||||||
|
gimp_drawable_bytes(drawable));
|
||||||
|
|
||||||
|
/* The application should occur only within selection bounds */
|
||||||
|
gimp_drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
|
||||||
|
|
||||||
|
pixel_region_init (&srcPR, gimp_drawable_data (drawable),
|
||||||
|
x1, y1, (x2 - x1), (y2 - y1), FALSE);
|
||||||
|
pixel_region_init (&destPR, gimp_drawable_shadow (drawable),
|
||||||
|
x1, y1, (x2 - x1), (y2 - y1), TRUE);
|
||||||
|
|
||||||
|
pixel_regions_process_parallel((p_func)gimp_lut_process, lut,
|
||||||
|
2, &srcPR, &destPR);
|
||||||
|
|
||||||
|
gimp_lut_free(lut);
|
||||||
|
gimp_drawable_merge_shadow (drawable, TRUE);
|
||||||
|
drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1));
|
||||||
|
}
|
||||||
|
|
||||||
|
return procedural_db_return_args (&brightness_contrast_proc, success);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* ---------------- The levels procedure definition ----------------- */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
ProcArg levels_args[] =
|
||||||
|
{
|
||||||
|
{ PDB_DRAWABLE,
|
||||||
|
"drawable",
|
||||||
|
"the drawable"
|
||||||
|
},
|
||||||
|
{ PDB_INT32,
|
||||||
|
"channel",
|
||||||
|
"the channel to modify: { VALUE (0), RED (1), GREEN (2), BLUE (3), GRAY (0) }"
|
||||||
|
},
|
||||||
|
{ PDB_INT32,
|
||||||
|
"low_input",
|
||||||
|
"intensity of lowest input: (0 <= low_input <= 255)"
|
||||||
|
},
|
||||||
|
{ PDB_INT32,
|
||||||
|
"high_input",
|
||||||
|
"intensity of highest input: (0 <= high_input <= 255)"
|
||||||
|
},
|
||||||
|
{ PDB_FLOAT,
|
||||||
|
"gamma",
|
||||||
|
"gamma correction factor: (0.1 <= gamma <= 10)"
|
||||||
|
},
|
||||||
|
{ PDB_INT32,
|
||||||
|
"low_output",
|
||||||
|
"intensity of lowest output: (0 <= low_input <= 255)"
|
||||||
|
},
|
||||||
|
{ PDB_INT32,
|
||||||
|
"high_output",
|
||||||
|
"intensity of highest output: (0 <= high_input <= 255)"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ProcRecord levels_proc =
|
||||||
|
{
|
||||||
|
"gimp_levels",
|
||||||
|
"Modifies intensity levels in the specified drawable",
|
||||||
|
"This tool allows intensity levels in the specified drawable to be remapped according to a set of parameters. The low/high input levels specify an initial mapping from the source intensities. The gamma value determines how intensities between the low and high input intensities are interpolated. A gamma value of 1.0 results in a linear interpolation. Higher gamma values result in more high-level intensities. Lower gamma values result in more low-level intensities. The low/high output levels constrain the final intensity mapping--that is, no final intensity will be lower than the low output level and no final intensity will be higher than the high output level. This tool is only valid on RGB color and grayscale images. It will not operate on indexed drawables.",
|
||||||
|
"Spencer Kimball & Peter Mattis",
|
||||||
|
"Spencer Kimball & Peter Mattis",
|
||||||
|
"1995-1996",
|
||||||
|
PDB_INTERNAL,
|
||||||
|
|
||||||
|
/* Input arguments */
|
||||||
|
7,
|
||||||
|
levels_args,
|
||||||
|
|
||||||
|
/* Output arguments */
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
|
||||||
|
/* Exec method */
|
||||||
|
{ { levels_invoker } },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static Argument *
|
||||||
|
levels_invoker (Argument *args)
|
||||||
|
{
|
||||||
|
PixelRegion srcPR, destPR;
|
||||||
|
int success = TRUE;
|
||||||
|
GimpDrawable *drawable;
|
||||||
|
int channel;
|
||||||
|
int low_inputv;
|
||||||
|
int high_inputv;
|
||||||
|
double gammav;
|
||||||
|
int low_outputv;
|
||||||
|
int high_outputv;
|
||||||
|
int int_value;
|
||||||
|
double fp_value;
|
||||||
|
int x1, y1, x2, y2;
|
||||||
|
int i;
|
||||||
|
int low_input[5];
|
||||||
|
double gamma[5];
|
||||||
|
int high_input[5];
|
||||||
|
int low_output[5];
|
||||||
|
int high_output[5];
|
||||||
|
|
||||||
|
drawable = NULL;
|
||||||
|
low_inputv = 0;
|
||||||
|
high_inputv = 0;
|
||||||
|
gammav = 1.0;
|
||||||
|
low_outputv = 0;
|
||||||
|
high_outputv = 0;
|
||||||
|
|
||||||
|
/* the drawable */
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
int_value = args[0].value.pdb_int;
|
||||||
|
drawable = gimp_drawable_get_ID (int_value);
|
||||||
|
if (drawable == NULL)
|
||||||
|
success = FALSE;
|
||||||
|
}
|
||||||
|
/* make sure the drawable is not indexed color */
|
||||||
|
if (success)
|
||||||
|
success = ! gimp_drawable_indexed (drawable);
|
||||||
|
|
||||||
|
/* channel */
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
int_value = args[1].value.pdb_int;
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
if (gimp_drawable_gray (drawable))
|
||||||
|
{
|
||||||
|
if (int_value != 0)
|
||||||
|
success = FALSE;
|
||||||
|
}
|
||||||
|
else if (gimp_drawable_color (drawable))
|
||||||
|
{
|
||||||
|
if (int_value < 0 || int_value > 3)
|
||||||
|
success = FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
success = FALSE;
|
||||||
|
}
|
||||||
|
channel = int_value;
|
||||||
|
}
|
||||||
|
/* low input */
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
int_value = args[2].value.pdb_int;
|
||||||
|
if (int_value >= 0 && int_value < 256)
|
||||||
|
low_inputv = int_value;
|
||||||
|
else
|
||||||
|
success = FALSE;
|
||||||
|
}
|
||||||
|
/* high input */
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
int_value = args[3].value.pdb_int;
|
||||||
|
if (int_value >= 0 && int_value < 256)
|
||||||
|
high_inputv = int_value;
|
||||||
|
else
|
||||||
|
success = FALSE;
|
||||||
|
}
|
||||||
|
/* gamma */
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
fp_value = args[4].value.pdb_float;
|
||||||
|
if (fp_value >= 0.1 && fp_value <= 10.0)
|
||||||
|
gammav = fp_value;
|
||||||
|
else
|
||||||
|
success = FALSE;
|
||||||
|
}
|
||||||
|
/* low output */
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
int_value = args[5].value.pdb_int;
|
||||||
|
if (int_value >= 0 && int_value < 256)
|
||||||
|
low_outputv = int_value;
|
||||||
|
else
|
||||||
|
success = FALSE;
|
||||||
|
}
|
||||||
|
/* high output */
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
int_value = args[6].value.pdb_int;
|
||||||
|
if (int_value >= 0 && int_value < 256)
|
||||||
|
high_outputv = int_value;
|
||||||
|
else
|
||||||
|
success = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* arrange to modify the levels */
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
GimpLut *lut;
|
||||||
|
for (i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
low_input[i] = 0;
|
||||||
|
gamma[i] = 1.0;
|
||||||
|
high_input[i] = 255;
|
||||||
|
low_output[i] = 0;
|
||||||
|
high_output[i] = 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
low_input[channel] = low_inputv;
|
||||||
|
high_input[channel] = high_inputv;
|
||||||
|
gamma[channel] = gammav;
|
||||||
|
low_output[channel] = low_outputv;
|
||||||
|
high_output[channel] = high_outputv;
|
||||||
|
|
||||||
|
/* setup the lut */
|
||||||
|
lut = levels_lut_new(gamma, low_input, high_input,
|
||||||
|
low_output, high_output,
|
||||||
|
gimp_drawable_bytes(drawable));
|
||||||
|
|
||||||
|
/* The application should occur only within selection bounds */
|
||||||
|
gimp_drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
|
||||||
|
|
||||||
|
pixel_region_init (&srcPR, gimp_drawable_data (drawable),
|
||||||
|
x1, y1, (x2 - x1), (y2 - y1), FALSE);
|
||||||
|
pixel_region_init (&destPR, gimp_drawable_shadow (drawable),
|
||||||
|
x1, y1, (x2 - x1), (y2 - y1), TRUE);
|
||||||
|
|
||||||
|
pixel_regions_process_parallel((p_func)gimp_lut_process, lut,
|
||||||
|
2, &srcPR, &destPR);
|
||||||
|
|
||||||
|
gimp_lut_free(lut);
|
||||||
|
gimp_drawable_merge_shadow (drawable, TRUE);
|
||||||
|
drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1));
|
||||||
|
}
|
||||||
|
|
||||||
|
return procedural_db_return_args (&levels_proc, success);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* ---------------- The posterize procedure definition -------------- */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
ProcArg posterize_args[] =
|
||||||
|
{
|
||||||
|
{ PDB_DRAWABLE,
|
||||||
|
"drawable",
|
||||||
|
"the drawable"
|
||||||
|
},
|
||||||
|
{ PDB_INT32,
|
||||||
|
"levels",
|
||||||
|
"levels of posterization: (2 <= levels <= 255)"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ProcRecord posterize_proc =
|
||||||
|
{
|
||||||
|
"gimp_posterize",
|
||||||
|
"Posterize the specified drawable",
|
||||||
|
"This procedures reduces the number of shades allows in each intensity channel to the specified 'levels' parameter.",
|
||||||
|
"Spencer Kimball & Peter Mattis",
|
||||||
|
"Spencer Kimball & Peter Mattis",
|
||||||
|
"1997",
|
||||||
|
PDB_INTERNAL,
|
||||||
|
|
||||||
|
/* Input arguments */
|
||||||
|
2,
|
||||||
|
posterize_args,
|
||||||
|
|
||||||
|
/* Output arguments */
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
|
||||||
|
/* Exec method */
|
||||||
|
{ { posterize_invoker } },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static Argument *
|
||||||
|
posterize_invoker (Argument *args)
|
||||||
|
{
|
||||||
|
PixelRegion srcPR, destPR;
|
||||||
|
int success = TRUE;
|
||||||
|
GimpImage *gimage;
|
||||||
|
GimpDrawable *drawable;
|
||||||
|
int levels;
|
||||||
|
int int_value;
|
||||||
|
int x1, y1, x2, y2;
|
||||||
|
|
||||||
|
drawable = NULL;
|
||||||
|
levels = 0;
|
||||||
|
|
||||||
|
/* the drawable */
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
int_value = args[0].value.pdb_int;
|
||||||
|
drawable = gimp_drawable_get_ID (int_value);
|
||||||
|
if (drawable == NULL)
|
||||||
|
success = FALSE;
|
||||||
|
else
|
||||||
|
gimage = gimp_drawable_gimage (drawable);
|
||||||
|
}
|
||||||
|
/* make sure the drawable is not indexed color */
|
||||||
|
if (success)
|
||||||
|
success = ! gimp_drawable_indexed (drawable);
|
||||||
|
|
||||||
|
/* levels */
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
int_value = args[1].value.pdb_int;
|
||||||
|
if (int_value >= 2 && int_value < 256)
|
||||||
|
levels = int_value;
|
||||||
|
else
|
||||||
|
success = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* arrange to modify the levels */
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
GimpLut *lut;
|
||||||
|
lut = posterize_lut_new(levels, gimp_drawable_bytes(drawable));
|
||||||
|
/* The application should occur only within selection bounds */
|
||||||
|
gimp_drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
|
||||||
|
|
||||||
|
pixel_region_init (&srcPR, gimp_drawable_data (drawable),
|
||||||
|
x1, y1, (x2 - x1), (y2 - y1), FALSE);
|
||||||
|
pixel_region_init (&destPR, gimp_drawable_shadow (drawable),
|
||||||
|
x1, y1, (x2 - x1), (y2 - y1), TRUE);
|
||||||
|
|
||||||
|
pixel_regions_process_parallel((p_func)gimp_lut_process, lut,
|
||||||
|
2, &srcPR, &destPR);
|
||||||
|
|
||||||
|
gimp_lut_free(lut);
|
||||||
|
gimp_drawable_merge_shadow (drawable, TRUE);
|
||||||
|
drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1));
|
||||||
|
}
|
||||||
|
|
||||||
|
return procedural_db_return_args (&posterize_proc, success);
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
/* The GIMP -- an image manipulation program
|
||||||
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __COLOR_CMDS_H__
|
||||||
|
#define __COLOR_CMDS_H__
|
||||||
|
|
||||||
|
#include "procedural_db.h"
|
||||||
|
|
||||||
|
extern ProcRecord brightness_contrast_proc;
|
||||||
|
extern ProcRecord levels_proc;
|
||||||
|
extern ProcRecord posterize_proc;
|
||||||
|
|
||||||
|
#endif /* __COLOR_CMDS_H__ */
|
|
@ -16,8 +16,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include "parasitelist.h"
|
#include "parasitelist.h"
|
||||||
#include "gimpparasite.h"
|
#include "gimpparasite.h"
|
||||||
|
#include "libgimp/parasite.h"
|
||||||
|
#include "libgimp/gimpenv.h"
|
||||||
|
|
||||||
static ParasiteList *parasites = NULL;
|
static ParasiteList *parasites = NULL;
|
||||||
|
|
||||||
|
@ -26,6 +30,7 @@ gimp_init_parasites()
|
||||||
{
|
{
|
||||||
g_return_if_fail(parasites == NULL);
|
g_return_if_fail(parasites == NULL);
|
||||||
parasites = parasite_list_new();
|
parasites = parasite_list_new();
|
||||||
|
gimp_parasiterc_load();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -64,5 +69,40 @@ gimp_parasite_list (gint *count)
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gimp_parasiterc_save()
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
guint32 num, version = 1;
|
||||||
|
if (!(fp = fopen(gimp_personal_rc_file ("#parasiterc.tmp"), "w")))
|
||||||
|
return;
|
||||||
|
version = GINT32_TO_BE(version);
|
||||||
|
fwrite(&version, 4, 1, fp);
|
||||||
|
|
||||||
|
parasite_list_save(parasites, fp);
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
if (rename(gimp_personal_rc_file ("#parasiterc.tmp"),
|
||||||
|
gimp_personal_rc_file("parasiterc")) != 0)
|
||||||
|
unlink(gimp_personal_rc_file ("#parasiterc.tmp"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gimp_parasiterc_load()
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
guint32 num, version;
|
||||||
|
if (!(fp = fopen(gimp_personal_rc_file ("parasiterc"), "r")))
|
||||||
|
return;
|
||||||
|
fread(&version, 4, 1, fp);
|
||||||
|
version = GINT32_FROM_BE(version);
|
||||||
|
if (version != 1)
|
||||||
|
{
|
||||||
|
fclose(fp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parasite_list_load(parasites, fp);
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
|
@ -25,5 +25,7 @@ void gimp_attach_parasite (Parasite *p);
|
||||||
void gimp_detach_parasite (char *name);
|
void gimp_detach_parasite (char *name);
|
||||||
Parasite * gimp_find_parasite (char *name);
|
Parasite * gimp_find_parasite (char *name);
|
||||||
char ** gimp_parasite_list (gint *count);
|
char ** gimp_parasite_list (gint *count);
|
||||||
|
void gimp_parasiterc_save (void);
|
||||||
|
void gimp_parasiterc_load (void);
|
||||||
|
|
||||||
#endif /* __GIMP_PARASITE_H__ */
|
#endif /* __GIMP_PARASITE_H__ */
|
||||||
|
|
|
@ -36,6 +36,9 @@
|
||||||
#include "channel_pvt.h"
|
#include "channel_pvt.h"
|
||||||
#include "tile.h"
|
#include "tile.h"
|
||||||
|
|
||||||
|
#include "gimplut.h"
|
||||||
|
#include "lut_funcs.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
enum {
|
enum {
|
||||||
LAST_SIGNAL
|
LAST_SIGNAL
|
||||||
|
@ -602,9 +605,9 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2)
|
||||||
unsigned char * data;
|
unsigned char * data;
|
||||||
int x, y;
|
int x, y;
|
||||||
int ex, ey;
|
int ex, ey;
|
||||||
int found;
|
|
||||||
void *pr;
|
void *pr;
|
||||||
|
int tx1, tx2, ty1, ty2;
|
||||||
|
int minx, maxx;
|
||||||
/* if the mask's bounds have already been reliably calculated... */
|
/* if the mask's bounds have already been reliably calculated... */
|
||||||
if (mask->bounds_known)
|
if (mask->bounds_known)
|
||||||
{
|
{
|
||||||
|
@ -617,10 +620,10 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* go through and calculate the bounds */
|
/* go through and calculate the bounds */
|
||||||
*x1 = GIMP_DRAWABLE(mask)->width;
|
tx1 = GIMP_DRAWABLE(mask)->width;
|
||||||
*y1 = GIMP_DRAWABLE(mask)->height;
|
ty1 = GIMP_DRAWABLE(mask)->height;
|
||||||
*x2 = 0;
|
tx2 = 0;
|
||||||
*y2 = 0;
|
ty2 = 0;
|
||||||
|
|
||||||
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, 0, 0, GIMP_DRAWABLE(mask)->width, GIMP_DRAWABLE(mask)->height, FALSE);
|
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, 0, 0, GIMP_DRAWABLE(mask)->width, GIMP_DRAWABLE(mask)->height, FALSE);
|
||||||
for (pr = pixel_regions_register (1, &maskPR); pr != NULL; pr = pixel_regions_process (pr))
|
for (pr = pixel_regions_register (1, &maskPR); pr != NULL; pr = pixel_regions_process (pr))
|
||||||
|
@ -630,36 +633,50 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2)
|
||||||
ey = maskPR.y + maskPR.h;
|
ey = maskPR.y + maskPR.h;
|
||||||
/* only check the pixels if this tile is not fully within the currently
|
/* only check the pixels if this tile is not fully within the currently
|
||||||
computed bounds */
|
computed bounds */
|
||||||
if (maskPR.x < *x1 || ex > *x2 ||
|
if (maskPR.x < tx1 || ex > tx2 ||
|
||||||
maskPR.y < *y1 || ey > *y2)
|
maskPR.y < ty1 || ey > ty2)
|
||||||
{
|
{
|
||||||
for (y = maskPR.y; y < ey; y++)
|
/* Check upper left and lower right corners to see if we can
|
||||||
|
avoid checking the rest of the pixels in this tile */
|
||||||
|
if (data[0] && data[maskPR.rowstride*(maskPR.h - 1) + maskPR.w - 1])
|
||||||
|
{
|
||||||
|
if (maskPR.x < tx1)
|
||||||
|
tx1 = maskPR.x;
|
||||||
|
if (ex > tx2)
|
||||||
|
tx2 = ex;
|
||||||
|
if (maskPR.y < ty1)
|
||||||
|
ty1 = maskPR.y;
|
||||||
|
if (ey > ty2)
|
||||||
|
ty2 = ey;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
for (y = maskPR.y; y < ey; y++)
|
||||||
{
|
{
|
||||||
found = FALSE;
|
|
||||||
for (x = maskPR.x; x < ex; x++, data++)
|
for (x = maskPR.x; x < ex; x++, data++)
|
||||||
if (*data)
|
if (*data)
|
||||||
{
|
{
|
||||||
if (x < *x1)
|
minx = x;
|
||||||
*x1 = x;
|
maxx = x;
|
||||||
if (x > *x2)
|
for (; x < ex; x++, data++)
|
||||||
*x2 = x;
|
if (*data)
|
||||||
found = TRUE;
|
maxx = x;
|
||||||
}
|
if (minx < tx1)
|
||||||
if (found)
|
tx1 = minx;
|
||||||
{
|
if (maxx > tx2)
|
||||||
if (y < *y1)
|
tx2 = maxx;
|
||||||
*y1 = y;
|
if (y < ty1)
|
||||||
if (y > *y2)
|
ty1 = y;
|
||||||
*y2 = y;
|
if (y > ty2)
|
||||||
}
|
ty2 = y;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*x2 = BOUNDS (*x2 + 1, 0, GIMP_DRAWABLE(mask)->width);
|
tx2 = BOUNDS (tx2 + 1, 0, GIMP_DRAWABLE(mask)->width);
|
||||||
*y2 = BOUNDS (*y2 + 1, 0, GIMP_DRAWABLE(mask)->height);
|
ty2 = BOUNDS (ty2 + 1, 0, GIMP_DRAWABLE(mask)->height);
|
||||||
|
|
||||||
if (*x1 == GIMP_DRAWABLE(mask)->width && *y1 == GIMP_DRAWABLE(mask)->height)
|
if (tx1 == GIMP_DRAWABLE(mask)->width && ty1 == GIMP_DRAWABLE(mask)->height)
|
||||||
{
|
{
|
||||||
mask->empty = TRUE;
|
mask->empty = TRUE;
|
||||||
mask->x1 = 0; mask->y1 = 0;
|
mask->x1 = 0; mask->y1 = 0;
|
||||||
|
@ -669,13 +686,18 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mask->empty = FALSE;
|
mask->empty = FALSE;
|
||||||
mask->x1 = *x1;
|
mask->x1 = tx1;
|
||||||
mask->y1 = *y1;
|
mask->y1 = ty1;
|
||||||
mask->x2 = *x2;
|
mask->x2 = tx2;
|
||||||
mask->y2 = *y2;
|
mask->y2 = ty2;
|
||||||
}
|
}
|
||||||
mask->bounds_known = TRUE;
|
mask->bounds_known = TRUE;
|
||||||
|
|
||||||
|
*x1 = tx1;
|
||||||
|
*x2 = tx2;
|
||||||
|
*y1 = ty1;
|
||||||
|
*y2 = ty2;
|
||||||
|
|
||||||
return (mask->empty) ? FALSE : TRUE;
|
return (mask->empty) ? FALSE : TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -800,61 +822,31 @@ channel_sub_segment (Channel *mask, int x, int y, int width, int value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
channel_inter_segment (Channel *mask, int x, int y, int width, int value)
|
|
||||||
{
|
|
||||||
PixelRegion maskPR;
|
|
||||||
unsigned char *data;
|
|
||||||
int val;
|
|
||||||
int x2;
|
|
||||||
void * pr;
|
|
||||||
|
|
||||||
/* check horizontal extents... */
|
|
||||||
x2 = x + width;
|
|
||||||
if (x2 < 0) x2 = 0;
|
|
||||||
if (x2 > GIMP_DRAWABLE(mask)->width) x2 = GIMP_DRAWABLE(mask)->width;
|
|
||||||
if (x < 0) x = 0;
|
|
||||||
if (x > GIMP_DRAWABLE(mask)->width) x = GIMP_DRAWABLE(mask)->width;
|
|
||||||
width = x2 - x;
|
|
||||||
if (!width) return;
|
|
||||||
|
|
||||||
if (y < 0 || y > GIMP_DRAWABLE(mask)->height)
|
|
||||||
return;
|
|
||||||
|
|
||||||
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, x, y, width, 1, TRUE);
|
|
||||||
for (pr = pixel_regions_register (1, &maskPR); pr != NULL; pr = pixel_regions_process (pr))
|
|
||||||
{
|
|
||||||
data = maskPR.data;
|
|
||||||
width = maskPR.w;
|
|
||||||
while (width--)
|
|
||||||
{
|
|
||||||
val = MINIMUM(*data, value);
|
|
||||||
*data++ = val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
channel_combine_rect (Channel *mask, int op, int x, int y, int w, int h)
|
channel_combine_rect (Channel *mask, int op, int x, int y, int w, int h)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
int x2, y2;
|
||||||
|
PixelRegion maskPR;
|
||||||
|
unsigned char color;
|
||||||
|
y2 = y + h;
|
||||||
|
x2 = x + w;
|
||||||
|
|
||||||
for (i = y; i < y + h; i++)
|
x = BOUNDS (x, 0, GIMP_DRAWABLE(mask)->width);
|
||||||
{
|
y = BOUNDS (y, 0, GIMP_DRAWABLE(mask)->height);
|
||||||
if (i >= 0 && i < GIMP_DRAWABLE(mask)->height)
|
x2 = BOUNDS (x2, 0, GIMP_DRAWABLE(mask)->width);
|
||||||
switch (op)
|
y2 = BOUNDS (y2, 0, GIMP_DRAWABLE(mask)->height);
|
||||||
{
|
|
||||||
case ADD: case REPLACE:
|
if (x2 - x <= 0 || y2 - y <= 0)
|
||||||
channel_add_segment (mask, x, i, w, 255);
|
return;
|
||||||
break;
|
|
||||||
case SUB:
|
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, x, y,
|
||||||
channel_sub_segment (mask, x, i, w, 255);
|
x2 - x, y2 - y, TRUE);
|
||||||
break;
|
if (op == ADD || op == REPLACE)
|
||||||
case INTERSECT:
|
color = 255;
|
||||||
channel_inter_segment (mask, x, i, w, 255);
|
else
|
||||||
break;
|
color = 0;
|
||||||
}
|
color_region(&maskPR, &color);
|
||||||
}
|
|
||||||
|
|
||||||
/* Determine new boundary */
|
/* Determine new boundary */
|
||||||
if (mask->bounds_known && (op == ADD) && !mask->empty)
|
if (mask->bounds_known && (op == ADD) && !mask->empty)
|
||||||
|
@ -933,9 +925,6 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h,
|
||||||
case SUB :
|
case SUB :
|
||||||
channel_sub_segment (mask, x1, i, (x2 - x1), 255);
|
channel_sub_segment (mask, x1, i, (x2 - x1), 255);
|
||||||
break;
|
break;
|
||||||
case INTERSECT:
|
|
||||||
channel_inter_segment (mask, x1, i, (x2 - x1), 255);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* antialiasing */
|
/* antialiasing */
|
||||||
|
@ -965,7 +954,7 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h,
|
||||||
val = (int) (255 * (1 - (dist + 0.5)));
|
val = (int) (255 * (1 - (dist + 0.5)));
|
||||||
else
|
else
|
||||||
val = 0;
|
val = 0;
|
||||||
|
|
||||||
if (last != val && last)
|
if (last != val && last)
|
||||||
{
|
{
|
||||||
switch (op)
|
switch (op)
|
||||||
|
@ -976,8 +965,6 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h,
|
||||||
case SUB:
|
case SUB:
|
||||||
channel_sub_segment (mask, x0, i, j - x0, last);
|
channel_sub_segment (mask, x0, i, j - x0, last);
|
||||||
break;
|
break;
|
||||||
case INTERSECT:
|
|
||||||
channel_inter_segment (mask, x0, i, j - x0, last);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -985,6 +972,10 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h,
|
||||||
{
|
{
|
||||||
x0 = j;
|
x0 = j;
|
||||||
last = val;
|
last = val;
|
||||||
|
/* because we are symetric accross the y axis we can
|
||||||
|
skip ahead a bit if we are inside the ellipse*/
|
||||||
|
if (val == 255 && j < cx)
|
||||||
|
j = cx + (cx - j) - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -994,8 +985,6 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h,
|
||||||
channel_add_segment (mask, x0, i, j - x0, last);
|
channel_add_segment (mask, x0, i, j - x0, last);
|
||||||
else if (op == SUB)
|
else if (op == SUB)
|
||||||
channel_sub_segment (mask, x0, i, j - x0, last);
|
channel_sub_segment (mask, x0, i, j - x0, last);
|
||||||
else if (op == INTERSECT)
|
|
||||||
channel_inter_segment (mask, x0, i, j - x0, last);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1032,18 +1021,81 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
channel_combine_sub_region_add (void *unused,
|
||||||
|
PixelRegion *srcPR,
|
||||||
|
PixelRegion *destPR)
|
||||||
|
{
|
||||||
|
unsigned char *src, *dest;
|
||||||
|
int x, y, val;
|
||||||
|
src = srcPR->data;
|
||||||
|
dest = destPR->data;
|
||||||
|
for (y = 0; y < srcPR->h; y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < srcPR->w; x++)
|
||||||
|
{
|
||||||
|
val = dest[x] + src[x];
|
||||||
|
if (val > 255)
|
||||||
|
dest[x] = 255;
|
||||||
|
else
|
||||||
|
dest[x] = val;
|
||||||
|
}
|
||||||
|
src += srcPR->rowstride;
|
||||||
|
dest += destPR->rowstride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
channel_combine_sub_region_sub (void *unused,
|
||||||
|
PixelRegion *srcPR,
|
||||||
|
PixelRegion *destPR)
|
||||||
|
{
|
||||||
|
unsigned char *src, *dest;
|
||||||
|
int x, y;
|
||||||
|
src = srcPR->data;
|
||||||
|
dest = destPR->data;
|
||||||
|
for (y = 0; y < srcPR->h; y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < srcPR->w; x++)
|
||||||
|
{
|
||||||
|
if (src[x] > dest[x])
|
||||||
|
dest[x] = 0;
|
||||||
|
else
|
||||||
|
dest[x]-= src[x];
|
||||||
|
}
|
||||||
|
src += srcPR->rowstride;
|
||||||
|
dest += destPR->rowstride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
channel_combine_sub_region_intersect (void *unused,
|
||||||
|
PixelRegion *srcPR,
|
||||||
|
PixelRegion *destPR)
|
||||||
|
{
|
||||||
|
unsigned char *src, *dest;
|
||||||
|
int x, y;
|
||||||
|
src = srcPR->data;
|
||||||
|
dest = destPR->data;
|
||||||
|
for (y = 0; y < srcPR->h; y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < srcPR->w; x++)
|
||||||
|
{
|
||||||
|
dest[x] = MINIMUM(dest[x], src[x]);
|
||||||
|
}
|
||||||
|
src += srcPR->rowstride;
|
||||||
|
dest += destPR->rowstride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
channel_combine_mask (Channel *mask, Channel *add_on, int op,
|
channel_combine_mask (Channel *mask, Channel *add_on, int op,
|
||||||
int off_x, int off_y)
|
int off_x, int off_y)
|
||||||
{
|
{
|
||||||
PixelRegion srcPR, destPR;
|
PixelRegion srcPR, destPR;
|
||||||
unsigned char *src;
|
|
||||||
unsigned char *dest;
|
|
||||||
int val;
|
|
||||||
int x1, y1, x2, y2;
|
int x1, y1, x2, y2;
|
||||||
int x, y;
|
|
||||||
int w, h;
|
int w, h;
|
||||||
void * pr;
|
|
||||||
|
|
||||||
x1 = BOUNDS (off_x, 0, GIMP_DRAWABLE(mask)->width);
|
x1 = BOUNDS (off_x, 0, GIMP_DRAWABLE(mask)->width);
|
||||||
y1 = BOUNDS (off_y, 0, GIMP_DRAWABLE(mask)->height);
|
y1 = BOUNDS (off_y, 0, GIMP_DRAWABLE(mask)->height);
|
||||||
|
@ -1056,39 +1108,25 @@ channel_combine_mask (Channel *mask, Channel *add_on, int op,
|
||||||
pixel_region_init (&srcPR, GIMP_DRAWABLE(add_on)->tiles, (x1 - off_x), (y1 - off_y), w, h, FALSE);
|
pixel_region_init (&srcPR, GIMP_DRAWABLE(add_on)->tiles, (x1 - off_x), (y1 - off_y), w, h, FALSE);
|
||||||
pixel_region_init (&destPR, GIMP_DRAWABLE(mask)->tiles, x1, y1, w, h, TRUE);
|
pixel_region_init (&destPR, GIMP_DRAWABLE(mask)->tiles, x1, y1, w, h, TRUE);
|
||||||
|
|
||||||
for (pr = pixel_regions_register (2, &srcPR, &destPR); pr != NULL; pr = pixel_regions_process (pr))
|
switch (op)
|
||||||
{
|
{
|
||||||
src = srcPR.data;
|
case ADD: case REPLACE:
|
||||||
dest = destPR.data;
|
pixel_regions_process_parallel ((p_func)channel_combine_sub_region_add,
|
||||||
|
NULL, 2, &srcPR, &destPR);
|
||||||
for (y = 0; y < srcPR.h; y++)
|
break;
|
||||||
{
|
case SUB:
|
||||||
for (x = 0; x < srcPR.w; x++)
|
pixel_regions_process_parallel ((p_func)channel_combine_sub_region_sub,
|
||||||
{
|
NULL, 2, &srcPR, &destPR);
|
||||||
switch (op)
|
break;
|
||||||
{
|
case INTERSECT:
|
||||||
case ADD: case REPLACE:
|
pixel_regions_process_parallel ((p_func)
|
||||||
val = dest[x] + src[x];
|
channel_combine_sub_region_intersect,
|
||||||
if (val > 255) val = 255;
|
NULL, 2, &srcPR, &destPR);
|
||||||
break;
|
break;
|
||||||
case SUB:
|
default:
|
||||||
val = dest[x] - src[x];
|
g_message("Error: unknown opperation type in channel_combine_mask\n");
|
||||||
if (val < 0) val = 0;
|
break;
|
||||||
break;
|
}
|
||||||
case INTERSECT:
|
|
||||||
val = MINIMUM(dest[x], src[x]);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
val = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
dest[x] = val;
|
|
||||||
}
|
|
||||||
src += srcPR.rowstride;
|
|
||||||
dest += destPR.rowstride;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mask->bounds_known = FALSE;
|
mask->bounds_known = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1184,57 +1222,35 @@ void
|
||||||
channel_invert (Channel *mask)
|
channel_invert (Channel *mask)
|
||||||
{
|
{
|
||||||
PixelRegion maskPR;
|
PixelRegion maskPR;
|
||||||
unsigned char *data;
|
GimpLut *lut;
|
||||||
int size;
|
|
||||||
void * pr;
|
|
||||||
|
|
||||||
/* push the current channel onto the undo stack */
|
/* push the current channel onto the undo stack */
|
||||||
channel_push_undo (mask);
|
channel_push_undo (mask);
|
||||||
|
|
||||||
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, 0, 0, GIMP_DRAWABLE(mask)->width, GIMP_DRAWABLE(mask)->height, TRUE);
|
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, 0, 0, GIMP_DRAWABLE(mask)->width, GIMP_DRAWABLE(mask)->height, TRUE);
|
||||||
for (pr = pixel_regions_register (1, &maskPR); pr != NULL; pr = pixel_regions_process (pr))
|
|
||||||
{
|
lut = invert_lut_new(1);
|
||||||
/* subtract each pixel in the mask from 255 */
|
|
||||||
data = maskPR.data;
|
|
||||||
size = maskPR.w * maskPR.h;
|
|
||||||
while (size --)
|
|
||||||
{
|
|
||||||
*data = 255 - *data;
|
|
||||||
data++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
pixel_regions_process_parallel ((p_func)gimp_lut_process_inline,
|
||||||
|
lut, 1, &maskPR);
|
||||||
|
gimp_lut_free(lut);
|
||||||
mask->bounds_known = FALSE;
|
mask->bounds_known = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
channel_sharpen (Channel *mask)
|
channel_sharpen (Channel *mask)
|
||||||
{
|
{
|
||||||
PixelRegion maskPR;
|
PixelRegion maskPR;
|
||||||
unsigned char *data;
|
GimpLut *lut;
|
||||||
int size;
|
|
||||||
void * pr;
|
|
||||||
|
|
||||||
/* push the current channel onto the undo stack */
|
/* push the current channel onto the undo stack */
|
||||||
channel_push_undo (mask);
|
channel_push_undo (mask);
|
||||||
|
|
||||||
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, 0, 0, GIMP_DRAWABLE(mask)->width, GIMP_DRAWABLE(mask)->height, TRUE);
|
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, 0, 0, GIMP_DRAWABLE(mask)->width, GIMP_DRAWABLE(mask)->height, TRUE);
|
||||||
for (pr = pixel_regions_register (1, &maskPR); pr != NULL; pr = pixel_regions_process (pr))
|
lut = threshold_lut_new(0.5, 1);
|
||||||
{
|
|
||||||
/* if a pixel in the mask has a non-zero value, make it 255 */
|
|
||||||
data = maskPR.data;
|
|
||||||
size = maskPR.w * maskPR.h;
|
|
||||||
while (size--)
|
|
||||||
{
|
|
||||||
if (*data > HALF_WAY)
|
|
||||||
*data++ = 255;
|
|
||||||
else
|
|
||||||
*data++ = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mask->bounds_known = FALSE;
|
pixel_regions_process_parallel ((p_func)gimp_lut_process_inline,
|
||||||
|
lut, 1, &maskPR);
|
||||||
|
gimp_lut_free(lut);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,9 @@
|
||||||
#include "channel_pvt.h"
|
#include "channel_pvt.h"
|
||||||
#include "tile.h"
|
#include "tile.h"
|
||||||
|
|
||||||
|
#include "gimplut.h"
|
||||||
|
#include "lut_funcs.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
enum {
|
enum {
|
||||||
LAST_SIGNAL
|
LAST_SIGNAL
|
||||||
|
@ -602,9 +605,9 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2)
|
||||||
unsigned char * data;
|
unsigned char * data;
|
||||||
int x, y;
|
int x, y;
|
||||||
int ex, ey;
|
int ex, ey;
|
||||||
int found;
|
|
||||||
void *pr;
|
void *pr;
|
||||||
|
int tx1, tx2, ty1, ty2;
|
||||||
|
int minx, maxx;
|
||||||
/* if the mask's bounds have already been reliably calculated... */
|
/* if the mask's bounds have already been reliably calculated... */
|
||||||
if (mask->bounds_known)
|
if (mask->bounds_known)
|
||||||
{
|
{
|
||||||
|
@ -617,10 +620,10 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* go through and calculate the bounds */
|
/* go through and calculate the bounds */
|
||||||
*x1 = GIMP_DRAWABLE(mask)->width;
|
tx1 = GIMP_DRAWABLE(mask)->width;
|
||||||
*y1 = GIMP_DRAWABLE(mask)->height;
|
ty1 = GIMP_DRAWABLE(mask)->height;
|
||||||
*x2 = 0;
|
tx2 = 0;
|
||||||
*y2 = 0;
|
ty2 = 0;
|
||||||
|
|
||||||
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, 0, 0, GIMP_DRAWABLE(mask)->width, GIMP_DRAWABLE(mask)->height, FALSE);
|
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, 0, 0, GIMP_DRAWABLE(mask)->width, GIMP_DRAWABLE(mask)->height, FALSE);
|
||||||
for (pr = pixel_regions_register (1, &maskPR); pr != NULL; pr = pixel_regions_process (pr))
|
for (pr = pixel_regions_register (1, &maskPR); pr != NULL; pr = pixel_regions_process (pr))
|
||||||
|
@ -630,36 +633,50 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2)
|
||||||
ey = maskPR.y + maskPR.h;
|
ey = maskPR.y + maskPR.h;
|
||||||
/* only check the pixels if this tile is not fully within the currently
|
/* only check the pixels if this tile is not fully within the currently
|
||||||
computed bounds */
|
computed bounds */
|
||||||
if (maskPR.x < *x1 || ex > *x2 ||
|
if (maskPR.x < tx1 || ex > tx2 ||
|
||||||
maskPR.y < *y1 || ey > *y2)
|
maskPR.y < ty1 || ey > ty2)
|
||||||
{
|
{
|
||||||
for (y = maskPR.y; y < ey; y++)
|
/* Check upper left and lower right corners to see if we can
|
||||||
|
avoid checking the rest of the pixels in this tile */
|
||||||
|
if (data[0] && data[maskPR.rowstride*(maskPR.h - 1) + maskPR.w - 1])
|
||||||
|
{
|
||||||
|
if (maskPR.x < tx1)
|
||||||
|
tx1 = maskPR.x;
|
||||||
|
if (ex > tx2)
|
||||||
|
tx2 = ex;
|
||||||
|
if (maskPR.y < ty1)
|
||||||
|
ty1 = maskPR.y;
|
||||||
|
if (ey > ty2)
|
||||||
|
ty2 = ey;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
for (y = maskPR.y; y < ey; y++)
|
||||||
{
|
{
|
||||||
found = FALSE;
|
|
||||||
for (x = maskPR.x; x < ex; x++, data++)
|
for (x = maskPR.x; x < ex; x++, data++)
|
||||||
if (*data)
|
if (*data)
|
||||||
{
|
{
|
||||||
if (x < *x1)
|
minx = x;
|
||||||
*x1 = x;
|
maxx = x;
|
||||||
if (x > *x2)
|
for (; x < ex; x++, data++)
|
||||||
*x2 = x;
|
if (*data)
|
||||||
found = TRUE;
|
maxx = x;
|
||||||
}
|
if (minx < tx1)
|
||||||
if (found)
|
tx1 = minx;
|
||||||
{
|
if (maxx > tx2)
|
||||||
if (y < *y1)
|
tx2 = maxx;
|
||||||
*y1 = y;
|
if (y < ty1)
|
||||||
if (y > *y2)
|
ty1 = y;
|
||||||
*y2 = y;
|
if (y > ty2)
|
||||||
}
|
ty2 = y;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*x2 = BOUNDS (*x2 + 1, 0, GIMP_DRAWABLE(mask)->width);
|
tx2 = BOUNDS (tx2 + 1, 0, GIMP_DRAWABLE(mask)->width);
|
||||||
*y2 = BOUNDS (*y2 + 1, 0, GIMP_DRAWABLE(mask)->height);
|
ty2 = BOUNDS (ty2 + 1, 0, GIMP_DRAWABLE(mask)->height);
|
||||||
|
|
||||||
if (*x1 == GIMP_DRAWABLE(mask)->width && *y1 == GIMP_DRAWABLE(mask)->height)
|
if (tx1 == GIMP_DRAWABLE(mask)->width && ty1 == GIMP_DRAWABLE(mask)->height)
|
||||||
{
|
{
|
||||||
mask->empty = TRUE;
|
mask->empty = TRUE;
|
||||||
mask->x1 = 0; mask->y1 = 0;
|
mask->x1 = 0; mask->y1 = 0;
|
||||||
|
@ -669,13 +686,18 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mask->empty = FALSE;
|
mask->empty = FALSE;
|
||||||
mask->x1 = *x1;
|
mask->x1 = tx1;
|
||||||
mask->y1 = *y1;
|
mask->y1 = ty1;
|
||||||
mask->x2 = *x2;
|
mask->x2 = tx2;
|
||||||
mask->y2 = *y2;
|
mask->y2 = ty2;
|
||||||
}
|
}
|
||||||
mask->bounds_known = TRUE;
|
mask->bounds_known = TRUE;
|
||||||
|
|
||||||
|
*x1 = tx1;
|
||||||
|
*x2 = tx2;
|
||||||
|
*y1 = ty1;
|
||||||
|
*y2 = ty2;
|
||||||
|
|
||||||
return (mask->empty) ? FALSE : TRUE;
|
return (mask->empty) ? FALSE : TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -800,61 +822,31 @@ channel_sub_segment (Channel *mask, int x, int y, int width, int value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
channel_inter_segment (Channel *mask, int x, int y, int width, int value)
|
|
||||||
{
|
|
||||||
PixelRegion maskPR;
|
|
||||||
unsigned char *data;
|
|
||||||
int val;
|
|
||||||
int x2;
|
|
||||||
void * pr;
|
|
||||||
|
|
||||||
/* check horizontal extents... */
|
|
||||||
x2 = x + width;
|
|
||||||
if (x2 < 0) x2 = 0;
|
|
||||||
if (x2 > GIMP_DRAWABLE(mask)->width) x2 = GIMP_DRAWABLE(mask)->width;
|
|
||||||
if (x < 0) x = 0;
|
|
||||||
if (x > GIMP_DRAWABLE(mask)->width) x = GIMP_DRAWABLE(mask)->width;
|
|
||||||
width = x2 - x;
|
|
||||||
if (!width) return;
|
|
||||||
|
|
||||||
if (y < 0 || y > GIMP_DRAWABLE(mask)->height)
|
|
||||||
return;
|
|
||||||
|
|
||||||
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, x, y, width, 1, TRUE);
|
|
||||||
for (pr = pixel_regions_register (1, &maskPR); pr != NULL; pr = pixel_regions_process (pr))
|
|
||||||
{
|
|
||||||
data = maskPR.data;
|
|
||||||
width = maskPR.w;
|
|
||||||
while (width--)
|
|
||||||
{
|
|
||||||
val = MINIMUM(*data, value);
|
|
||||||
*data++ = val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
channel_combine_rect (Channel *mask, int op, int x, int y, int w, int h)
|
channel_combine_rect (Channel *mask, int op, int x, int y, int w, int h)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
int x2, y2;
|
||||||
|
PixelRegion maskPR;
|
||||||
|
unsigned char color;
|
||||||
|
y2 = y + h;
|
||||||
|
x2 = x + w;
|
||||||
|
|
||||||
for (i = y; i < y + h; i++)
|
x = BOUNDS (x, 0, GIMP_DRAWABLE(mask)->width);
|
||||||
{
|
y = BOUNDS (y, 0, GIMP_DRAWABLE(mask)->height);
|
||||||
if (i >= 0 && i < GIMP_DRAWABLE(mask)->height)
|
x2 = BOUNDS (x2, 0, GIMP_DRAWABLE(mask)->width);
|
||||||
switch (op)
|
y2 = BOUNDS (y2, 0, GIMP_DRAWABLE(mask)->height);
|
||||||
{
|
|
||||||
case ADD: case REPLACE:
|
if (x2 - x <= 0 || y2 - y <= 0)
|
||||||
channel_add_segment (mask, x, i, w, 255);
|
return;
|
||||||
break;
|
|
||||||
case SUB:
|
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, x, y,
|
||||||
channel_sub_segment (mask, x, i, w, 255);
|
x2 - x, y2 - y, TRUE);
|
||||||
break;
|
if (op == ADD || op == REPLACE)
|
||||||
case INTERSECT:
|
color = 255;
|
||||||
channel_inter_segment (mask, x, i, w, 255);
|
else
|
||||||
break;
|
color = 0;
|
||||||
}
|
color_region(&maskPR, &color);
|
||||||
}
|
|
||||||
|
|
||||||
/* Determine new boundary */
|
/* Determine new boundary */
|
||||||
if (mask->bounds_known && (op == ADD) && !mask->empty)
|
if (mask->bounds_known && (op == ADD) && !mask->empty)
|
||||||
|
@ -933,9 +925,6 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h,
|
||||||
case SUB :
|
case SUB :
|
||||||
channel_sub_segment (mask, x1, i, (x2 - x1), 255);
|
channel_sub_segment (mask, x1, i, (x2 - x1), 255);
|
||||||
break;
|
break;
|
||||||
case INTERSECT:
|
|
||||||
channel_inter_segment (mask, x1, i, (x2 - x1), 255);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* antialiasing */
|
/* antialiasing */
|
||||||
|
@ -965,7 +954,7 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h,
|
||||||
val = (int) (255 * (1 - (dist + 0.5)));
|
val = (int) (255 * (1 - (dist + 0.5)));
|
||||||
else
|
else
|
||||||
val = 0;
|
val = 0;
|
||||||
|
|
||||||
if (last != val && last)
|
if (last != val && last)
|
||||||
{
|
{
|
||||||
switch (op)
|
switch (op)
|
||||||
|
@ -976,8 +965,6 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h,
|
||||||
case SUB:
|
case SUB:
|
||||||
channel_sub_segment (mask, x0, i, j - x0, last);
|
channel_sub_segment (mask, x0, i, j - x0, last);
|
||||||
break;
|
break;
|
||||||
case INTERSECT:
|
|
||||||
channel_inter_segment (mask, x0, i, j - x0, last);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -985,6 +972,10 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h,
|
||||||
{
|
{
|
||||||
x0 = j;
|
x0 = j;
|
||||||
last = val;
|
last = val;
|
||||||
|
/* because we are symetric accross the y axis we can
|
||||||
|
skip ahead a bit if we are inside the ellipse*/
|
||||||
|
if (val == 255 && j < cx)
|
||||||
|
j = cx + (cx - j) - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -994,8 +985,6 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h,
|
||||||
channel_add_segment (mask, x0, i, j - x0, last);
|
channel_add_segment (mask, x0, i, j - x0, last);
|
||||||
else if (op == SUB)
|
else if (op == SUB)
|
||||||
channel_sub_segment (mask, x0, i, j - x0, last);
|
channel_sub_segment (mask, x0, i, j - x0, last);
|
||||||
else if (op == INTERSECT)
|
|
||||||
channel_inter_segment (mask, x0, i, j - x0, last);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1032,18 +1021,81 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
channel_combine_sub_region_add (void *unused,
|
||||||
|
PixelRegion *srcPR,
|
||||||
|
PixelRegion *destPR)
|
||||||
|
{
|
||||||
|
unsigned char *src, *dest;
|
||||||
|
int x, y, val;
|
||||||
|
src = srcPR->data;
|
||||||
|
dest = destPR->data;
|
||||||
|
for (y = 0; y < srcPR->h; y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < srcPR->w; x++)
|
||||||
|
{
|
||||||
|
val = dest[x] + src[x];
|
||||||
|
if (val > 255)
|
||||||
|
dest[x] = 255;
|
||||||
|
else
|
||||||
|
dest[x] = val;
|
||||||
|
}
|
||||||
|
src += srcPR->rowstride;
|
||||||
|
dest += destPR->rowstride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
channel_combine_sub_region_sub (void *unused,
|
||||||
|
PixelRegion *srcPR,
|
||||||
|
PixelRegion *destPR)
|
||||||
|
{
|
||||||
|
unsigned char *src, *dest;
|
||||||
|
int x, y;
|
||||||
|
src = srcPR->data;
|
||||||
|
dest = destPR->data;
|
||||||
|
for (y = 0; y < srcPR->h; y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < srcPR->w; x++)
|
||||||
|
{
|
||||||
|
if (src[x] > dest[x])
|
||||||
|
dest[x] = 0;
|
||||||
|
else
|
||||||
|
dest[x]-= src[x];
|
||||||
|
}
|
||||||
|
src += srcPR->rowstride;
|
||||||
|
dest += destPR->rowstride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
channel_combine_sub_region_intersect (void *unused,
|
||||||
|
PixelRegion *srcPR,
|
||||||
|
PixelRegion *destPR)
|
||||||
|
{
|
||||||
|
unsigned char *src, *dest;
|
||||||
|
int x, y;
|
||||||
|
src = srcPR->data;
|
||||||
|
dest = destPR->data;
|
||||||
|
for (y = 0; y < srcPR->h; y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < srcPR->w; x++)
|
||||||
|
{
|
||||||
|
dest[x] = MINIMUM(dest[x], src[x]);
|
||||||
|
}
|
||||||
|
src += srcPR->rowstride;
|
||||||
|
dest += destPR->rowstride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
channel_combine_mask (Channel *mask, Channel *add_on, int op,
|
channel_combine_mask (Channel *mask, Channel *add_on, int op,
|
||||||
int off_x, int off_y)
|
int off_x, int off_y)
|
||||||
{
|
{
|
||||||
PixelRegion srcPR, destPR;
|
PixelRegion srcPR, destPR;
|
||||||
unsigned char *src;
|
|
||||||
unsigned char *dest;
|
|
||||||
int val;
|
|
||||||
int x1, y1, x2, y2;
|
int x1, y1, x2, y2;
|
||||||
int x, y;
|
|
||||||
int w, h;
|
int w, h;
|
||||||
void * pr;
|
|
||||||
|
|
||||||
x1 = BOUNDS (off_x, 0, GIMP_DRAWABLE(mask)->width);
|
x1 = BOUNDS (off_x, 0, GIMP_DRAWABLE(mask)->width);
|
||||||
y1 = BOUNDS (off_y, 0, GIMP_DRAWABLE(mask)->height);
|
y1 = BOUNDS (off_y, 0, GIMP_DRAWABLE(mask)->height);
|
||||||
|
@ -1056,39 +1108,25 @@ channel_combine_mask (Channel *mask, Channel *add_on, int op,
|
||||||
pixel_region_init (&srcPR, GIMP_DRAWABLE(add_on)->tiles, (x1 - off_x), (y1 - off_y), w, h, FALSE);
|
pixel_region_init (&srcPR, GIMP_DRAWABLE(add_on)->tiles, (x1 - off_x), (y1 - off_y), w, h, FALSE);
|
||||||
pixel_region_init (&destPR, GIMP_DRAWABLE(mask)->tiles, x1, y1, w, h, TRUE);
|
pixel_region_init (&destPR, GIMP_DRAWABLE(mask)->tiles, x1, y1, w, h, TRUE);
|
||||||
|
|
||||||
for (pr = pixel_regions_register (2, &srcPR, &destPR); pr != NULL; pr = pixel_regions_process (pr))
|
switch (op)
|
||||||
{
|
{
|
||||||
src = srcPR.data;
|
case ADD: case REPLACE:
|
||||||
dest = destPR.data;
|
pixel_regions_process_parallel ((p_func)channel_combine_sub_region_add,
|
||||||
|
NULL, 2, &srcPR, &destPR);
|
||||||
for (y = 0; y < srcPR.h; y++)
|
break;
|
||||||
{
|
case SUB:
|
||||||
for (x = 0; x < srcPR.w; x++)
|
pixel_regions_process_parallel ((p_func)channel_combine_sub_region_sub,
|
||||||
{
|
NULL, 2, &srcPR, &destPR);
|
||||||
switch (op)
|
break;
|
||||||
{
|
case INTERSECT:
|
||||||
case ADD: case REPLACE:
|
pixel_regions_process_parallel ((p_func)
|
||||||
val = dest[x] + src[x];
|
channel_combine_sub_region_intersect,
|
||||||
if (val > 255) val = 255;
|
NULL, 2, &srcPR, &destPR);
|
||||||
break;
|
break;
|
||||||
case SUB:
|
default:
|
||||||
val = dest[x] - src[x];
|
g_message("Error: unknown opperation type in channel_combine_mask\n");
|
||||||
if (val < 0) val = 0;
|
break;
|
||||||
break;
|
}
|
||||||
case INTERSECT:
|
|
||||||
val = MINIMUM(dest[x], src[x]);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
val = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
dest[x] = val;
|
|
||||||
}
|
|
||||||
src += srcPR.rowstride;
|
|
||||||
dest += destPR.rowstride;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mask->bounds_known = FALSE;
|
mask->bounds_known = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1184,57 +1222,35 @@ void
|
||||||
channel_invert (Channel *mask)
|
channel_invert (Channel *mask)
|
||||||
{
|
{
|
||||||
PixelRegion maskPR;
|
PixelRegion maskPR;
|
||||||
unsigned char *data;
|
GimpLut *lut;
|
||||||
int size;
|
|
||||||
void * pr;
|
|
||||||
|
|
||||||
/* push the current channel onto the undo stack */
|
/* push the current channel onto the undo stack */
|
||||||
channel_push_undo (mask);
|
channel_push_undo (mask);
|
||||||
|
|
||||||
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, 0, 0, GIMP_DRAWABLE(mask)->width, GIMP_DRAWABLE(mask)->height, TRUE);
|
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, 0, 0, GIMP_DRAWABLE(mask)->width, GIMP_DRAWABLE(mask)->height, TRUE);
|
||||||
for (pr = pixel_regions_register (1, &maskPR); pr != NULL; pr = pixel_regions_process (pr))
|
|
||||||
{
|
lut = invert_lut_new(1);
|
||||||
/* subtract each pixel in the mask from 255 */
|
|
||||||
data = maskPR.data;
|
|
||||||
size = maskPR.w * maskPR.h;
|
|
||||||
while (size --)
|
|
||||||
{
|
|
||||||
*data = 255 - *data;
|
|
||||||
data++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
pixel_regions_process_parallel ((p_func)gimp_lut_process_inline,
|
||||||
|
lut, 1, &maskPR);
|
||||||
|
gimp_lut_free(lut);
|
||||||
mask->bounds_known = FALSE;
|
mask->bounds_known = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
channel_sharpen (Channel *mask)
|
channel_sharpen (Channel *mask)
|
||||||
{
|
{
|
||||||
PixelRegion maskPR;
|
PixelRegion maskPR;
|
||||||
unsigned char *data;
|
GimpLut *lut;
|
||||||
int size;
|
|
||||||
void * pr;
|
|
||||||
|
|
||||||
/* push the current channel onto the undo stack */
|
/* push the current channel onto the undo stack */
|
||||||
channel_push_undo (mask);
|
channel_push_undo (mask);
|
||||||
|
|
||||||
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, 0, 0, GIMP_DRAWABLE(mask)->width, GIMP_DRAWABLE(mask)->height, TRUE);
|
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, 0, 0, GIMP_DRAWABLE(mask)->width, GIMP_DRAWABLE(mask)->height, TRUE);
|
||||||
for (pr = pixel_regions_register (1, &maskPR); pr != NULL; pr = pixel_regions_process (pr))
|
lut = threshold_lut_new(0.5, 1);
|
||||||
{
|
|
||||||
/* if a pixel in the mask has a non-zero value, make it 255 */
|
|
||||||
data = maskPR.data;
|
|
||||||
size = maskPR.w * maskPR.h;
|
|
||||||
while (size--)
|
|
||||||
{
|
|
||||||
if (*data > HALF_WAY)
|
|
||||||
*data++ = 255;
|
|
||||||
else
|
|
||||||
*data++ = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mask->bounds_known = FALSE;
|
pixel_regions_process_parallel ((p_func)gimp_lut_process_inline,
|
||||||
|
lut, 1, &maskPR);
|
||||||
|
gimp_lut_free(lut);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,27 +19,17 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "appenv.h"
|
|
||||||
#include "drawable.h"
|
#include "drawable.h"
|
||||||
#include "equalize.h"
|
#include "equalize.h"
|
||||||
#include "interface.h"
|
|
||||||
#include "gimage.h"
|
#include "gimage.h"
|
||||||
#include "gimplut.h"
|
#include "gimplut.h"
|
||||||
|
#include "lut_funcs.h"
|
||||||
#include "gimphistogram.h"
|
#include "gimphistogram.h"
|
||||||
|
|
||||||
#include "libgimp/gimpintl.h"
|
#include "libgimp/gimpintl.h"
|
||||||
|
|
||||||
struct hist_lut_struct
|
|
||||||
{
|
|
||||||
GimpHistogram *histogram;
|
|
||||||
int part[5][257];
|
|
||||||
};
|
|
||||||
|
|
||||||
static float equalize_lut_func(struct hist_lut_struct *hlut,
|
|
||||||
int nchannels, int channel, float value);
|
|
||||||
static void equalize (GImage *, GimpDrawable *, int);
|
static void equalize (GImage *, GimpDrawable *, int);
|
||||||
static Argument * equalize_invoker (Argument *);
|
static Argument * equalize_invoker (Argument *);
|
||||||
static GimpLut * eq_histogram_lut (GimpHistogram *hist, int bytes);
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -87,7 +77,7 @@ equalize(gimage, drawable, mask_only)
|
||||||
|
|
||||||
|
|
||||||
/* Build equalization LUT */
|
/* Build equalization LUT */
|
||||||
lut = eq_histogram_lut (hist, bytes);
|
lut = eq_histogram_lut_new (hist, bytes);
|
||||||
|
|
||||||
/* Apply the histogram */
|
/* Apply the histogram */
|
||||||
drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
|
drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
|
||||||
|
@ -105,71 +95,10 @@ equalize(gimage, drawable, mask_only)
|
||||||
drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1));
|
drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* --------------- The equalize procedure definition ---------------- */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
/*****/
|
|
||||||
|
|
||||||
static GimpLut *
|
|
||||||
eq_histogram_lut (GimpHistogram *hist, int bytes)
|
|
||||||
{
|
|
||||||
int i, k, j;
|
|
||||||
struct hist_lut_struct hlut;
|
|
||||||
double pixels_per_value;
|
|
||||||
double desired;
|
|
||||||
GimpLut *lut;
|
|
||||||
double sum, dif;
|
|
||||||
|
|
||||||
/* Find partition points */
|
|
||||||
pixels_per_value = gimp_histogram_get_count(hist, 0, 255) / 256.0;
|
|
||||||
|
|
||||||
for (k = 0; k < bytes; k++)
|
|
||||||
{
|
|
||||||
/* First and last points in partition */
|
|
||||||
hlut.part[k][0] = 0;
|
|
||||||
hlut.part[k][256] = 256;
|
|
||||||
|
|
||||||
/* Find intermediate points */
|
|
||||||
j = 0;
|
|
||||||
sum = gimp_histogram_get_channel(hist, k, 0) +
|
|
||||||
gimp_histogram_get_channel(hist, k, 1);
|
|
||||||
for (i = 1; i < 256; i++)
|
|
||||||
{
|
|
||||||
desired = i * pixels_per_value;
|
|
||||||
while (sum <= desired)
|
|
||||||
{
|
|
||||||
j++;
|
|
||||||
sum += gimp_histogram_get_channel(hist, k, j + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Nearest sum */
|
|
||||||
dif = sum - gimp_histogram_get_channel(hist, k, j);
|
|
||||||
if ((sum - desired) > (dif / 2.0))
|
|
||||||
hlut.part[k][i] = j;
|
|
||||||
else
|
|
||||||
hlut.part[k][i] = j + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lut = gimp_lut_new();
|
|
||||||
|
|
||||||
gimp_lut_setup(lut, (GimpLutFunc) equalize_lut_func,
|
|
||||||
(void *) &hlut, bytes);
|
|
||||||
|
|
||||||
return lut;
|
|
||||||
}
|
|
||||||
|
|
||||||
static float
|
|
||||||
equalize_lut_func(struct hist_lut_struct *hlut,
|
|
||||||
int nchannels, int channel, float value)
|
|
||||||
{
|
|
||||||
int i = 0, j;
|
|
||||||
j = (int)(value * 255.0 + 0.5);
|
|
||||||
while (hlut->part[channel][i + 1] <= j)
|
|
||||||
i++;
|
|
||||||
return i / 255.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* The equalize procedure definition */
|
|
||||||
ProcArg equalize_args[] =
|
ProcArg equalize_args[] =
|
||||||
{
|
{
|
||||||
{ PDB_DRAWABLE,
|
{ PDB_DRAWABLE,
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "invert.h"
|
#include "invert.h"
|
||||||
#include "gimage.h"
|
#include "gimage.h"
|
||||||
#include "gimplut.h"
|
#include "gimplut.h"
|
||||||
|
#include "lut_funcs.h"
|
||||||
|
|
||||||
#include "libgimp/gimpintl.h"
|
#include "libgimp/gimpintl.h"
|
||||||
|
|
||||||
|
@ -58,18 +59,6 @@ image_invert (GImage *gimage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static float
|
|
||||||
invert_lut_func(void *unused,
|
|
||||||
int nchannels, int channel, float value)
|
|
||||||
{
|
|
||||||
/* don't invert the alpha channel */
|
|
||||||
if ((nchannels == 2 || nchannels == 4) && channel == nchannels -1)
|
|
||||||
return value;
|
|
||||||
|
|
||||||
return 1.0 - value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Inverter */
|
/* Inverter */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -79,10 +68,7 @@ invert (GimpDrawable *drawable)
|
||||||
int x1, y1, x2, y2;
|
int x1, y1, x2, y2;
|
||||||
GimpLut *lut;
|
GimpLut *lut;
|
||||||
|
|
||||||
lut = gimp_lut_new();
|
lut = invert_lut_new(gimp_drawable_bytes(drawable));
|
||||||
|
|
||||||
gimp_lut_setup_exact(lut, (GimpLutFunc) invert_lut_func,
|
|
||||||
(void *) NULL, gimp_drawable_bytes(drawable));
|
|
||||||
|
|
||||||
drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
|
drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
|
||||||
pixel_region_init (&srcPR, drawable_data (drawable), x1, y1, (x2 - x1), (y2 - y1), FALSE);
|
pixel_region_init (&srcPR, drawable_data (drawable), x1, y1, (x2 - x1), (y2 - y1), FALSE);
|
||||||
|
@ -97,8 +83,10 @@ invert (GimpDrawable *drawable)
|
||||||
drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1));
|
drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* ----------------- The invert procedure definition ---------------- */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
/* The invert procedure definition */
|
|
||||||
ProcArg invert_args[] =
|
ProcArg invert_args[] =
|
||||||
{
|
{
|
||||||
{ PDB_DRAWABLE,
|
{ PDB_DRAWABLE,
|
||||||
|
|
|
@ -640,7 +640,6 @@ gimp_drawable_init (GimpDrawable *drawable)
|
||||||
drawable->preview_valid = FALSE;
|
drawable->preview_valid = FALSE;
|
||||||
drawable->parasites = parasite_list_new();
|
drawable->parasites = parasite_list_new();
|
||||||
drawable->tattoo = 0;
|
drawable->tattoo = 0;
|
||||||
gimp_matrix_identity(drawable->transform);
|
|
||||||
|
|
||||||
drawable->ID = global_drawable_ID++;
|
drawable->ID = global_drawable_ID++;
|
||||||
if (gimp_drawable_table == NULL)
|
if (gimp_drawable_table == NULL)
|
||||||
|
|
|
@ -169,7 +169,6 @@ static void gimp_image_init (GimpImage *gimage)
|
||||||
gimage->comp_preview_valid[2] = FALSE;
|
gimage->comp_preview_valid[2] = FALSE;
|
||||||
gimage->comp_preview = NULL;
|
gimage->comp_preview = NULL;
|
||||||
gimage->parasites = parasite_list_new();
|
gimage->parasites = parasite_list_new();
|
||||||
gimp_matrix_identity(gimage->transform);
|
|
||||||
gimage->xresolution = default_xresolution;
|
gimage->xresolution = default_xresolution;
|
||||||
gimage->yresolution = default_yresolution;
|
gimage->yresolution = default_yresolution;
|
||||||
gimage->unit = default_units;
|
gimage->unit = default_units;
|
||||||
|
|
|
@ -169,7 +169,6 @@ static void gimp_image_init (GimpImage *gimage)
|
||||||
gimage->comp_preview_valid[2] = FALSE;
|
gimage->comp_preview_valid[2] = FALSE;
|
||||||
gimage->comp_preview = NULL;
|
gimage->comp_preview = NULL;
|
||||||
gimage->parasites = parasite_list_new();
|
gimage->parasites = parasite_list_new();
|
||||||
gimp_matrix_identity(gimage->transform);
|
|
||||||
gimage->xresolution = default_xresolution;
|
gimage->xresolution = default_xresolution;
|
||||||
gimage->yresolution = default_yresolution;
|
gimage->yresolution = default_yresolution;
|
||||||
gimage->unit = default_units;
|
gimage->unit = default_units;
|
||||||
|
|
|
@ -169,7 +169,6 @@ static void gimp_image_init (GimpImage *gimage)
|
||||||
gimage->comp_preview_valid[2] = FALSE;
|
gimage->comp_preview_valid[2] = FALSE;
|
||||||
gimage->comp_preview = NULL;
|
gimage->comp_preview = NULL;
|
||||||
gimage->parasites = parasite_list_new();
|
gimage->parasites = parasite_list_new();
|
||||||
gimp_matrix_identity(gimage->transform);
|
|
||||||
gimage->xresolution = default_xresolution;
|
gimage->xresolution = default_xresolution;
|
||||||
gimage->yresolution = default_yresolution;
|
gimage->yresolution = default_yresolution;
|
||||||
gimage->unit = default_units;
|
gimage->unit = default_units;
|
||||||
|
|
|
@ -169,7 +169,6 @@ static void gimp_image_init (GimpImage *gimage)
|
||||||
gimage->comp_preview_valid[2] = FALSE;
|
gimage->comp_preview_valid[2] = FALSE;
|
||||||
gimage->comp_preview = NULL;
|
gimage->comp_preview = NULL;
|
||||||
gimage->parasites = parasite_list_new();
|
gimage->parasites = parasite_list_new();
|
||||||
gimp_matrix_identity(gimage->transform);
|
|
||||||
gimage->xresolution = default_xresolution;
|
gimage->xresolution = default_xresolution;
|
||||||
gimage->yresolution = default_yresolution;
|
gimage->yresolution = default_yresolution;
|
||||||
gimage->unit = default_units;
|
gimage->unit = default_units;
|
||||||
|
|
|
@ -169,7 +169,6 @@ static void gimp_image_init (GimpImage *gimage)
|
||||||
gimage->comp_preview_valid[2] = FALSE;
|
gimage->comp_preview_valid[2] = FALSE;
|
||||||
gimage->comp_preview = NULL;
|
gimage->comp_preview = NULL;
|
||||||
gimage->parasites = parasite_list_new();
|
gimage->parasites = parasite_list_new();
|
||||||
gimp_matrix_identity(gimage->transform);
|
|
||||||
gimage->xresolution = default_xresolution;
|
gimage->xresolution = default_xresolution;
|
||||||
gimage->yresolution = default_yresolution;
|
gimage->yresolution = default_yresolution;
|
||||||
gimage->unit = default_units;
|
gimage->unit = default_units;
|
||||||
|
|
|
@ -169,7 +169,6 @@ static void gimp_image_init (GimpImage *gimage)
|
||||||
gimage->comp_preview_valid[2] = FALSE;
|
gimage->comp_preview_valid[2] = FALSE;
|
||||||
gimage->comp_preview = NULL;
|
gimage->comp_preview = NULL;
|
||||||
gimage->parasites = parasite_list_new();
|
gimage->parasites = parasite_list_new();
|
||||||
gimp_matrix_identity(gimage->transform);
|
|
||||||
gimage->xresolution = default_xresolution;
|
gimage->xresolution = default_xresolution;
|
||||||
gimage->yresolution = default_yresolution;
|
gimage->yresolution = default_yresolution;
|
||||||
gimage->unit = default_units;
|
gimage->unit = default_units;
|
||||||
|
|
|
@ -16,8 +16,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include "parasitelist.h"
|
#include "parasitelist.h"
|
||||||
#include "gimpparasite.h"
|
#include "gimpparasite.h"
|
||||||
|
#include "libgimp/parasite.h"
|
||||||
|
#include "libgimp/gimpenv.h"
|
||||||
|
|
||||||
static ParasiteList *parasites = NULL;
|
static ParasiteList *parasites = NULL;
|
||||||
|
|
||||||
|
@ -26,6 +30,7 @@ gimp_init_parasites()
|
||||||
{
|
{
|
||||||
g_return_if_fail(parasites == NULL);
|
g_return_if_fail(parasites == NULL);
|
||||||
parasites = parasite_list_new();
|
parasites = parasite_list_new();
|
||||||
|
gimp_parasiterc_load();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -64,5 +69,40 @@ gimp_parasite_list (gint *count)
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gimp_parasiterc_save()
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
guint32 num, version = 1;
|
||||||
|
if (!(fp = fopen(gimp_personal_rc_file ("#parasiterc.tmp"), "w")))
|
||||||
|
return;
|
||||||
|
version = GINT32_TO_BE(version);
|
||||||
|
fwrite(&version, 4, 1, fp);
|
||||||
|
|
||||||
|
parasite_list_save(parasites, fp);
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
if (rename(gimp_personal_rc_file ("#parasiterc.tmp"),
|
||||||
|
gimp_personal_rc_file("parasiterc")) != 0)
|
||||||
|
unlink(gimp_personal_rc_file ("#parasiterc.tmp"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gimp_parasiterc_load()
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
guint32 num, version;
|
||||||
|
if (!(fp = fopen(gimp_personal_rc_file ("parasiterc"), "r")))
|
||||||
|
return;
|
||||||
|
fread(&version, 4, 1, fp);
|
||||||
|
version = GINT32_FROM_BE(version);
|
||||||
|
if (version != 1)
|
||||||
|
{
|
||||||
|
fclose(fp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parasite_list_load(parasites, fp);
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
|
@ -25,5 +25,7 @@ void gimp_attach_parasite (Parasite *p);
|
||||||
void gimp_detach_parasite (char *name);
|
void gimp_detach_parasite (char *name);
|
||||||
Parasite * gimp_find_parasite (char *name);
|
Parasite * gimp_find_parasite (char *name);
|
||||||
char ** gimp_parasite_list (gint *count);
|
char ** gimp_parasite_list (gint *count);
|
||||||
|
void gimp_parasiterc_save (void);
|
||||||
|
void gimp_parasiterc_load (void);
|
||||||
|
|
||||||
#endif /* __GIMP_PARASITE_H__ */
|
#endif /* __GIMP_PARASITE_H__ */
|
||||||
|
|
|
@ -214,6 +214,42 @@ parasite_list_find(ParasiteList *list, const char *name)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int saved_bytes;
|
||||||
|
|
||||||
|
static void
|
||||||
|
save_a_parasite(char *key, Parasite *p, FILE *fp)
|
||||||
|
{
|
||||||
|
if (parasite_is_persistent(p))
|
||||||
|
saved_bytes += parasite_save(p, fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
parasite_list_save(ParasiteList *list, FILE *fp)
|
||||||
|
{
|
||||||
|
guint32 num;
|
||||||
|
num = parasite_list_persistent_length (list);
|
||||||
|
num = GINT32_TO_BE(num);
|
||||||
|
fwrite(&num, 4, 1, fp);
|
||||||
|
saved_bytes = 4;
|
||||||
|
parasite_list_foreach(list, (GHFunc)save_a_parasite, fp);
|
||||||
|
return saved_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parasite_list_load(ParasiteList *list, FILE *fp)
|
||||||
|
{
|
||||||
|
Parasite *p;
|
||||||
|
guint32 num, version;
|
||||||
|
num = 0;
|
||||||
|
fread(&num, 4, 1, fp);
|
||||||
|
num = GINT32_FROM_BE(num);
|
||||||
|
while (num--)
|
||||||
|
{
|
||||||
|
p = parasite_load(fp);
|
||||||
|
parasite_list_add(list, p);
|
||||||
|
parasite_free(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
parasite_shift_parent(Parasite *p)
|
parasite_shift_parent(Parasite *p)
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#define __PARASITE_LIST_H__
|
#define __PARASITE_LIST_H__
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include "libgimp/parasiteF.h"
|
#include "libgimp/parasiteF.h"
|
||||||
#include "parasitelistF.h"
|
#include "parasitelistF.h"
|
||||||
#include "gimpobject.h"
|
#include "gimpobject.h"
|
||||||
|
@ -46,6 +47,8 @@ void parasite_list_foreach (ParasiteList *list, GHFunc function,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
Parasite *parasite_list_find (ParasiteList *list, const char *name);
|
Parasite *parasite_list_find (ParasiteList *list, const char *name);
|
||||||
|
|
||||||
|
int parasite_list_save (ParasiteList *list, FILE *fp);
|
||||||
|
void parasite_list_load (ParasiteList *list, FILE *fp);
|
||||||
void parasite_shift_parent (Parasite *p);
|
void parasite_shift_parent (Parasite *p);
|
||||||
|
|
||||||
#endif /* __GIMP_PARASITE_H__ */
|
#endif /* __GIMP_PARASITE_H__ */
|
||||||
|
|
|
@ -169,7 +169,6 @@ static void gimp_image_init (GimpImage *gimage)
|
||||||
gimage->comp_preview_valid[2] = FALSE;
|
gimage->comp_preview_valid[2] = FALSE;
|
||||||
gimage->comp_preview = NULL;
|
gimage->comp_preview = NULL;
|
||||||
gimage->parasites = parasite_list_new();
|
gimage->parasites = parasite_list_new();
|
||||||
gimp_matrix_identity(gimage->transform);
|
|
||||||
gimage->xresolution = default_xresolution;
|
gimage->xresolution = default_xresolution;
|
||||||
gimage->yresolution = default_yresolution;
|
gimage->yresolution = default_yresolution;
|
||||||
gimage->unit = default_units;
|
gimage->unit = default_units;
|
||||||
|
|
|
@ -19,27 +19,17 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "appenv.h"
|
|
||||||
#include "drawable.h"
|
#include "drawable.h"
|
||||||
#include "equalize.h"
|
#include "equalize.h"
|
||||||
#include "interface.h"
|
|
||||||
#include "gimage.h"
|
#include "gimage.h"
|
||||||
#include "gimplut.h"
|
#include "gimplut.h"
|
||||||
|
#include "lut_funcs.h"
|
||||||
#include "gimphistogram.h"
|
#include "gimphistogram.h"
|
||||||
|
|
||||||
#include "libgimp/gimpintl.h"
|
#include "libgimp/gimpintl.h"
|
||||||
|
|
||||||
struct hist_lut_struct
|
|
||||||
{
|
|
||||||
GimpHistogram *histogram;
|
|
||||||
int part[5][257];
|
|
||||||
};
|
|
||||||
|
|
||||||
static float equalize_lut_func(struct hist_lut_struct *hlut,
|
|
||||||
int nchannels, int channel, float value);
|
|
||||||
static void equalize (GImage *, GimpDrawable *, int);
|
static void equalize (GImage *, GimpDrawable *, int);
|
||||||
static Argument * equalize_invoker (Argument *);
|
static Argument * equalize_invoker (Argument *);
|
||||||
static GimpLut * eq_histogram_lut (GimpHistogram *hist, int bytes);
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -87,7 +77,7 @@ equalize(gimage, drawable, mask_only)
|
||||||
|
|
||||||
|
|
||||||
/* Build equalization LUT */
|
/* Build equalization LUT */
|
||||||
lut = eq_histogram_lut (hist, bytes);
|
lut = eq_histogram_lut_new (hist, bytes);
|
||||||
|
|
||||||
/* Apply the histogram */
|
/* Apply the histogram */
|
||||||
drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
|
drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
|
||||||
|
@ -105,71 +95,10 @@ equalize(gimage, drawable, mask_only)
|
||||||
drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1));
|
drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* --------------- The equalize procedure definition ---------------- */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
/*****/
|
|
||||||
|
|
||||||
static GimpLut *
|
|
||||||
eq_histogram_lut (GimpHistogram *hist, int bytes)
|
|
||||||
{
|
|
||||||
int i, k, j;
|
|
||||||
struct hist_lut_struct hlut;
|
|
||||||
double pixels_per_value;
|
|
||||||
double desired;
|
|
||||||
GimpLut *lut;
|
|
||||||
double sum, dif;
|
|
||||||
|
|
||||||
/* Find partition points */
|
|
||||||
pixels_per_value = gimp_histogram_get_count(hist, 0, 255) / 256.0;
|
|
||||||
|
|
||||||
for (k = 0; k < bytes; k++)
|
|
||||||
{
|
|
||||||
/* First and last points in partition */
|
|
||||||
hlut.part[k][0] = 0;
|
|
||||||
hlut.part[k][256] = 256;
|
|
||||||
|
|
||||||
/* Find intermediate points */
|
|
||||||
j = 0;
|
|
||||||
sum = gimp_histogram_get_channel(hist, k, 0) +
|
|
||||||
gimp_histogram_get_channel(hist, k, 1);
|
|
||||||
for (i = 1; i < 256; i++)
|
|
||||||
{
|
|
||||||
desired = i * pixels_per_value;
|
|
||||||
while (sum <= desired)
|
|
||||||
{
|
|
||||||
j++;
|
|
||||||
sum += gimp_histogram_get_channel(hist, k, j + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Nearest sum */
|
|
||||||
dif = sum - gimp_histogram_get_channel(hist, k, j);
|
|
||||||
if ((sum - desired) > (dif / 2.0))
|
|
||||||
hlut.part[k][i] = j;
|
|
||||||
else
|
|
||||||
hlut.part[k][i] = j + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lut = gimp_lut_new();
|
|
||||||
|
|
||||||
gimp_lut_setup(lut, (GimpLutFunc) equalize_lut_func,
|
|
||||||
(void *) &hlut, bytes);
|
|
||||||
|
|
||||||
return lut;
|
|
||||||
}
|
|
||||||
|
|
||||||
static float
|
|
||||||
equalize_lut_func(struct hist_lut_struct *hlut,
|
|
||||||
int nchannels, int channel, float value)
|
|
||||||
{
|
|
||||||
int i = 0, j;
|
|
||||||
j = (int)(value * 255.0 + 0.5);
|
|
||||||
while (hlut->part[channel][i + 1] <= j)
|
|
||||||
i++;
|
|
||||||
return i / 255.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* The equalize procedure definition */
|
|
||||||
ProcArg equalize_args[] =
|
ProcArg equalize_args[] =
|
||||||
{
|
{
|
||||||
{ PDB_DRAWABLE,
|
{ PDB_DRAWABLE,
|
||||||
|
|
|
@ -36,6 +36,9 @@
|
||||||
#include "channel_pvt.h"
|
#include "channel_pvt.h"
|
||||||
#include "tile.h"
|
#include "tile.h"
|
||||||
|
|
||||||
|
#include "gimplut.h"
|
||||||
|
#include "lut_funcs.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
enum {
|
enum {
|
||||||
LAST_SIGNAL
|
LAST_SIGNAL
|
||||||
|
@ -602,9 +605,9 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2)
|
||||||
unsigned char * data;
|
unsigned char * data;
|
||||||
int x, y;
|
int x, y;
|
||||||
int ex, ey;
|
int ex, ey;
|
||||||
int found;
|
|
||||||
void *pr;
|
void *pr;
|
||||||
|
int tx1, tx2, ty1, ty2;
|
||||||
|
int minx, maxx;
|
||||||
/* if the mask's bounds have already been reliably calculated... */
|
/* if the mask's bounds have already been reliably calculated... */
|
||||||
if (mask->bounds_known)
|
if (mask->bounds_known)
|
||||||
{
|
{
|
||||||
|
@ -617,10 +620,10 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* go through and calculate the bounds */
|
/* go through and calculate the bounds */
|
||||||
*x1 = GIMP_DRAWABLE(mask)->width;
|
tx1 = GIMP_DRAWABLE(mask)->width;
|
||||||
*y1 = GIMP_DRAWABLE(mask)->height;
|
ty1 = GIMP_DRAWABLE(mask)->height;
|
||||||
*x2 = 0;
|
tx2 = 0;
|
||||||
*y2 = 0;
|
ty2 = 0;
|
||||||
|
|
||||||
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, 0, 0, GIMP_DRAWABLE(mask)->width, GIMP_DRAWABLE(mask)->height, FALSE);
|
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, 0, 0, GIMP_DRAWABLE(mask)->width, GIMP_DRAWABLE(mask)->height, FALSE);
|
||||||
for (pr = pixel_regions_register (1, &maskPR); pr != NULL; pr = pixel_regions_process (pr))
|
for (pr = pixel_regions_register (1, &maskPR); pr != NULL; pr = pixel_regions_process (pr))
|
||||||
|
@ -630,36 +633,50 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2)
|
||||||
ey = maskPR.y + maskPR.h;
|
ey = maskPR.y + maskPR.h;
|
||||||
/* only check the pixels if this tile is not fully within the currently
|
/* only check the pixels if this tile is not fully within the currently
|
||||||
computed bounds */
|
computed bounds */
|
||||||
if (maskPR.x < *x1 || ex > *x2 ||
|
if (maskPR.x < tx1 || ex > tx2 ||
|
||||||
maskPR.y < *y1 || ey > *y2)
|
maskPR.y < ty1 || ey > ty2)
|
||||||
{
|
{
|
||||||
for (y = maskPR.y; y < ey; y++)
|
/* Check upper left and lower right corners to see if we can
|
||||||
|
avoid checking the rest of the pixels in this tile */
|
||||||
|
if (data[0] && data[maskPR.rowstride*(maskPR.h - 1) + maskPR.w - 1])
|
||||||
|
{
|
||||||
|
if (maskPR.x < tx1)
|
||||||
|
tx1 = maskPR.x;
|
||||||
|
if (ex > tx2)
|
||||||
|
tx2 = ex;
|
||||||
|
if (maskPR.y < ty1)
|
||||||
|
ty1 = maskPR.y;
|
||||||
|
if (ey > ty2)
|
||||||
|
ty2 = ey;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
for (y = maskPR.y; y < ey; y++)
|
||||||
{
|
{
|
||||||
found = FALSE;
|
|
||||||
for (x = maskPR.x; x < ex; x++, data++)
|
for (x = maskPR.x; x < ex; x++, data++)
|
||||||
if (*data)
|
if (*data)
|
||||||
{
|
{
|
||||||
if (x < *x1)
|
minx = x;
|
||||||
*x1 = x;
|
maxx = x;
|
||||||
if (x > *x2)
|
for (; x < ex; x++, data++)
|
||||||
*x2 = x;
|
if (*data)
|
||||||
found = TRUE;
|
maxx = x;
|
||||||
}
|
if (minx < tx1)
|
||||||
if (found)
|
tx1 = minx;
|
||||||
{
|
if (maxx > tx2)
|
||||||
if (y < *y1)
|
tx2 = maxx;
|
||||||
*y1 = y;
|
if (y < ty1)
|
||||||
if (y > *y2)
|
ty1 = y;
|
||||||
*y2 = y;
|
if (y > ty2)
|
||||||
}
|
ty2 = y;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*x2 = BOUNDS (*x2 + 1, 0, GIMP_DRAWABLE(mask)->width);
|
tx2 = BOUNDS (tx2 + 1, 0, GIMP_DRAWABLE(mask)->width);
|
||||||
*y2 = BOUNDS (*y2 + 1, 0, GIMP_DRAWABLE(mask)->height);
|
ty2 = BOUNDS (ty2 + 1, 0, GIMP_DRAWABLE(mask)->height);
|
||||||
|
|
||||||
if (*x1 == GIMP_DRAWABLE(mask)->width && *y1 == GIMP_DRAWABLE(mask)->height)
|
if (tx1 == GIMP_DRAWABLE(mask)->width && ty1 == GIMP_DRAWABLE(mask)->height)
|
||||||
{
|
{
|
||||||
mask->empty = TRUE;
|
mask->empty = TRUE;
|
||||||
mask->x1 = 0; mask->y1 = 0;
|
mask->x1 = 0; mask->y1 = 0;
|
||||||
|
@ -669,13 +686,18 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mask->empty = FALSE;
|
mask->empty = FALSE;
|
||||||
mask->x1 = *x1;
|
mask->x1 = tx1;
|
||||||
mask->y1 = *y1;
|
mask->y1 = ty1;
|
||||||
mask->x2 = *x2;
|
mask->x2 = tx2;
|
||||||
mask->y2 = *y2;
|
mask->y2 = ty2;
|
||||||
}
|
}
|
||||||
mask->bounds_known = TRUE;
|
mask->bounds_known = TRUE;
|
||||||
|
|
||||||
|
*x1 = tx1;
|
||||||
|
*x2 = tx2;
|
||||||
|
*y1 = ty1;
|
||||||
|
*y2 = ty2;
|
||||||
|
|
||||||
return (mask->empty) ? FALSE : TRUE;
|
return (mask->empty) ? FALSE : TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -800,61 +822,31 @@ channel_sub_segment (Channel *mask, int x, int y, int width, int value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
channel_inter_segment (Channel *mask, int x, int y, int width, int value)
|
|
||||||
{
|
|
||||||
PixelRegion maskPR;
|
|
||||||
unsigned char *data;
|
|
||||||
int val;
|
|
||||||
int x2;
|
|
||||||
void * pr;
|
|
||||||
|
|
||||||
/* check horizontal extents... */
|
|
||||||
x2 = x + width;
|
|
||||||
if (x2 < 0) x2 = 0;
|
|
||||||
if (x2 > GIMP_DRAWABLE(mask)->width) x2 = GIMP_DRAWABLE(mask)->width;
|
|
||||||
if (x < 0) x = 0;
|
|
||||||
if (x > GIMP_DRAWABLE(mask)->width) x = GIMP_DRAWABLE(mask)->width;
|
|
||||||
width = x2 - x;
|
|
||||||
if (!width) return;
|
|
||||||
|
|
||||||
if (y < 0 || y > GIMP_DRAWABLE(mask)->height)
|
|
||||||
return;
|
|
||||||
|
|
||||||
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, x, y, width, 1, TRUE);
|
|
||||||
for (pr = pixel_regions_register (1, &maskPR); pr != NULL; pr = pixel_regions_process (pr))
|
|
||||||
{
|
|
||||||
data = maskPR.data;
|
|
||||||
width = maskPR.w;
|
|
||||||
while (width--)
|
|
||||||
{
|
|
||||||
val = MINIMUM(*data, value);
|
|
||||||
*data++ = val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
channel_combine_rect (Channel *mask, int op, int x, int y, int w, int h)
|
channel_combine_rect (Channel *mask, int op, int x, int y, int w, int h)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
int x2, y2;
|
||||||
|
PixelRegion maskPR;
|
||||||
|
unsigned char color;
|
||||||
|
y2 = y + h;
|
||||||
|
x2 = x + w;
|
||||||
|
|
||||||
for (i = y; i < y + h; i++)
|
x = BOUNDS (x, 0, GIMP_DRAWABLE(mask)->width);
|
||||||
{
|
y = BOUNDS (y, 0, GIMP_DRAWABLE(mask)->height);
|
||||||
if (i >= 0 && i < GIMP_DRAWABLE(mask)->height)
|
x2 = BOUNDS (x2, 0, GIMP_DRAWABLE(mask)->width);
|
||||||
switch (op)
|
y2 = BOUNDS (y2, 0, GIMP_DRAWABLE(mask)->height);
|
||||||
{
|
|
||||||
case ADD: case REPLACE:
|
if (x2 - x <= 0 || y2 - y <= 0)
|
||||||
channel_add_segment (mask, x, i, w, 255);
|
return;
|
||||||
break;
|
|
||||||
case SUB:
|
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, x, y,
|
||||||
channel_sub_segment (mask, x, i, w, 255);
|
x2 - x, y2 - y, TRUE);
|
||||||
break;
|
if (op == ADD || op == REPLACE)
|
||||||
case INTERSECT:
|
color = 255;
|
||||||
channel_inter_segment (mask, x, i, w, 255);
|
else
|
||||||
break;
|
color = 0;
|
||||||
}
|
color_region(&maskPR, &color);
|
||||||
}
|
|
||||||
|
|
||||||
/* Determine new boundary */
|
/* Determine new boundary */
|
||||||
if (mask->bounds_known && (op == ADD) && !mask->empty)
|
if (mask->bounds_known && (op == ADD) && !mask->empty)
|
||||||
|
@ -933,9 +925,6 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h,
|
||||||
case SUB :
|
case SUB :
|
||||||
channel_sub_segment (mask, x1, i, (x2 - x1), 255);
|
channel_sub_segment (mask, x1, i, (x2 - x1), 255);
|
||||||
break;
|
break;
|
||||||
case INTERSECT:
|
|
||||||
channel_inter_segment (mask, x1, i, (x2 - x1), 255);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* antialiasing */
|
/* antialiasing */
|
||||||
|
@ -965,7 +954,7 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h,
|
||||||
val = (int) (255 * (1 - (dist + 0.5)));
|
val = (int) (255 * (1 - (dist + 0.5)));
|
||||||
else
|
else
|
||||||
val = 0;
|
val = 0;
|
||||||
|
|
||||||
if (last != val && last)
|
if (last != val && last)
|
||||||
{
|
{
|
||||||
switch (op)
|
switch (op)
|
||||||
|
@ -976,8 +965,6 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h,
|
||||||
case SUB:
|
case SUB:
|
||||||
channel_sub_segment (mask, x0, i, j - x0, last);
|
channel_sub_segment (mask, x0, i, j - x0, last);
|
||||||
break;
|
break;
|
||||||
case INTERSECT:
|
|
||||||
channel_inter_segment (mask, x0, i, j - x0, last);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -985,6 +972,10 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h,
|
||||||
{
|
{
|
||||||
x0 = j;
|
x0 = j;
|
||||||
last = val;
|
last = val;
|
||||||
|
/* because we are symetric accross the y axis we can
|
||||||
|
skip ahead a bit if we are inside the ellipse*/
|
||||||
|
if (val == 255 && j < cx)
|
||||||
|
j = cx + (cx - j) - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -994,8 +985,6 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h,
|
||||||
channel_add_segment (mask, x0, i, j - x0, last);
|
channel_add_segment (mask, x0, i, j - x0, last);
|
||||||
else if (op == SUB)
|
else if (op == SUB)
|
||||||
channel_sub_segment (mask, x0, i, j - x0, last);
|
channel_sub_segment (mask, x0, i, j - x0, last);
|
||||||
else if (op == INTERSECT)
|
|
||||||
channel_inter_segment (mask, x0, i, j - x0, last);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1032,18 +1021,81 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
channel_combine_sub_region_add (void *unused,
|
||||||
|
PixelRegion *srcPR,
|
||||||
|
PixelRegion *destPR)
|
||||||
|
{
|
||||||
|
unsigned char *src, *dest;
|
||||||
|
int x, y, val;
|
||||||
|
src = srcPR->data;
|
||||||
|
dest = destPR->data;
|
||||||
|
for (y = 0; y < srcPR->h; y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < srcPR->w; x++)
|
||||||
|
{
|
||||||
|
val = dest[x] + src[x];
|
||||||
|
if (val > 255)
|
||||||
|
dest[x] = 255;
|
||||||
|
else
|
||||||
|
dest[x] = val;
|
||||||
|
}
|
||||||
|
src += srcPR->rowstride;
|
||||||
|
dest += destPR->rowstride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
channel_combine_sub_region_sub (void *unused,
|
||||||
|
PixelRegion *srcPR,
|
||||||
|
PixelRegion *destPR)
|
||||||
|
{
|
||||||
|
unsigned char *src, *dest;
|
||||||
|
int x, y;
|
||||||
|
src = srcPR->data;
|
||||||
|
dest = destPR->data;
|
||||||
|
for (y = 0; y < srcPR->h; y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < srcPR->w; x++)
|
||||||
|
{
|
||||||
|
if (src[x] > dest[x])
|
||||||
|
dest[x] = 0;
|
||||||
|
else
|
||||||
|
dest[x]-= src[x];
|
||||||
|
}
|
||||||
|
src += srcPR->rowstride;
|
||||||
|
dest += destPR->rowstride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
channel_combine_sub_region_intersect (void *unused,
|
||||||
|
PixelRegion *srcPR,
|
||||||
|
PixelRegion *destPR)
|
||||||
|
{
|
||||||
|
unsigned char *src, *dest;
|
||||||
|
int x, y;
|
||||||
|
src = srcPR->data;
|
||||||
|
dest = destPR->data;
|
||||||
|
for (y = 0; y < srcPR->h; y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < srcPR->w; x++)
|
||||||
|
{
|
||||||
|
dest[x] = MINIMUM(dest[x], src[x]);
|
||||||
|
}
|
||||||
|
src += srcPR->rowstride;
|
||||||
|
dest += destPR->rowstride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
channel_combine_mask (Channel *mask, Channel *add_on, int op,
|
channel_combine_mask (Channel *mask, Channel *add_on, int op,
|
||||||
int off_x, int off_y)
|
int off_x, int off_y)
|
||||||
{
|
{
|
||||||
PixelRegion srcPR, destPR;
|
PixelRegion srcPR, destPR;
|
||||||
unsigned char *src;
|
|
||||||
unsigned char *dest;
|
|
||||||
int val;
|
|
||||||
int x1, y1, x2, y2;
|
int x1, y1, x2, y2;
|
||||||
int x, y;
|
|
||||||
int w, h;
|
int w, h;
|
||||||
void * pr;
|
|
||||||
|
|
||||||
x1 = BOUNDS (off_x, 0, GIMP_DRAWABLE(mask)->width);
|
x1 = BOUNDS (off_x, 0, GIMP_DRAWABLE(mask)->width);
|
||||||
y1 = BOUNDS (off_y, 0, GIMP_DRAWABLE(mask)->height);
|
y1 = BOUNDS (off_y, 0, GIMP_DRAWABLE(mask)->height);
|
||||||
|
@ -1056,39 +1108,25 @@ channel_combine_mask (Channel *mask, Channel *add_on, int op,
|
||||||
pixel_region_init (&srcPR, GIMP_DRAWABLE(add_on)->tiles, (x1 - off_x), (y1 - off_y), w, h, FALSE);
|
pixel_region_init (&srcPR, GIMP_DRAWABLE(add_on)->tiles, (x1 - off_x), (y1 - off_y), w, h, FALSE);
|
||||||
pixel_region_init (&destPR, GIMP_DRAWABLE(mask)->tiles, x1, y1, w, h, TRUE);
|
pixel_region_init (&destPR, GIMP_DRAWABLE(mask)->tiles, x1, y1, w, h, TRUE);
|
||||||
|
|
||||||
for (pr = pixel_regions_register (2, &srcPR, &destPR); pr != NULL; pr = pixel_regions_process (pr))
|
switch (op)
|
||||||
{
|
{
|
||||||
src = srcPR.data;
|
case ADD: case REPLACE:
|
||||||
dest = destPR.data;
|
pixel_regions_process_parallel ((p_func)channel_combine_sub_region_add,
|
||||||
|
NULL, 2, &srcPR, &destPR);
|
||||||
for (y = 0; y < srcPR.h; y++)
|
break;
|
||||||
{
|
case SUB:
|
||||||
for (x = 0; x < srcPR.w; x++)
|
pixel_regions_process_parallel ((p_func)channel_combine_sub_region_sub,
|
||||||
{
|
NULL, 2, &srcPR, &destPR);
|
||||||
switch (op)
|
break;
|
||||||
{
|
case INTERSECT:
|
||||||
case ADD: case REPLACE:
|
pixel_regions_process_parallel ((p_func)
|
||||||
val = dest[x] + src[x];
|
channel_combine_sub_region_intersect,
|
||||||
if (val > 255) val = 255;
|
NULL, 2, &srcPR, &destPR);
|
||||||
break;
|
break;
|
||||||
case SUB:
|
default:
|
||||||
val = dest[x] - src[x];
|
g_message("Error: unknown opperation type in channel_combine_mask\n");
|
||||||
if (val < 0) val = 0;
|
break;
|
||||||
break;
|
}
|
||||||
case INTERSECT:
|
|
||||||
val = MINIMUM(dest[x], src[x]);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
val = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
dest[x] = val;
|
|
||||||
}
|
|
||||||
src += srcPR.rowstride;
|
|
||||||
dest += destPR.rowstride;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mask->bounds_known = FALSE;
|
mask->bounds_known = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1184,57 +1222,35 @@ void
|
||||||
channel_invert (Channel *mask)
|
channel_invert (Channel *mask)
|
||||||
{
|
{
|
||||||
PixelRegion maskPR;
|
PixelRegion maskPR;
|
||||||
unsigned char *data;
|
GimpLut *lut;
|
||||||
int size;
|
|
||||||
void * pr;
|
|
||||||
|
|
||||||
/* push the current channel onto the undo stack */
|
/* push the current channel onto the undo stack */
|
||||||
channel_push_undo (mask);
|
channel_push_undo (mask);
|
||||||
|
|
||||||
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, 0, 0, GIMP_DRAWABLE(mask)->width, GIMP_DRAWABLE(mask)->height, TRUE);
|
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, 0, 0, GIMP_DRAWABLE(mask)->width, GIMP_DRAWABLE(mask)->height, TRUE);
|
||||||
for (pr = pixel_regions_register (1, &maskPR); pr != NULL; pr = pixel_regions_process (pr))
|
|
||||||
{
|
lut = invert_lut_new(1);
|
||||||
/* subtract each pixel in the mask from 255 */
|
|
||||||
data = maskPR.data;
|
|
||||||
size = maskPR.w * maskPR.h;
|
|
||||||
while (size --)
|
|
||||||
{
|
|
||||||
*data = 255 - *data;
|
|
||||||
data++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
pixel_regions_process_parallel ((p_func)gimp_lut_process_inline,
|
||||||
|
lut, 1, &maskPR);
|
||||||
|
gimp_lut_free(lut);
|
||||||
mask->bounds_known = FALSE;
|
mask->bounds_known = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
channel_sharpen (Channel *mask)
|
channel_sharpen (Channel *mask)
|
||||||
{
|
{
|
||||||
PixelRegion maskPR;
|
PixelRegion maskPR;
|
||||||
unsigned char *data;
|
GimpLut *lut;
|
||||||
int size;
|
|
||||||
void * pr;
|
|
||||||
|
|
||||||
/* push the current channel onto the undo stack */
|
/* push the current channel onto the undo stack */
|
||||||
channel_push_undo (mask);
|
channel_push_undo (mask);
|
||||||
|
|
||||||
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, 0, 0, GIMP_DRAWABLE(mask)->width, GIMP_DRAWABLE(mask)->height, TRUE);
|
pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, 0, 0, GIMP_DRAWABLE(mask)->width, GIMP_DRAWABLE(mask)->height, TRUE);
|
||||||
for (pr = pixel_regions_register (1, &maskPR); pr != NULL; pr = pixel_regions_process (pr))
|
lut = threshold_lut_new(0.5, 1);
|
||||||
{
|
|
||||||
/* if a pixel in the mask has a non-zero value, make it 255 */
|
|
||||||
data = maskPR.data;
|
|
||||||
size = maskPR.w * maskPR.h;
|
|
||||||
while (size--)
|
|
||||||
{
|
|
||||||
if (*data > HALF_WAY)
|
|
||||||
*data++ = 255;
|
|
||||||
else
|
|
||||||
*data++ = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mask->bounds_known = FALSE;
|
pixel_regions_process_parallel ((p_func)gimp_lut_process_inline,
|
||||||
|
lut, 1, &maskPR);
|
||||||
|
gimp_lut_free(lut);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,27 +19,17 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "appenv.h"
|
|
||||||
#include "drawable.h"
|
#include "drawable.h"
|
||||||
#include "equalize.h"
|
#include "equalize.h"
|
||||||
#include "interface.h"
|
|
||||||
#include "gimage.h"
|
#include "gimage.h"
|
||||||
#include "gimplut.h"
|
#include "gimplut.h"
|
||||||
|
#include "lut_funcs.h"
|
||||||
#include "gimphistogram.h"
|
#include "gimphistogram.h"
|
||||||
|
|
||||||
#include "libgimp/gimpintl.h"
|
#include "libgimp/gimpintl.h"
|
||||||
|
|
||||||
struct hist_lut_struct
|
|
||||||
{
|
|
||||||
GimpHistogram *histogram;
|
|
||||||
int part[5][257];
|
|
||||||
};
|
|
||||||
|
|
||||||
static float equalize_lut_func(struct hist_lut_struct *hlut,
|
|
||||||
int nchannels, int channel, float value);
|
|
||||||
static void equalize (GImage *, GimpDrawable *, int);
|
static void equalize (GImage *, GimpDrawable *, int);
|
||||||
static Argument * equalize_invoker (Argument *);
|
static Argument * equalize_invoker (Argument *);
|
||||||
static GimpLut * eq_histogram_lut (GimpHistogram *hist, int bytes);
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -87,7 +77,7 @@ equalize(gimage, drawable, mask_only)
|
||||||
|
|
||||||
|
|
||||||
/* Build equalization LUT */
|
/* Build equalization LUT */
|
||||||
lut = eq_histogram_lut (hist, bytes);
|
lut = eq_histogram_lut_new (hist, bytes);
|
||||||
|
|
||||||
/* Apply the histogram */
|
/* Apply the histogram */
|
||||||
drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
|
drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
|
||||||
|
@ -105,71 +95,10 @@ equalize(gimage, drawable, mask_only)
|
||||||
drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1));
|
drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* --------------- The equalize procedure definition ---------------- */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
/*****/
|
|
||||||
|
|
||||||
static GimpLut *
|
|
||||||
eq_histogram_lut (GimpHistogram *hist, int bytes)
|
|
||||||
{
|
|
||||||
int i, k, j;
|
|
||||||
struct hist_lut_struct hlut;
|
|
||||||
double pixels_per_value;
|
|
||||||
double desired;
|
|
||||||
GimpLut *lut;
|
|
||||||
double sum, dif;
|
|
||||||
|
|
||||||
/* Find partition points */
|
|
||||||
pixels_per_value = gimp_histogram_get_count(hist, 0, 255) / 256.0;
|
|
||||||
|
|
||||||
for (k = 0; k < bytes; k++)
|
|
||||||
{
|
|
||||||
/* First and last points in partition */
|
|
||||||
hlut.part[k][0] = 0;
|
|
||||||
hlut.part[k][256] = 256;
|
|
||||||
|
|
||||||
/* Find intermediate points */
|
|
||||||
j = 0;
|
|
||||||
sum = gimp_histogram_get_channel(hist, k, 0) +
|
|
||||||
gimp_histogram_get_channel(hist, k, 1);
|
|
||||||
for (i = 1; i < 256; i++)
|
|
||||||
{
|
|
||||||
desired = i * pixels_per_value;
|
|
||||||
while (sum <= desired)
|
|
||||||
{
|
|
||||||
j++;
|
|
||||||
sum += gimp_histogram_get_channel(hist, k, j + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Nearest sum */
|
|
||||||
dif = sum - gimp_histogram_get_channel(hist, k, j);
|
|
||||||
if ((sum - desired) > (dif / 2.0))
|
|
||||||
hlut.part[k][i] = j;
|
|
||||||
else
|
|
||||||
hlut.part[k][i] = j + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lut = gimp_lut_new();
|
|
||||||
|
|
||||||
gimp_lut_setup(lut, (GimpLutFunc) equalize_lut_func,
|
|
||||||
(void *) &hlut, bytes);
|
|
||||||
|
|
||||||
return lut;
|
|
||||||
}
|
|
||||||
|
|
||||||
static float
|
|
||||||
equalize_lut_func(struct hist_lut_struct *hlut,
|
|
||||||
int nchannels, int channel, float value)
|
|
||||||
{
|
|
||||||
int i = 0, j;
|
|
||||||
j = (int)(value * 255.0 + 0.5);
|
|
||||||
while (hlut->part[channel][i + 1] <= j)
|
|
||||||
i++;
|
|
||||||
return i / 255.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* The equalize procedure definition */
|
|
||||||
ProcArg equalize_args[] =
|
ProcArg equalize_args[] =
|
||||||
{
|
{
|
||||||
{ PDB_DRAWABLE,
|
{ PDB_DRAWABLE,
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "invert.h"
|
#include "invert.h"
|
||||||
#include "gimage.h"
|
#include "gimage.h"
|
||||||
#include "gimplut.h"
|
#include "gimplut.h"
|
||||||
|
#include "lut_funcs.h"
|
||||||
|
|
||||||
#include "libgimp/gimpintl.h"
|
#include "libgimp/gimpintl.h"
|
||||||
|
|
||||||
|
@ -58,18 +59,6 @@ image_invert (GImage *gimage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static float
|
|
||||||
invert_lut_func(void *unused,
|
|
||||||
int nchannels, int channel, float value)
|
|
||||||
{
|
|
||||||
/* don't invert the alpha channel */
|
|
||||||
if ((nchannels == 2 || nchannels == 4) && channel == nchannels -1)
|
|
||||||
return value;
|
|
||||||
|
|
||||||
return 1.0 - value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Inverter */
|
/* Inverter */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -79,10 +68,7 @@ invert (GimpDrawable *drawable)
|
||||||
int x1, y1, x2, y2;
|
int x1, y1, x2, y2;
|
||||||
GimpLut *lut;
|
GimpLut *lut;
|
||||||
|
|
||||||
lut = gimp_lut_new();
|
lut = invert_lut_new(gimp_drawable_bytes(drawable));
|
||||||
|
|
||||||
gimp_lut_setup_exact(lut, (GimpLutFunc) invert_lut_func,
|
|
||||||
(void *) NULL, gimp_drawable_bytes(drawable));
|
|
||||||
|
|
||||||
drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
|
drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
|
||||||
pixel_region_init (&srcPR, drawable_data (drawable), x1, y1, (x2 - x1), (y2 - y1), FALSE);
|
pixel_region_init (&srcPR, drawable_data (drawable), x1, y1, (x2 - x1), (y2 - y1), FALSE);
|
||||||
|
@ -97,8 +83,10 @@ invert (GimpDrawable *drawable)
|
||||||
drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1));
|
drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* ----------------- The invert procedure definition ---------------- */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
/* The invert procedure definition */
|
|
||||||
ProcArg invert_args[] =
|
ProcArg invert_args[] =
|
||||||
{
|
{
|
||||||
{ PDB_DRAWABLE,
|
{ PDB_DRAWABLE,
|
||||||
|
|
|
@ -640,7 +640,6 @@ gimp_drawable_init (GimpDrawable *drawable)
|
||||||
drawable->preview_valid = FALSE;
|
drawable->preview_valid = FALSE;
|
||||||
drawable->parasites = parasite_list_new();
|
drawable->parasites = parasite_list_new();
|
||||||
drawable->tattoo = 0;
|
drawable->tattoo = 0;
|
||||||
gimp_matrix_identity(drawable->transform);
|
|
||||||
|
|
||||||
drawable->ID = global_drawable_ID++;
|
drawable->ID = global_drawable_ID++;
|
||||||
if (gimp_drawable_table == NULL)
|
if (gimp_drawable_table == NULL)
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
#include "gimpobjectP.h"
|
#include "gimpobjectP.h"
|
||||||
#include "gimpdrawable.h"
|
#include "gimpdrawable.h"
|
||||||
#include "parasitelistF.h"
|
#include "parasitelistF.h"
|
||||||
#include "libgimp/gimpmatrix.h"
|
|
||||||
|
|
||||||
struct _GimpDrawable
|
struct _GimpDrawable
|
||||||
{
|
{
|
||||||
|
@ -43,10 +42,6 @@ struct _GimpDrawable
|
||||||
|
|
||||||
ParasiteList *parasites; /* Plug-in parasite data */
|
ParasiteList *parasites; /* Plug-in parasite data */
|
||||||
|
|
||||||
GimpMatrix transform; /* a matrix describing all of the
|
|
||||||
transformations this drawable
|
|
||||||
has undergone */
|
|
||||||
|
|
||||||
/* Preview variables */
|
/* Preview variables */
|
||||||
TempBuf *preview; /* preview of the channel */
|
TempBuf *preview; /* preview of the channel */
|
||||||
int preview_valid; /* is the preview valid? */
|
int preview_valid; /* is the preview valid? */
|
||||||
|
|
|
@ -169,7 +169,6 @@ static void gimp_image_init (GimpImage *gimage)
|
||||||
gimage->comp_preview_valid[2] = FALSE;
|
gimage->comp_preview_valid[2] = FALSE;
|
||||||
gimage->comp_preview = NULL;
|
gimage->comp_preview = NULL;
|
||||||
gimage->parasites = parasite_list_new();
|
gimage->parasites = parasite_list_new();
|
||||||
gimp_matrix_identity(gimage->transform);
|
|
||||||
gimage->xresolution = default_xresolution;
|
gimage->xresolution = default_xresolution;
|
||||||
gimage->yresolution = default_yresolution;
|
gimage->yresolution = default_yresolution;
|
||||||
gimage->unit = default_units;
|
gimage->unit = default_units;
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#include "layer.h"
|
#include "layer.h"
|
||||||
#include "parasitelistF.h"
|
#include "parasitelistF.h"
|
||||||
#include "pathsP.h"
|
#include "pathsP.h"
|
||||||
#include "libgimp/gimpmatrix.h"
|
|
||||||
|
|
||||||
|
|
||||||
#define MAX_CHANNELS 4
|
#define MAX_CHANNELS 4
|
||||||
|
@ -65,10 +64,6 @@ struct _GimpImage
|
||||||
|
|
||||||
PathsList *paths; /* Paths data for this image */
|
PathsList *paths; /* Paths data for this image */
|
||||||
|
|
||||||
GimpMatrix transform; /* a matrix describing all of the
|
|
||||||
transformations this image
|
|
||||||
has undergone */
|
|
||||||
|
|
||||||
int visible [MAX_CHANNELS]; /* visible channels */
|
int visible [MAX_CHANNELS]; /* visible channels */
|
||||||
int active [MAX_CHANNELS]; /* active channels */
|
int active [MAX_CHANNELS]; /* active channels */
|
||||||
|
|
||||||
|
|
|
@ -160,6 +160,79 @@ gimp_lut_process (GimpLut *lut,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gimp_lut_process_inline (GimpLut *lut,
|
||||||
|
PixelRegion *srcPR)
|
||||||
|
{
|
||||||
|
int h, width, src_r_i;
|
||||||
|
unsigned char *src;
|
||||||
|
unsigned char *lut0 = NULL, *lut1 = NULL, *lut2 = NULL, *lut3 = NULL;
|
||||||
|
|
||||||
|
if (lut->nchannels > 0)
|
||||||
|
lut0 = lut->luts[0];
|
||||||
|
if (lut->nchannels > 1)
|
||||||
|
lut1 = lut->luts[1];
|
||||||
|
if (lut->nchannels > 2)
|
||||||
|
lut2 = lut->luts[2];
|
||||||
|
if (lut->nchannels > 3)
|
||||||
|
lut3 = lut->luts[3];
|
||||||
|
|
||||||
|
h = srcPR->h;
|
||||||
|
src = srcPR->data;
|
||||||
|
width = srcPR->w;
|
||||||
|
src_r_i = srcPR->rowstride - (srcPR->bytes * srcPR->w);
|
||||||
|
|
||||||
|
if (src_r_i == 0)
|
||||||
|
{
|
||||||
|
width *= h;
|
||||||
|
h = 1;
|
||||||
|
}
|
||||||
|
while (h--)
|
||||||
|
{
|
||||||
|
switch (lut->nchannels)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
while (width--)
|
||||||
|
{
|
||||||
|
*src = lut0[*src];
|
||||||
|
src++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
while (width--)
|
||||||
|
{
|
||||||
|
src[0] = lut0[src[0]];
|
||||||
|
src[1] = lut1[src[1]];
|
||||||
|
src += 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
while (width--)
|
||||||
|
{
|
||||||
|
src[0] = lut0[src[0]];
|
||||||
|
src[1] = lut1[src[1]];
|
||||||
|
src[2] = lut2[src[2]];
|
||||||
|
src += 3;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
while (width--)
|
||||||
|
{
|
||||||
|
src[0] = lut0[src[0]];
|
||||||
|
src[1] = lut1[src[1]];
|
||||||
|
src[2] = lut2[src[2]];
|
||||||
|
src[3] = lut3[src[3]];
|
||||||
|
src += 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "gimplut: Error: nchannels = %d\n", lut->nchannels);
|
||||||
|
}
|
||||||
|
width = srcPR->w;
|
||||||
|
src += src_r_i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gimp_lut_process_2 (PixelRegion *srcPR,
|
gimp_lut_process_2 (PixelRegion *srcPR,
|
||||||
PixelRegion *destPR,
|
PixelRegion *destPR,
|
||||||
|
|
|
@ -49,6 +49,11 @@ void gimp_lut_process (GimpLut *lut,
|
||||||
PixelRegion *srcPR,
|
PixelRegion *srcPR,
|
||||||
PixelRegion *destPR);
|
PixelRegion *destPR);
|
||||||
|
|
||||||
|
/* gimp_lut_process_inline is like gimp_lut_process except it uses a
|
||||||
|
single PixelRegion as both the source and destination */
|
||||||
|
void gimp_lut_process_inline(GimpLut *lut,
|
||||||
|
PixelRegion *src_destPR);
|
||||||
|
|
||||||
/* gimp_lut_process_2 is the same as gimp_lut_process but the lut
|
/* gimp_lut_process_2 is the same as gimp_lut_process but the lut
|
||||||
perameter is last instead of first. this is necesary because
|
perameter is last instead of first. this is necesary because
|
||||||
pixel_region_process_paralell sends the user_data as the 1st
|
pixel_region_process_paralell sends the user_data as the 1st
|
||||||
|
|
|
@ -16,8 +16,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include "parasitelist.h"
|
#include "parasitelist.h"
|
||||||
#include "gimpparasite.h"
|
#include "gimpparasite.h"
|
||||||
|
#include "libgimp/parasite.h"
|
||||||
|
#include "libgimp/gimpenv.h"
|
||||||
|
|
||||||
static ParasiteList *parasites = NULL;
|
static ParasiteList *parasites = NULL;
|
||||||
|
|
||||||
|
@ -26,6 +30,7 @@ gimp_init_parasites()
|
||||||
{
|
{
|
||||||
g_return_if_fail(parasites == NULL);
|
g_return_if_fail(parasites == NULL);
|
||||||
parasites = parasite_list_new();
|
parasites = parasite_list_new();
|
||||||
|
gimp_parasiterc_load();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -64,5 +69,40 @@ gimp_parasite_list (gint *count)
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gimp_parasiterc_save()
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
guint32 num, version = 1;
|
||||||
|
if (!(fp = fopen(gimp_personal_rc_file ("#parasiterc.tmp"), "w")))
|
||||||
|
return;
|
||||||
|
version = GINT32_TO_BE(version);
|
||||||
|
fwrite(&version, 4, 1, fp);
|
||||||
|
|
||||||
|
parasite_list_save(parasites, fp);
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
if (rename(gimp_personal_rc_file ("#parasiterc.tmp"),
|
||||||
|
gimp_personal_rc_file("parasiterc")) != 0)
|
||||||
|
unlink(gimp_personal_rc_file ("#parasiterc.tmp"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gimp_parasiterc_load()
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
guint32 num, version;
|
||||||
|
if (!(fp = fopen(gimp_personal_rc_file ("parasiterc"), "r")))
|
||||||
|
return;
|
||||||
|
fread(&version, 4, 1, fp);
|
||||||
|
version = GINT32_FROM_BE(version);
|
||||||
|
if (version != 1)
|
||||||
|
{
|
||||||
|
fclose(fp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parasite_list_load(parasites, fp);
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
|
@ -25,5 +25,7 @@ void gimp_attach_parasite (Parasite *p);
|
||||||
void gimp_detach_parasite (char *name);
|
void gimp_detach_parasite (char *name);
|
||||||
Parasite * gimp_find_parasite (char *name);
|
Parasite * gimp_find_parasite (char *name);
|
||||||
char ** gimp_parasite_list (gint *count);
|
char ** gimp_parasite_list (gint *count);
|
||||||
|
void gimp_parasiterc_save (void);
|
||||||
|
void gimp_parasiterc_load (void);
|
||||||
|
|
||||||
#endif /* __GIMP_PARASITE_H__ */
|
#endif /* __GIMP_PARASITE_H__ */
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
#include "app_procs.h"
|
#include "app_procs.h"
|
||||||
#include "airbrush.h"
|
#include "airbrush.h"
|
||||||
#include "blend.h"
|
#include "blend.h"
|
||||||
#include "brightness_contrast.h"
|
|
||||||
#include "brush_select.h"
|
#include "brush_select.h"
|
||||||
#include "bucket_fill.h"
|
#include "bucket_fill.h"
|
||||||
#include "gimpbrushlist.h"
|
#include "gimpbrushlist.h"
|
||||||
|
@ -31,6 +30,7 @@
|
||||||
#include "channel_ops.h"
|
#include "channel_ops.h"
|
||||||
#include "clone.h"
|
#include "clone.h"
|
||||||
#include "color_balance.h"
|
#include "color_balance.h"
|
||||||
|
#include "color_cmds.h"
|
||||||
#include "color_picker.h"
|
#include "color_picker.h"
|
||||||
#include "convolve.h"
|
#include "convolve.h"
|
||||||
#include "crop.h"
|
#include "crop.h"
|
||||||
|
@ -51,14 +51,12 @@
|
||||||
#include "hue_saturation.h"
|
#include "hue_saturation.h"
|
||||||
#include "invert.h"
|
#include "invert.h"
|
||||||
#include "layer_cmds.h"
|
#include "layer_cmds.h"
|
||||||
#include "levels.h"
|
|
||||||
#include "internal_procs.h"
|
#include "internal_procs.h"
|
||||||
#include "paintbrush.h"
|
#include "paintbrush.h"
|
||||||
#include "patterns.h"
|
#include "patterns.h"
|
||||||
#include "pattern_select.h"
|
#include "pattern_select.h"
|
||||||
#include "pencil.h"
|
#include "pencil.h"
|
||||||
#include "perspective_tool.h"
|
#include "perspective_tool.h"
|
||||||
#include "posterize.h"
|
|
||||||
#include "rect_select.h"
|
#include "rect_select.h"
|
||||||
#include "rotate_tool.h"
|
#include "rotate_tool.h"
|
||||||
#include "scale_tool.h"
|
#include "scale_tool.h"
|
||||||
|
|
22
app/invert.c
22
app/invert.c
|
@ -24,6 +24,7 @@
|
||||||
#include "invert.h"
|
#include "invert.h"
|
||||||
#include "gimage.h"
|
#include "gimage.h"
|
||||||
#include "gimplut.h"
|
#include "gimplut.h"
|
||||||
|
#include "lut_funcs.h"
|
||||||
|
|
||||||
#include "libgimp/gimpintl.h"
|
#include "libgimp/gimpintl.h"
|
||||||
|
|
||||||
|
@ -58,18 +59,6 @@ image_invert (GImage *gimage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static float
|
|
||||||
invert_lut_func(void *unused,
|
|
||||||
int nchannels, int channel, float value)
|
|
||||||
{
|
|
||||||
/* don't invert the alpha channel */
|
|
||||||
if ((nchannels == 2 || nchannels == 4) && channel == nchannels -1)
|
|
||||||
return value;
|
|
||||||
|
|
||||||
return 1.0 - value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Inverter */
|
/* Inverter */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -79,10 +68,7 @@ invert (GimpDrawable *drawable)
|
||||||
int x1, y1, x2, y2;
|
int x1, y1, x2, y2;
|
||||||
GimpLut *lut;
|
GimpLut *lut;
|
||||||
|
|
||||||
lut = gimp_lut_new();
|
lut = invert_lut_new(gimp_drawable_bytes(drawable));
|
||||||
|
|
||||||
gimp_lut_setup_exact(lut, (GimpLutFunc) invert_lut_func,
|
|
||||||
(void *) NULL, gimp_drawable_bytes(drawable));
|
|
||||||
|
|
||||||
drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
|
drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
|
||||||
pixel_region_init (&srcPR, drawable_data (drawable), x1, y1, (x2 - x1), (y2 - y1), FALSE);
|
pixel_region_init (&srcPR, drawable_data (drawable), x1, y1, (x2 - x1), (y2 - y1), FALSE);
|
||||||
|
@ -97,8 +83,10 @@ invert (GimpDrawable *drawable)
|
||||||
drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1));
|
drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* ----------------- The invert procedure definition ---------------- */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
/* The invert procedure definition */
|
|
||||||
ProcArg invert_args[] =
|
ProcArg invert_args[] =
|
||||||
{
|
{
|
||||||
{ PDB_DRAWABLE,
|
{ PDB_DRAWABLE,
|
||||||
|
|
267
app/levels.c
267
app/levels.c
|
@ -31,6 +31,7 @@
|
||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
#include "levels.h"
|
#include "levels.h"
|
||||||
#include "gimplut.h"
|
#include "gimplut.h"
|
||||||
|
#include "lut_funcs.h"
|
||||||
|
|
||||||
#include "libgimp/gimpintl.h"
|
#include "libgimp/gimpintl.h"
|
||||||
|
|
||||||
|
@ -141,61 +142,6 @@ static gint levels_output_da_events (GtkWidget *, GdkEvent *,
|
||||||
|
|
||||||
static void levels_histogram_range (HistogramWidget *, int, int,
|
static void levels_histogram_range (HistogramWidget *, int, int,
|
||||||
void *);
|
void *);
|
||||||
static Argument * levels_invoker (Argument *);
|
|
||||||
|
|
||||||
|
|
||||||
/* levels machinery */
|
|
||||||
|
|
||||||
static float
|
|
||||||
levels_lut_func(LevelsDialog *ld,
|
|
||||||
int nchannels, int channel, float value)
|
|
||||||
{
|
|
||||||
double inten;
|
|
||||||
int j;
|
|
||||||
|
|
||||||
if (nchannels == 1)
|
|
||||||
j = 0;
|
|
||||||
else
|
|
||||||
j = channel + 1;
|
|
||||||
inten = value;
|
|
||||||
/* For color images this runs through the loop with j = channel +1
|
|
||||||
the first time and j = 0 the second time */
|
|
||||||
/* For bw images this runs through the loop with j = 0 the first and
|
|
||||||
only time */
|
|
||||||
for (; j >= 0; j -= (channel + 1))
|
|
||||||
{
|
|
||||||
/* don't apply the overall curve to the alpha channel */
|
|
||||||
if (j == 0 && (nchannels == 2 || nchannels == 4)
|
|
||||||
&& channel == nchannels -1)
|
|
||||||
return inten;
|
|
||||||
|
|
||||||
/* determine input intensity */
|
|
||||||
if (ld->high_input[j] != ld->low_input[j])
|
|
||||||
inten = (double) (255.0*inten - ld->low_input[j]) /
|
|
||||||
(double) (ld->high_input[j] - ld->low_input[j]);
|
|
||||||
else
|
|
||||||
inten = (double) (255.0*inten - ld->low_input[j]);
|
|
||||||
|
|
||||||
if (ld->gamma[j] != 0.0)
|
|
||||||
{
|
|
||||||
if (inten >= 0.0)
|
|
||||||
inten = pow ( inten, (1.0 / ld->gamma[j]));
|
|
||||||
else
|
|
||||||
inten = -pow (-inten, (1.0 / ld->gamma[j]));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* determine the output intensity */
|
|
||||||
if (ld->high_output[j] >= ld->low_output[j])
|
|
||||||
inten = (double) (inten * (ld->high_output[j] - ld->low_output[j]) +
|
|
||||||
ld->low_output[j]);
|
|
||||||
else if (ld->high_output[j] < ld->low_output[j])
|
|
||||||
inten = (double) (ld->low_output[j] - inten *
|
|
||||||
(ld->low_output[j] - ld->high_output[j]));
|
|
||||||
|
|
||||||
inten /= 255.0;
|
|
||||||
}
|
|
||||||
return inten;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
levels_histogram_range (HistogramWidget *h,
|
levels_histogram_range (HistogramWidget *h,
|
||||||
|
@ -715,8 +661,9 @@ levels_update (LevelsDialog *ld,
|
||||||
/* Recalculate the transfer arrays */
|
/* Recalculate the transfer arrays */
|
||||||
levels_calculate_transfers (ld);
|
levels_calculate_transfers (ld);
|
||||||
/* set up the lut */
|
/* set up the lut */
|
||||||
gimp_lut_setup(ld->lut, (GimpLutFunc) levels_lut_func,
|
levels_lut_setup(ld->lut, ld->gamma, ld->low_input, ld->high_input,
|
||||||
(void *) ld, gimp_drawable_bytes(ld->drawable));
|
ld->low_output, ld->high_output,
|
||||||
|
gimp_drawable_bytes(ld->drawable));
|
||||||
|
|
||||||
if (update & LOW_INPUT)
|
if (update & LOW_INPUT)
|
||||||
{
|
{
|
||||||
|
@ -1005,8 +952,9 @@ levels_ok_callback (GtkWidget *widget,
|
||||||
|
|
||||||
if (!ld->preview)
|
if (!ld->preview)
|
||||||
{
|
{
|
||||||
gimp_lut_setup(ld->lut, (GimpLutFunc) levels_lut_func,
|
levels_lut_setup(ld->lut, ld->gamma, ld->low_input, ld->high_input,
|
||||||
(void *) ld, gimp_drawable_bytes(ld->drawable));
|
ld->low_output, ld->high_output,
|
||||||
|
gimp_drawable_bytes(ld->drawable));
|
||||||
image_map_apply (ld->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
image_map_apply (ld->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
||||||
(void *) ld->lut);
|
(void *) ld->lut);
|
||||||
}
|
}
|
||||||
|
@ -1359,204 +1307,3 @@ levels_output_da_events (GtkWidget *widget,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* The levels procedure definition */
|
|
||||||
ProcArg levels_args[] =
|
|
||||||
{
|
|
||||||
{ PDB_DRAWABLE,
|
|
||||||
"drawable",
|
|
||||||
"the drawable"
|
|
||||||
},
|
|
||||||
{ PDB_INT32,
|
|
||||||
"channel",
|
|
||||||
"the channel to modify: { VALUE (0), RED (1), GREEN (2), BLUE (3), GRAY (0) }"
|
|
||||||
},
|
|
||||||
{ PDB_INT32,
|
|
||||||
"low_input",
|
|
||||||
"intensity of lowest input: (0 <= low_input <= 255)"
|
|
||||||
},
|
|
||||||
{ PDB_INT32,
|
|
||||||
"high_input",
|
|
||||||
"intensity of highest input: (0 <= high_input <= 255)"
|
|
||||||
},
|
|
||||||
{ PDB_FLOAT,
|
|
||||||
"gamma",
|
|
||||||
"gamma correction factor: (0.1 <= gamma <= 10)"
|
|
||||||
},
|
|
||||||
{ PDB_INT32,
|
|
||||||
"low_output",
|
|
||||||
"intensity of lowest output: (0 <= low_input <= 255)"
|
|
||||||
},
|
|
||||||
{ PDB_INT32,
|
|
||||||
"high_output",
|
|
||||||
"intensity of highest output: (0 <= high_input <= 255)"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ProcRecord levels_proc =
|
|
||||||
{
|
|
||||||
"gimp_levels",
|
|
||||||
"Modifies intensity levels in the specified drawable",
|
|
||||||
"This tool allows intensity levels in the specified drawable to be remapped according to a set of parameters. The low/high input levels specify an initial mapping from the source intensities. The gamma value determines how intensities between the low and high input intensities are interpolated. A gamma value of 1.0 results in a linear interpolation. Higher gamma values result in more high-level intensities. Lower gamma values result in more low-level intensities. The low/high output levels constrain the final intensity mapping--that is, no final intensity will be lower than the low output level and no final intensity will be higher than the high output level. This tool is only valid on RGB color and grayscale images. It will not operate on indexed drawables.",
|
|
||||||
"Spencer Kimball & Peter Mattis",
|
|
||||||
"Spencer Kimball & Peter Mattis",
|
|
||||||
"1995-1996",
|
|
||||||
PDB_INTERNAL,
|
|
||||||
|
|
||||||
/* Input arguments */
|
|
||||||
7,
|
|
||||||
levels_args,
|
|
||||||
|
|
||||||
/* Output arguments */
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
|
|
||||||
/* Exec method */
|
|
||||||
{ { levels_invoker } },
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static Argument *
|
|
||||||
levels_invoker (Argument *args)
|
|
||||||
{
|
|
||||||
PixelRegion srcPR, destPR;
|
|
||||||
int success = TRUE;
|
|
||||||
LevelsDialog ld;
|
|
||||||
GimpDrawable *drawable;
|
|
||||||
int channel;
|
|
||||||
int low_input;
|
|
||||||
int high_input;
|
|
||||||
double gamma;
|
|
||||||
int low_output;
|
|
||||||
int high_output;
|
|
||||||
int int_value;
|
|
||||||
double fp_value;
|
|
||||||
int x1, y1, x2, y2;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
drawable = NULL;
|
|
||||||
low_input = 0;
|
|
||||||
high_input = 0;
|
|
||||||
gamma = 1.0;
|
|
||||||
low_output = 0;
|
|
||||||
high_output = 0;
|
|
||||||
|
|
||||||
/* the drawable */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[0].value.pdb_int;
|
|
||||||
drawable = drawable_get_ID (int_value);
|
|
||||||
if (drawable == NULL)
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
/* make sure the drawable is not indexed color */
|
|
||||||
if (success)
|
|
||||||
success = ! drawable_indexed (drawable);
|
|
||||||
|
|
||||||
/* channel */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[1].value.pdb_int;
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
if (drawable_gray (drawable))
|
|
||||||
{
|
|
||||||
if (int_value != 0)
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
else if (drawable_color (drawable))
|
|
||||||
{
|
|
||||||
if (int_value < 0 || int_value > 3)
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
channel = int_value;
|
|
||||||
}
|
|
||||||
/* low input */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[2].value.pdb_int;
|
|
||||||
if (int_value >= 0 && int_value < 256)
|
|
||||||
low_input = int_value;
|
|
||||||
else
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
/* high input */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[3].value.pdb_int;
|
|
||||||
if (int_value >= 0 && int_value < 256)
|
|
||||||
high_input = int_value;
|
|
||||||
else
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
/* gamma */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
fp_value = args[4].value.pdb_float;
|
|
||||||
if (fp_value >= 0.1 && fp_value <= 10.0)
|
|
||||||
gamma = fp_value;
|
|
||||||
else
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
/* low output */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[5].value.pdb_int;
|
|
||||||
if (int_value >= 0 && int_value < 256)
|
|
||||||
low_output = int_value;
|
|
||||||
else
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
/* high output */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[6].value.pdb_int;
|
|
||||||
if (int_value >= 0 && int_value < 256)
|
|
||||||
high_output = int_value;
|
|
||||||
else
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* arrange to modify the levels */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
for (i = 0; i < 5; i++)
|
|
||||||
{
|
|
||||||
ld.low_input[i] = 0;
|
|
||||||
ld.gamma[i] = 1.0;
|
|
||||||
ld.high_input[i] = 255;
|
|
||||||
ld.low_output[i] = 0;
|
|
||||||
ld.high_output[i] = 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
ld.lut = gimp_lut_new();
|
|
||||||
ld.channel = channel;
|
|
||||||
ld.color = drawable_color (drawable);
|
|
||||||
ld.low_input[channel] = low_input;
|
|
||||||
ld.high_input[channel] = high_input;
|
|
||||||
ld.gamma[channel] = gamma;
|
|
||||||
ld.low_output[channel] = low_output;
|
|
||||||
ld.high_output[channel] = high_output;
|
|
||||||
|
|
||||||
/* setup the lut */
|
|
||||||
gimp_lut_setup(ld.lut, (GimpLutFunc) levels_lut_func,
|
|
||||||
(void *) &ld, gimp_drawable_bytes(drawable));
|
|
||||||
|
|
||||||
/* The application should occur only within selection bounds */
|
|
||||||
drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
|
|
||||||
|
|
||||||
pixel_region_init (&srcPR, drawable_data (drawable), x1, y1, (x2 - x1), (y2 - y1), FALSE);
|
|
||||||
pixel_region_init (&destPR, drawable_shadow (drawable), x1, y1, (x2 - x1), (y2 - y1), TRUE);
|
|
||||||
|
|
||||||
pixel_regions_process_parallel((p_func)gimp_lut_process, ld.lut,
|
|
||||||
2, &srcPR, &destPR);
|
|
||||||
|
|
||||||
gimp_lut_free(ld.lut);
|
|
||||||
drawable_merge_shadow (drawable, TRUE);
|
|
||||||
drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1));
|
|
||||||
}
|
|
||||||
|
|
||||||
return procedural_db_return_args (&levels_proc, success);
|
|
||||||
}
|
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#define __LEVELS_H__
|
#define __LEVELS_H__
|
||||||
|
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
#include "procedural_db.h"
|
|
||||||
|
|
||||||
/* hue-saturation functions */
|
/* hue-saturation functions */
|
||||||
Tool * tools_new_levels (void);
|
Tool * tools_new_levels (void);
|
||||||
|
@ -28,7 +27,4 @@ void tools_free_levels (Tool *);
|
||||||
void levels_initialize (GDisplay *);
|
void levels_initialize (GDisplay *);
|
||||||
void levels_free (void);
|
void levels_free (void);
|
||||||
|
|
||||||
/* Procedure definition and marshalling function */
|
|
||||||
extern ProcRecord levels_proc;
|
|
||||||
|
|
||||||
#endif /* __LEVELS_H__ */
|
#endif /* __LEVELS_H__ */
|
||||||
|
|
|
@ -0,0 +1,417 @@
|
||||||
|
/* The GIMP -- an image manipulation program
|
||||||
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "gimplut.h"
|
||||||
|
#include "gimphistogram.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
/* ---------- Brightness/Contrast -----------*/
|
||||||
|
|
||||||
|
typedef struct B_C_struct
|
||||||
|
{
|
||||||
|
double brightness;
|
||||||
|
double contrast;
|
||||||
|
} B_C_struct;
|
||||||
|
|
||||||
|
static float
|
||||||
|
brightness_contrast_lut_func(B_C_struct *data,
|
||||||
|
int nchannels, int channel, float value)
|
||||||
|
{
|
||||||
|
float nvalue;
|
||||||
|
double power;
|
||||||
|
|
||||||
|
/* return the original value for the alpha channel */
|
||||||
|
if ((nchannels == 2 || nchannels == 4) && channel == nchannels -1)
|
||||||
|
return value;
|
||||||
|
|
||||||
|
/* apply brightness */
|
||||||
|
if (data->brightness < 0.0)
|
||||||
|
value = value * (1.0 + data->brightness);
|
||||||
|
else
|
||||||
|
value = value + ((1.0 - value) * data->brightness);
|
||||||
|
|
||||||
|
/* apply contrast */
|
||||||
|
if (data->contrast < 0.0)
|
||||||
|
{
|
||||||
|
if (value > 0.5)
|
||||||
|
nvalue = 1.0 - value;
|
||||||
|
else
|
||||||
|
nvalue = value;
|
||||||
|
if (nvalue < 0.0)
|
||||||
|
nvalue = 0.0;
|
||||||
|
nvalue = 0.5 * pow (nvalue * 2.0 , (double) (1.0 + data->contrast));
|
||||||
|
if (value > 0.5)
|
||||||
|
value = 1.0 - nvalue;
|
||||||
|
else
|
||||||
|
value = nvalue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (value > 0.5)
|
||||||
|
nvalue = 1.0 - value;
|
||||||
|
else
|
||||||
|
nvalue = value;
|
||||||
|
if (nvalue < 0.0)
|
||||||
|
nvalue = 0.0;
|
||||||
|
power = (data->contrast == 1.0) ? 127 : 1.0 / (1.0 - data->contrast);
|
||||||
|
nvalue = 0.5 * pow (2.0 * nvalue, power);
|
||||||
|
if (value > 0.5)
|
||||||
|
value = 1.0 - nvalue;
|
||||||
|
else
|
||||||
|
value = nvalue;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
brightness_contrast_lut_setup(GimpLut *lut, double brightness, double contrast,
|
||||||
|
int nchannels)
|
||||||
|
{
|
||||||
|
B_C_struct data;
|
||||||
|
data.brightness = brightness;
|
||||||
|
data.contrast = contrast;
|
||||||
|
gimp_lut_setup(lut, (GimpLutFunc) brightness_contrast_lut_func,
|
||||||
|
(void *) &data, nchannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
GimpLut *
|
||||||
|
brightness_contrast_lut_new(double brightness, double contrast,
|
||||||
|
int nchannels)
|
||||||
|
{
|
||||||
|
GimpLut *lut;
|
||||||
|
lut = gimp_lut_new();
|
||||||
|
brightness_contrast_lut_setup(lut, brightness, contrast, nchannels);
|
||||||
|
return lut;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------- invert ------------------ */
|
||||||
|
|
||||||
|
static float
|
||||||
|
invert_lut_func(void *unused,
|
||||||
|
int nchannels, int channel, float value)
|
||||||
|
{
|
||||||
|
/* don't invert the alpha channel */
|
||||||
|
if ((nchannels == 2 || nchannels == 4) && channel == nchannels -1)
|
||||||
|
return value;
|
||||||
|
|
||||||
|
return 1.0 - value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
invert_lut_setup(GimpLut *lut, int nchannels)
|
||||||
|
{
|
||||||
|
gimp_lut_setup_exact(lut, (GimpLutFunc) invert_lut_func,
|
||||||
|
NULL , nchannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
GimpLut *
|
||||||
|
invert_lut_new(int nchannels)
|
||||||
|
{
|
||||||
|
GimpLut *lut;
|
||||||
|
lut = gimp_lut_new();
|
||||||
|
invert_lut_setup(lut, nchannels);
|
||||||
|
return lut;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------- add (or subract)------------------ */
|
||||||
|
|
||||||
|
static float
|
||||||
|
add_lut_func(double *ammount,
|
||||||
|
int nchannels, int channel, float value)
|
||||||
|
{
|
||||||
|
/* don't change the alpha channel */
|
||||||
|
if ((nchannels == 2 || nchannels == 4) && channel == nchannels -1)
|
||||||
|
return value;
|
||||||
|
|
||||||
|
return (value + *ammount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
add_lut_setup(GimpLut *lut, double ammount, int nchannels)
|
||||||
|
{
|
||||||
|
gimp_lut_setup(lut, (GimpLutFunc) add_lut_func,
|
||||||
|
(void *) &ammount , nchannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
GimpLut *
|
||||||
|
add_lut_new(double ammount, int nchannels)
|
||||||
|
{
|
||||||
|
GimpLut *lut;
|
||||||
|
lut = gimp_lut_new();
|
||||||
|
add_lut_setup(lut, ammount, nchannels);
|
||||||
|
return lut;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------- intersect (MINIMUM(pixel, value)) ------------------ */
|
||||||
|
|
||||||
|
static float
|
||||||
|
intersect_lut_func(double *min,
|
||||||
|
int nchannels, int channel, float value)
|
||||||
|
{
|
||||||
|
/* don't change the alpha channel */
|
||||||
|
if ((nchannels == 2 || nchannels == 4) && channel == nchannels -1)
|
||||||
|
return value;
|
||||||
|
|
||||||
|
return MIN(value, *min);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
intersect_lut_setup(GimpLut *lut, double value, int nchannels)
|
||||||
|
{
|
||||||
|
gimp_lut_setup_exact(lut, (GimpLutFunc) intersect_lut_func,
|
||||||
|
(void *) &value , nchannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
GimpLut *
|
||||||
|
intersect_lut_new(double value, int nchannels)
|
||||||
|
{
|
||||||
|
GimpLut *lut;
|
||||||
|
lut = gimp_lut_new();
|
||||||
|
intersect_lut_setup(lut, value, nchannels);
|
||||||
|
return lut;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------- Threshold ------------------ */
|
||||||
|
|
||||||
|
static float
|
||||||
|
threshold_lut_func(double *min,
|
||||||
|
int nchannels, int channel, float value)
|
||||||
|
{
|
||||||
|
/* don't change the alpha channel */
|
||||||
|
if ((nchannels == 2 || nchannels == 4) && channel == nchannels -1)
|
||||||
|
return value;
|
||||||
|
if (value < *min)
|
||||||
|
return 0.0;
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
threshold_lut_setup(GimpLut *lut, double value, int nchannels)
|
||||||
|
{
|
||||||
|
gimp_lut_setup_exact(lut, (GimpLutFunc) threshold_lut_func,
|
||||||
|
(void *) &value , nchannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
GimpLut *
|
||||||
|
threshold_lut_new(double value, int nchannels)
|
||||||
|
{
|
||||||
|
GimpLut *lut;
|
||||||
|
lut = gimp_lut_new();
|
||||||
|
threshold_lut_setup(lut, value, nchannels);
|
||||||
|
return lut;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------- levels ------------ */
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
double *gamma;
|
||||||
|
|
||||||
|
int *low_input;
|
||||||
|
int *high_input;
|
||||||
|
|
||||||
|
int *low_output;
|
||||||
|
int *high_output;
|
||||||
|
} levels_struct;
|
||||||
|
|
||||||
|
static float
|
||||||
|
levels_lut_func(levels_struct *data,
|
||||||
|
int nchannels, int channel, float value)
|
||||||
|
{
|
||||||
|
double inten;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
if (nchannels == 1)
|
||||||
|
j = 0;
|
||||||
|
else
|
||||||
|
j = channel + 1;
|
||||||
|
inten = value;
|
||||||
|
/* For color images this runs through the loop with j = channel +1
|
||||||
|
the first time and j = 0 the second time */
|
||||||
|
/* For bw images this runs through the loop with j = 0 the first and
|
||||||
|
only time */
|
||||||
|
for (; j >= 0; j -= (channel + 1))
|
||||||
|
{
|
||||||
|
/* don't apply the overall curve to the alpha channel */
|
||||||
|
if (j == 0 && (nchannels == 2 || nchannels == 4)
|
||||||
|
&& channel == nchannels -1)
|
||||||
|
return inten;
|
||||||
|
|
||||||
|
/* determine input intensity */
|
||||||
|
if (data->high_input[j] != data->low_input[j])
|
||||||
|
inten = (double) (255.0*inten - data->low_input[j]) /
|
||||||
|
(double) (data->high_input[j] - data->low_input[j]);
|
||||||
|
else
|
||||||
|
inten = (double) (255.0*inten - data->low_input[j]);
|
||||||
|
|
||||||
|
if (data->gamma[j] != 0.0)
|
||||||
|
{
|
||||||
|
if (inten >= 0.0)
|
||||||
|
inten = pow ( inten, (1.0 / data->gamma[j]));
|
||||||
|
else
|
||||||
|
inten = -pow (-inten, (1.0 / data->gamma[j]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* determine the output intensity */
|
||||||
|
if (data->high_output[j] >= data->low_output[j])
|
||||||
|
inten = (double) (inten * (data->high_output[j] - data->low_output[j]) +
|
||||||
|
data->low_output[j]);
|
||||||
|
else if (data->high_output[j] < data->low_output[j])
|
||||||
|
inten = (double) (data->low_output[j] - inten *
|
||||||
|
(data->low_output[j] - data->high_output[j]));
|
||||||
|
|
||||||
|
inten /= 255.0;
|
||||||
|
}
|
||||||
|
return inten;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
levels_lut_setup(GimpLut *lut, double *gamma, int *low_input, int *high_input,
|
||||||
|
int *low_output, int *high_output, int nchannels)
|
||||||
|
{
|
||||||
|
levels_struct data;
|
||||||
|
data.gamma = gamma;
|
||||||
|
data.low_input = low_input;
|
||||||
|
data.high_input = high_input;
|
||||||
|
data.low_output = low_output;
|
||||||
|
data.high_output = high_output;
|
||||||
|
gimp_lut_setup(lut, (GimpLutFunc) levels_lut_func,
|
||||||
|
(void *) &data, nchannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
GimpLut *
|
||||||
|
levels_lut_new(double *gamma, int *low_input, int *high_input,
|
||||||
|
int *low_output, int *high_output, int nchannels)
|
||||||
|
{
|
||||||
|
GimpLut *lut;
|
||||||
|
lut = gimp_lut_new();
|
||||||
|
levels_lut_setup(lut, gamma, low_input, high_input,
|
||||||
|
low_output, high_output, nchannels);
|
||||||
|
return lut;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------- posterize ---------------- */
|
||||||
|
|
||||||
|
static float
|
||||||
|
posterize_lut_func(int *ilevels,
|
||||||
|
int nchannels, int channel, float value)
|
||||||
|
{
|
||||||
|
int levels;
|
||||||
|
/* don't posterize the alpha channel */
|
||||||
|
if ((nchannels == 2 || nchannels == 4) && channel == nchannels -1)
|
||||||
|
return value;
|
||||||
|
|
||||||
|
if (*ilevels < 2)
|
||||||
|
levels = 2;
|
||||||
|
else
|
||||||
|
levels = *ilevels;
|
||||||
|
|
||||||
|
value = rint(value * (levels - 1.0)) / (levels - 1.0);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
posterize_lut_setup(GimpLut *lut, int levels, int nchannels)
|
||||||
|
{
|
||||||
|
gimp_lut_setup_exact(lut, (GimpLutFunc) posterize_lut_func,
|
||||||
|
(void *) &levels , nchannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
GimpLut *
|
||||||
|
posterize_lut_new(int levels, int nchannels)
|
||||||
|
{
|
||||||
|
GimpLut *lut;
|
||||||
|
lut = gimp_lut_new();
|
||||||
|
posterize_lut_setup(lut, levels, nchannels);
|
||||||
|
return lut;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------- equalize ------------- */
|
||||||
|
|
||||||
|
struct hist_lut_struct
|
||||||
|
{
|
||||||
|
GimpHistogram *histogram;
|
||||||
|
int part[5][257];
|
||||||
|
};
|
||||||
|
|
||||||
|
static float
|
||||||
|
equalize_lut_func(struct hist_lut_struct *hlut,
|
||||||
|
int nchannels, int channel, float value)
|
||||||
|
{
|
||||||
|
int i = 0, j;
|
||||||
|
j = (int)(value * 255.0 + 0.5);
|
||||||
|
while (hlut->part[channel][i + 1] <= j)
|
||||||
|
i++;
|
||||||
|
return i / 255.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
eq_histogram_lut_setup (GimpLut *lut, GimpHistogram *hist, int bytes)
|
||||||
|
{
|
||||||
|
int i, k, j;
|
||||||
|
struct hist_lut_struct hlut;
|
||||||
|
double pixels_per_value;
|
||||||
|
double desired;
|
||||||
|
double sum, dif;
|
||||||
|
|
||||||
|
/* Find partition points */
|
||||||
|
pixels_per_value = gimp_histogram_get_count(hist, 0, 255) / 256.0;
|
||||||
|
|
||||||
|
for (k = 0; k < bytes; k++)
|
||||||
|
{
|
||||||
|
/* First and last points in partition */
|
||||||
|
hlut.part[k][0] = 0;
|
||||||
|
hlut.part[k][256] = 256;
|
||||||
|
|
||||||
|
/* Find intermediate points */
|
||||||
|
j = 0;
|
||||||
|
sum = gimp_histogram_get_channel(hist, k, 0) +
|
||||||
|
gimp_histogram_get_channel(hist, k, 1);
|
||||||
|
for (i = 1; i < 256; i++)
|
||||||
|
{
|
||||||
|
desired = i * pixels_per_value;
|
||||||
|
while (sum <= desired)
|
||||||
|
{
|
||||||
|
j++;
|
||||||
|
sum += gimp_histogram_get_channel(hist, k, j + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Nearest sum */
|
||||||
|
dif = sum - gimp_histogram_get_channel(hist, k, j);
|
||||||
|
if ((sum - desired) > (dif / 2.0))
|
||||||
|
hlut.part[k][i] = j;
|
||||||
|
else
|
||||||
|
hlut.part[k][i] = j + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gimp_lut_setup(lut, (GimpLutFunc) equalize_lut_func,
|
||||||
|
(void *) &hlut, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
GimpLut *
|
||||||
|
eq_histogram_lut_new(GimpHistogram *h, int nchannels)
|
||||||
|
{
|
||||||
|
GimpLut *lut;
|
||||||
|
lut = gimp_lut_new();
|
||||||
|
eq_histogram_lut_setup(lut, h, nchannels);
|
||||||
|
return lut;
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/* The GIMP -- an image manipulation program
|
||||||
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LUT_FUNCS_H__
|
||||||
|
#define __LUT_FUNCS_H__
|
||||||
|
|
||||||
|
#include "gimplutF.h"
|
||||||
|
#include "gimphistogramF.h"
|
||||||
|
|
||||||
|
/* brightness contrast */
|
||||||
|
void brightness_contrast_lut_setup (GimpLut *lut,
|
||||||
|
double brightness, double contrast,
|
||||||
|
int nchannels);
|
||||||
|
GimpLut *brightness_contrast_lut_new (double brightness, double contrast,
|
||||||
|
int nchannels);
|
||||||
|
|
||||||
|
/* invert */
|
||||||
|
void invert_lut_setup (GimpLut *lut, int nchannels);
|
||||||
|
GimpLut *invert_lut_new (int nchannels);
|
||||||
|
|
||||||
|
/* add (or subtract) */
|
||||||
|
void add_lut_setup (GimpLut *lut, double ammount, int nchannels);
|
||||||
|
GimpLut *add_lut_new (double ammount, int nchannels);
|
||||||
|
|
||||||
|
/* intersect (MINIMUM(pixel, value)) */
|
||||||
|
void intersect_lut_setup (GimpLut *lut, double value, int nchannels);
|
||||||
|
GimpLut *intersect_lut_new (double value, int nchannels);
|
||||||
|
|
||||||
|
/* threshold */
|
||||||
|
void threshold_lut_setup (GimpLut *lut, double value, int nchannels);
|
||||||
|
GimpLut *threshold_lut_new (double value, int nchannels);
|
||||||
|
|
||||||
|
/* levels */
|
||||||
|
void levels_lut_setup (GimpLut *lut, double *gamma,
|
||||||
|
int *low_input, int *high_input,
|
||||||
|
int *low_output, int *high_output, int nchannels);
|
||||||
|
GimpLut *levels_lut_new (double *gamma, int *low_input, int *high_input,
|
||||||
|
int *low_output, int *high_output, int nchannels);
|
||||||
|
/* posterize */
|
||||||
|
void posterize_lut_setup (GimpLut *lut, int levels, int nchannels);
|
||||||
|
GimpLut *posterize_lut_new (int levels, int nchannels);
|
||||||
|
|
||||||
|
/* equalize histogram */
|
||||||
|
void eq_histogram_lut_setup (GimpLut *lut, GimpHistogram *hist, int bytes);
|
||||||
|
GimpLut *eq_histogram_lut_new (GimpHistogram *h, int nchannels);
|
||||||
|
|
||||||
|
#endif /* __LUT_FUNCS_H__ */
|
|
@ -214,6 +214,42 @@ parasite_list_find(ParasiteList *list, const char *name)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int saved_bytes;
|
||||||
|
|
||||||
|
static void
|
||||||
|
save_a_parasite(char *key, Parasite *p, FILE *fp)
|
||||||
|
{
|
||||||
|
if (parasite_is_persistent(p))
|
||||||
|
saved_bytes += parasite_save(p, fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
parasite_list_save(ParasiteList *list, FILE *fp)
|
||||||
|
{
|
||||||
|
guint32 num;
|
||||||
|
num = parasite_list_persistent_length (list);
|
||||||
|
num = GINT32_TO_BE(num);
|
||||||
|
fwrite(&num, 4, 1, fp);
|
||||||
|
saved_bytes = 4;
|
||||||
|
parasite_list_foreach(list, (GHFunc)save_a_parasite, fp);
|
||||||
|
return saved_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parasite_list_load(ParasiteList *list, FILE *fp)
|
||||||
|
{
|
||||||
|
Parasite *p;
|
||||||
|
guint32 num, version;
|
||||||
|
num = 0;
|
||||||
|
fread(&num, 4, 1, fp);
|
||||||
|
num = GINT32_FROM_BE(num);
|
||||||
|
while (num--)
|
||||||
|
{
|
||||||
|
p = parasite_load(fp);
|
||||||
|
parasite_list_add(list, p);
|
||||||
|
parasite_free(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
parasite_shift_parent(Parasite *p)
|
parasite_shift_parent(Parasite *p)
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#define __PARASITE_LIST_H__
|
#define __PARASITE_LIST_H__
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include "libgimp/parasiteF.h"
|
#include "libgimp/parasiteF.h"
|
||||||
#include "parasitelistF.h"
|
#include "parasitelistF.h"
|
||||||
#include "gimpobject.h"
|
#include "gimpobject.h"
|
||||||
|
@ -46,6 +47,8 @@ void parasite_list_foreach (ParasiteList *list, GHFunc function,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
Parasite *parasite_list_find (ParasiteList *list, const char *name);
|
Parasite *parasite_list_find (ParasiteList *list, const char *name);
|
||||||
|
|
||||||
|
int parasite_list_save (ParasiteList *list, FILE *fp);
|
||||||
|
void parasite_list_load (ParasiteList *list, FILE *fp);
|
||||||
void parasite_shift_parent (Parasite *p);
|
void parasite_shift_parent (Parasite *p);
|
||||||
|
|
||||||
#endif /* __GIMP_PARASITE_H__ */
|
#endif /* __GIMP_PARASITE_H__ */
|
||||||
|
|
|
@ -0,0 +1,292 @@
|
||||||
|
/* The GIMP -- an image manipulation program
|
||||||
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||||
|
*
|
||||||
|
* pixel_processor.c: Copyright (C) 1999 Jay Cox <jaycox@earthlink.net>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../config.h"
|
||||||
|
#include "pixel_processor.h"
|
||||||
|
#include "pixel_region.h"
|
||||||
|
#include "gimprc.h"
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifdef ENABLE_MP
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#define IF_THREAD(statement) statement
|
||||||
|
|
||||||
|
#else /* !USE_PTHREADS */
|
||||||
|
|
||||||
|
#define IF_THREAD(statement)
|
||||||
|
|
||||||
|
#endif /* !USE_PTHREADS */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef void (*p1_func)(void *, PixelRegion *);
|
||||||
|
typedef void (*p2_func)(void *, PixelRegion * ,PixelRegion *);
|
||||||
|
typedef void (*p3_func)(void *, PixelRegion * ,PixelRegion *, PixelRegion *);
|
||||||
|
typedef void (*p4_func)(void *, PixelRegion * ,PixelRegion *, PixelRegion *,
|
||||||
|
PixelRegion *);
|
||||||
|
|
||||||
|
typedef struct _PixelRegionIterator PixelRegionIterator;
|
||||||
|
|
||||||
|
struct _PixelProcessor
|
||||||
|
{
|
||||||
|
void *data;
|
||||||
|
p_func f;
|
||||||
|
PixelRegionIterator *PRI;
|
||||||
|
IF_THREAD(pthread_mutex_t mutex;)
|
||||||
|
int nthreads;
|
||||||
|
int n_regions;
|
||||||
|
PixelRegion *r[4];
|
||||||
|
|
||||||
|
void *progress_report_data;
|
||||||
|
ProgressReportFunc progress_report_func;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void *
|
||||||
|
do_parallel_regions(PixelProcessor *p_s)
|
||||||
|
{
|
||||||
|
PixelRegion tr[4];
|
||||||
|
int ntiles = 0;
|
||||||
|
int i;
|
||||||
|
int cont = 1;
|
||||||
|
|
||||||
|
IF_THREAD(pthread_mutex_lock(&p_s->mutex);)
|
||||||
|
if (p_s->nthreads != 0 && p_s->PRI)
|
||||||
|
p_s->PRI = (PixelRegionIterator*)pixel_regions_process(p_s->PRI);
|
||||||
|
if (p_s->PRI == NULL)
|
||||||
|
{
|
||||||
|
IF_THREAD(pthread_mutex_unlock(&p_s->mutex);)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
p_s->nthreads++;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
for (i = 0; i < p_s->n_regions; i++)
|
||||||
|
if (p_s->r[i])
|
||||||
|
memcpy(&tr[i], p_s->r[i], sizeof(PixelRegion));
|
||||||
|
IF_THREAD(pthread_mutex_unlock(&p_s->mutex);)
|
||||||
|
ntiles++;
|
||||||
|
switch(p_s->n_regions)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
((p1_func)p_s->f)(p_s->data,
|
||||||
|
p_s->r[0] ? &tr[0] : NULL);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
((p2_func)p_s->f)(p_s->data,
|
||||||
|
p_s->r[0] ? &tr[0] : NULL,
|
||||||
|
p_s->r[1] ? &tr[1] : NULL);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
((p3_func)p_s->f)(p_s->data,
|
||||||
|
p_s->r[0] ? &tr[0] : NULL,
|
||||||
|
p_s->r[1] ? &tr[1] : NULL,
|
||||||
|
p_s->r[2] ? &tr[2] : NULL);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
((p4_func)p_s->f)(p_s->data,
|
||||||
|
p_s->r[0] ? &tr[0] : NULL,
|
||||||
|
p_s->r[1] ? &tr[1] : NULL,
|
||||||
|
p_s->r[2] ? &tr[2] : NULL,
|
||||||
|
p_s->r[3] ? &tr[3] : NULL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_message("do_parallel_regions: Bad number of regions %d\n",
|
||||||
|
p_s->n_regions);
|
||||||
|
}
|
||||||
|
IF_THREAD(pthread_mutex_lock(&p_s->mutex);)
|
||||||
|
if (p_s->progress_report_func)
|
||||||
|
if (!p_s->progress_report_func(p_s->progress_report_data,
|
||||||
|
p_s->r[0]->x, p_s->r[0]->y,
|
||||||
|
p_s->r[0]->w, p_s->r[0]->h))
|
||||||
|
cont = 0;
|
||||||
|
} while (cont && p_s->PRI &&
|
||||||
|
(p_s->PRI = (PixelRegionIterator*)pixel_regions_process(p_s->PRI)));
|
||||||
|
p_s->nthreads--;
|
||||||
|
/* fprintf(stderr, "processed %d tiles\n", ntiles); */
|
||||||
|
IF_THREAD(pthread_mutex_unlock(&p_s->mutex);)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX_THREADS 30
|
||||||
|
|
||||||
|
static void
|
||||||
|
pixel_regions_do_parallel(PixelProcessor *p_s)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
IF_THREAD(int nthreads;)
|
||||||
|
IF_THREAD(pthread_t threads[MAX_THREADS];)
|
||||||
|
IF_THREAD(pthread_attr_t pthread_attr;)
|
||||||
|
|
||||||
|
/* (p_s->PRI->region_width * p_s->PRI->region_height) /(64*64)); */
|
||||||
|
IF_THREAD(
|
||||||
|
nthreads = MIN(num_processors, 5);
|
||||||
|
if (nthreads > 1)
|
||||||
|
{
|
||||||
|
pthread_attr_init (&pthread_attr);
|
||||||
|
for (i = 0; i < nthreads; i++)
|
||||||
|
{
|
||||||
|
pthread_create (&threads[i], &pthread_attr,
|
||||||
|
(void *(*)(void *)) do_parallel_regions,
|
||||||
|
p_s);
|
||||||
|
}
|
||||||
|
for (i = 0; i < nthreads; i++)
|
||||||
|
{
|
||||||
|
pthread_join(threads[i], NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
)
|
||||||
|
do_parallel_regions(p_s);
|
||||||
|
if (p_s->nthreads != 0)
|
||||||
|
fprintf(stderr, "Ack, we lost a thread\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static PixelProcessor *
|
||||||
|
pixel_regions_real_process_parallel(p_func f, void *data,
|
||||||
|
ProgressReportFunc report_func,
|
||||||
|
void *report_data,
|
||||||
|
int num_regions, va_list ap)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
PixelProcessor *p_s;
|
||||||
|
|
||||||
|
|
||||||
|
p_s = g_new(PixelProcessor, 200);
|
||||||
|
|
||||||
|
|
||||||
|
for (i = 0; i < num_regions; i++)
|
||||||
|
p_s->r[i] = va_arg (ap, PixelRegion *);
|
||||||
|
|
||||||
|
switch(num_regions)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
p_s->PRI = (PixelRegionIterator *) pixel_regions_register(num_regions,
|
||||||
|
p_s->r[0]);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
p_s->PRI = (PixelRegionIterator *) pixel_regions_register(num_regions,
|
||||||
|
p_s->r[0],
|
||||||
|
p_s->r[1]);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
p_s->PRI = (PixelRegionIterator *) pixel_regions_register(num_regions,
|
||||||
|
p_s->r[0],
|
||||||
|
p_s->r[1],
|
||||||
|
p_s->r[2]);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
p_s->PRI = (PixelRegionIterator *) pixel_regions_register(num_regions,
|
||||||
|
p_s->r[0],
|
||||||
|
p_s->r[1],
|
||||||
|
p_s->r[2],
|
||||||
|
p_s->r[3]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_message("pixel_regions_real_process_parallel: Bad number of regions %d\n",
|
||||||
|
p_s->n_regions);
|
||||||
|
}
|
||||||
|
if (!p_s->PRI)
|
||||||
|
{
|
||||||
|
pixel_processor_free(p_s);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
p_s->f = f;
|
||||||
|
p_s->data = data;
|
||||||
|
p_s->n_regions = num_regions;
|
||||||
|
IF_THREAD(pthread_mutex_init(&(p_s->mutex), NULL);)
|
||||||
|
p_s->nthreads = 0;
|
||||||
|
|
||||||
|
p_s->progress_report_data = report_data;
|
||||||
|
p_s->progress_report_func = report_func;
|
||||||
|
|
||||||
|
|
||||||
|
pixel_regions_do_parallel(p_s);
|
||||||
|
|
||||||
|
if (p_s->PRI)
|
||||||
|
return p_s;
|
||||||
|
pixel_processor_free (p_s);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pixel_regions_process_parallel(p_func f, void *data, int num_regions, ...)
|
||||||
|
{
|
||||||
|
va_list va;
|
||||||
|
va_start (va, num_regions);
|
||||||
|
|
||||||
|
pixel_regions_real_process_parallel(f, data, NULL, NULL, num_regions, va);
|
||||||
|
|
||||||
|
va_end (va);
|
||||||
|
}
|
||||||
|
|
||||||
|
PixelProcessor *
|
||||||
|
pixel_regions_process_parallel_progress(p_func f, void *data,
|
||||||
|
ProgressReportFunc progress_func,
|
||||||
|
void *progress_data, int num_regions,
|
||||||
|
...)
|
||||||
|
{
|
||||||
|
PixelProcessor *ret;
|
||||||
|
va_list va;
|
||||||
|
va_start (va, num_regions);
|
||||||
|
|
||||||
|
ret = pixel_regions_real_process_parallel(f, data,
|
||||||
|
progress_func, progress_data,
|
||||||
|
num_regions, va);
|
||||||
|
|
||||||
|
va_end (va);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pixel_processor_stop(PixelProcessor *pp)
|
||||||
|
{
|
||||||
|
if (!pp)
|
||||||
|
return;
|
||||||
|
if (pp->PRI)
|
||||||
|
{
|
||||||
|
pixel_regions_process_stop (pp->PRI);
|
||||||
|
pp->PRI = NULL;
|
||||||
|
}
|
||||||
|
pixel_processor_free(pp);
|
||||||
|
}
|
||||||
|
|
||||||
|
PixelProcessor *
|
||||||
|
pixel_processor_cont(PixelProcessor *pp)
|
||||||
|
{
|
||||||
|
pixel_regions_do_parallel(pp);
|
||||||
|
if (pp->PRI)
|
||||||
|
return pp;
|
||||||
|
pixel_processor_free (pp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pixel_processor_free (PixelProcessor *pp)
|
||||||
|
{
|
||||||
|
if (pp->PRI)
|
||||||
|
pixel_processor_stop(pp);
|
||||||
|
else
|
||||||
|
g_free(pp);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
/* The GIMP -- an image manipulation program
|
||||||
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||||
|
*
|
||||||
|
* pixel_processor.h: Copyright (C) 1999 Jay Cox <jaycox@earthlink.net>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PIXEL_PROCESSOR_H__
|
||||||
|
#define __PIXEL_PROCESSOR_H__
|
||||||
|
|
||||||
|
typedef struct _PixelProcessor PixelProcessor;
|
||||||
|
|
||||||
|
typedef void (*p_func)(void);
|
||||||
|
typedef int (*ProgressReportFunc)(void *, int, int, int, int);
|
||||||
|
|
||||||
|
void pixel_regions_process_parallel (p_func f, void *data, int num_regions,
|
||||||
|
...);
|
||||||
|
PixelProcessor *pixel_process_progress (p_func f, void *data,
|
||||||
|
ProgressReportFunc progress_func,
|
||||||
|
void *progress_data,
|
||||||
|
int num_regions, ...);
|
||||||
|
|
||||||
|
void pixel_processor_free (PixelProcessor *);
|
||||||
|
void pixel_processor_stop (PixelProcessor *);
|
||||||
|
PixelProcessor *pixel_processor_cont (PixelProcessor *);
|
||||||
|
|
||||||
|
#endif /* __PIXEL_PROCESSOR_H__ */
|
|
@ -26,18 +26,6 @@
|
||||||
#include "tile_manager_pvt.h"
|
#include "tile_manager_pvt.h"
|
||||||
#include "tile.h" /* ick. */
|
#include "tile.h" /* ick. */
|
||||||
|
|
||||||
#ifdef ENABLE_MP
|
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
#define IF_THREAD(statement) statement
|
|
||||||
|
|
||||||
#else /* !USE_PTHREADS */
|
|
||||||
|
|
||||||
#define IF_THREAD(statement)
|
|
||||||
|
|
||||||
#endif /* !USE_PTHREADS */
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct _PixelRegionHolder PixelRegionHolder;
|
typedef struct _PixelRegionHolder PixelRegionHolder;
|
||||||
|
|
||||||
|
@ -303,159 +291,6 @@ pixel_region_set_col (PR, x, y, h, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef void (*p1_func)(void *, PixelRegion *);
|
|
||||||
typedef void (*p2_func)(void *, PixelRegion * ,PixelRegion *);
|
|
||||||
typedef void (*p3_func)(void *, PixelRegion * ,PixelRegion *, PixelRegion *);
|
|
||||||
typedef void (*p4_func)(void *, PixelRegion * ,PixelRegion *, PixelRegion *,
|
|
||||||
PixelRegion *);
|
|
||||||
|
|
||||||
struct parallel_struct
|
|
||||||
{
|
|
||||||
void *data;
|
|
||||||
p_func f;
|
|
||||||
PixelRegionIterator *PRI;
|
|
||||||
IF_THREAD(pthread_mutex_t mutex;)
|
|
||||||
int nthreads;
|
|
||||||
int n_regions;
|
|
||||||
PixelRegion *r[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
static void *
|
|
||||||
do_parallel_regions(struct parallel_struct *p_s)
|
|
||||||
{
|
|
||||||
PixelRegion tr[4];
|
|
||||||
int ntiles = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
IF_THREAD(pthread_mutex_lock(&p_s->mutex);)
|
|
||||||
if (p_s->nthreads != 0 && p_s->PRI)
|
|
||||||
p_s->PRI = (PixelRegionIterator*)pixel_regions_process(p_s->PRI);
|
|
||||||
if (p_s->PRI == NULL)
|
|
||||||
{
|
|
||||||
IF_THREAD(pthread_mutex_unlock(&p_s->mutex);)
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
p_s->nthreads++;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
for (i = 0; i < p_s->n_regions; i++)
|
|
||||||
if (p_s->r[i])
|
|
||||||
memcpy(&tr[i], p_s->r[i], sizeof(PixelRegion));
|
|
||||||
IF_THREAD(pthread_mutex_unlock(&p_s->mutex);)
|
|
||||||
ntiles++;
|
|
||||||
switch(p_s->n_regions)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
((p1_func)p_s->f)(p_s->data,
|
|
||||||
p_s->r[0] ? &tr[0] : NULL);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
((p2_func)p_s->f)(p_s->data,
|
|
||||||
p_s->r[0] ? &tr[0] : NULL,
|
|
||||||
p_s->r[1] ? &tr[1] : NULL);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
((p3_func)p_s->f)(p_s->data,
|
|
||||||
p_s->r[0] ? &tr[0] : NULL,
|
|
||||||
p_s->r[1] ? &tr[1] : NULL,
|
|
||||||
p_s->r[2] ? &tr[2] : NULL);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
((p4_func)p_s->f)(p_s->data,
|
|
||||||
p_s->r[0] ? &tr[0] : NULL,
|
|
||||||
p_s->r[1] ? &tr[1] : NULL,
|
|
||||||
p_s->r[2] ? &tr[2] : NULL,
|
|
||||||
p_s->r[3] ? &tr[3] : NULL);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
g_message("do_parallel_regions: Bad number of regions %d\n",
|
|
||||||
p_s->n_regions);
|
|
||||||
}
|
|
||||||
IF_THREAD(pthread_mutex_lock(&p_s->mutex);)
|
|
||||||
} while (p_s->PRI && (p_s->PRI = (PixelRegionIterator*)pixel_regions_process(p_s->PRI)));
|
|
||||||
p_s->nthreads--;
|
|
||||||
/* fprintf(stderr, "processed %d tiles\n", ntiles); */
|
|
||||||
IF_THREAD(pthread_mutex_unlock(&p_s->mutex);)
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MAX_THREADS 30
|
|
||||||
|
|
||||||
void pixel_regions_process_parallel(p_func f, void *data, int num_regions, ...)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
struct parallel_struct p_s;
|
|
||||||
IF_THREAD(pthread_t threads[MAX_THREADS];)
|
|
||||||
IF_THREAD(pthread_attr_t pthread_attr;)
|
|
||||||
IF_THREAD(int nthreads;)
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start (ap, num_regions);
|
|
||||||
for (i = 0; i < num_regions; i++)
|
|
||||||
p_s.r[i] = va_arg (ap, PixelRegion *);
|
|
||||||
va_end (ap);
|
|
||||||
|
|
||||||
switch(num_regions)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
p_s.PRI = (PixelRegionIterator *) pixel_regions_register(num_regions,
|
|
||||||
p_s.r[0]);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
p_s.PRI = (PixelRegionIterator *) pixel_regions_register(num_regions,
|
|
||||||
p_s.r[0],
|
|
||||||
p_s.r[1]);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
p_s.PRI = (PixelRegionIterator *) pixel_regions_register(num_regions,
|
|
||||||
p_s.r[0],
|
|
||||||
p_s.r[1],
|
|
||||||
p_s.r[2]);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
p_s.PRI = (PixelRegionIterator *) pixel_regions_register(num_regions,
|
|
||||||
p_s.r[0],
|
|
||||||
p_s.r[1],
|
|
||||||
p_s.r[2],
|
|
||||||
p_s.r[3]);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
g_message("pixel_regions_process_parallel: Bad number of regions %d\n",
|
|
||||||
p_s.n_regions);
|
|
||||||
}
|
|
||||||
if (!p_s.PRI)
|
|
||||||
return;
|
|
||||||
p_s.f = f;
|
|
||||||
p_s.data = data;
|
|
||||||
p_s.n_regions = num_regions;
|
|
||||||
IF_THREAD(pthread_mutex_init(&p_s.mutex, NULL);)
|
|
||||||
p_s.nthreads = 0;
|
|
||||||
|
|
||||||
IF_THREAD(
|
|
||||||
nthreads = MIN(num_processors,
|
|
||||||
(p_s.PRI->region_width * p_s.PRI->region_height) /(64*64));
|
|
||||||
if (nthreads > 1)
|
|
||||||
{
|
|
||||||
pthread_attr_init (&pthread_attr);
|
|
||||||
for (i = 0; i < nthreads; i++)
|
|
||||||
{
|
|
||||||
pthread_create (&threads[i], &pthread_attr,
|
|
||||||
(void *(*)(void *)) do_parallel_regions,
|
|
||||||
&p_s);
|
|
||||||
}
|
|
||||||
for (i = 0; i < nthreads; i++)
|
|
||||||
{
|
|
||||||
pthread_join(threads[i], NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
)
|
|
||||||
do_parallel_regions(&p_s);
|
|
||||||
if (p_s.nthreads != 0)
|
|
||||||
fprintf(stderr, "Ack, we've lost a thread.");
|
|
||||||
}
|
|
||||||
|
|
||||||
void *
|
void *
|
||||||
pixel_regions_register (int num_regions, ...)
|
pixel_regions_register (int num_regions, ...)
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#define __PIXEL_REGION_H__
|
#define __PIXEL_REGION_H__
|
||||||
|
|
||||||
#include "tile_manager.h"
|
#include "tile_manager.h"
|
||||||
|
#include "pixel_processor.h" /* this is temporary, */
|
||||||
|
|
||||||
typedef struct _PixelRegion PixelRegion;
|
typedef struct _PixelRegion PixelRegion;
|
||||||
|
|
||||||
|
@ -36,7 +37,6 @@ struct _PixelRegion
|
||||||
int process_count; /* used internally */
|
int process_count; /* used internally */
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void (*p_func)(void);
|
|
||||||
|
|
||||||
/* PixelRegion functions */
|
/* PixelRegion functions */
|
||||||
void pixel_region_init (PixelRegion *, TileManager *, int, int, int, int, int);
|
void pixel_region_init (PixelRegion *, TileManager *, int, int, int, int, int);
|
||||||
|
@ -48,8 +48,6 @@ void pixel_region_set_row (PixelRegion *, int, int, int, unsigned char *)
|
||||||
void pixel_region_get_col (PixelRegion *, int, int, int, unsigned char *, int);
|
void pixel_region_get_col (PixelRegion *, int, int, int, unsigned char *, int);
|
||||||
void pixel_region_set_col (PixelRegion *, int, int, int, unsigned char *);
|
void pixel_region_set_col (PixelRegion *, int, int, int, unsigned char *);
|
||||||
void *pixel_regions_register (int, ...);
|
void *pixel_regions_register (int, ...);
|
||||||
void pixel_regions_process_parallel (p_func f, void *data, int num_regions,
|
|
||||||
...);
|
|
||||||
void *pixel_regions_process (void *);
|
void *pixel_regions_process (void *);
|
||||||
void pixel_regions_process_stop (void *);
|
void pixel_regions_process_stop (void *);
|
||||||
|
|
||||||
|
|
128
app/posterize.c
128
app/posterize.c
|
@ -34,6 +34,7 @@
|
||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
#include "posterize.h"
|
#include "posterize.h"
|
||||||
#include "gimplut.h"
|
#include "gimplut.h"
|
||||||
|
#include "lut_funcs.h"
|
||||||
|
|
||||||
#include "libgimp/gimpintl.h"
|
#include "libgimp/gimpintl.h"
|
||||||
|
|
||||||
|
@ -84,29 +85,6 @@ static void posterize_preview_update (GtkWidget *, gpointer);
|
||||||
static void posterize_levels_text_update (GtkWidget *, gpointer);
|
static void posterize_levels_text_update (GtkWidget *, gpointer);
|
||||||
static gint posterize_delete_callback (GtkWidget *, GdkEvent *, gpointer);
|
static gint posterize_delete_callback (GtkWidget *, GdkEvent *, gpointer);
|
||||||
|
|
||||||
static Argument * posterize_invoker (Argument *);
|
|
||||||
|
|
||||||
|
|
||||||
/* posterize machinery */
|
|
||||||
|
|
||||||
static float
|
|
||||||
posterize_lut_func(PosterizeDialog *pd,
|
|
||||||
int nchannels, int channel, float value)
|
|
||||||
{
|
|
||||||
int levels;
|
|
||||||
/* don't posterize the alpha channel */
|
|
||||||
if ((nchannels == 2 || nchannels == 4) && channel == nchannels -1)
|
|
||||||
return value;
|
|
||||||
|
|
||||||
if (pd->levels < 2)
|
|
||||||
levels = 2;
|
|
||||||
else
|
|
||||||
levels = pd->levels;
|
|
||||||
|
|
||||||
value = rint(value * (pd->levels - 1.0)) / (pd->levels - 1.0);
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* by_color select action functions */
|
/* by_color select action functions */
|
||||||
|
|
||||||
|
@ -343,8 +321,7 @@ posterize_preview (PosterizeDialog *pd)
|
||||||
if (!pd->image_map)
|
if (!pd->image_map)
|
||||||
g_message (_("posterize_preview(): No image map"));
|
g_message (_("posterize_preview(): No image map"));
|
||||||
active_tool->preserve = TRUE;
|
active_tool->preserve = TRUE;
|
||||||
gimp_lut_setup_exact(pd->lut, (GimpLutFunc) posterize_lut_func,
|
posterize_lut_setup(pd->lut, pd->levels, gimp_drawable_bytes(pd->drawable));
|
||||||
(void *) pd, gimp_drawable_bytes(pd->drawable));
|
|
||||||
image_map_apply (pd->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
image_map_apply (pd->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
||||||
(void *) pd->lut);
|
(void *) pd->lut);
|
||||||
active_tool->preserve = FALSE;
|
active_tool->preserve = FALSE;
|
||||||
|
@ -365,8 +342,8 @@ posterize_ok_callback (GtkWidget *widget,
|
||||||
|
|
||||||
if (!pd->preview)
|
if (!pd->preview)
|
||||||
{
|
{
|
||||||
gimp_lut_setup_exact(pd->lut, (GimpLutFunc) posterize_lut_func,
|
posterize_lut_setup(pd->lut, pd->levels,
|
||||||
(void *) pd, gimp_drawable_bytes(pd->drawable));
|
gimp_drawable_bytes(pd->drawable));
|
||||||
image_map_apply (pd->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
image_map_apply (pd->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
||||||
(void *) pd->lut);
|
(void *) pd->lut);
|
||||||
}
|
}
|
||||||
|
@ -444,100 +421,3 @@ posterize_levels_text_update (GtkWidget *w,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* The posterize procedure definition */
|
|
||||||
ProcArg posterize_args[] =
|
|
||||||
{
|
|
||||||
{ PDB_DRAWABLE,
|
|
||||||
"drawable",
|
|
||||||
"the drawable"
|
|
||||||
},
|
|
||||||
{ PDB_INT32,
|
|
||||||
"levels",
|
|
||||||
"levels of posterization: (2 <= levels <= 255)"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ProcRecord posterize_proc =
|
|
||||||
{
|
|
||||||
"gimp_posterize",
|
|
||||||
"Posterize the specified drawable",
|
|
||||||
"This procedures reduces the number of shades allows in each intensity channel to the specified 'levels' parameter.",
|
|
||||||
"Spencer Kimball & Peter Mattis",
|
|
||||||
"Spencer Kimball & Peter Mattis",
|
|
||||||
"1997",
|
|
||||||
PDB_INTERNAL,
|
|
||||||
|
|
||||||
/* Input arguments */
|
|
||||||
2,
|
|
||||||
posterize_args,
|
|
||||||
|
|
||||||
/* Output arguments */
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
|
|
||||||
/* Exec method */
|
|
||||||
{ { posterize_invoker } },
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static Argument *
|
|
||||||
posterize_invoker (Argument *args)
|
|
||||||
{
|
|
||||||
PixelRegion srcPR, destPR;
|
|
||||||
int success = TRUE;
|
|
||||||
PosterizeDialog pd;
|
|
||||||
GImage *gimage;
|
|
||||||
GimpDrawable *drawable;
|
|
||||||
int levels;
|
|
||||||
int int_value;
|
|
||||||
int x1, y1, x2, y2;
|
|
||||||
|
|
||||||
drawable = NULL;
|
|
||||||
levels = 0;
|
|
||||||
|
|
||||||
/* the drawable */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[0].value.pdb_int;
|
|
||||||
drawable = drawable_get_ID (int_value);
|
|
||||||
if (drawable == NULL)
|
|
||||||
success = FALSE;
|
|
||||||
else
|
|
||||||
gimage = drawable_gimage (drawable);
|
|
||||||
}
|
|
||||||
/* make sure the drawable is not indexed color */
|
|
||||||
if (success)
|
|
||||||
success = ! drawable_indexed (drawable);
|
|
||||||
|
|
||||||
/* levels */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[1].value.pdb_int;
|
|
||||||
if (int_value >= 2 && int_value < 256)
|
|
||||||
levels = int_value;
|
|
||||||
else
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* arrange to modify the levels */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
pd.levels = levels;
|
|
||||||
pd.lut = gimp_lut_new();
|
|
||||||
/* The application should occur only within selection bounds */
|
|
||||||
drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
|
|
||||||
|
|
||||||
pixel_region_init (&srcPR, drawable_data (drawable), x1, y1, (x2 - x1), (y2 - y1), FALSE);
|
|
||||||
pixel_region_init (&destPR, drawable_shadow (drawable), x1, y1, (x2 - x1), (y2 - y1), TRUE);
|
|
||||||
|
|
||||||
pixel_regions_process_parallel((p_func)gimp_lut_process, pd.lut,
|
|
||||||
2, &srcPR, &destPR);
|
|
||||||
|
|
||||||
gimp_lut_free(pd.lut);
|
|
||||||
drawable_merge_shadow (drawable, TRUE);
|
|
||||||
drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1));
|
|
||||||
}
|
|
||||||
|
|
||||||
return procedural_db_return_args (&posterize_proc, success);
|
|
||||||
}
|
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#define __POSTERIZE_H__
|
#define __POSTERIZE_H__
|
||||||
|
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
#include "procedural_db.h"
|
|
||||||
|
|
||||||
/* by_color select functions */
|
/* by_color select functions */
|
||||||
Tool * tools_new_posterize (void);
|
Tool * tools_new_posterize (void);
|
||||||
|
@ -27,7 +26,4 @@ void tools_free_posterize (Tool *);
|
||||||
|
|
||||||
void posterize_initialize (GDisplay *);
|
void posterize_initialize (GDisplay *);
|
||||||
|
|
||||||
/* Procedure definition and marshalling function */
|
|
||||||
extern ProcRecord posterize_proc;
|
|
||||||
|
|
||||||
#endif /* __POSTERIZE_H__ */
|
#endif /* __POSTERIZE_H__ */
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "image_map.h"
|
#include "image_map.h"
|
||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
#include "gimplut.h"
|
#include "gimplut.h"
|
||||||
|
#include "lut_funcs.h"
|
||||||
|
|
||||||
#include "libgimp/gimpintl.h"
|
#include "libgimp/gimpintl.h"
|
||||||
|
|
||||||
|
@ -94,59 +95,6 @@ static void brightness_contrast_contrast_text_update (GtkWidget *, gpointer
|
||||||
static void *brightness_contrast_options = NULL;
|
static void *brightness_contrast_options = NULL;
|
||||||
static BrightnessContrastDialog *brightness_contrast_dialog = NULL;
|
static BrightnessContrastDialog *brightness_contrast_dialog = NULL;
|
||||||
|
|
||||||
static Argument * brightness_contrast_invoker (Argument *);
|
|
||||||
|
|
||||||
/* brightness contrast machinery */
|
|
||||||
|
|
||||||
static float
|
|
||||||
brightness_contrast_lut_func(BrightnessContrastDialog *bcd,
|
|
||||||
int nchannels, int channel, float value)
|
|
||||||
{
|
|
||||||
float nvalue;
|
|
||||||
double power;
|
|
||||||
|
|
||||||
/* return the original value for the alpha channel */
|
|
||||||
if ((nchannels == 2 || nchannels == 4) && channel == nchannels -1)
|
|
||||||
return value;
|
|
||||||
|
|
||||||
/* apply brightness */
|
|
||||||
if (bcd->brightness < 0)
|
|
||||||
value = value * (1.0 + bcd->brightness/255.0);
|
|
||||||
else
|
|
||||||
value = value + ((1.0 - value) * bcd->brightness/255.0);
|
|
||||||
|
|
||||||
/* apply contrast */
|
|
||||||
if (bcd->contrast < 0)
|
|
||||||
{
|
|
||||||
if (value > 0.5)
|
|
||||||
nvalue = 1.0 - value;
|
|
||||||
else
|
|
||||||
nvalue = value;
|
|
||||||
if (nvalue < 0.0)
|
|
||||||
nvalue = 0.0;
|
|
||||||
nvalue = 0.5 * pow (nvalue * 2.0 , (double) (127 + bcd->contrast) / 127.0);
|
|
||||||
if (value > 0.5)
|
|
||||||
value = 1.0 - nvalue;
|
|
||||||
else
|
|
||||||
value = nvalue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (value > 0.5)
|
|
||||||
nvalue = 1.0 - value;
|
|
||||||
else
|
|
||||||
nvalue = value;
|
|
||||||
if (nvalue < 0.0)
|
|
||||||
nvalue = 0.0;
|
|
||||||
power = (bcd->contrast == 127) ? 127 : 127.0 / (127 - bcd->contrast);
|
|
||||||
nvalue = 0.5 * pow (2.0 * nvalue, power);
|
|
||||||
if (value > 0.5)
|
|
||||||
value = 1.0 - nvalue;
|
|
||||||
else
|
|
||||||
value = nvalue;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* by_color select action functions */
|
/* by_color select action functions */
|
||||||
|
@ -467,8 +415,9 @@ brightness_contrast_preview (BrightnessContrastDialog *bcd)
|
||||||
if (!bcd->image_map)
|
if (!bcd->image_map)
|
||||||
g_message (_("brightness_contrast_preview(): No image map"));
|
g_message (_("brightness_contrast_preview(): No image map"));
|
||||||
active_tool->preserve = TRUE;
|
active_tool->preserve = TRUE;
|
||||||
gimp_lut_setup(bcd->lut, (GimpLutFunc) brightness_contrast_lut_func,
|
brightness_contrast_lut_setup(bcd->lut, bcd->brightness / 255.0,
|
||||||
(void *) bcd, gimp_drawable_bytes(bcd->drawable));
|
bcd->contrast / 127.0,
|
||||||
|
gimp_drawable_bytes(bcd->drawable));
|
||||||
image_map_apply (bcd->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
image_map_apply (bcd->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
||||||
(void *) bcd->lut);
|
(void *) bcd->lut);
|
||||||
active_tool->preserve = FALSE;
|
active_tool->preserve = FALSE;
|
||||||
|
@ -489,8 +438,9 @@ brightness_contrast_ok_callback (GtkWidget *widget,
|
||||||
|
|
||||||
if (!bcd->preview)
|
if (!bcd->preview)
|
||||||
{
|
{
|
||||||
gimp_lut_setup(bcd->lut, (GimpLutFunc) brightness_contrast_lut_func,
|
brightness_contrast_lut_setup(bcd->lut, bcd->brightness / 255.0,
|
||||||
(void *) bcd, gimp_drawable_bytes(bcd->drawable));
|
bcd->contrast / 127.0,
|
||||||
|
gimp_drawable_bytes(bcd->drawable));
|
||||||
image_map_apply (bcd->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
image_map_apply (bcd->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
||||||
(void *) bcd->lut);
|
(void *) bcd->lut);
|
||||||
}
|
}
|
||||||
|
@ -632,119 +582,3 @@ brightness_contrast_contrast_text_update (GtkWidget *w,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* The brightness_contrast procedure definition */
|
|
||||||
ProcArg brightness_contrast_args[] =
|
|
||||||
{
|
|
||||||
{ PDB_DRAWABLE,
|
|
||||||
"drawable",
|
|
||||||
"the drawable"
|
|
||||||
},
|
|
||||||
{ PDB_INT32,
|
|
||||||
"brightness",
|
|
||||||
"brightness adjustment: (-127 <= brightness <= 127)"
|
|
||||||
},
|
|
||||||
{ PDB_INT32,
|
|
||||||
"contrast",
|
|
||||||
"constrast adjustment: (-127 <= contrast <= 127)"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ProcRecord brightness_contrast_proc =
|
|
||||||
{
|
|
||||||
"gimp_brightness_contrast",
|
|
||||||
"Modify brightness/contrast in the specified drawable",
|
|
||||||
"This procedures allows the brightness and contrast of the specified drawable to be modified. Both 'brightness' and 'contrast' parameters are defined between -127 and 127.",
|
|
||||||
"Spencer Kimball & Peter Mattis",
|
|
||||||
"Spencer Kimball & Peter Mattis",
|
|
||||||
"1997",
|
|
||||||
PDB_INTERNAL,
|
|
||||||
|
|
||||||
/* Input arguments */
|
|
||||||
3,
|
|
||||||
brightness_contrast_args,
|
|
||||||
|
|
||||||
/* Output arguments */
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
|
|
||||||
/* Exec method */
|
|
||||||
{ { brightness_contrast_invoker } },
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static Argument *
|
|
||||||
brightness_contrast_invoker (Argument *args)
|
|
||||||
{
|
|
||||||
PixelRegion srcPR, destPR;
|
|
||||||
int success = TRUE;
|
|
||||||
int int_value;
|
|
||||||
BrightnessContrastDialog bcd;
|
|
||||||
GImage *gimage;
|
|
||||||
int brightness;
|
|
||||||
int contrast;
|
|
||||||
int x1, y1, x2, y2;
|
|
||||||
GimpDrawable *drawable;
|
|
||||||
|
|
||||||
drawable = NULL;
|
|
||||||
brightness = 0;
|
|
||||||
contrast = 0;
|
|
||||||
|
|
||||||
/* the drawable */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[0].value.pdb_int;
|
|
||||||
drawable = drawable_get_ID (int_value);
|
|
||||||
if (drawable == NULL)
|
|
||||||
success = FALSE;
|
|
||||||
else
|
|
||||||
gimage = drawable_gimage (drawable);
|
|
||||||
}
|
|
||||||
/* make sure the drawable is not indexed color */
|
|
||||||
if (success)
|
|
||||||
success = ! drawable_indexed (drawable);
|
|
||||||
|
|
||||||
/* brightness */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[1].value.pdb_int;
|
|
||||||
if (int_value < -127 || int_value > 127)
|
|
||||||
success = FALSE;
|
|
||||||
else
|
|
||||||
brightness = int_value;
|
|
||||||
}
|
|
||||||
/* contrast */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[2].value.pdb_int;
|
|
||||||
if (int_value < -127 || int_value > 127)
|
|
||||||
success = FALSE;
|
|
||||||
else
|
|
||||||
contrast = int_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* arrange to modify the brightness/contrast */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
bcd.brightness = brightness;
|
|
||||||
bcd.contrast = contrast;
|
|
||||||
bcd.lut = gimp_lut_new();
|
|
||||||
|
|
||||||
/* The application should occur only within selection bounds */
|
|
||||||
drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
|
|
||||||
|
|
||||||
pixel_region_init (&srcPR, drawable_data (drawable), x1, y1, (x2 - x1), (y2 - y1), FALSE);
|
|
||||||
pixel_region_init (&destPR, drawable_shadow (drawable), x1, y1, (x2 - x1), (y2 - y1), TRUE);
|
|
||||||
|
|
||||||
gimp_lut_setup(bcd.lut, (GimpLutFunc) brightness_contrast_lut_func,
|
|
||||||
(void *) &bcd, gimp_drawable_bytes(drawable));
|
|
||||||
|
|
||||||
pixel_regions_process_parallel((p_func)gimp_lut_process, bcd.lut,
|
|
||||||
2, &srcPR, &destPR);
|
|
||||||
|
|
||||||
gimp_lut_free(bcd.lut);
|
|
||||||
drawable_merge_shadow (drawable, TRUE);
|
|
||||||
drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1));
|
|
||||||
}
|
|
||||||
|
|
||||||
return procedural_db_return_args (&brightness_contrast_proc, success);
|
|
||||||
}
|
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#define __BRIGHTNESS_CONTRAST_H__
|
#define __BRIGHTNESS_CONTRAST_H__
|
||||||
|
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
#include "procedural_db.h"
|
|
||||||
|
|
||||||
/* by_color select functions */
|
/* by_color select functions */
|
||||||
Tool * tools_new_brightness_contrast (void);
|
Tool * tools_new_brightness_contrast (void);
|
||||||
|
@ -27,7 +26,4 @@ void tools_free_brightness_contrast (Tool *);
|
||||||
|
|
||||||
void brightness_contrast_initialize (GDisplay *);
|
void brightness_contrast_initialize (GDisplay *);
|
||||||
|
|
||||||
/* Procedure definition and marshalling function */
|
|
||||||
extern ProcRecord brightness_contrast_proc;
|
|
||||||
|
|
||||||
#endif /* __BRIGHTNESS_CONTRAST_H__ */
|
#endif /* __BRIGHTNESS_CONTRAST_H__ */
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "image_map.h"
|
#include "image_map.h"
|
||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
#include "gimplut.h"
|
#include "gimplut.h"
|
||||||
|
#include "lut_funcs.h"
|
||||||
|
|
||||||
#include "libgimp/gimpintl.h"
|
#include "libgimp/gimpintl.h"
|
||||||
|
|
||||||
|
@ -94,59 +95,6 @@ static void brightness_contrast_contrast_text_update (GtkWidget *, gpointer
|
||||||
static void *brightness_contrast_options = NULL;
|
static void *brightness_contrast_options = NULL;
|
||||||
static BrightnessContrastDialog *brightness_contrast_dialog = NULL;
|
static BrightnessContrastDialog *brightness_contrast_dialog = NULL;
|
||||||
|
|
||||||
static Argument * brightness_contrast_invoker (Argument *);
|
|
||||||
|
|
||||||
/* brightness contrast machinery */
|
|
||||||
|
|
||||||
static float
|
|
||||||
brightness_contrast_lut_func(BrightnessContrastDialog *bcd,
|
|
||||||
int nchannels, int channel, float value)
|
|
||||||
{
|
|
||||||
float nvalue;
|
|
||||||
double power;
|
|
||||||
|
|
||||||
/* return the original value for the alpha channel */
|
|
||||||
if ((nchannels == 2 || nchannels == 4) && channel == nchannels -1)
|
|
||||||
return value;
|
|
||||||
|
|
||||||
/* apply brightness */
|
|
||||||
if (bcd->brightness < 0)
|
|
||||||
value = value * (1.0 + bcd->brightness/255.0);
|
|
||||||
else
|
|
||||||
value = value + ((1.0 - value) * bcd->brightness/255.0);
|
|
||||||
|
|
||||||
/* apply contrast */
|
|
||||||
if (bcd->contrast < 0)
|
|
||||||
{
|
|
||||||
if (value > 0.5)
|
|
||||||
nvalue = 1.0 - value;
|
|
||||||
else
|
|
||||||
nvalue = value;
|
|
||||||
if (nvalue < 0.0)
|
|
||||||
nvalue = 0.0;
|
|
||||||
nvalue = 0.5 * pow (nvalue * 2.0 , (double) (127 + bcd->contrast) / 127.0);
|
|
||||||
if (value > 0.5)
|
|
||||||
value = 1.0 - nvalue;
|
|
||||||
else
|
|
||||||
value = nvalue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (value > 0.5)
|
|
||||||
nvalue = 1.0 - value;
|
|
||||||
else
|
|
||||||
nvalue = value;
|
|
||||||
if (nvalue < 0.0)
|
|
||||||
nvalue = 0.0;
|
|
||||||
power = (bcd->contrast == 127) ? 127 : 127.0 / (127 - bcd->contrast);
|
|
||||||
nvalue = 0.5 * pow (2.0 * nvalue, power);
|
|
||||||
if (value > 0.5)
|
|
||||||
value = 1.0 - nvalue;
|
|
||||||
else
|
|
||||||
value = nvalue;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* by_color select action functions */
|
/* by_color select action functions */
|
||||||
|
@ -467,8 +415,9 @@ brightness_contrast_preview (BrightnessContrastDialog *bcd)
|
||||||
if (!bcd->image_map)
|
if (!bcd->image_map)
|
||||||
g_message (_("brightness_contrast_preview(): No image map"));
|
g_message (_("brightness_contrast_preview(): No image map"));
|
||||||
active_tool->preserve = TRUE;
|
active_tool->preserve = TRUE;
|
||||||
gimp_lut_setup(bcd->lut, (GimpLutFunc) brightness_contrast_lut_func,
|
brightness_contrast_lut_setup(bcd->lut, bcd->brightness / 255.0,
|
||||||
(void *) bcd, gimp_drawable_bytes(bcd->drawable));
|
bcd->contrast / 127.0,
|
||||||
|
gimp_drawable_bytes(bcd->drawable));
|
||||||
image_map_apply (bcd->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
image_map_apply (bcd->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
||||||
(void *) bcd->lut);
|
(void *) bcd->lut);
|
||||||
active_tool->preserve = FALSE;
|
active_tool->preserve = FALSE;
|
||||||
|
@ -489,8 +438,9 @@ brightness_contrast_ok_callback (GtkWidget *widget,
|
||||||
|
|
||||||
if (!bcd->preview)
|
if (!bcd->preview)
|
||||||
{
|
{
|
||||||
gimp_lut_setup(bcd->lut, (GimpLutFunc) brightness_contrast_lut_func,
|
brightness_contrast_lut_setup(bcd->lut, bcd->brightness / 255.0,
|
||||||
(void *) bcd, gimp_drawable_bytes(bcd->drawable));
|
bcd->contrast / 127.0,
|
||||||
|
gimp_drawable_bytes(bcd->drawable));
|
||||||
image_map_apply (bcd->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
image_map_apply (bcd->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
||||||
(void *) bcd->lut);
|
(void *) bcd->lut);
|
||||||
}
|
}
|
||||||
|
@ -632,119 +582,3 @@ brightness_contrast_contrast_text_update (GtkWidget *w,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* The brightness_contrast procedure definition */
|
|
||||||
ProcArg brightness_contrast_args[] =
|
|
||||||
{
|
|
||||||
{ PDB_DRAWABLE,
|
|
||||||
"drawable",
|
|
||||||
"the drawable"
|
|
||||||
},
|
|
||||||
{ PDB_INT32,
|
|
||||||
"brightness",
|
|
||||||
"brightness adjustment: (-127 <= brightness <= 127)"
|
|
||||||
},
|
|
||||||
{ PDB_INT32,
|
|
||||||
"contrast",
|
|
||||||
"constrast adjustment: (-127 <= contrast <= 127)"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ProcRecord brightness_contrast_proc =
|
|
||||||
{
|
|
||||||
"gimp_brightness_contrast",
|
|
||||||
"Modify brightness/contrast in the specified drawable",
|
|
||||||
"This procedures allows the brightness and contrast of the specified drawable to be modified. Both 'brightness' and 'contrast' parameters are defined between -127 and 127.",
|
|
||||||
"Spencer Kimball & Peter Mattis",
|
|
||||||
"Spencer Kimball & Peter Mattis",
|
|
||||||
"1997",
|
|
||||||
PDB_INTERNAL,
|
|
||||||
|
|
||||||
/* Input arguments */
|
|
||||||
3,
|
|
||||||
brightness_contrast_args,
|
|
||||||
|
|
||||||
/* Output arguments */
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
|
|
||||||
/* Exec method */
|
|
||||||
{ { brightness_contrast_invoker } },
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static Argument *
|
|
||||||
brightness_contrast_invoker (Argument *args)
|
|
||||||
{
|
|
||||||
PixelRegion srcPR, destPR;
|
|
||||||
int success = TRUE;
|
|
||||||
int int_value;
|
|
||||||
BrightnessContrastDialog bcd;
|
|
||||||
GImage *gimage;
|
|
||||||
int brightness;
|
|
||||||
int contrast;
|
|
||||||
int x1, y1, x2, y2;
|
|
||||||
GimpDrawable *drawable;
|
|
||||||
|
|
||||||
drawable = NULL;
|
|
||||||
brightness = 0;
|
|
||||||
contrast = 0;
|
|
||||||
|
|
||||||
/* the drawable */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[0].value.pdb_int;
|
|
||||||
drawable = drawable_get_ID (int_value);
|
|
||||||
if (drawable == NULL)
|
|
||||||
success = FALSE;
|
|
||||||
else
|
|
||||||
gimage = drawable_gimage (drawable);
|
|
||||||
}
|
|
||||||
/* make sure the drawable is not indexed color */
|
|
||||||
if (success)
|
|
||||||
success = ! drawable_indexed (drawable);
|
|
||||||
|
|
||||||
/* brightness */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[1].value.pdb_int;
|
|
||||||
if (int_value < -127 || int_value > 127)
|
|
||||||
success = FALSE;
|
|
||||||
else
|
|
||||||
brightness = int_value;
|
|
||||||
}
|
|
||||||
/* contrast */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[2].value.pdb_int;
|
|
||||||
if (int_value < -127 || int_value > 127)
|
|
||||||
success = FALSE;
|
|
||||||
else
|
|
||||||
contrast = int_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* arrange to modify the brightness/contrast */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
bcd.brightness = brightness;
|
|
||||||
bcd.contrast = contrast;
|
|
||||||
bcd.lut = gimp_lut_new();
|
|
||||||
|
|
||||||
/* The application should occur only within selection bounds */
|
|
||||||
drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
|
|
||||||
|
|
||||||
pixel_region_init (&srcPR, drawable_data (drawable), x1, y1, (x2 - x1), (y2 - y1), FALSE);
|
|
||||||
pixel_region_init (&destPR, drawable_shadow (drawable), x1, y1, (x2 - x1), (y2 - y1), TRUE);
|
|
||||||
|
|
||||||
gimp_lut_setup(bcd.lut, (GimpLutFunc) brightness_contrast_lut_func,
|
|
||||||
(void *) &bcd, gimp_drawable_bytes(drawable));
|
|
||||||
|
|
||||||
pixel_regions_process_parallel((p_func)gimp_lut_process, bcd.lut,
|
|
||||||
2, &srcPR, &destPR);
|
|
||||||
|
|
||||||
gimp_lut_free(bcd.lut);
|
|
||||||
drawable_merge_shadow (drawable, TRUE);
|
|
||||||
drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1));
|
|
||||||
}
|
|
||||||
|
|
||||||
return procedural_db_return_args (&brightness_contrast_proc, success);
|
|
||||||
}
|
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#define __BRIGHTNESS_CONTRAST_H__
|
#define __BRIGHTNESS_CONTRAST_H__
|
||||||
|
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
#include "procedural_db.h"
|
|
||||||
|
|
||||||
/* by_color select functions */
|
/* by_color select functions */
|
||||||
Tool * tools_new_brightness_contrast (void);
|
Tool * tools_new_brightness_contrast (void);
|
||||||
|
@ -27,7 +26,4 @@ void tools_free_brightness_contrast (Tool *);
|
||||||
|
|
||||||
void brightness_contrast_initialize (GDisplay *);
|
void brightness_contrast_initialize (GDisplay *);
|
||||||
|
|
||||||
/* Procedure definition and marshalling function */
|
|
||||||
extern ProcRecord brightness_contrast_proc;
|
|
||||||
|
|
||||||
#endif /* __BRIGHTNESS_CONTRAST_H__ */
|
#endif /* __BRIGHTNESS_CONTRAST_H__ */
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
#include "levels.h"
|
#include "levels.h"
|
||||||
#include "gimplut.h"
|
#include "gimplut.h"
|
||||||
|
#include "lut_funcs.h"
|
||||||
|
|
||||||
#include "libgimp/gimpintl.h"
|
#include "libgimp/gimpintl.h"
|
||||||
|
|
||||||
|
@ -141,61 +142,6 @@ static gint levels_output_da_events (GtkWidget *, GdkEvent *,
|
||||||
|
|
||||||
static void levels_histogram_range (HistogramWidget *, int, int,
|
static void levels_histogram_range (HistogramWidget *, int, int,
|
||||||
void *);
|
void *);
|
||||||
static Argument * levels_invoker (Argument *);
|
|
||||||
|
|
||||||
|
|
||||||
/* levels machinery */
|
|
||||||
|
|
||||||
static float
|
|
||||||
levels_lut_func(LevelsDialog *ld,
|
|
||||||
int nchannels, int channel, float value)
|
|
||||||
{
|
|
||||||
double inten;
|
|
||||||
int j;
|
|
||||||
|
|
||||||
if (nchannels == 1)
|
|
||||||
j = 0;
|
|
||||||
else
|
|
||||||
j = channel + 1;
|
|
||||||
inten = value;
|
|
||||||
/* For color images this runs through the loop with j = channel +1
|
|
||||||
the first time and j = 0 the second time */
|
|
||||||
/* For bw images this runs through the loop with j = 0 the first and
|
|
||||||
only time */
|
|
||||||
for (; j >= 0; j -= (channel + 1))
|
|
||||||
{
|
|
||||||
/* don't apply the overall curve to the alpha channel */
|
|
||||||
if (j == 0 && (nchannels == 2 || nchannels == 4)
|
|
||||||
&& channel == nchannels -1)
|
|
||||||
return inten;
|
|
||||||
|
|
||||||
/* determine input intensity */
|
|
||||||
if (ld->high_input[j] != ld->low_input[j])
|
|
||||||
inten = (double) (255.0*inten - ld->low_input[j]) /
|
|
||||||
(double) (ld->high_input[j] - ld->low_input[j]);
|
|
||||||
else
|
|
||||||
inten = (double) (255.0*inten - ld->low_input[j]);
|
|
||||||
|
|
||||||
if (ld->gamma[j] != 0.0)
|
|
||||||
{
|
|
||||||
if (inten >= 0.0)
|
|
||||||
inten = pow ( inten, (1.0 / ld->gamma[j]));
|
|
||||||
else
|
|
||||||
inten = -pow (-inten, (1.0 / ld->gamma[j]));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* determine the output intensity */
|
|
||||||
if (ld->high_output[j] >= ld->low_output[j])
|
|
||||||
inten = (double) (inten * (ld->high_output[j] - ld->low_output[j]) +
|
|
||||||
ld->low_output[j]);
|
|
||||||
else if (ld->high_output[j] < ld->low_output[j])
|
|
||||||
inten = (double) (ld->low_output[j] - inten *
|
|
||||||
(ld->low_output[j] - ld->high_output[j]));
|
|
||||||
|
|
||||||
inten /= 255.0;
|
|
||||||
}
|
|
||||||
return inten;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
levels_histogram_range (HistogramWidget *h,
|
levels_histogram_range (HistogramWidget *h,
|
||||||
|
@ -715,8 +661,9 @@ levels_update (LevelsDialog *ld,
|
||||||
/* Recalculate the transfer arrays */
|
/* Recalculate the transfer arrays */
|
||||||
levels_calculate_transfers (ld);
|
levels_calculate_transfers (ld);
|
||||||
/* set up the lut */
|
/* set up the lut */
|
||||||
gimp_lut_setup(ld->lut, (GimpLutFunc) levels_lut_func,
|
levels_lut_setup(ld->lut, ld->gamma, ld->low_input, ld->high_input,
|
||||||
(void *) ld, gimp_drawable_bytes(ld->drawable));
|
ld->low_output, ld->high_output,
|
||||||
|
gimp_drawable_bytes(ld->drawable));
|
||||||
|
|
||||||
if (update & LOW_INPUT)
|
if (update & LOW_INPUT)
|
||||||
{
|
{
|
||||||
|
@ -1005,8 +952,9 @@ levels_ok_callback (GtkWidget *widget,
|
||||||
|
|
||||||
if (!ld->preview)
|
if (!ld->preview)
|
||||||
{
|
{
|
||||||
gimp_lut_setup(ld->lut, (GimpLutFunc) levels_lut_func,
|
levels_lut_setup(ld->lut, ld->gamma, ld->low_input, ld->high_input,
|
||||||
(void *) ld, gimp_drawable_bytes(ld->drawable));
|
ld->low_output, ld->high_output,
|
||||||
|
gimp_drawable_bytes(ld->drawable));
|
||||||
image_map_apply (ld->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
image_map_apply (ld->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
||||||
(void *) ld->lut);
|
(void *) ld->lut);
|
||||||
}
|
}
|
||||||
|
@ -1359,204 +1307,3 @@ levels_output_da_events (GtkWidget *widget,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* The levels procedure definition */
|
|
||||||
ProcArg levels_args[] =
|
|
||||||
{
|
|
||||||
{ PDB_DRAWABLE,
|
|
||||||
"drawable",
|
|
||||||
"the drawable"
|
|
||||||
},
|
|
||||||
{ PDB_INT32,
|
|
||||||
"channel",
|
|
||||||
"the channel to modify: { VALUE (0), RED (1), GREEN (2), BLUE (3), GRAY (0) }"
|
|
||||||
},
|
|
||||||
{ PDB_INT32,
|
|
||||||
"low_input",
|
|
||||||
"intensity of lowest input: (0 <= low_input <= 255)"
|
|
||||||
},
|
|
||||||
{ PDB_INT32,
|
|
||||||
"high_input",
|
|
||||||
"intensity of highest input: (0 <= high_input <= 255)"
|
|
||||||
},
|
|
||||||
{ PDB_FLOAT,
|
|
||||||
"gamma",
|
|
||||||
"gamma correction factor: (0.1 <= gamma <= 10)"
|
|
||||||
},
|
|
||||||
{ PDB_INT32,
|
|
||||||
"low_output",
|
|
||||||
"intensity of lowest output: (0 <= low_input <= 255)"
|
|
||||||
},
|
|
||||||
{ PDB_INT32,
|
|
||||||
"high_output",
|
|
||||||
"intensity of highest output: (0 <= high_input <= 255)"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ProcRecord levels_proc =
|
|
||||||
{
|
|
||||||
"gimp_levels",
|
|
||||||
"Modifies intensity levels in the specified drawable",
|
|
||||||
"This tool allows intensity levels in the specified drawable to be remapped according to a set of parameters. The low/high input levels specify an initial mapping from the source intensities. The gamma value determines how intensities between the low and high input intensities are interpolated. A gamma value of 1.0 results in a linear interpolation. Higher gamma values result in more high-level intensities. Lower gamma values result in more low-level intensities. The low/high output levels constrain the final intensity mapping--that is, no final intensity will be lower than the low output level and no final intensity will be higher than the high output level. This tool is only valid on RGB color and grayscale images. It will not operate on indexed drawables.",
|
|
||||||
"Spencer Kimball & Peter Mattis",
|
|
||||||
"Spencer Kimball & Peter Mattis",
|
|
||||||
"1995-1996",
|
|
||||||
PDB_INTERNAL,
|
|
||||||
|
|
||||||
/* Input arguments */
|
|
||||||
7,
|
|
||||||
levels_args,
|
|
||||||
|
|
||||||
/* Output arguments */
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
|
|
||||||
/* Exec method */
|
|
||||||
{ { levels_invoker } },
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static Argument *
|
|
||||||
levels_invoker (Argument *args)
|
|
||||||
{
|
|
||||||
PixelRegion srcPR, destPR;
|
|
||||||
int success = TRUE;
|
|
||||||
LevelsDialog ld;
|
|
||||||
GimpDrawable *drawable;
|
|
||||||
int channel;
|
|
||||||
int low_input;
|
|
||||||
int high_input;
|
|
||||||
double gamma;
|
|
||||||
int low_output;
|
|
||||||
int high_output;
|
|
||||||
int int_value;
|
|
||||||
double fp_value;
|
|
||||||
int x1, y1, x2, y2;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
drawable = NULL;
|
|
||||||
low_input = 0;
|
|
||||||
high_input = 0;
|
|
||||||
gamma = 1.0;
|
|
||||||
low_output = 0;
|
|
||||||
high_output = 0;
|
|
||||||
|
|
||||||
/* the drawable */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[0].value.pdb_int;
|
|
||||||
drawable = drawable_get_ID (int_value);
|
|
||||||
if (drawable == NULL)
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
/* make sure the drawable is not indexed color */
|
|
||||||
if (success)
|
|
||||||
success = ! drawable_indexed (drawable);
|
|
||||||
|
|
||||||
/* channel */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[1].value.pdb_int;
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
if (drawable_gray (drawable))
|
|
||||||
{
|
|
||||||
if (int_value != 0)
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
else if (drawable_color (drawable))
|
|
||||||
{
|
|
||||||
if (int_value < 0 || int_value > 3)
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
channel = int_value;
|
|
||||||
}
|
|
||||||
/* low input */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[2].value.pdb_int;
|
|
||||||
if (int_value >= 0 && int_value < 256)
|
|
||||||
low_input = int_value;
|
|
||||||
else
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
/* high input */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[3].value.pdb_int;
|
|
||||||
if (int_value >= 0 && int_value < 256)
|
|
||||||
high_input = int_value;
|
|
||||||
else
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
/* gamma */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
fp_value = args[4].value.pdb_float;
|
|
||||||
if (fp_value >= 0.1 && fp_value <= 10.0)
|
|
||||||
gamma = fp_value;
|
|
||||||
else
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
/* low output */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[5].value.pdb_int;
|
|
||||||
if (int_value >= 0 && int_value < 256)
|
|
||||||
low_output = int_value;
|
|
||||||
else
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
/* high output */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[6].value.pdb_int;
|
|
||||||
if (int_value >= 0 && int_value < 256)
|
|
||||||
high_output = int_value;
|
|
||||||
else
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* arrange to modify the levels */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
for (i = 0; i < 5; i++)
|
|
||||||
{
|
|
||||||
ld.low_input[i] = 0;
|
|
||||||
ld.gamma[i] = 1.0;
|
|
||||||
ld.high_input[i] = 255;
|
|
||||||
ld.low_output[i] = 0;
|
|
||||||
ld.high_output[i] = 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
ld.lut = gimp_lut_new();
|
|
||||||
ld.channel = channel;
|
|
||||||
ld.color = drawable_color (drawable);
|
|
||||||
ld.low_input[channel] = low_input;
|
|
||||||
ld.high_input[channel] = high_input;
|
|
||||||
ld.gamma[channel] = gamma;
|
|
||||||
ld.low_output[channel] = low_output;
|
|
||||||
ld.high_output[channel] = high_output;
|
|
||||||
|
|
||||||
/* setup the lut */
|
|
||||||
gimp_lut_setup(ld.lut, (GimpLutFunc) levels_lut_func,
|
|
||||||
(void *) &ld, gimp_drawable_bytes(drawable));
|
|
||||||
|
|
||||||
/* The application should occur only within selection bounds */
|
|
||||||
drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
|
|
||||||
|
|
||||||
pixel_region_init (&srcPR, drawable_data (drawable), x1, y1, (x2 - x1), (y2 - y1), FALSE);
|
|
||||||
pixel_region_init (&destPR, drawable_shadow (drawable), x1, y1, (x2 - x1), (y2 - y1), TRUE);
|
|
||||||
|
|
||||||
pixel_regions_process_parallel((p_func)gimp_lut_process, ld.lut,
|
|
||||||
2, &srcPR, &destPR);
|
|
||||||
|
|
||||||
gimp_lut_free(ld.lut);
|
|
||||||
drawable_merge_shadow (drawable, TRUE);
|
|
||||||
drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1));
|
|
||||||
}
|
|
||||||
|
|
||||||
return procedural_db_return_args (&levels_proc, success);
|
|
||||||
}
|
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#define __LEVELS_H__
|
#define __LEVELS_H__
|
||||||
|
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
#include "procedural_db.h"
|
|
||||||
|
|
||||||
/* hue-saturation functions */
|
/* hue-saturation functions */
|
||||||
Tool * tools_new_levels (void);
|
Tool * tools_new_levels (void);
|
||||||
|
@ -28,7 +27,4 @@ void tools_free_levels (Tool *);
|
||||||
void levels_initialize (GDisplay *);
|
void levels_initialize (GDisplay *);
|
||||||
void levels_free (void);
|
void levels_free (void);
|
||||||
|
|
||||||
/* Procedure definition and marshalling function */
|
|
||||||
extern ProcRecord levels_proc;
|
|
||||||
|
|
||||||
#endif /* __LEVELS_H__ */
|
#endif /* __LEVELS_H__ */
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
#include "posterize.h"
|
#include "posterize.h"
|
||||||
#include "gimplut.h"
|
#include "gimplut.h"
|
||||||
|
#include "lut_funcs.h"
|
||||||
|
|
||||||
#include "libgimp/gimpintl.h"
|
#include "libgimp/gimpintl.h"
|
||||||
|
|
||||||
|
@ -84,29 +85,6 @@ static void posterize_preview_update (GtkWidget *, gpointer);
|
||||||
static void posterize_levels_text_update (GtkWidget *, gpointer);
|
static void posterize_levels_text_update (GtkWidget *, gpointer);
|
||||||
static gint posterize_delete_callback (GtkWidget *, GdkEvent *, gpointer);
|
static gint posterize_delete_callback (GtkWidget *, GdkEvent *, gpointer);
|
||||||
|
|
||||||
static Argument * posterize_invoker (Argument *);
|
|
||||||
|
|
||||||
|
|
||||||
/* posterize machinery */
|
|
||||||
|
|
||||||
static float
|
|
||||||
posterize_lut_func(PosterizeDialog *pd,
|
|
||||||
int nchannels, int channel, float value)
|
|
||||||
{
|
|
||||||
int levels;
|
|
||||||
/* don't posterize the alpha channel */
|
|
||||||
if ((nchannels == 2 || nchannels == 4) && channel == nchannels -1)
|
|
||||||
return value;
|
|
||||||
|
|
||||||
if (pd->levels < 2)
|
|
||||||
levels = 2;
|
|
||||||
else
|
|
||||||
levels = pd->levels;
|
|
||||||
|
|
||||||
value = rint(value * (pd->levels - 1.0)) / (pd->levels - 1.0);
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* by_color select action functions */
|
/* by_color select action functions */
|
||||||
|
|
||||||
|
@ -343,8 +321,7 @@ posterize_preview (PosterizeDialog *pd)
|
||||||
if (!pd->image_map)
|
if (!pd->image_map)
|
||||||
g_message (_("posterize_preview(): No image map"));
|
g_message (_("posterize_preview(): No image map"));
|
||||||
active_tool->preserve = TRUE;
|
active_tool->preserve = TRUE;
|
||||||
gimp_lut_setup_exact(pd->lut, (GimpLutFunc) posterize_lut_func,
|
posterize_lut_setup(pd->lut, pd->levels, gimp_drawable_bytes(pd->drawable));
|
||||||
(void *) pd, gimp_drawable_bytes(pd->drawable));
|
|
||||||
image_map_apply (pd->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
image_map_apply (pd->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
||||||
(void *) pd->lut);
|
(void *) pd->lut);
|
||||||
active_tool->preserve = FALSE;
|
active_tool->preserve = FALSE;
|
||||||
|
@ -365,8 +342,8 @@ posterize_ok_callback (GtkWidget *widget,
|
||||||
|
|
||||||
if (!pd->preview)
|
if (!pd->preview)
|
||||||
{
|
{
|
||||||
gimp_lut_setup_exact(pd->lut, (GimpLutFunc) posterize_lut_func,
|
posterize_lut_setup(pd->lut, pd->levels,
|
||||||
(void *) pd, gimp_drawable_bytes(pd->drawable));
|
gimp_drawable_bytes(pd->drawable));
|
||||||
image_map_apply (pd->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
image_map_apply (pd->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
||||||
(void *) pd->lut);
|
(void *) pd->lut);
|
||||||
}
|
}
|
||||||
|
@ -444,100 +421,3 @@ posterize_levels_text_update (GtkWidget *w,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* The posterize procedure definition */
|
|
||||||
ProcArg posterize_args[] =
|
|
||||||
{
|
|
||||||
{ PDB_DRAWABLE,
|
|
||||||
"drawable",
|
|
||||||
"the drawable"
|
|
||||||
},
|
|
||||||
{ PDB_INT32,
|
|
||||||
"levels",
|
|
||||||
"levels of posterization: (2 <= levels <= 255)"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ProcRecord posterize_proc =
|
|
||||||
{
|
|
||||||
"gimp_posterize",
|
|
||||||
"Posterize the specified drawable",
|
|
||||||
"This procedures reduces the number of shades allows in each intensity channel to the specified 'levels' parameter.",
|
|
||||||
"Spencer Kimball & Peter Mattis",
|
|
||||||
"Spencer Kimball & Peter Mattis",
|
|
||||||
"1997",
|
|
||||||
PDB_INTERNAL,
|
|
||||||
|
|
||||||
/* Input arguments */
|
|
||||||
2,
|
|
||||||
posterize_args,
|
|
||||||
|
|
||||||
/* Output arguments */
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
|
|
||||||
/* Exec method */
|
|
||||||
{ { posterize_invoker } },
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static Argument *
|
|
||||||
posterize_invoker (Argument *args)
|
|
||||||
{
|
|
||||||
PixelRegion srcPR, destPR;
|
|
||||||
int success = TRUE;
|
|
||||||
PosterizeDialog pd;
|
|
||||||
GImage *gimage;
|
|
||||||
GimpDrawable *drawable;
|
|
||||||
int levels;
|
|
||||||
int int_value;
|
|
||||||
int x1, y1, x2, y2;
|
|
||||||
|
|
||||||
drawable = NULL;
|
|
||||||
levels = 0;
|
|
||||||
|
|
||||||
/* the drawable */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[0].value.pdb_int;
|
|
||||||
drawable = drawable_get_ID (int_value);
|
|
||||||
if (drawable == NULL)
|
|
||||||
success = FALSE;
|
|
||||||
else
|
|
||||||
gimage = drawable_gimage (drawable);
|
|
||||||
}
|
|
||||||
/* make sure the drawable is not indexed color */
|
|
||||||
if (success)
|
|
||||||
success = ! drawable_indexed (drawable);
|
|
||||||
|
|
||||||
/* levels */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[1].value.pdb_int;
|
|
||||||
if (int_value >= 2 && int_value < 256)
|
|
||||||
levels = int_value;
|
|
||||||
else
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* arrange to modify the levels */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
pd.levels = levels;
|
|
||||||
pd.lut = gimp_lut_new();
|
|
||||||
/* The application should occur only within selection bounds */
|
|
||||||
drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
|
|
||||||
|
|
||||||
pixel_region_init (&srcPR, drawable_data (drawable), x1, y1, (x2 - x1), (y2 - y1), FALSE);
|
|
||||||
pixel_region_init (&destPR, drawable_shadow (drawable), x1, y1, (x2 - x1), (y2 - y1), TRUE);
|
|
||||||
|
|
||||||
pixel_regions_process_parallel((p_func)gimp_lut_process, pd.lut,
|
|
||||||
2, &srcPR, &destPR);
|
|
||||||
|
|
||||||
gimp_lut_free(pd.lut);
|
|
||||||
drawable_merge_shadow (drawable, TRUE);
|
|
||||||
drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1));
|
|
||||||
}
|
|
||||||
|
|
||||||
return procedural_db_return_args (&posterize_proc, success);
|
|
||||||
}
|
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#define __POSTERIZE_H__
|
#define __POSTERIZE_H__
|
||||||
|
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
#include "procedural_db.h"
|
|
||||||
|
|
||||||
/* by_color select functions */
|
/* by_color select functions */
|
||||||
Tool * tools_new_posterize (void);
|
Tool * tools_new_posterize (void);
|
||||||
|
@ -27,7 +26,4 @@ void tools_free_posterize (Tool *);
|
||||||
|
|
||||||
void posterize_initialize (GDisplay *);
|
void posterize_initialize (GDisplay *);
|
||||||
|
|
||||||
/* Procedure definition and marshalling function */
|
|
||||||
extern ProcRecord posterize_proc;
|
|
||||||
|
|
||||||
#endif /* __POSTERIZE_H__ */
|
#endif /* __POSTERIZE_H__ */
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
#include "levels.h"
|
#include "levels.h"
|
||||||
#include "gimplut.h"
|
#include "gimplut.h"
|
||||||
|
#include "lut_funcs.h"
|
||||||
|
|
||||||
#include "libgimp/gimpintl.h"
|
#include "libgimp/gimpintl.h"
|
||||||
|
|
||||||
|
@ -141,61 +142,6 @@ static gint levels_output_da_events (GtkWidget *, GdkEvent *,
|
||||||
|
|
||||||
static void levels_histogram_range (HistogramWidget *, int, int,
|
static void levels_histogram_range (HistogramWidget *, int, int,
|
||||||
void *);
|
void *);
|
||||||
static Argument * levels_invoker (Argument *);
|
|
||||||
|
|
||||||
|
|
||||||
/* levels machinery */
|
|
||||||
|
|
||||||
static float
|
|
||||||
levels_lut_func(LevelsDialog *ld,
|
|
||||||
int nchannels, int channel, float value)
|
|
||||||
{
|
|
||||||
double inten;
|
|
||||||
int j;
|
|
||||||
|
|
||||||
if (nchannels == 1)
|
|
||||||
j = 0;
|
|
||||||
else
|
|
||||||
j = channel + 1;
|
|
||||||
inten = value;
|
|
||||||
/* For color images this runs through the loop with j = channel +1
|
|
||||||
the first time and j = 0 the second time */
|
|
||||||
/* For bw images this runs through the loop with j = 0 the first and
|
|
||||||
only time */
|
|
||||||
for (; j >= 0; j -= (channel + 1))
|
|
||||||
{
|
|
||||||
/* don't apply the overall curve to the alpha channel */
|
|
||||||
if (j == 0 && (nchannels == 2 || nchannels == 4)
|
|
||||||
&& channel == nchannels -1)
|
|
||||||
return inten;
|
|
||||||
|
|
||||||
/* determine input intensity */
|
|
||||||
if (ld->high_input[j] != ld->low_input[j])
|
|
||||||
inten = (double) (255.0*inten - ld->low_input[j]) /
|
|
||||||
(double) (ld->high_input[j] - ld->low_input[j]);
|
|
||||||
else
|
|
||||||
inten = (double) (255.0*inten - ld->low_input[j]);
|
|
||||||
|
|
||||||
if (ld->gamma[j] != 0.0)
|
|
||||||
{
|
|
||||||
if (inten >= 0.0)
|
|
||||||
inten = pow ( inten, (1.0 / ld->gamma[j]));
|
|
||||||
else
|
|
||||||
inten = -pow (-inten, (1.0 / ld->gamma[j]));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* determine the output intensity */
|
|
||||||
if (ld->high_output[j] >= ld->low_output[j])
|
|
||||||
inten = (double) (inten * (ld->high_output[j] - ld->low_output[j]) +
|
|
||||||
ld->low_output[j]);
|
|
||||||
else if (ld->high_output[j] < ld->low_output[j])
|
|
||||||
inten = (double) (ld->low_output[j] - inten *
|
|
||||||
(ld->low_output[j] - ld->high_output[j]));
|
|
||||||
|
|
||||||
inten /= 255.0;
|
|
||||||
}
|
|
||||||
return inten;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
levels_histogram_range (HistogramWidget *h,
|
levels_histogram_range (HistogramWidget *h,
|
||||||
|
@ -715,8 +661,9 @@ levels_update (LevelsDialog *ld,
|
||||||
/* Recalculate the transfer arrays */
|
/* Recalculate the transfer arrays */
|
||||||
levels_calculate_transfers (ld);
|
levels_calculate_transfers (ld);
|
||||||
/* set up the lut */
|
/* set up the lut */
|
||||||
gimp_lut_setup(ld->lut, (GimpLutFunc) levels_lut_func,
|
levels_lut_setup(ld->lut, ld->gamma, ld->low_input, ld->high_input,
|
||||||
(void *) ld, gimp_drawable_bytes(ld->drawable));
|
ld->low_output, ld->high_output,
|
||||||
|
gimp_drawable_bytes(ld->drawable));
|
||||||
|
|
||||||
if (update & LOW_INPUT)
|
if (update & LOW_INPUT)
|
||||||
{
|
{
|
||||||
|
@ -1005,8 +952,9 @@ levels_ok_callback (GtkWidget *widget,
|
||||||
|
|
||||||
if (!ld->preview)
|
if (!ld->preview)
|
||||||
{
|
{
|
||||||
gimp_lut_setup(ld->lut, (GimpLutFunc) levels_lut_func,
|
levels_lut_setup(ld->lut, ld->gamma, ld->low_input, ld->high_input,
|
||||||
(void *) ld, gimp_drawable_bytes(ld->drawable));
|
ld->low_output, ld->high_output,
|
||||||
|
gimp_drawable_bytes(ld->drawable));
|
||||||
image_map_apply (ld->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
image_map_apply (ld->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
||||||
(void *) ld->lut);
|
(void *) ld->lut);
|
||||||
}
|
}
|
||||||
|
@ -1359,204 +1307,3 @@ levels_output_da_events (GtkWidget *widget,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* The levels procedure definition */
|
|
||||||
ProcArg levels_args[] =
|
|
||||||
{
|
|
||||||
{ PDB_DRAWABLE,
|
|
||||||
"drawable",
|
|
||||||
"the drawable"
|
|
||||||
},
|
|
||||||
{ PDB_INT32,
|
|
||||||
"channel",
|
|
||||||
"the channel to modify: { VALUE (0), RED (1), GREEN (2), BLUE (3), GRAY (0) }"
|
|
||||||
},
|
|
||||||
{ PDB_INT32,
|
|
||||||
"low_input",
|
|
||||||
"intensity of lowest input: (0 <= low_input <= 255)"
|
|
||||||
},
|
|
||||||
{ PDB_INT32,
|
|
||||||
"high_input",
|
|
||||||
"intensity of highest input: (0 <= high_input <= 255)"
|
|
||||||
},
|
|
||||||
{ PDB_FLOAT,
|
|
||||||
"gamma",
|
|
||||||
"gamma correction factor: (0.1 <= gamma <= 10)"
|
|
||||||
},
|
|
||||||
{ PDB_INT32,
|
|
||||||
"low_output",
|
|
||||||
"intensity of lowest output: (0 <= low_input <= 255)"
|
|
||||||
},
|
|
||||||
{ PDB_INT32,
|
|
||||||
"high_output",
|
|
||||||
"intensity of highest output: (0 <= high_input <= 255)"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ProcRecord levels_proc =
|
|
||||||
{
|
|
||||||
"gimp_levels",
|
|
||||||
"Modifies intensity levels in the specified drawable",
|
|
||||||
"This tool allows intensity levels in the specified drawable to be remapped according to a set of parameters. The low/high input levels specify an initial mapping from the source intensities. The gamma value determines how intensities between the low and high input intensities are interpolated. A gamma value of 1.0 results in a linear interpolation. Higher gamma values result in more high-level intensities. Lower gamma values result in more low-level intensities. The low/high output levels constrain the final intensity mapping--that is, no final intensity will be lower than the low output level and no final intensity will be higher than the high output level. This tool is only valid on RGB color and grayscale images. It will not operate on indexed drawables.",
|
|
||||||
"Spencer Kimball & Peter Mattis",
|
|
||||||
"Spencer Kimball & Peter Mattis",
|
|
||||||
"1995-1996",
|
|
||||||
PDB_INTERNAL,
|
|
||||||
|
|
||||||
/* Input arguments */
|
|
||||||
7,
|
|
||||||
levels_args,
|
|
||||||
|
|
||||||
/* Output arguments */
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
|
|
||||||
/* Exec method */
|
|
||||||
{ { levels_invoker } },
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static Argument *
|
|
||||||
levels_invoker (Argument *args)
|
|
||||||
{
|
|
||||||
PixelRegion srcPR, destPR;
|
|
||||||
int success = TRUE;
|
|
||||||
LevelsDialog ld;
|
|
||||||
GimpDrawable *drawable;
|
|
||||||
int channel;
|
|
||||||
int low_input;
|
|
||||||
int high_input;
|
|
||||||
double gamma;
|
|
||||||
int low_output;
|
|
||||||
int high_output;
|
|
||||||
int int_value;
|
|
||||||
double fp_value;
|
|
||||||
int x1, y1, x2, y2;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
drawable = NULL;
|
|
||||||
low_input = 0;
|
|
||||||
high_input = 0;
|
|
||||||
gamma = 1.0;
|
|
||||||
low_output = 0;
|
|
||||||
high_output = 0;
|
|
||||||
|
|
||||||
/* the drawable */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[0].value.pdb_int;
|
|
||||||
drawable = drawable_get_ID (int_value);
|
|
||||||
if (drawable == NULL)
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
/* make sure the drawable is not indexed color */
|
|
||||||
if (success)
|
|
||||||
success = ! drawable_indexed (drawable);
|
|
||||||
|
|
||||||
/* channel */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[1].value.pdb_int;
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
if (drawable_gray (drawable))
|
|
||||||
{
|
|
||||||
if (int_value != 0)
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
else if (drawable_color (drawable))
|
|
||||||
{
|
|
||||||
if (int_value < 0 || int_value > 3)
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
channel = int_value;
|
|
||||||
}
|
|
||||||
/* low input */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[2].value.pdb_int;
|
|
||||||
if (int_value >= 0 && int_value < 256)
|
|
||||||
low_input = int_value;
|
|
||||||
else
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
/* high input */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[3].value.pdb_int;
|
|
||||||
if (int_value >= 0 && int_value < 256)
|
|
||||||
high_input = int_value;
|
|
||||||
else
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
/* gamma */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
fp_value = args[4].value.pdb_float;
|
|
||||||
if (fp_value >= 0.1 && fp_value <= 10.0)
|
|
||||||
gamma = fp_value;
|
|
||||||
else
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
/* low output */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[5].value.pdb_int;
|
|
||||||
if (int_value >= 0 && int_value < 256)
|
|
||||||
low_output = int_value;
|
|
||||||
else
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
/* high output */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[6].value.pdb_int;
|
|
||||||
if (int_value >= 0 && int_value < 256)
|
|
||||||
high_output = int_value;
|
|
||||||
else
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* arrange to modify the levels */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
for (i = 0; i < 5; i++)
|
|
||||||
{
|
|
||||||
ld.low_input[i] = 0;
|
|
||||||
ld.gamma[i] = 1.0;
|
|
||||||
ld.high_input[i] = 255;
|
|
||||||
ld.low_output[i] = 0;
|
|
||||||
ld.high_output[i] = 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
ld.lut = gimp_lut_new();
|
|
||||||
ld.channel = channel;
|
|
||||||
ld.color = drawable_color (drawable);
|
|
||||||
ld.low_input[channel] = low_input;
|
|
||||||
ld.high_input[channel] = high_input;
|
|
||||||
ld.gamma[channel] = gamma;
|
|
||||||
ld.low_output[channel] = low_output;
|
|
||||||
ld.high_output[channel] = high_output;
|
|
||||||
|
|
||||||
/* setup the lut */
|
|
||||||
gimp_lut_setup(ld.lut, (GimpLutFunc) levels_lut_func,
|
|
||||||
(void *) &ld, gimp_drawable_bytes(drawable));
|
|
||||||
|
|
||||||
/* The application should occur only within selection bounds */
|
|
||||||
drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
|
|
||||||
|
|
||||||
pixel_region_init (&srcPR, drawable_data (drawable), x1, y1, (x2 - x1), (y2 - y1), FALSE);
|
|
||||||
pixel_region_init (&destPR, drawable_shadow (drawable), x1, y1, (x2 - x1), (y2 - y1), TRUE);
|
|
||||||
|
|
||||||
pixel_regions_process_parallel((p_func)gimp_lut_process, ld.lut,
|
|
||||||
2, &srcPR, &destPR);
|
|
||||||
|
|
||||||
gimp_lut_free(ld.lut);
|
|
||||||
drawable_merge_shadow (drawable, TRUE);
|
|
||||||
drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1));
|
|
||||||
}
|
|
||||||
|
|
||||||
return procedural_db_return_args (&levels_proc, success);
|
|
||||||
}
|
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#define __LEVELS_H__
|
#define __LEVELS_H__
|
||||||
|
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
#include "procedural_db.h"
|
|
||||||
|
|
||||||
/* hue-saturation functions */
|
/* hue-saturation functions */
|
||||||
Tool * tools_new_levels (void);
|
Tool * tools_new_levels (void);
|
||||||
|
@ -28,7 +27,4 @@ void tools_free_levels (Tool *);
|
||||||
void levels_initialize (GDisplay *);
|
void levels_initialize (GDisplay *);
|
||||||
void levels_free (void);
|
void levels_free (void);
|
||||||
|
|
||||||
/* Procedure definition and marshalling function */
|
|
||||||
extern ProcRecord levels_proc;
|
|
||||||
|
|
||||||
#endif /* __LEVELS_H__ */
|
#endif /* __LEVELS_H__ */
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
#include "posterize.h"
|
#include "posterize.h"
|
||||||
#include "gimplut.h"
|
#include "gimplut.h"
|
||||||
|
#include "lut_funcs.h"
|
||||||
|
|
||||||
#include "libgimp/gimpintl.h"
|
#include "libgimp/gimpintl.h"
|
||||||
|
|
||||||
|
@ -84,29 +85,6 @@ static void posterize_preview_update (GtkWidget *, gpointer);
|
||||||
static void posterize_levels_text_update (GtkWidget *, gpointer);
|
static void posterize_levels_text_update (GtkWidget *, gpointer);
|
||||||
static gint posterize_delete_callback (GtkWidget *, GdkEvent *, gpointer);
|
static gint posterize_delete_callback (GtkWidget *, GdkEvent *, gpointer);
|
||||||
|
|
||||||
static Argument * posterize_invoker (Argument *);
|
|
||||||
|
|
||||||
|
|
||||||
/* posterize machinery */
|
|
||||||
|
|
||||||
static float
|
|
||||||
posterize_lut_func(PosterizeDialog *pd,
|
|
||||||
int nchannels, int channel, float value)
|
|
||||||
{
|
|
||||||
int levels;
|
|
||||||
/* don't posterize the alpha channel */
|
|
||||||
if ((nchannels == 2 || nchannels == 4) && channel == nchannels -1)
|
|
||||||
return value;
|
|
||||||
|
|
||||||
if (pd->levels < 2)
|
|
||||||
levels = 2;
|
|
||||||
else
|
|
||||||
levels = pd->levels;
|
|
||||||
|
|
||||||
value = rint(value * (pd->levels - 1.0)) / (pd->levels - 1.0);
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* by_color select action functions */
|
/* by_color select action functions */
|
||||||
|
|
||||||
|
@ -343,8 +321,7 @@ posterize_preview (PosterizeDialog *pd)
|
||||||
if (!pd->image_map)
|
if (!pd->image_map)
|
||||||
g_message (_("posterize_preview(): No image map"));
|
g_message (_("posterize_preview(): No image map"));
|
||||||
active_tool->preserve = TRUE;
|
active_tool->preserve = TRUE;
|
||||||
gimp_lut_setup_exact(pd->lut, (GimpLutFunc) posterize_lut_func,
|
posterize_lut_setup(pd->lut, pd->levels, gimp_drawable_bytes(pd->drawable));
|
||||||
(void *) pd, gimp_drawable_bytes(pd->drawable));
|
|
||||||
image_map_apply (pd->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
image_map_apply (pd->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
||||||
(void *) pd->lut);
|
(void *) pd->lut);
|
||||||
active_tool->preserve = FALSE;
|
active_tool->preserve = FALSE;
|
||||||
|
@ -365,8 +342,8 @@ posterize_ok_callback (GtkWidget *widget,
|
||||||
|
|
||||||
if (!pd->preview)
|
if (!pd->preview)
|
||||||
{
|
{
|
||||||
gimp_lut_setup_exact(pd->lut, (GimpLutFunc) posterize_lut_func,
|
posterize_lut_setup(pd->lut, pd->levels,
|
||||||
(void *) pd, gimp_drawable_bytes(pd->drawable));
|
gimp_drawable_bytes(pd->drawable));
|
||||||
image_map_apply (pd->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
image_map_apply (pd->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
|
||||||
(void *) pd->lut);
|
(void *) pd->lut);
|
||||||
}
|
}
|
||||||
|
@ -444,100 +421,3 @@ posterize_levels_text_update (GtkWidget *w,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* The posterize procedure definition */
|
|
||||||
ProcArg posterize_args[] =
|
|
||||||
{
|
|
||||||
{ PDB_DRAWABLE,
|
|
||||||
"drawable",
|
|
||||||
"the drawable"
|
|
||||||
},
|
|
||||||
{ PDB_INT32,
|
|
||||||
"levels",
|
|
||||||
"levels of posterization: (2 <= levels <= 255)"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ProcRecord posterize_proc =
|
|
||||||
{
|
|
||||||
"gimp_posterize",
|
|
||||||
"Posterize the specified drawable",
|
|
||||||
"This procedures reduces the number of shades allows in each intensity channel to the specified 'levels' parameter.",
|
|
||||||
"Spencer Kimball & Peter Mattis",
|
|
||||||
"Spencer Kimball & Peter Mattis",
|
|
||||||
"1997",
|
|
||||||
PDB_INTERNAL,
|
|
||||||
|
|
||||||
/* Input arguments */
|
|
||||||
2,
|
|
||||||
posterize_args,
|
|
||||||
|
|
||||||
/* Output arguments */
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
|
|
||||||
/* Exec method */
|
|
||||||
{ { posterize_invoker } },
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static Argument *
|
|
||||||
posterize_invoker (Argument *args)
|
|
||||||
{
|
|
||||||
PixelRegion srcPR, destPR;
|
|
||||||
int success = TRUE;
|
|
||||||
PosterizeDialog pd;
|
|
||||||
GImage *gimage;
|
|
||||||
GimpDrawable *drawable;
|
|
||||||
int levels;
|
|
||||||
int int_value;
|
|
||||||
int x1, y1, x2, y2;
|
|
||||||
|
|
||||||
drawable = NULL;
|
|
||||||
levels = 0;
|
|
||||||
|
|
||||||
/* the drawable */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[0].value.pdb_int;
|
|
||||||
drawable = drawable_get_ID (int_value);
|
|
||||||
if (drawable == NULL)
|
|
||||||
success = FALSE;
|
|
||||||
else
|
|
||||||
gimage = drawable_gimage (drawable);
|
|
||||||
}
|
|
||||||
/* make sure the drawable is not indexed color */
|
|
||||||
if (success)
|
|
||||||
success = ! drawable_indexed (drawable);
|
|
||||||
|
|
||||||
/* levels */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
int_value = args[1].value.pdb_int;
|
|
||||||
if (int_value >= 2 && int_value < 256)
|
|
||||||
levels = int_value;
|
|
||||||
else
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* arrange to modify the levels */
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
pd.levels = levels;
|
|
||||||
pd.lut = gimp_lut_new();
|
|
||||||
/* The application should occur only within selection bounds */
|
|
||||||
drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
|
|
||||||
|
|
||||||
pixel_region_init (&srcPR, drawable_data (drawable), x1, y1, (x2 - x1), (y2 - y1), FALSE);
|
|
||||||
pixel_region_init (&destPR, drawable_shadow (drawable), x1, y1, (x2 - x1), (y2 - y1), TRUE);
|
|
||||||
|
|
||||||
pixel_regions_process_parallel((p_func)gimp_lut_process, pd.lut,
|
|
||||||
2, &srcPR, &destPR);
|
|
||||||
|
|
||||||
gimp_lut_free(pd.lut);
|
|
||||||
drawable_merge_shadow (drawable, TRUE);
|
|
||||||
drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1));
|
|
||||||
}
|
|
||||||
|
|
||||||
return procedural_db_return_args (&posterize_proc, success);
|
|
||||||
}
|
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#define __POSTERIZE_H__
|
#define __POSTERIZE_H__
|
||||||
|
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
#include "procedural_db.h"
|
|
||||||
|
|
||||||
/* by_color select functions */
|
/* by_color select functions */
|
||||||
Tool * tools_new_posterize (void);
|
Tool * tools_new_posterize (void);
|
||||||
|
@ -27,7 +26,4 @@ void tools_free_posterize (Tool *);
|
||||||
|
|
||||||
void posterize_initialize (GDisplay *);
|
void posterize_initialize (GDisplay *);
|
||||||
|
|
||||||
/* Procedure definition and marshalling function */
|
|
||||||
extern ProcRecord posterize_proc;
|
|
||||||
|
|
||||||
#endif /* __POSTERIZE_H__ */
|
#endif /* __POSTERIZE_H__ */
|
||||||
|
|
|
@ -75,6 +75,65 @@ parasite_new (const char *name, guint32 flags,
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Parasite *
|
||||||
|
parasite_load(FILE *fp)
|
||||||
|
{
|
||||||
|
guint32 tmp;
|
||||||
|
Parasite *p;
|
||||||
|
|
||||||
|
p = g_new(Parasite, 1);
|
||||||
|
tmp = 0;
|
||||||
|
fread(&tmp, 4, 1, fp);
|
||||||
|
tmp = GUINT32_FROM_BE(tmp);
|
||||||
|
if (tmp > 0)
|
||||||
|
{
|
||||||
|
p->name = g_malloc(tmp);
|
||||||
|
fread(p->name, tmp, 1, fp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_free (p);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
fread(&tmp, 4, 1, fp);
|
||||||
|
p->flags = GUINT32_FROM_BE(tmp);
|
||||||
|
tmp = 0;
|
||||||
|
fread(&tmp, 4, 1, fp);
|
||||||
|
p->size = GUINT32_FROM_BE(tmp);
|
||||||
|
if (p->size > 0)
|
||||||
|
{
|
||||||
|
p->data = g_malloc(p->size);
|
||||||
|
fread(p->data, p->size, 1, fp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
p->data = NULL;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
parasite_save(const Parasite *p, FILE *fp)
|
||||||
|
{
|
||||||
|
gint32 len, bytes = 0;
|
||||||
|
guint32 tmp;
|
||||||
|
len = strlen(p->name) + 1;
|
||||||
|
tmp = GUINT32_TO_BE(len);
|
||||||
|
fwrite(&tmp, 4, 1, fp);
|
||||||
|
bytes += 4;
|
||||||
|
if (len > 0)
|
||||||
|
fwrite(p->name, len, 1, fp);
|
||||||
|
bytes += len;
|
||||||
|
tmp = GUINT32_TO_BE(p->flags);
|
||||||
|
fwrite(&tmp, 4, 1, fp);
|
||||||
|
bytes += 4;
|
||||||
|
tmp = GUINT32_TO_BE(p->size);
|
||||||
|
fwrite(&tmp, 4, 1, fp);
|
||||||
|
bytes += 4;
|
||||||
|
if (p->size > 0)
|
||||||
|
fwrite(p->data, 1, p->size, fp);
|
||||||
|
bytes += p->size;
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
parasite_free (Parasite *parasite)
|
parasite_free (Parasite *parasite)
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#define _PARASITE_H_
|
#define _PARASITE_H_
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <libgimp/parasiteF.h>
|
#include <libgimp/parasiteF.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -36,7 +37,9 @@ extern "C" {
|
||||||
#define PARASITE_GRANDPARENT_PERSISTENT (PARASITE_PERSISTENT << 16)
|
#define PARASITE_GRANDPARENT_PERSISTENT (PARASITE_PERSISTENT << 16)
|
||||||
|
|
||||||
Parasite *parasite_new (const char *name, guint32 flags,
|
Parasite *parasite_new (const char *name, guint32 flags,
|
||||||
guint32 size, const void *data);
|
guint32 size, const void *data);
|
||||||
|
Parasite *parasite_load (FILE *fp);
|
||||||
|
int parasite_save (const Parasite *p, FILE *fp);
|
||||||
void parasite_free (Parasite *parasite);
|
void parasite_free (Parasite *parasite);
|
||||||
|
|
||||||
Parasite *parasite_copy (const Parasite *parasite);
|
Parasite *parasite_copy (const Parasite *parasite);
|
||||||
|
|
|
@ -75,6 +75,65 @@ parasite_new (const char *name, guint32 flags,
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Parasite *
|
||||||
|
parasite_load(FILE *fp)
|
||||||
|
{
|
||||||
|
guint32 tmp;
|
||||||
|
Parasite *p;
|
||||||
|
|
||||||
|
p = g_new(Parasite, 1);
|
||||||
|
tmp = 0;
|
||||||
|
fread(&tmp, 4, 1, fp);
|
||||||
|
tmp = GUINT32_FROM_BE(tmp);
|
||||||
|
if (tmp > 0)
|
||||||
|
{
|
||||||
|
p->name = g_malloc(tmp);
|
||||||
|
fread(p->name, tmp, 1, fp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_free (p);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
fread(&tmp, 4, 1, fp);
|
||||||
|
p->flags = GUINT32_FROM_BE(tmp);
|
||||||
|
tmp = 0;
|
||||||
|
fread(&tmp, 4, 1, fp);
|
||||||
|
p->size = GUINT32_FROM_BE(tmp);
|
||||||
|
if (p->size > 0)
|
||||||
|
{
|
||||||
|
p->data = g_malloc(p->size);
|
||||||
|
fread(p->data, p->size, 1, fp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
p->data = NULL;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
parasite_save(const Parasite *p, FILE *fp)
|
||||||
|
{
|
||||||
|
gint32 len, bytes = 0;
|
||||||
|
guint32 tmp;
|
||||||
|
len = strlen(p->name) + 1;
|
||||||
|
tmp = GUINT32_TO_BE(len);
|
||||||
|
fwrite(&tmp, 4, 1, fp);
|
||||||
|
bytes += 4;
|
||||||
|
if (len > 0)
|
||||||
|
fwrite(p->name, len, 1, fp);
|
||||||
|
bytes += len;
|
||||||
|
tmp = GUINT32_TO_BE(p->flags);
|
||||||
|
fwrite(&tmp, 4, 1, fp);
|
||||||
|
bytes += 4;
|
||||||
|
tmp = GUINT32_TO_BE(p->size);
|
||||||
|
fwrite(&tmp, 4, 1, fp);
|
||||||
|
bytes += 4;
|
||||||
|
if (p->size > 0)
|
||||||
|
fwrite(p->data, 1, p->size, fp);
|
||||||
|
bytes += p->size;
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
parasite_free (Parasite *parasite)
|
parasite_free (Parasite *parasite)
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#define _PARASITE_H_
|
#define _PARASITE_H_
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <libgimp/parasiteF.h>
|
#include <libgimp/parasiteF.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -36,7 +37,9 @@ extern "C" {
|
||||||
#define PARASITE_GRANDPARENT_PERSISTENT (PARASITE_PERSISTENT << 16)
|
#define PARASITE_GRANDPARENT_PERSISTENT (PARASITE_PERSISTENT << 16)
|
||||||
|
|
||||||
Parasite *parasite_new (const char *name, guint32 flags,
|
Parasite *parasite_new (const char *name, guint32 flags,
|
||||||
guint32 size, const void *data);
|
guint32 size, const void *data);
|
||||||
|
Parasite *parasite_load (FILE *fp);
|
||||||
|
int parasite_save (const Parasite *p, FILE *fp);
|
||||||
void parasite_free (Parasite *parasite);
|
void parasite_free (Parasite *parasite);
|
||||||
|
|
||||||
Parasite *parasite_copy (const Parasite *parasite);
|
Parasite *parasite_copy (const Parasite *parasite);
|
||||||
|
|
|
@ -75,6 +75,65 @@ parasite_new (const char *name, guint32 flags,
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Parasite *
|
||||||
|
parasite_load(FILE *fp)
|
||||||
|
{
|
||||||
|
guint32 tmp;
|
||||||
|
Parasite *p;
|
||||||
|
|
||||||
|
p = g_new(Parasite, 1);
|
||||||
|
tmp = 0;
|
||||||
|
fread(&tmp, 4, 1, fp);
|
||||||
|
tmp = GUINT32_FROM_BE(tmp);
|
||||||
|
if (tmp > 0)
|
||||||
|
{
|
||||||
|
p->name = g_malloc(tmp);
|
||||||
|
fread(p->name, tmp, 1, fp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_free (p);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
fread(&tmp, 4, 1, fp);
|
||||||
|
p->flags = GUINT32_FROM_BE(tmp);
|
||||||
|
tmp = 0;
|
||||||
|
fread(&tmp, 4, 1, fp);
|
||||||
|
p->size = GUINT32_FROM_BE(tmp);
|
||||||
|
if (p->size > 0)
|
||||||
|
{
|
||||||
|
p->data = g_malloc(p->size);
|
||||||
|
fread(p->data, p->size, 1, fp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
p->data = NULL;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
parasite_save(const Parasite *p, FILE *fp)
|
||||||
|
{
|
||||||
|
gint32 len, bytes = 0;
|
||||||
|
guint32 tmp;
|
||||||
|
len = strlen(p->name) + 1;
|
||||||
|
tmp = GUINT32_TO_BE(len);
|
||||||
|
fwrite(&tmp, 4, 1, fp);
|
||||||
|
bytes += 4;
|
||||||
|
if (len > 0)
|
||||||
|
fwrite(p->name, len, 1, fp);
|
||||||
|
bytes += len;
|
||||||
|
tmp = GUINT32_TO_BE(p->flags);
|
||||||
|
fwrite(&tmp, 4, 1, fp);
|
||||||
|
bytes += 4;
|
||||||
|
tmp = GUINT32_TO_BE(p->size);
|
||||||
|
fwrite(&tmp, 4, 1, fp);
|
||||||
|
bytes += 4;
|
||||||
|
if (p->size > 0)
|
||||||
|
fwrite(p->data, 1, p->size, fp);
|
||||||
|
bytes += p->size;
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
parasite_free (Parasite *parasite)
|
parasite_free (Parasite *parasite)
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#define _PARASITE_H_
|
#define _PARASITE_H_
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <libgimp/parasiteF.h>
|
#include <libgimp/parasiteF.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -36,7 +37,9 @@ extern "C" {
|
||||||
#define PARASITE_GRANDPARENT_PERSISTENT (PARASITE_PERSISTENT << 16)
|
#define PARASITE_GRANDPARENT_PERSISTENT (PARASITE_PERSISTENT << 16)
|
||||||
|
|
||||||
Parasite *parasite_new (const char *name, guint32 flags,
|
Parasite *parasite_new (const char *name, guint32 flags,
|
||||||
guint32 size, const void *data);
|
guint32 size, const void *data);
|
||||||
|
Parasite *parasite_load (FILE *fp);
|
||||||
|
int parasite_save (const Parasite *p, FILE *fp);
|
||||||
void parasite_free (Parasite *parasite);
|
void parasite_free (Parasite *parasite);
|
||||||
|
|
||||||
Parasite *parasite_copy (const Parasite *parasite);
|
Parasite *parasite_copy (const Parasite *parasite);
|
||||||
|
|
Loading…
Reference in New Issue