diff --git a/ChangeLog b/ChangeLog index c4ee5ef35d..5b9eb09872 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,55 @@ +1999-04-08 Jay Cox + + * 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 * plug-ins/autocrop/autocrop.c: Fixed a Bad Bug(TM). diff --git a/app/Makefile.am b/app/Makefile.am index 707bb2462a..ba1c4b68a2 100644 --- a/app/Makefile.am +++ b/app/Makefile.am @@ -77,6 +77,8 @@ gimp_SOURCES = \ color_area.h \ color_balance.c \ color_balance.h \ + color_cmds.c \ + color_cmds.h \ color_notebook.c \ color_notebook.h \ color_panel.c \ @@ -245,6 +247,8 @@ gimp_SOURCES = \ layers_dialogP.h \ levels.c \ levels.h \ + lut_funcs.c \ + lut_funcs.h \ magnify.c \ magnify.h \ main.c \ @@ -288,6 +292,8 @@ gimp_SOURCES = \ pencil.h \ perspective_tool.c \ perspective_tool.h \ + pixel_processor.c \ + pixel_processor.h \ pixel_region.c \ pixel_region.h \ pixmaps.h \ diff --git a/app/app_procs.c b/app/app_procs.c index ad0aa7bd61..a4493b81ec 100644 --- a/app/app_procs.c +++ b/app/app_procs.c @@ -85,6 +85,7 @@ #include "color_notebook.h" #include "color_select.h" +#include "gimpparasite.h" #include "libgimp/gimpintl.h" @@ -535,15 +536,16 @@ app_init (void) file_ops_pre_init (); /* pre-initialize the file types */ RESET_BAR(); 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 */ - 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 */ - 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 */ - 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 */ app_init_update_status (NULL, NULL, 1.00); @@ -635,6 +637,7 @@ app_exit_finish (void) menus_quit (); tile_swap_exit (); save_unitrc (); + gimp_parasiterc_save (); /* Things to do only if there is an interface */ if (no_interface == FALSE) diff --git a/app/base/boundary.c b/app/base/boundary.c index 1eb9bbf78c..c85b3e30c8 100644 --- a/app/base/boundary.c +++ b/app/base/boundary.c @@ -83,6 +83,8 @@ find_empty_segs (PixelRegion *maskPR, int val, last; int tilex; Tile *tile = NULL; + int endx, l_num_empty, dstep; + data = NULL; start = 0; @@ -121,7 +123,9 @@ find_empty_segs (PixelRegion *maskPR, empty_segs[(*num_empty)++] = 0; 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 */ 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); 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) empty_segs[(*num_empty)++] = x; diff --git a/app/base/gimplut.c b/app/base/gimplut.c index 8587ee4e03..b4d733e8e3 100644 --- a/app/base/gimplut.c +++ b/app/base/gimplut.c @@ -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 gimp_lut_process_2 (PixelRegion *srcPR, PixelRegion *destPR, diff --git a/app/base/gimplut.h b/app/base/gimplut.h index b18c4113c3..5ce2a44d19 100644 --- a/app/base/gimplut.h +++ b/app/base/gimplut.h @@ -49,6 +49,11 @@ void gimp_lut_process (GimpLut *lut, PixelRegion *srcPR, 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 perameter is last instead of first. this is necesary because pixel_region_process_paralell sends the user_data as the 1st diff --git a/app/base/lut-funcs.c b/app/base/lut-funcs.c new file mode 100644 index 0000000000..8255314b51 --- /dev/null +++ b/app/base/lut-funcs.c @@ -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 +#include +#include + +/* ---------- 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; +} diff --git a/app/base/lut-funcs.h b/app/base/lut-funcs.h new file mode 100644 index 0000000000..09acfad0bf --- /dev/null +++ b/app/base/lut-funcs.h @@ -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__ */ diff --git a/app/base/pixel-processor.c b/app/base/pixel-processor.c new file mode 100644 index 0000000000..dd1d1905e2 --- /dev/null +++ b/app/base/pixel-processor.c @@ -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 + * + * 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 +#include + +#ifdef ENABLE_MP + +#include + +#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); +} + diff --git a/app/base/pixel-processor.h b/app/base/pixel-processor.h new file mode 100644 index 0000000000..96ff634d33 --- /dev/null +++ b/app/base/pixel-processor.h @@ -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 + * + * 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__ */ diff --git a/app/base/pixel-region.c b/app/base/pixel-region.c index 7d448cf8ac..53d05672b7 100644 --- a/app/base/pixel-region.c +++ b/app/base/pixel-region.c @@ -26,18 +26,6 @@ #include "tile_manager_pvt.h" #include "tile.h" /* ick. */ -#ifdef ENABLE_MP - -#include - -#define IF_THREAD(statement) statement - -#else /* !USE_PTHREADS */ - -#define IF_THREAD(statement) - -#endif /* !USE_PTHREADS */ - 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 * pixel_regions_register (int num_regions, ...) { diff --git a/app/base/pixel-region.h b/app/base/pixel-region.h index 3bf03e747a..fc2d63d600 100644 --- a/app/base/pixel-region.h +++ b/app/base/pixel-region.h @@ -19,6 +19,7 @@ #define __PIXEL_REGION_H__ #include "tile_manager.h" +#include "pixel_processor.h" /* this is temporary, */ typedef struct _PixelRegion PixelRegion; @@ -36,7 +37,6 @@ struct _PixelRegion int process_count; /* used internally */ }; -typedef void (*p_func)(void); /* PixelRegion functions */ 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_set_col (PixelRegion *, int, int, int, unsigned char *); 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_stop (void *); diff --git a/app/boundary.c b/app/boundary.c index 1eb9bbf78c..c85b3e30c8 100644 --- a/app/boundary.c +++ b/app/boundary.c @@ -83,6 +83,8 @@ find_empty_segs (PixelRegion *maskPR, int val, last; int tilex; Tile *tile = NULL; + int endx, l_num_empty, dstep; + data = NULL; start = 0; @@ -121,7 +123,9 @@ find_empty_segs (PixelRegion *maskPR, empty_segs[(*num_empty)++] = 0; 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 */ 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); 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) empty_segs[(*num_empty)++] = x; diff --git a/app/brightness_contrast.c b/app/brightness_contrast.c index 2778b98499..1421701d73 100644 --- a/app/brightness_contrast.c +++ b/app/brightness_contrast.c @@ -28,6 +28,7 @@ #include "image_map.h" #include "interface.h" #include "gimplut.h" +#include "lut_funcs.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 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 */ @@ -467,8 +415,9 @@ brightness_contrast_preview (BrightnessContrastDialog *bcd) if (!bcd->image_map) g_message (_("brightness_contrast_preview(): No image map")); active_tool->preserve = TRUE; - gimp_lut_setup(bcd->lut, (GimpLutFunc) brightness_contrast_lut_func, - (void *) bcd, gimp_drawable_bytes(bcd->drawable)); + brightness_contrast_lut_setup(bcd->lut, bcd->brightness / 255.0, + bcd->contrast / 127.0, + gimp_drawable_bytes(bcd->drawable)); image_map_apply (bcd->image_map, (ImageMapApplyFunc)gimp_lut_process_2, (void *) bcd->lut); active_tool->preserve = FALSE; @@ -489,8 +438,9 @@ brightness_contrast_ok_callback (GtkWidget *widget, if (!bcd->preview) { - gimp_lut_setup(bcd->lut, (GimpLutFunc) brightness_contrast_lut_func, - (void *) bcd, gimp_drawable_bytes(bcd->drawable)); + brightness_contrast_lut_setup(bcd->lut, bcd->brightness / 255.0, + bcd->contrast / 127.0, + gimp_drawable_bytes(bcd->drawable)); image_map_apply (bcd->image_map, (ImageMapApplyFunc)gimp_lut_process_2, (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); -} diff --git a/app/brightness_contrast.h b/app/brightness_contrast.h index d3b2f214de..45467e1962 100644 --- a/app/brightness_contrast.h +++ b/app/brightness_contrast.h @@ -19,7 +19,6 @@ #define __BRIGHTNESS_CONTRAST_H__ #include "tools.h" -#include "procedural_db.h" /* by_color select functions */ Tool * tools_new_brightness_contrast (void); @@ -27,7 +26,4 @@ void tools_free_brightness_contrast (Tool *); void brightness_contrast_initialize (GDisplay *); -/* Procedure definition and marshalling function */ -extern ProcRecord brightness_contrast_proc; - #endif /* __BRIGHTNESS_CONTRAST_H__ */ diff --git a/app/channel.c b/app/channel.c index 17ebf70866..6b570da0f5 100644 --- a/app/channel.c +++ b/app/channel.c @@ -36,6 +36,9 @@ #include "channel_pvt.h" #include "tile.h" +#include "gimplut.h" +#include "lut_funcs.h" + /* enum { LAST_SIGNAL @@ -602,9 +605,9 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2) unsigned char * data; int x, y; int ex, ey; - int found; void *pr; - + int tx1, tx2, ty1, ty2; + int minx, maxx; /* if the mask's bounds have already been reliably calculated... */ 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 */ - *x1 = GIMP_DRAWABLE(mask)->width; - *y1 = GIMP_DRAWABLE(mask)->height; - *x2 = 0; - *y2 = 0; + tx1 = GIMP_DRAWABLE(mask)->width; + ty1 = GIMP_DRAWABLE(mask)->height; + tx2 = 0; + ty2 = 0; 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)) @@ -630,36 +633,50 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2) ey = maskPR.y + maskPR.h; /* only check the pixels if this tile is not fully within the currently computed bounds */ - if (maskPR.x < *x1 || ex > *x2 || - maskPR.y < *y1 || ey > *y2) + if (maskPR.x < tx1 || ex > tx2 || + 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++) if (*data) - { - if (x < *x1) - *x1 = x; - if (x > *x2) - *x2 = x; - found = TRUE; - } - if (found) - { - if (y < *y1) - *y1 = y; - if (y > *y2) - *y2 = y; - } + { + minx = x; + maxx = x; + for (; x < ex; x++, data++) + if (*data) + maxx = x; + if (minx < tx1) + tx1 = minx; + if (maxx > tx2) + tx2 = maxx; + if (y < ty1) + ty1 = y; + if (y > ty2) + ty2 = y; + } } } } - *x2 = BOUNDS (*x2 + 1, 0, GIMP_DRAWABLE(mask)->width); - *y2 = BOUNDS (*y2 + 1, 0, GIMP_DRAWABLE(mask)->height); + tx2 = BOUNDS (tx2 + 1, 0, GIMP_DRAWABLE(mask)->width); + 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->x1 = 0; mask->y1 = 0; @@ -669,13 +686,18 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2) else { mask->empty = FALSE; - mask->x1 = *x1; - mask->y1 = *y1; - mask->x2 = *x2; - mask->y2 = *y2; + mask->x1 = tx1; + mask->y1 = ty1; + mask->x2 = tx2; + mask->y2 = ty2; } mask->bounds_known = TRUE; + *x1 = tx1; + *x2 = tx2; + *y1 = ty1; + *y2 = ty2; + 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 channel_combine_rect (Channel *mask, int op, int x, int y, int w, int h) { int i; + int x2, y2; + PixelRegion maskPR; + unsigned char color; + y2 = y + h; + x2 = x + w; - for (i = y; i < y + h; i++) - { - if (i >= 0 && i < GIMP_DRAWABLE(mask)->height) - switch (op) - { - case ADD: case REPLACE: - channel_add_segment (mask, x, i, w, 255); - break; - case SUB: - channel_sub_segment (mask, x, i, w, 255); - break; - case INTERSECT: - channel_inter_segment (mask, x, i, w, 255); - break; - } - } + x = BOUNDS (x, 0, GIMP_DRAWABLE(mask)->width); + y = BOUNDS (y, 0, GIMP_DRAWABLE(mask)->height); + x2 = BOUNDS (x2, 0, GIMP_DRAWABLE(mask)->width); + y2 = BOUNDS (y2, 0, GIMP_DRAWABLE(mask)->height); + + if (x2 - x <= 0 || y2 - y <= 0) + return; + + pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, x, y, + x2 - x, y2 - y, TRUE); + if (op == ADD || op == REPLACE) + color = 255; + else + color = 0; + color_region(&maskPR, &color); /* Determine new boundary */ 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 : channel_sub_segment (mask, x1, i, (x2 - x1), 255); break; - case INTERSECT: - channel_inter_segment (mask, x1, i, (x2 - x1), 255); - break; } } /* 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))); else val = 0; - + if (last != val && last) { switch (op) @@ -976,8 +965,6 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h, case SUB: channel_sub_segment (mask, x0, i, j - x0, last); 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; 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); else if (op == SUB) 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 channel_combine_mask (Channel *mask, Channel *add_on, int op, int off_x, int off_y) { PixelRegion srcPR, destPR; - unsigned char *src; - unsigned char *dest; - int val; int x1, y1, x2, y2; - int x, y; int w, h; - void * pr; x1 = BOUNDS (off_x, 0, GIMP_DRAWABLE(mask)->width); 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 (&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)) - { - src = srcPR.data; - dest = destPR.data; - - for (y = 0; y < srcPR.h; y++) - { - for (x = 0; x < srcPR.w; x++) - { - switch (op) - { - case ADD: case REPLACE: - val = dest[x] + src[x]; - if (val > 255) val = 255; - break; - case SUB: - val = dest[x] - src[x]; - if (val < 0) val = 0; - break; - case INTERSECT: - val = MINIMUM(dest[x], src[x]); - break; - default: - val = 0; - break; - } - dest[x] = val; - } - src += srcPR.rowstride; - dest += destPR.rowstride; - } - } - + switch (op) + { + case ADD: case REPLACE: + pixel_regions_process_parallel ((p_func)channel_combine_sub_region_add, + NULL, 2, &srcPR, &destPR); + break; + case SUB: + pixel_regions_process_parallel ((p_func)channel_combine_sub_region_sub, + NULL, 2, &srcPR, &destPR); + break; + case INTERSECT: + pixel_regions_process_parallel ((p_func) + channel_combine_sub_region_intersect, + NULL, 2, &srcPR, &destPR); + break; + default: + g_message("Error: unknown opperation type in channel_combine_mask\n"); + break; + } mask->bounds_known = FALSE; } @@ -1184,57 +1222,35 @@ void channel_invert (Channel *mask) { PixelRegion maskPR; - unsigned char *data; - int size; - void * pr; + GimpLut *lut; /* push the current channel onto the undo stack */ channel_push_undo (mask); 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)) - { - /* subtract each pixel in the mask from 255 */ - data = maskPR.data; - size = maskPR.w * maskPR.h; - while (size --) - { - *data = 255 - *data; - data++; - } - } + + lut = invert_lut_new(1); + pixel_regions_process_parallel ((p_func)gimp_lut_process_inline, + lut, 1, &maskPR); + gimp_lut_free(lut); mask->bounds_known = FALSE; } - void channel_sharpen (Channel *mask) { PixelRegion maskPR; - unsigned char *data; - int size; - void * pr; - + GimpLut *lut; /* push the current channel onto the undo stack */ channel_push_undo (mask); 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)) - { - /* 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; - } - } + lut = threshold_lut_new(0.5, 1); - mask->bounds_known = FALSE; + pixel_regions_process_parallel ((p_func)gimp_lut_process_inline, + lut, 1, &maskPR); + gimp_lut_free(lut); } diff --git a/app/color_cmds.c b/app/color_cmds.c new file mode 100644 index 0000000000..80616095fd --- /dev/null +++ b/app/color_cmds.c @@ -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); +} diff --git a/app/color_cmds.h b/app/color_cmds.h new file mode 100644 index 0000000000..16757f667c --- /dev/null +++ b/app/color_cmds.h @@ -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__ */ diff --git a/app/core/gimp-parasites.c b/app/core/gimp-parasites.c index 25cd5255e6..44776501a4 100644 --- a/app/core/gimp-parasites.c +++ b/app/core/gimp-parasites.c @@ -16,8 +16,12 @@ */ #include +#include +#include #include "parasitelist.h" #include "gimpparasite.h" +#include "libgimp/parasite.h" +#include "libgimp/gimpenv.h" static ParasiteList *parasites = NULL; @@ -26,6 +30,7 @@ gimp_init_parasites() { g_return_if_fail(parasites == NULL); parasites = parasite_list_new(); + gimp_parasiterc_load(); } void @@ -64,5 +69,40 @@ gimp_parasite_list (gint *count) 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); +} diff --git a/app/core/gimp-parasites.h b/app/core/gimp-parasites.h index 49ed74baf5..eaaceb197e 100644 --- a/app/core/gimp-parasites.h +++ b/app/core/gimp-parasites.h @@ -25,5 +25,7 @@ void gimp_attach_parasite (Parasite *p); void gimp_detach_parasite (char *name); Parasite * gimp_find_parasite (char *name); char ** gimp_parasite_list (gint *count); +void gimp_parasiterc_save (void); +void gimp_parasiterc_load (void); #endif /* __GIMP_PARASITE_H__ */ diff --git a/app/core/gimpchannel-combine.c b/app/core/gimpchannel-combine.c index 17ebf70866..6b570da0f5 100644 --- a/app/core/gimpchannel-combine.c +++ b/app/core/gimpchannel-combine.c @@ -36,6 +36,9 @@ #include "channel_pvt.h" #include "tile.h" +#include "gimplut.h" +#include "lut_funcs.h" + /* enum { LAST_SIGNAL @@ -602,9 +605,9 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2) unsigned char * data; int x, y; int ex, ey; - int found; void *pr; - + int tx1, tx2, ty1, ty2; + int minx, maxx; /* if the mask's bounds have already been reliably calculated... */ 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 */ - *x1 = GIMP_DRAWABLE(mask)->width; - *y1 = GIMP_DRAWABLE(mask)->height; - *x2 = 0; - *y2 = 0; + tx1 = GIMP_DRAWABLE(mask)->width; + ty1 = GIMP_DRAWABLE(mask)->height; + tx2 = 0; + ty2 = 0; 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)) @@ -630,36 +633,50 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2) ey = maskPR.y + maskPR.h; /* only check the pixels if this tile is not fully within the currently computed bounds */ - if (maskPR.x < *x1 || ex > *x2 || - maskPR.y < *y1 || ey > *y2) + if (maskPR.x < tx1 || ex > tx2 || + 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++) if (*data) - { - if (x < *x1) - *x1 = x; - if (x > *x2) - *x2 = x; - found = TRUE; - } - if (found) - { - if (y < *y1) - *y1 = y; - if (y > *y2) - *y2 = y; - } + { + minx = x; + maxx = x; + for (; x < ex; x++, data++) + if (*data) + maxx = x; + if (minx < tx1) + tx1 = minx; + if (maxx > tx2) + tx2 = maxx; + if (y < ty1) + ty1 = y; + if (y > ty2) + ty2 = y; + } } } } - *x2 = BOUNDS (*x2 + 1, 0, GIMP_DRAWABLE(mask)->width); - *y2 = BOUNDS (*y2 + 1, 0, GIMP_DRAWABLE(mask)->height); + tx2 = BOUNDS (tx2 + 1, 0, GIMP_DRAWABLE(mask)->width); + 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->x1 = 0; mask->y1 = 0; @@ -669,13 +686,18 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2) else { mask->empty = FALSE; - mask->x1 = *x1; - mask->y1 = *y1; - mask->x2 = *x2; - mask->y2 = *y2; + mask->x1 = tx1; + mask->y1 = ty1; + mask->x2 = tx2; + mask->y2 = ty2; } mask->bounds_known = TRUE; + *x1 = tx1; + *x2 = tx2; + *y1 = ty1; + *y2 = ty2; + 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 channel_combine_rect (Channel *mask, int op, int x, int y, int w, int h) { int i; + int x2, y2; + PixelRegion maskPR; + unsigned char color; + y2 = y + h; + x2 = x + w; - for (i = y; i < y + h; i++) - { - if (i >= 0 && i < GIMP_DRAWABLE(mask)->height) - switch (op) - { - case ADD: case REPLACE: - channel_add_segment (mask, x, i, w, 255); - break; - case SUB: - channel_sub_segment (mask, x, i, w, 255); - break; - case INTERSECT: - channel_inter_segment (mask, x, i, w, 255); - break; - } - } + x = BOUNDS (x, 0, GIMP_DRAWABLE(mask)->width); + y = BOUNDS (y, 0, GIMP_DRAWABLE(mask)->height); + x2 = BOUNDS (x2, 0, GIMP_DRAWABLE(mask)->width); + y2 = BOUNDS (y2, 0, GIMP_DRAWABLE(mask)->height); + + if (x2 - x <= 0 || y2 - y <= 0) + return; + + pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, x, y, + x2 - x, y2 - y, TRUE); + if (op == ADD || op == REPLACE) + color = 255; + else + color = 0; + color_region(&maskPR, &color); /* Determine new boundary */ 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 : channel_sub_segment (mask, x1, i, (x2 - x1), 255); break; - case INTERSECT: - channel_inter_segment (mask, x1, i, (x2 - x1), 255); - break; } } /* 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))); else val = 0; - + if (last != val && last) { switch (op) @@ -976,8 +965,6 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h, case SUB: channel_sub_segment (mask, x0, i, j - x0, last); 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; 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); else if (op == SUB) 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 channel_combine_mask (Channel *mask, Channel *add_on, int op, int off_x, int off_y) { PixelRegion srcPR, destPR; - unsigned char *src; - unsigned char *dest; - int val; int x1, y1, x2, y2; - int x, y; int w, h; - void * pr; x1 = BOUNDS (off_x, 0, GIMP_DRAWABLE(mask)->width); 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 (&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)) - { - src = srcPR.data; - dest = destPR.data; - - for (y = 0; y < srcPR.h; y++) - { - for (x = 0; x < srcPR.w; x++) - { - switch (op) - { - case ADD: case REPLACE: - val = dest[x] + src[x]; - if (val > 255) val = 255; - break; - case SUB: - val = dest[x] - src[x]; - if (val < 0) val = 0; - break; - case INTERSECT: - val = MINIMUM(dest[x], src[x]); - break; - default: - val = 0; - break; - } - dest[x] = val; - } - src += srcPR.rowstride; - dest += destPR.rowstride; - } - } - + switch (op) + { + case ADD: case REPLACE: + pixel_regions_process_parallel ((p_func)channel_combine_sub_region_add, + NULL, 2, &srcPR, &destPR); + break; + case SUB: + pixel_regions_process_parallel ((p_func)channel_combine_sub_region_sub, + NULL, 2, &srcPR, &destPR); + break; + case INTERSECT: + pixel_regions_process_parallel ((p_func) + channel_combine_sub_region_intersect, + NULL, 2, &srcPR, &destPR); + break; + default: + g_message("Error: unknown opperation type in channel_combine_mask\n"); + break; + } mask->bounds_known = FALSE; } @@ -1184,57 +1222,35 @@ void channel_invert (Channel *mask) { PixelRegion maskPR; - unsigned char *data; - int size; - void * pr; + GimpLut *lut; /* push the current channel onto the undo stack */ channel_push_undo (mask); 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)) - { - /* subtract each pixel in the mask from 255 */ - data = maskPR.data; - size = maskPR.w * maskPR.h; - while (size --) - { - *data = 255 - *data; - data++; - } - } + + lut = invert_lut_new(1); + pixel_regions_process_parallel ((p_func)gimp_lut_process_inline, + lut, 1, &maskPR); + gimp_lut_free(lut); mask->bounds_known = FALSE; } - void channel_sharpen (Channel *mask) { PixelRegion maskPR; - unsigned char *data; - int size; - void * pr; - + GimpLut *lut; /* push the current channel onto the undo stack */ channel_push_undo (mask); 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)) - { - /* 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; - } - } + lut = threshold_lut_new(0.5, 1); - mask->bounds_known = FALSE; + pixel_regions_process_parallel ((p_func)gimp_lut_process_inline, + lut, 1, &maskPR); + gimp_lut_free(lut); } diff --git a/app/core/gimpchannel.c b/app/core/gimpchannel.c index 17ebf70866..6b570da0f5 100644 --- a/app/core/gimpchannel.c +++ b/app/core/gimpchannel.c @@ -36,6 +36,9 @@ #include "channel_pvt.h" #include "tile.h" +#include "gimplut.h" +#include "lut_funcs.h" + /* enum { LAST_SIGNAL @@ -602,9 +605,9 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2) unsigned char * data; int x, y; int ex, ey; - int found; void *pr; - + int tx1, tx2, ty1, ty2; + int minx, maxx; /* if the mask's bounds have already been reliably calculated... */ 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 */ - *x1 = GIMP_DRAWABLE(mask)->width; - *y1 = GIMP_DRAWABLE(mask)->height; - *x2 = 0; - *y2 = 0; + tx1 = GIMP_DRAWABLE(mask)->width; + ty1 = GIMP_DRAWABLE(mask)->height; + tx2 = 0; + ty2 = 0; 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)) @@ -630,36 +633,50 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2) ey = maskPR.y + maskPR.h; /* only check the pixels if this tile is not fully within the currently computed bounds */ - if (maskPR.x < *x1 || ex > *x2 || - maskPR.y < *y1 || ey > *y2) + if (maskPR.x < tx1 || ex > tx2 || + 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++) if (*data) - { - if (x < *x1) - *x1 = x; - if (x > *x2) - *x2 = x; - found = TRUE; - } - if (found) - { - if (y < *y1) - *y1 = y; - if (y > *y2) - *y2 = y; - } + { + minx = x; + maxx = x; + for (; x < ex; x++, data++) + if (*data) + maxx = x; + if (minx < tx1) + tx1 = minx; + if (maxx > tx2) + tx2 = maxx; + if (y < ty1) + ty1 = y; + if (y > ty2) + ty2 = y; + } } } } - *x2 = BOUNDS (*x2 + 1, 0, GIMP_DRAWABLE(mask)->width); - *y2 = BOUNDS (*y2 + 1, 0, GIMP_DRAWABLE(mask)->height); + tx2 = BOUNDS (tx2 + 1, 0, GIMP_DRAWABLE(mask)->width); + 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->x1 = 0; mask->y1 = 0; @@ -669,13 +686,18 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2) else { mask->empty = FALSE; - mask->x1 = *x1; - mask->y1 = *y1; - mask->x2 = *x2; - mask->y2 = *y2; + mask->x1 = tx1; + mask->y1 = ty1; + mask->x2 = tx2; + mask->y2 = ty2; } mask->bounds_known = TRUE; + *x1 = tx1; + *x2 = tx2; + *y1 = ty1; + *y2 = ty2; + 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 channel_combine_rect (Channel *mask, int op, int x, int y, int w, int h) { int i; + int x2, y2; + PixelRegion maskPR; + unsigned char color; + y2 = y + h; + x2 = x + w; - for (i = y; i < y + h; i++) - { - if (i >= 0 && i < GIMP_DRAWABLE(mask)->height) - switch (op) - { - case ADD: case REPLACE: - channel_add_segment (mask, x, i, w, 255); - break; - case SUB: - channel_sub_segment (mask, x, i, w, 255); - break; - case INTERSECT: - channel_inter_segment (mask, x, i, w, 255); - break; - } - } + x = BOUNDS (x, 0, GIMP_DRAWABLE(mask)->width); + y = BOUNDS (y, 0, GIMP_DRAWABLE(mask)->height); + x2 = BOUNDS (x2, 0, GIMP_DRAWABLE(mask)->width); + y2 = BOUNDS (y2, 0, GIMP_DRAWABLE(mask)->height); + + if (x2 - x <= 0 || y2 - y <= 0) + return; + + pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, x, y, + x2 - x, y2 - y, TRUE); + if (op == ADD || op == REPLACE) + color = 255; + else + color = 0; + color_region(&maskPR, &color); /* Determine new boundary */ 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 : channel_sub_segment (mask, x1, i, (x2 - x1), 255); break; - case INTERSECT: - channel_inter_segment (mask, x1, i, (x2 - x1), 255); - break; } } /* 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))); else val = 0; - + if (last != val && last) { switch (op) @@ -976,8 +965,6 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h, case SUB: channel_sub_segment (mask, x0, i, j - x0, last); 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; 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); else if (op == SUB) 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 channel_combine_mask (Channel *mask, Channel *add_on, int op, int off_x, int off_y) { PixelRegion srcPR, destPR; - unsigned char *src; - unsigned char *dest; - int val; int x1, y1, x2, y2; - int x, y; int w, h; - void * pr; x1 = BOUNDS (off_x, 0, GIMP_DRAWABLE(mask)->width); 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 (&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)) - { - src = srcPR.data; - dest = destPR.data; - - for (y = 0; y < srcPR.h; y++) - { - for (x = 0; x < srcPR.w; x++) - { - switch (op) - { - case ADD: case REPLACE: - val = dest[x] + src[x]; - if (val > 255) val = 255; - break; - case SUB: - val = dest[x] - src[x]; - if (val < 0) val = 0; - break; - case INTERSECT: - val = MINIMUM(dest[x], src[x]); - break; - default: - val = 0; - break; - } - dest[x] = val; - } - src += srcPR.rowstride; - dest += destPR.rowstride; - } - } - + switch (op) + { + case ADD: case REPLACE: + pixel_regions_process_parallel ((p_func)channel_combine_sub_region_add, + NULL, 2, &srcPR, &destPR); + break; + case SUB: + pixel_regions_process_parallel ((p_func)channel_combine_sub_region_sub, + NULL, 2, &srcPR, &destPR); + break; + case INTERSECT: + pixel_regions_process_parallel ((p_func) + channel_combine_sub_region_intersect, + NULL, 2, &srcPR, &destPR); + break; + default: + g_message("Error: unknown opperation type in channel_combine_mask\n"); + break; + } mask->bounds_known = FALSE; } @@ -1184,57 +1222,35 @@ void channel_invert (Channel *mask) { PixelRegion maskPR; - unsigned char *data; - int size; - void * pr; + GimpLut *lut; /* push the current channel onto the undo stack */ channel_push_undo (mask); 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)) - { - /* subtract each pixel in the mask from 255 */ - data = maskPR.data; - size = maskPR.w * maskPR.h; - while (size --) - { - *data = 255 - *data; - data++; - } - } + + lut = invert_lut_new(1); + pixel_regions_process_parallel ((p_func)gimp_lut_process_inline, + lut, 1, &maskPR); + gimp_lut_free(lut); mask->bounds_known = FALSE; } - void channel_sharpen (Channel *mask) { PixelRegion maskPR; - unsigned char *data; - int size; - void * pr; - + GimpLut *lut; /* push the current channel onto the undo stack */ channel_push_undo (mask); 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)) - { - /* 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; - } - } + lut = threshold_lut_new(0.5, 1); - mask->bounds_known = FALSE; + pixel_regions_process_parallel ((p_func)gimp_lut_process_inline, + lut, 1, &maskPR); + gimp_lut_free(lut); } diff --git a/app/core/gimpdrawable-equalize.c b/app/core/gimpdrawable-equalize.c index eeaeb0e036..158106f065 100644 --- a/app/core/gimpdrawable-equalize.c +++ b/app/core/gimpdrawable-equalize.c @@ -19,27 +19,17 @@ #include #include #include -#include "appenv.h" #include "drawable.h" #include "equalize.h" -#include "interface.h" #include "gimage.h" #include "gimplut.h" +#include "lut_funcs.h" #include "gimphistogram.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 Argument * equalize_invoker (Argument *); -static GimpLut * eq_histogram_lut (GimpHistogram *hist, int bytes); void @@ -87,7 +77,7 @@ equalize(gimage, drawable, mask_only) /* Build equalization LUT */ - lut = eq_histogram_lut (hist, bytes); + lut = eq_histogram_lut_new (hist, bytes); /* Apply the histogram */ 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)); } +/* ------------------------------------------------------------------ */ +/* --------------- 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[] = { { PDB_DRAWABLE, diff --git a/app/core/gimpdrawable-invert.c b/app/core/gimpdrawable-invert.c index e83220c1bd..c188f46e76 100644 --- a/app/core/gimpdrawable-invert.c +++ b/app/core/gimpdrawable-invert.c @@ -24,6 +24,7 @@ #include "invert.h" #include "gimage.h" #include "gimplut.h" +#include "lut_funcs.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 */ static void @@ -79,10 +68,7 @@ invert (GimpDrawable *drawable) int x1, y1, x2, y2; GimpLut *lut; - lut = gimp_lut_new(); - - gimp_lut_setup_exact(lut, (GimpLutFunc) invert_lut_func, - (void *) NULL, gimp_drawable_bytes(drawable)); + lut = invert_lut_new(gimp_drawable_bytes(drawable)); drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2); 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)); } +/* ------------------------------------------------------------------ */ +/* ----------------- The invert procedure definition ---------------- */ +/* ------------------------------------------------------------------ */ -/* The invert procedure definition */ ProcArg invert_args[] = { { PDB_DRAWABLE, diff --git a/app/core/gimpdrawable.c b/app/core/gimpdrawable.c index f9cd6dbd6d..31b3da4dfe 100644 --- a/app/core/gimpdrawable.c +++ b/app/core/gimpdrawable.c @@ -640,7 +640,6 @@ gimp_drawable_init (GimpDrawable *drawable) drawable->preview_valid = FALSE; drawable->parasites = parasite_list_new(); drawable->tattoo = 0; - gimp_matrix_identity(drawable->transform); drawable->ID = global_drawable_ID++; if (gimp_drawable_table == NULL) diff --git a/app/core/gimpimage-guides.c b/app/core/gimpimage-guides.c index b6c79b79a6..7c4f8a73e0 100644 --- a/app/core/gimpimage-guides.c +++ b/app/core/gimpimage-guides.c @@ -169,7 +169,6 @@ static void gimp_image_init (GimpImage *gimage) gimage->comp_preview_valid[2] = FALSE; gimage->comp_preview = NULL; gimage->parasites = parasite_list_new(); - gimp_matrix_identity(gimage->transform); gimage->xresolution = default_xresolution; gimage->yresolution = default_yresolution; gimage->unit = default_units; diff --git a/app/core/gimpimage-merge.c b/app/core/gimpimage-merge.c index b6c79b79a6..7c4f8a73e0 100644 --- a/app/core/gimpimage-merge.c +++ b/app/core/gimpimage-merge.c @@ -169,7 +169,6 @@ static void gimp_image_init (GimpImage *gimage) gimage->comp_preview_valid[2] = FALSE; gimage->comp_preview = NULL; gimage->parasites = parasite_list_new(); - gimp_matrix_identity(gimage->transform); gimage->xresolution = default_xresolution; gimage->yresolution = default_yresolution; gimage->unit = default_units; diff --git a/app/core/gimpimage-projection.c b/app/core/gimpimage-projection.c index b6c79b79a6..7c4f8a73e0 100644 --- a/app/core/gimpimage-projection.c +++ b/app/core/gimpimage-projection.c @@ -169,7 +169,6 @@ static void gimp_image_init (GimpImage *gimage) gimage->comp_preview_valid[2] = FALSE; gimage->comp_preview = NULL; gimage->parasites = parasite_list_new(); - gimp_matrix_identity(gimage->transform); gimage->xresolution = default_xresolution; gimage->yresolution = default_yresolution; gimage->unit = default_units; diff --git a/app/core/gimpimage-resize.c b/app/core/gimpimage-resize.c index b6c79b79a6..7c4f8a73e0 100644 --- a/app/core/gimpimage-resize.c +++ b/app/core/gimpimage-resize.c @@ -169,7 +169,6 @@ static void gimp_image_init (GimpImage *gimage) gimage->comp_preview_valid[2] = FALSE; gimage->comp_preview = NULL; gimage->parasites = parasite_list_new(); - gimp_matrix_identity(gimage->transform); gimage->xresolution = default_xresolution; gimage->yresolution = default_yresolution; gimage->unit = default_units; diff --git a/app/core/gimpimage-scale.c b/app/core/gimpimage-scale.c index b6c79b79a6..7c4f8a73e0 100644 --- a/app/core/gimpimage-scale.c +++ b/app/core/gimpimage-scale.c @@ -169,7 +169,6 @@ static void gimp_image_init (GimpImage *gimage) gimage->comp_preview_valid[2] = FALSE; gimage->comp_preview = NULL; gimage->parasites = parasite_list_new(); - gimp_matrix_identity(gimage->transform); gimage->xresolution = default_xresolution; gimage->yresolution = default_yresolution; gimage->unit = default_units; diff --git a/app/core/gimpimage.c b/app/core/gimpimage.c index b6c79b79a6..7c4f8a73e0 100644 --- a/app/core/gimpimage.c +++ b/app/core/gimpimage.c @@ -169,7 +169,6 @@ static void gimp_image_init (GimpImage *gimage) gimage->comp_preview_valid[2] = FALSE; gimage->comp_preview = NULL; gimage->parasites = parasite_list_new(); - gimp_matrix_identity(gimage->transform); gimage->xresolution = default_xresolution; gimage->yresolution = default_yresolution; gimage->unit = default_units; diff --git a/app/core/gimpparasite.c b/app/core/gimpparasite.c index 25cd5255e6..44776501a4 100644 --- a/app/core/gimpparasite.c +++ b/app/core/gimpparasite.c @@ -16,8 +16,12 @@ */ #include +#include +#include #include "parasitelist.h" #include "gimpparasite.h" +#include "libgimp/parasite.h" +#include "libgimp/gimpenv.h" static ParasiteList *parasites = NULL; @@ -26,6 +30,7 @@ gimp_init_parasites() { g_return_if_fail(parasites == NULL); parasites = parasite_list_new(); + gimp_parasiterc_load(); } void @@ -64,5 +69,40 @@ gimp_parasite_list (gint *count) 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); +} diff --git a/app/core/gimpparasite.h b/app/core/gimpparasite.h index 49ed74baf5..eaaceb197e 100644 --- a/app/core/gimpparasite.h +++ b/app/core/gimpparasite.h @@ -25,5 +25,7 @@ void gimp_attach_parasite (Parasite *p); void gimp_detach_parasite (char *name); Parasite * gimp_find_parasite (char *name); char ** gimp_parasite_list (gint *count); +void gimp_parasiterc_save (void); +void gimp_parasiterc_load (void); #endif /* __GIMP_PARASITE_H__ */ diff --git a/app/core/gimpparasitelist.c b/app/core/gimpparasitelist.c index 11cc0b1c39..3e0f001bbf 100644 --- a/app/core/gimpparasitelist.c +++ b/app/core/gimpparasitelist.c @@ -214,6 +214,42 @@ parasite_list_find(ParasiteList *list, const char *name) 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 parasite_shift_parent(Parasite *p) diff --git a/app/core/gimpparasitelist.h b/app/core/gimpparasitelist.h index a4d086b6af..8985d190b8 100644 --- a/app/core/gimpparasitelist.h +++ b/app/core/gimpparasitelist.h @@ -19,6 +19,7 @@ #define __PARASITE_LIST_H__ #include +#include #include "libgimp/parasiteF.h" #include "parasitelistF.h" #include "gimpobject.h" @@ -46,6 +47,8 @@ void parasite_list_foreach (ParasiteList *list, GHFunc function, gpointer user_data); 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); #endif /* __GIMP_PARASITE_H__ */ diff --git a/app/core/gimpprojection-construct.c b/app/core/gimpprojection-construct.c index b6c79b79a6..7c4f8a73e0 100644 --- a/app/core/gimpprojection-construct.c +++ b/app/core/gimpprojection-construct.c @@ -169,7 +169,6 @@ static void gimp_image_init (GimpImage *gimage) gimage->comp_preview_valid[2] = FALSE; gimage->comp_preview = NULL; gimage->parasites = parasite_list_new(); - gimp_matrix_identity(gimage->transform); gimage->xresolution = default_xresolution; gimage->yresolution = default_yresolution; gimage->unit = default_units; diff --git a/app/equalize.c b/app/equalize.c index eeaeb0e036..158106f065 100644 --- a/app/equalize.c +++ b/app/equalize.c @@ -19,27 +19,17 @@ #include #include #include -#include "appenv.h" #include "drawable.h" #include "equalize.h" -#include "interface.h" #include "gimage.h" #include "gimplut.h" +#include "lut_funcs.h" #include "gimphistogram.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 Argument * equalize_invoker (Argument *); -static GimpLut * eq_histogram_lut (GimpHistogram *hist, int bytes); void @@ -87,7 +77,7 @@ equalize(gimage, drawable, mask_only) /* Build equalization LUT */ - lut = eq_histogram_lut (hist, bytes); + lut = eq_histogram_lut_new (hist, bytes); /* Apply the histogram */ 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)); } +/* ------------------------------------------------------------------ */ +/* --------------- 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[] = { { PDB_DRAWABLE, diff --git a/app/gimpchannel.c b/app/gimpchannel.c index 17ebf70866..6b570da0f5 100644 --- a/app/gimpchannel.c +++ b/app/gimpchannel.c @@ -36,6 +36,9 @@ #include "channel_pvt.h" #include "tile.h" +#include "gimplut.h" +#include "lut_funcs.h" + /* enum { LAST_SIGNAL @@ -602,9 +605,9 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2) unsigned char * data; int x, y; int ex, ey; - int found; void *pr; - + int tx1, tx2, ty1, ty2; + int minx, maxx; /* if the mask's bounds have already been reliably calculated... */ 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 */ - *x1 = GIMP_DRAWABLE(mask)->width; - *y1 = GIMP_DRAWABLE(mask)->height; - *x2 = 0; - *y2 = 0; + tx1 = GIMP_DRAWABLE(mask)->width; + ty1 = GIMP_DRAWABLE(mask)->height; + tx2 = 0; + ty2 = 0; 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)) @@ -630,36 +633,50 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2) ey = maskPR.y + maskPR.h; /* only check the pixels if this tile is not fully within the currently computed bounds */ - if (maskPR.x < *x1 || ex > *x2 || - maskPR.y < *y1 || ey > *y2) + if (maskPR.x < tx1 || ex > tx2 || + 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++) if (*data) - { - if (x < *x1) - *x1 = x; - if (x > *x2) - *x2 = x; - found = TRUE; - } - if (found) - { - if (y < *y1) - *y1 = y; - if (y > *y2) - *y2 = y; - } + { + minx = x; + maxx = x; + for (; x < ex; x++, data++) + if (*data) + maxx = x; + if (minx < tx1) + tx1 = minx; + if (maxx > tx2) + tx2 = maxx; + if (y < ty1) + ty1 = y; + if (y > ty2) + ty2 = y; + } } } } - *x2 = BOUNDS (*x2 + 1, 0, GIMP_DRAWABLE(mask)->width); - *y2 = BOUNDS (*y2 + 1, 0, GIMP_DRAWABLE(mask)->height); + tx2 = BOUNDS (tx2 + 1, 0, GIMP_DRAWABLE(mask)->width); + 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->x1 = 0; mask->y1 = 0; @@ -669,13 +686,18 @@ channel_bounds (Channel *mask, int *x1, int *y1, int *x2, int *y2) else { mask->empty = FALSE; - mask->x1 = *x1; - mask->y1 = *y1; - mask->x2 = *x2; - mask->y2 = *y2; + mask->x1 = tx1; + mask->y1 = ty1; + mask->x2 = tx2; + mask->y2 = ty2; } mask->bounds_known = TRUE; + *x1 = tx1; + *x2 = tx2; + *y1 = ty1; + *y2 = ty2; + 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 channel_combine_rect (Channel *mask, int op, int x, int y, int w, int h) { int i; + int x2, y2; + PixelRegion maskPR; + unsigned char color; + y2 = y + h; + x2 = x + w; - for (i = y; i < y + h; i++) - { - if (i >= 0 && i < GIMP_DRAWABLE(mask)->height) - switch (op) - { - case ADD: case REPLACE: - channel_add_segment (mask, x, i, w, 255); - break; - case SUB: - channel_sub_segment (mask, x, i, w, 255); - break; - case INTERSECT: - channel_inter_segment (mask, x, i, w, 255); - break; - } - } + x = BOUNDS (x, 0, GIMP_DRAWABLE(mask)->width); + y = BOUNDS (y, 0, GIMP_DRAWABLE(mask)->height); + x2 = BOUNDS (x2, 0, GIMP_DRAWABLE(mask)->width); + y2 = BOUNDS (y2, 0, GIMP_DRAWABLE(mask)->height); + + if (x2 - x <= 0 || y2 - y <= 0) + return; + + pixel_region_init (&maskPR, GIMP_DRAWABLE(mask)->tiles, x, y, + x2 - x, y2 - y, TRUE); + if (op == ADD || op == REPLACE) + color = 255; + else + color = 0; + color_region(&maskPR, &color); /* Determine new boundary */ 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 : channel_sub_segment (mask, x1, i, (x2 - x1), 255); break; - case INTERSECT: - channel_inter_segment (mask, x1, i, (x2 - x1), 255); - break; } } /* 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))); else val = 0; - + if (last != val && last) { switch (op) @@ -976,8 +965,6 @@ channel_combine_ellipse (Channel *mask, int op, int x, int y, int w, int h, case SUB: channel_sub_segment (mask, x0, i, j - x0, last); 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; 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); else if (op == SUB) 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 channel_combine_mask (Channel *mask, Channel *add_on, int op, int off_x, int off_y) { PixelRegion srcPR, destPR; - unsigned char *src; - unsigned char *dest; - int val; int x1, y1, x2, y2; - int x, y; int w, h; - void * pr; x1 = BOUNDS (off_x, 0, GIMP_DRAWABLE(mask)->width); 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 (&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)) - { - src = srcPR.data; - dest = destPR.data; - - for (y = 0; y < srcPR.h; y++) - { - for (x = 0; x < srcPR.w; x++) - { - switch (op) - { - case ADD: case REPLACE: - val = dest[x] + src[x]; - if (val > 255) val = 255; - break; - case SUB: - val = dest[x] - src[x]; - if (val < 0) val = 0; - break; - case INTERSECT: - val = MINIMUM(dest[x], src[x]); - break; - default: - val = 0; - break; - } - dest[x] = val; - } - src += srcPR.rowstride; - dest += destPR.rowstride; - } - } - + switch (op) + { + case ADD: case REPLACE: + pixel_regions_process_parallel ((p_func)channel_combine_sub_region_add, + NULL, 2, &srcPR, &destPR); + break; + case SUB: + pixel_regions_process_parallel ((p_func)channel_combine_sub_region_sub, + NULL, 2, &srcPR, &destPR); + break; + case INTERSECT: + pixel_regions_process_parallel ((p_func) + channel_combine_sub_region_intersect, + NULL, 2, &srcPR, &destPR); + break; + default: + g_message("Error: unknown opperation type in channel_combine_mask\n"); + break; + } mask->bounds_known = FALSE; } @@ -1184,57 +1222,35 @@ void channel_invert (Channel *mask) { PixelRegion maskPR; - unsigned char *data; - int size; - void * pr; + GimpLut *lut; /* push the current channel onto the undo stack */ channel_push_undo (mask); 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)) - { - /* subtract each pixel in the mask from 255 */ - data = maskPR.data; - size = maskPR.w * maskPR.h; - while (size --) - { - *data = 255 - *data; - data++; - } - } + + lut = invert_lut_new(1); + pixel_regions_process_parallel ((p_func)gimp_lut_process_inline, + lut, 1, &maskPR); + gimp_lut_free(lut); mask->bounds_known = FALSE; } - void channel_sharpen (Channel *mask) { PixelRegion maskPR; - unsigned char *data; - int size; - void * pr; - + GimpLut *lut; /* push the current channel onto the undo stack */ channel_push_undo (mask); 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)) - { - /* 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; - } - } + lut = threshold_lut_new(0.5, 1); - mask->bounds_known = FALSE; + pixel_regions_process_parallel ((p_func)gimp_lut_process_inline, + lut, 1, &maskPR); + gimp_lut_free(lut); } diff --git a/app/gimpdrawable-equalize.c b/app/gimpdrawable-equalize.c index eeaeb0e036..158106f065 100644 --- a/app/gimpdrawable-equalize.c +++ b/app/gimpdrawable-equalize.c @@ -19,27 +19,17 @@ #include #include #include -#include "appenv.h" #include "drawable.h" #include "equalize.h" -#include "interface.h" #include "gimage.h" #include "gimplut.h" +#include "lut_funcs.h" #include "gimphistogram.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 Argument * equalize_invoker (Argument *); -static GimpLut * eq_histogram_lut (GimpHistogram *hist, int bytes); void @@ -87,7 +77,7 @@ equalize(gimage, drawable, mask_only) /* Build equalization LUT */ - lut = eq_histogram_lut (hist, bytes); + lut = eq_histogram_lut_new (hist, bytes); /* Apply the histogram */ 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)); } +/* ------------------------------------------------------------------ */ +/* --------------- 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[] = { { PDB_DRAWABLE, diff --git a/app/gimpdrawable-invert.c b/app/gimpdrawable-invert.c index e83220c1bd..c188f46e76 100644 --- a/app/gimpdrawable-invert.c +++ b/app/gimpdrawable-invert.c @@ -24,6 +24,7 @@ #include "invert.h" #include "gimage.h" #include "gimplut.h" +#include "lut_funcs.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 */ static void @@ -79,10 +68,7 @@ invert (GimpDrawable *drawable) int x1, y1, x2, y2; GimpLut *lut; - lut = gimp_lut_new(); - - gimp_lut_setup_exact(lut, (GimpLutFunc) invert_lut_func, - (void *) NULL, gimp_drawable_bytes(drawable)); + lut = invert_lut_new(gimp_drawable_bytes(drawable)); drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2); 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)); } +/* ------------------------------------------------------------------ */ +/* ----------------- The invert procedure definition ---------------- */ +/* ------------------------------------------------------------------ */ -/* The invert procedure definition */ ProcArg invert_args[] = { { PDB_DRAWABLE, diff --git a/app/gimpdrawable.c b/app/gimpdrawable.c index f9cd6dbd6d..31b3da4dfe 100644 --- a/app/gimpdrawable.c +++ b/app/gimpdrawable.c @@ -640,7 +640,6 @@ gimp_drawable_init (GimpDrawable *drawable) drawable->preview_valid = FALSE; drawable->parasites = parasite_list_new(); drawable->tattoo = 0; - gimp_matrix_identity(drawable->transform); drawable->ID = global_drawable_ID++; if (gimp_drawable_table == NULL) diff --git a/app/gimpdrawableP.h b/app/gimpdrawableP.h index b120810dfb..de5152bb09 100644 --- a/app/gimpdrawableP.h +++ b/app/gimpdrawableP.h @@ -21,7 +21,6 @@ #include "gimpobjectP.h" #include "gimpdrawable.h" #include "parasitelistF.h" -#include "libgimp/gimpmatrix.h" struct _GimpDrawable { @@ -43,10 +42,6 @@ struct _GimpDrawable ParasiteList *parasites; /* Plug-in parasite data */ - GimpMatrix transform; /* a matrix describing all of the - transformations this drawable - has undergone */ - /* Preview variables */ TempBuf *preview; /* preview of the channel */ int preview_valid; /* is the preview valid? */ diff --git a/app/gimpimage.c b/app/gimpimage.c index b6c79b79a6..7c4f8a73e0 100644 --- a/app/gimpimage.c +++ b/app/gimpimage.c @@ -169,7 +169,6 @@ static void gimp_image_init (GimpImage *gimage) gimage->comp_preview_valid[2] = FALSE; gimage->comp_preview = NULL; gimage->parasites = parasite_list_new(); - gimp_matrix_identity(gimage->transform); gimage->xresolution = default_xresolution; gimage->yresolution = default_yresolution; gimage->unit = default_units; diff --git a/app/gimpimageP.h b/app/gimpimageP.h index d8752cba3b..366fb0416c 100644 --- a/app/gimpimageP.h +++ b/app/gimpimageP.h @@ -10,7 +10,6 @@ #include "layer.h" #include "parasitelistF.h" #include "pathsP.h" -#include "libgimp/gimpmatrix.h" #define MAX_CHANNELS 4 @@ -65,10 +64,6 @@ struct _GimpImage 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 active [MAX_CHANNELS]; /* active channels */ diff --git a/app/gimplut.c b/app/gimplut.c index 8587ee4e03..b4d733e8e3 100644 --- a/app/gimplut.c +++ b/app/gimplut.c @@ -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 gimp_lut_process_2 (PixelRegion *srcPR, PixelRegion *destPR, diff --git a/app/gimplut.h b/app/gimplut.h index b18c4113c3..5ce2a44d19 100644 --- a/app/gimplut.h +++ b/app/gimplut.h @@ -49,6 +49,11 @@ void gimp_lut_process (GimpLut *lut, PixelRegion *srcPR, 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 perameter is last instead of first. this is necesary because pixel_region_process_paralell sends the user_data as the 1st diff --git a/app/gimpparasite.c b/app/gimpparasite.c index 25cd5255e6..44776501a4 100644 --- a/app/gimpparasite.c +++ b/app/gimpparasite.c @@ -16,8 +16,12 @@ */ #include +#include +#include #include "parasitelist.h" #include "gimpparasite.h" +#include "libgimp/parasite.h" +#include "libgimp/gimpenv.h" static ParasiteList *parasites = NULL; @@ -26,6 +30,7 @@ gimp_init_parasites() { g_return_if_fail(parasites == NULL); parasites = parasite_list_new(); + gimp_parasiterc_load(); } void @@ -64,5 +69,40 @@ gimp_parasite_list (gint *count) 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); +} diff --git a/app/gimpparasite.h b/app/gimpparasite.h index 49ed74baf5..eaaceb197e 100644 --- a/app/gimpparasite.h +++ b/app/gimpparasite.h @@ -25,5 +25,7 @@ void gimp_attach_parasite (Parasite *p); void gimp_detach_parasite (char *name); Parasite * gimp_find_parasite (char *name); char ** gimp_parasite_list (gint *count); +void gimp_parasiterc_save (void); +void gimp_parasiterc_load (void); #endif /* __GIMP_PARASITE_H__ */ diff --git a/app/internal_procs.c b/app/internal_procs.c index bc31822b4a..41f78272e0 100644 --- a/app/internal_procs.c +++ b/app/internal_procs.c @@ -22,7 +22,6 @@ #include "app_procs.h" #include "airbrush.h" #include "blend.h" -#include "brightness_contrast.h" #include "brush_select.h" #include "bucket_fill.h" #include "gimpbrushlist.h" @@ -31,6 +30,7 @@ #include "channel_ops.h" #include "clone.h" #include "color_balance.h" +#include "color_cmds.h" #include "color_picker.h" #include "convolve.h" #include "crop.h" @@ -51,14 +51,12 @@ #include "hue_saturation.h" #include "invert.h" #include "layer_cmds.h" -#include "levels.h" #include "internal_procs.h" #include "paintbrush.h" #include "patterns.h" #include "pattern_select.h" #include "pencil.h" #include "perspective_tool.h" -#include "posterize.h" #include "rect_select.h" #include "rotate_tool.h" #include "scale_tool.h" diff --git a/app/invert.c b/app/invert.c index e83220c1bd..c188f46e76 100644 --- a/app/invert.c +++ b/app/invert.c @@ -24,6 +24,7 @@ #include "invert.h" #include "gimage.h" #include "gimplut.h" +#include "lut_funcs.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 */ static void @@ -79,10 +68,7 @@ invert (GimpDrawable *drawable) int x1, y1, x2, y2; GimpLut *lut; - lut = gimp_lut_new(); - - gimp_lut_setup_exact(lut, (GimpLutFunc) invert_lut_func, - (void *) NULL, gimp_drawable_bytes(drawable)); + lut = invert_lut_new(gimp_drawable_bytes(drawable)); drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2); 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)); } +/* ------------------------------------------------------------------ */ +/* ----------------- The invert procedure definition ---------------- */ +/* ------------------------------------------------------------------ */ -/* The invert procedure definition */ ProcArg invert_args[] = { { PDB_DRAWABLE, diff --git a/app/levels.c b/app/levels.c index 4b4012c6bb..38212af8b2 100644 --- a/app/levels.c +++ b/app/levels.c @@ -31,6 +31,7 @@ #include "interface.h" #include "levels.h" #include "gimplut.h" +#include "lut_funcs.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, 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 levels_histogram_range (HistogramWidget *h, @@ -715,8 +661,9 @@ levels_update (LevelsDialog *ld, /* Recalculate the transfer arrays */ levels_calculate_transfers (ld); /* set up the lut */ - gimp_lut_setup(ld->lut, (GimpLutFunc) levels_lut_func, - (void *) ld, gimp_drawable_bytes(ld->drawable)); + levels_lut_setup(ld->lut, ld->gamma, ld->low_input, ld->high_input, + ld->low_output, ld->high_output, + gimp_drawable_bytes(ld->drawable)); if (update & LOW_INPUT) { @@ -1005,8 +952,9 @@ levels_ok_callback (GtkWidget *widget, if (!ld->preview) { - gimp_lut_setup(ld->lut, (GimpLutFunc) levels_lut_func, - (void *) ld, gimp_drawable_bytes(ld->drawable)); + levels_lut_setup(ld->lut, ld->gamma, ld->low_input, ld->high_input, + ld->low_output, ld->high_output, + gimp_drawable_bytes(ld->drawable)); image_map_apply (ld->image_map, (ImageMapApplyFunc)gimp_lut_process_2, (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); -} diff --git a/app/levels.h b/app/levels.h index 80066e5470..fb06db3266 100644 --- a/app/levels.h +++ b/app/levels.h @@ -19,7 +19,6 @@ #define __LEVELS_H__ #include "tools.h" -#include "procedural_db.h" /* hue-saturation functions */ Tool * tools_new_levels (void); @@ -28,7 +27,4 @@ void tools_free_levels (Tool *); void levels_initialize (GDisplay *); void levels_free (void); -/* Procedure definition and marshalling function */ -extern ProcRecord levels_proc; - #endif /* __LEVELS_H__ */ diff --git a/app/lut_funcs.c b/app/lut_funcs.c new file mode 100644 index 0000000000..8255314b51 --- /dev/null +++ b/app/lut_funcs.c @@ -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 +#include +#include + +/* ---------- 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; +} diff --git a/app/lut_funcs.h b/app/lut_funcs.h new file mode 100644 index 0000000000..09acfad0bf --- /dev/null +++ b/app/lut_funcs.h @@ -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__ */ diff --git a/app/parasitelist.c b/app/parasitelist.c index 11cc0b1c39..3e0f001bbf 100644 --- a/app/parasitelist.c +++ b/app/parasitelist.c @@ -214,6 +214,42 @@ parasite_list_find(ParasiteList *list, const char *name) 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 parasite_shift_parent(Parasite *p) diff --git a/app/parasitelist.h b/app/parasitelist.h index a4d086b6af..8985d190b8 100644 --- a/app/parasitelist.h +++ b/app/parasitelist.h @@ -19,6 +19,7 @@ #define __PARASITE_LIST_H__ #include +#include #include "libgimp/parasiteF.h" #include "parasitelistF.h" #include "gimpobject.h" @@ -46,6 +47,8 @@ void parasite_list_foreach (ParasiteList *list, GHFunc function, gpointer user_data); 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); #endif /* __GIMP_PARASITE_H__ */ diff --git a/app/pixel_processor.c b/app/pixel_processor.c new file mode 100644 index 0000000000..dd1d1905e2 --- /dev/null +++ b/app/pixel_processor.c @@ -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 + * + * 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 +#include + +#ifdef ENABLE_MP + +#include + +#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); +} + diff --git a/app/pixel_processor.h b/app/pixel_processor.h new file mode 100644 index 0000000000..96ff634d33 --- /dev/null +++ b/app/pixel_processor.h @@ -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 + * + * 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__ */ diff --git a/app/pixel_region.c b/app/pixel_region.c index 7d448cf8ac..53d05672b7 100644 --- a/app/pixel_region.c +++ b/app/pixel_region.c @@ -26,18 +26,6 @@ #include "tile_manager_pvt.h" #include "tile.h" /* ick. */ -#ifdef ENABLE_MP - -#include - -#define IF_THREAD(statement) statement - -#else /* !USE_PTHREADS */ - -#define IF_THREAD(statement) - -#endif /* !USE_PTHREADS */ - 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 * pixel_regions_register (int num_regions, ...) { diff --git a/app/pixel_region.h b/app/pixel_region.h index 3bf03e747a..fc2d63d600 100644 --- a/app/pixel_region.h +++ b/app/pixel_region.h @@ -19,6 +19,7 @@ #define __PIXEL_REGION_H__ #include "tile_manager.h" +#include "pixel_processor.h" /* this is temporary, */ typedef struct _PixelRegion PixelRegion; @@ -36,7 +37,6 @@ struct _PixelRegion int process_count; /* used internally */ }; -typedef void (*p_func)(void); /* PixelRegion functions */ 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_set_col (PixelRegion *, int, int, int, unsigned char *); 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_stop (void *); diff --git a/app/posterize.c b/app/posterize.c index 5df73a4cd1..3a410c3772 100644 --- a/app/posterize.c +++ b/app/posterize.c @@ -34,6 +34,7 @@ #include "interface.h" #include "posterize.h" #include "gimplut.h" +#include "lut_funcs.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 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 */ @@ -343,8 +321,7 @@ posterize_preview (PosterizeDialog *pd) if (!pd->image_map) g_message (_("posterize_preview(): No image map")); active_tool->preserve = TRUE; - gimp_lut_setup_exact(pd->lut, (GimpLutFunc) posterize_lut_func, - (void *) pd, gimp_drawable_bytes(pd->drawable)); + posterize_lut_setup(pd->lut, pd->levels, gimp_drawable_bytes(pd->drawable)); image_map_apply (pd->image_map, (ImageMapApplyFunc)gimp_lut_process_2, (void *) pd->lut); active_tool->preserve = FALSE; @@ -365,8 +342,8 @@ posterize_ok_callback (GtkWidget *widget, if (!pd->preview) { - gimp_lut_setup_exact(pd->lut, (GimpLutFunc) posterize_lut_func, - (void *) pd, gimp_drawable_bytes(pd->drawable)); + posterize_lut_setup(pd->lut, pd->levels, + gimp_drawable_bytes(pd->drawable)); image_map_apply (pd->image_map, (ImageMapApplyFunc)gimp_lut_process_2, (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); -} diff --git a/app/posterize.h b/app/posterize.h index 5cc8e8c1c1..7521591ad2 100644 --- a/app/posterize.h +++ b/app/posterize.h @@ -19,7 +19,6 @@ #define __POSTERIZE_H__ #include "tools.h" -#include "procedural_db.h" /* by_color select functions */ Tool * tools_new_posterize (void); @@ -27,7 +26,4 @@ void tools_free_posterize (Tool *); void posterize_initialize (GDisplay *); -/* Procedure definition and marshalling function */ -extern ProcRecord posterize_proc; - #endif /* __POSTERIZE_H__ */ diff --git a/app/tools/brightness_contrast.c b/app/tools/brightness_contrast.c index 2778b98499..1421701d73 100644 --- a/app/tools/brightness_contrast.c +++ b/app/tools/brightness_contrast.c @@ -28,6 +28,7 @@ #include "image_map.h" #include "interface.h" #include "gimplut.h" +#include "lut_funcs.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 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 */ @@ -467,8 +415,9 @@ brightness_contrast_preview (BrightnessContrastDialog *bcd) if (!bcd->image_map) g_message (_("brightness_contrast_preview(): No image map")); active_tool->preserve = TRUE; - gimp_lut_setup(bcd->lut, (GimpLutFunc) brightness_contrast_lut_func, - (void *) bcd, gimp_drawable_bytes(bcd->drawable)); + brightness_contrast_lut_setup(bcd->lut, bcd->brightness / 255.0, + bcd->contrast / 127.0, + gimp_drawable_bytes(bcd->drawable)); image_map_apply (bcd->image_map, (ImageMapApplyFunc)gimp_lut_process_2, (void *) bcd->lut); active_tool->preserve = FALSE; @@ -489,8 +438,9 @@ brightness_contrast_ok_callback (GtkWidget *widget, if (!bcd->preview) { - gimp_lut_setup(bcd->lut, (GimpLutFunc) brightness_contrast_lut_func, - (void *) bcd, gimp_drawable_bytes(bcd->drawable)); + brightness_contrast_lut_setup(bcd->lut, bcd->brightness / 255.0, + bcd->contrast / 127.0, + gimp_drawable_bytes(bcd->drawable)); image_map_apply (bcd->image_map, (ImageMapApplyFunc)gimp_lut_process_2, (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); -} diff --git a/app/tools/brightness_contrast.h b/app/tools/brightness_contrast.h index d3b2f214de..45467e1962 100644 --- a/app/tools/brightness_contrast.h +++ b/app/tools/brightness_contrast.h @@ -19,7 +19,6 @@ #define __BRIGHTNESS_CONTRAST_H__ #include "tools.h" -#include "procedural_db.h" /* by_color select functions */ Tool * tools_new_brightness_contrast (void); @@ -27,7 +26,4 @@ void tools_free_brightness_contrast (Tool *); void brightness_contrast_initialize (GDisplay *); -/* Procedure definition and marshalling function */ -extern ProcRecord brightness_contrast_proc; - #endif /* __BRIGHTNESS_CONTRAST_H__ */ diff --git a/app/tools/gimpbrightnesscontrasttool.c b/app/tools/gimpbrightnesscontrasttool.c index 2778b98499..1421701d73 100644 --- a/app/tools/gimpbrightnesscontrasttool.c +++ b/app/tools/gimpbrightnesscontrasttool.c @@ -28,6 +28,7 @@ #include "image_map.h" #include "interface.h" #include "gimplut.h" +#include "lut_funcs.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 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 */ @@ -467,8 +415,9 @@ brightness_contrast_preview (BrightnessContrastDialog *bcd) if (!bcd->image_map) g_message (_("brightness_contrast_preview(): No image map")); active_tool->preserve = TRUE; - gimp_lut_setup(bcd->lut, (GimpLutFunc) brightness_contrast_lut_func, - (void *) bcd, gimp_drawable_bytes(bcd->drawable)); + brightness_contrast_lut_setup(bcd->lut, bcd->brightness / 255.0, + bcd->contrast / 127.0, + gimp_drawable_bytes(bcd->drawable)); image_map_apply (bcd->image_map, (ImageMapApplyFunc)gimp_lut_process_2, (void *) bcd->lut); active_tool->preserve = FALSE; @@ -489,8 +438,9 @@ brightness_contrast_ok_callback (GtkWidget *widget, if (!bcd->preview) { - gimp_lut_setup(bcd->lut, (GimpLutFunc) brightness_contrast_lut_func, - (void *) bcd, gimp_drawable_bytes(bcd->drawable)); + brightness_contrast_lut_setup(bcd->lut, bcd->brightness / 255.0, + bcd->contrast / 127.0, + gimp_drawable_bytes(bcd->drawable)); image_map_apply (bcd->image_map, (ImageMapApplyFunc)gimp_lut_process_2, (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); -} diff --git a/app/tools/gimpbrightnesscontrasttool.h b/app/tools/gimpbrightnesscontrasttool.h index d3b2f214de..45467e1962 100644 --- a/app/tools/gimpbrightnesscontrasttool.h +++ b/app/tools/gimpbrightnesscontrasttool.h @@ -19,7 +19,6 @@ #define __BRIGHTNESS_CONTRAST_H__ #include "tools.h" -#include "procedural_db.h" /* by_color select functions */ Tool * tools_new_brightness_contrast (void); @@ -27,7 +26,4 @@ void tools_free_brightness_contrast (Tool *); void brightness_contrast_initialize (GDisplay *); -/* Procedure definition and marshalling function */ -extern ProcRecord brightness_contrast_proc; - #endif /* __BRIGHTNESS_CONTRAST_H__ */ diff --git a/app/tools/gimplevelstool.c b/app/tools/gimplevelstool.c index 4b4012c6bb..38212af8b2 100644 --- a/app/tools/gimplevelstool.c +++ b/app/tools/gimplevelstool.c @@ -31,6 +31,7 @@ #include "interface.h" #include "levels.h" #include "gimplut.h" +#include "lut_funcs.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, 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 levels_histogram_range (HistogramWidget *h, @@ -715,8 +661,9 @@ levels_update (LevelsDialog *ld, /* Recalculate the transfer arrays */ levels_calculate_transfers (ld); /* set up the lut */ - gimp_lut_setup(ld->lut, (GimpLutFunc) levels_lut_func, - (void *) ld, gimp_drawable_bytes(ld->drawable)); + levels_lut_setup(ld->lut, ld->gamma, ld->low_input, ld->high_input, + ld->low_output, ld->high_output, + gimp_drawable_bytes(ld->drawable)); if (update & LOW_INPUT) { @@ -1005,8 +952,9 @@ levels_ok_callback (GtkWidget *widget, if (!ld->preview) { - gimp_lut_setup(ld->lut, (GimpLutFunc) levels_lut_func, - (void *) ld, gimp_drawable_bytes(ld->drawable)); + levels_lut_setup(ld->lut, ld->gamma, ld->low_input, ld->high_input, + ld->low_output, ld->high_output, + gimp_drawable_bytes(ld->drawable)); image_map_apply (ld->image_map, (ImageMapApplyFunc)gimp_lut_process_2, (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); -} diff --git a/app/tools/gimplevelstool.h b/app/tools/gimplevelstool.h index 80066e5470..fb06db3266 100644 --- a/app/tools/gimplevelstool.h +++ b/app/tools/gimplevelstool.h @@ -19,7 +19,6 @@ #define __LEVELS_H__ #include "tools.h" -#include "procedural_db.h" /* hue-saturation functions */ Tool * tools_new_levels (void); @@ -28,7 +27,4 @@ void tools_free_levels (Tool *); void levels_initialize (GDisplay *); void levels_free (void); -/* Procedure definition and marshalling function */ -extern ProcRecord levels_proc; - #endif /* __LEVELS_H__ */ diff --git a/app/tools/gimpposterizetool.c b/app/tools/gimpposterizetool.c index 5df73a4cd1..3a410c3772 100644 --- a/app/tools/gimpposterizetool.c +++ b/app/tools/gimpposterizetool.c @@ -34,6 +34,7 @@ #include "interface.h" #include "posterize.h" #include "gimplut.h" +#include "lut_funcs.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 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 */ @@ -343,8 +321,7 @@ posterize_preview (PosterizeDialog *pd) if (!pd->image_map) g_message (_("posterize_preview(): No image map")); active_tool->preserve = TRUE; - gimp_lut_setup_exact(pd->lut, (GimpLutFunc) posterize_lut_func, - (void *) pd, gimp_drawable_bytes(pd->drawable)); + posterize_lut_setup(pd->lut, pd->levels, gimp_drawable_bytes(pd->drawable)); image_map_apply (pd->image_map, (ImageMapApplyFunc)gimp_lut_process_2, (void *) pd->lut); active_tool->preserve = FALSE; @@ -365,8 +342,8 @@ posterize_ok_callback (GtkWidget *widget, if (!pd->preview) { - gimp_lut_setup_exact(pd->lut, (GimpLutFunc) posterize_lut_func, - (void *) pd, gimp_drawable_bytes(pd->drawable)); + posterize_lut_setup(pd->lut, pd->levels, + gimp_drawable_bytes(pd->drawable)); image_map_apply (pd->image_map, (ImageMapApplyFunc)gimp_lut_process_2, (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); -} diff --git a/app/tools/gimpposterizetool.h b/app/tools/gimpposterizetool.h index 5cc8e8c1c1..7521591ad2 100644 --- a/app/tools/gimpposterizetool.h +++ b/app/tools/gimpposterizetool.h @@ -19,7 +19,6 @@ #define __POSTERIZE_H__ #include "tools.h" -#include "procedural_db.h" /* by_color select functions */ Tool * tools_new_posterize (void); @@ -27,7 +26,4 @@ void tools_free_posterize (Tool *); void posterize_initialize (GDisplay *); -/* Procedure definition and marshalling function */ -extern ProcRecord posterize_proc; - #endif /* __POSTERIZE_H__ */ diff --git a/app/tools/levels.c b/app/tools/levels.c index 4b4012c6bb..38212af8b2 100644 --- a/app/tools/levels.c +++ b/app/tools/levels.c @@ -31,6 +31,7 @@ #include "interface.h" #include "levels.h" #include "gimplut.h" +#include "lut_funcs.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, 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 levels_histogram_range (HistogramWidget *h, @@ -715,8 +661,9 @@ levels_update (LevelsDialog *ld, /* Recalculate the transfer arrays */ levels_calculate_transfers (ld); /* set up the lut */ - gimp_lut_setup(ld->lut, (GimpLutFunc) levels_lut_func, - (void *) ld, gimp_drawable_bytes(ld->drawable)); + levels_lut_setup(ld->lut, ld->gamma, ld->low_input, ld->high_input, + ld->low_output, ld->high_output, + gimp_drawable_bytes(ld->drawable)); if (update & LOW_INPUT) { @@ -1005,8 +952,9 @@ levels_ok_callback (GtkWidget *widget, if (!ld->preview) { - gimp_lut_setup(ld->lut, (GimpLutFunc) levels_lut_func, - (void *) ld, gimp_drawable_bytes(ld->drawable)); + levels_lut_setup(ld->lut, ld->gamma, ld->low_input, ld->high_input, + ld->low_output, ld->high_output, + gimp_drawable_bytes(ld->drawable)); image_map_apply (ld->image_map, (ImageMapApplyFunc)gimp_lut_process_2, (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); -} diff --git a/app/tools/levels.h b/app/tools/levels.h index 80066e5470..fb06db3266 100644 --- a/app/tools/levels.h +++ b/app/tools/levels.h @@ -19,7 +19,6 @@ #define __LEVELS_H__ #include "tools.h" -#include "procedural_db.h" /* hue-saturation functions */ Tool * tools_new_levels (void); @@ -28,7 +27,4 @@ void tools_free_levels (Tool *); void levels_initialize (GDisplay *); void levels_free (void); -/* Procedure definition and marshalling function */ -extern ProcRecord levels_proc; - #endif /* __LEVELS_H__ */ diff --git a/app/tools/posterize.c b/app/tools/posterize.c index 5df73a4cd1..3a410c3772 100644 --- a/app/tools/posterize.c +++ b/app/tools/posterize.c @@ -34,6 +34,7 @@ #include "interface.h" #include "posterize.h" #include "gimplut.h" +#include "lut_funcs.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 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 */ @@ -343,8 +321,7 @@ posterize_preview (PosterizeDialog *pd) if (!pd->image_map) g_message (_("posterize_preview(): No image map")); active_tool->preserve = TRUE; - gimp_lut_setup_exact(pd->lut, (GimpLutFunc) posterize_lut_func, - (void *) pd, gimp_drawable_bytes(pd->drawable)); + posterize_lut_setup(pd->lut, pd->levels, gimp_drawable_bytes(pd->drawable)); image_map_apply (pd->image_map, (ImageMapApplyFunc)gimp_lut_process_2, (void *) pd->lut); active_tool->preserve = FALSE; @@ -365,8 +342,8 @@ posterize_ok_callback (GtkWidget *widget, if (!pd->preview) { - gimp_lut_setup_exact(pd->lut, (GimpLutFunc) posterize_lut_func, - (void *) pd, gimp_drawable_bytes(pd->drawable)); + posterize_lut_setup(pd->lut, pd->levels, + gimp_drawable_bytes(pd->drawable)); image_map_apply (pd->image_map, (ImageMapApplyFunc)gimp_lut_process_2, (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); -} diff --git a/app/tools/posterize.h b/app/tools/posterize.h index 5cc8e8c1c1..7521591ad2 100644 --- a/app/tools/posterize.h +++ b/app/tools/posterize.h @@ -19,7 +19,6 @@ #define __POSTERIZE_H__ #include "tools.h" -#include "procedural_db.h" /* by_color select functions */ Tool * tools_new_posterize (void); @@ -27,7 +26,4 @@ void tools_free_posterize (Tool *); void posterize_initialize (GDisplay *); -/* Procedure definition and marshalling function */ -extern ProcRecord posterize_proc; - #endif /* __POSTERIZE_H__ */ diff --git a/libgimp/gimpparasite.c b/libgimp/gimpparasite.c index b5361c24ec..70b6de11d5 100644 --- a/libgimp/gimpparasite.c +++ b/libgimp/gimpparasite.c @@ -75,6 +75,65 @@ parasite_new (const char *name, guint32 flags, 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 parasite_free (Parasite *parasite) { diff --git a/libgimp/gimpparasite.h b/libgimp/gimpparasite.h index 742f8f5271..b5f271f69a 100644 --- a/libgimp/gimpparasite.h +++ b/libgimp/gimpparasite.h @@ -21,6 +21,7 @@ #define _PARASITE_H_ #include +#include #include #ifdef __cplusplus @@ -36,7 +37,9 @@ extern "C" { #define PARASITE_GRANDPARENT_PERSISTENT (PARASITE_PERSISTENT << 16) 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); Parasite *parasite_copy (const Parasite *parasite); diff --git a/libgimp/parasite.c b/libgimp/parasite.c index b5361c24ec..70b6de11d5 100644 --- a/libgimp/parasite.c +++ b/libgimp/parasite.c @@ -75,6 +75,65 @@ parasite_new (const char *name, guint32 flags, 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 parasite_free (Parasite *parasite) { diff --git a/libgimp/parasite.h b/libgimp/parasite.h index 742f8f5271..b5f271f69a 100644 --- a/libgimp/parasite.h +++ b/libgimp/parasite.h @@ -21,6 +21,7 @@ #define _PARASITE_H_ #include +#include #include #ifdef __cplusplus @@ -36,7 +37,9 @@ extern "C" { #define PARASITE_GRANDPARENT_PERSISTENT (PARASITE_PERSISTENT << 16) 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); Parasite *parasite_copy (const Parasite *parasite); diff --git a/libgimpbase/gimpparasite.c b/libgimpbase/gimpparasite.c index b5361c24ec..70b6de11d5 100644 --- a/libgimpbase/gimpparasite.c +++ b/libgimpbase/gimpparasite.c @@ -75,6 +75,65 @@ parasite_new (const char *name, guint32 flags, 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 parasite_free (Parasite *parasite) { diff --git a/libgimpbase/gimpparasite.h b/libgimpbase/gimpparasite.h index 742f8f5271..b5f271f69a 100644 --- a/libgimpbase/gimpparasite.h +++ b/libgimpbase/gimpparasite.h @@ -21,6 +21,7 @@ #define _PARASITE_H_ #include +#include #include #ifdef __cplusplus @@ -36,7 +37,9 @@ extern "C" { #define PARASITE_GRANDPARENT_PERSISTENT (PARASITE_PERSISTENT << 16) 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); Parasite *parasite_copy (const Parasite *parasite);