summaryrefslogtreecommitdiff
path: root/src/xsane-gamma.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xsane-gamma.c')
-rw-r--r--src/xsane-gamma.c2504
1 files changed, 2504 insertions, 0 deletions
diff --git a/src/xsane-gamma.c b/src/xsane-gamma.c
new file mode 100644
index 0000000..d47f6b7
--- /dev/null
+++ b/src/xsane-gamma.c
@@ -0,0 +1,2504 @@
+/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend
+
+ xsane-gamma.c
+
+ Oliver Rauch <Oliver.Rauch@rauch-domain.de>
+ Copyright (C) 1998-2002 Oliver Rauch
+ This file is part of the XSANE package.
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+#include "xsane.h"
+#include "xsane-back-gtk.h"
+#include "xsane-front-gtk.h"
+#include "xsane-preferences.h"
+#include "xsane-preview.h"
+#include "xsane-save.h"
+
+#ifdef HAVE_LIBPNG
+#ifdef HAVE_LIBZ
+#include <png.h>
+#include <zlib.h>
+#endif
+#endif
+
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+/* forward declarations: */
+
+void xsane_clear_histogram(XsanePixmap *hist);
+static void xsane_draw_histogram_with_points(XsanePixmap *hist,
+ SANE_Int *count, SANE_Int *count_red, SANE_Int *count_green, SANE_Int *count_blue,
+ int show_red, int show_green, int show_blue, int show_inten, double scale);
+static void xsane_draw_histogram_with_lines(XsanePixmap *hist,
+ SANE_Int *count, SANE_Int *count_red, SANE_Int *count_green, SANE_Int *count_blue,
+ int show_red, int show_green, int show_blue, int show_inten, double scale);
+void xsane_draw_slider_level(XsaneSlider *slider);
+static void xsane_set_slider(XsaneSlider *slider, double min, double mid, double max);
+void xsane_update_slider(XsaneSlider *slider);
+void xsane_update_sliders(void);
+static gint xsane_slider_callback(GtkWidget *widget, GdkEvent *event, XsaneSlider *slider);
+void xsane_create_slider(XsaneSlider *slider);
+void xsane_create_histogram(GtkWidget *parent, const char *title, int width, int height, XsanePixmap *hist);
+void xsane_get_free_gamma_curve(gfloat *free_color_gamma_data, SANE_Int *gammadata,
+ int negative, double gamma, double brightness, double contrast,
+ int len, int maxout);
+static void xsane_calculate_auto_enhancement(SANE_Int *count_raw,
+ SANE_Int *count_raw_red, SANE_Int *count_raw_green, SANE_Int *count_raw_blue);
+void xsane_calculate_raw_histogram(void);
+void xsane_calculate_enh_histogram(void);
+void xsane_update_histogram(int update_raw);
+void xsane_histogram_toggle_button_callback(GtkWidget *widget, gpointer data);
+void xsane_create_preview_threshold_curve(u_char *gammadata, double threshold, int numbers);
+void xsane_create_preview_gamma_curve(u_char *gammadata, int negative, double gamma,
+ double brightness, double contrast,
+ double medium_shadow, double medium_highlight, double medium_gamma,
+ int numbers);
+void xsane_create_gamma_curve(SANE_Int *gammadata,
+ int negative, double gamma, double brightness, double contrast,
+ double medium_shadow, double medium_highlight, double medium_gamma,
+ int numbers, int maxout);
+void xsane_update_gamma_curve(int update_raw);
+static void xsane_enhancement_update(void);
+static void xsane_gamma_to_histogram(double *min, double *mid, double *max,
+ double contrast, double brightness, double gamma);
+void xsane_enhancement_by_gamma(void);
+void xsane_enhancement_restore_default(void);
+void xsane_enhancement_restore(void);
+void xsane_enhancement_store(void);
+static int xsane_histogram_to_gamma(XsaneSlider *slider, double *contrast, double contrast_offset, double *brightness, double brightness_offset, double *gamma, double gamma_multiplier);
+void xsane_enhancement_by_histogram(int update_gamma);
+static gint xsane_histogram_win_delete(GtkWidget *widget, gpointer data);
+void xsane_create_histogram_dialog(const char *devicetext);
+#ifdef HAVE_WORKING_GTK_GAMMACURVE
+static gint xsane_gamma_win_delete(GtkWidget *widget, gpointer data);
+#endif
+void xsane_create_gamma_dialog(const char *devicetext);
+void xsane_update_gamma_dialog(void);
+void xsane_set_auto_enhancement(void);
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_clear_histogram(XsanePixmap *hist)
+{
+ GdkRectangle rect;
+
+ DBG(DBG_proc, "xsane_clear_histogram\n");
+
+ if(hist->pixmap)
+ {
+ rect.x=0;
+ rect.y=0;
+ rect.width = HIST_WIDTH;
+ rect.height = HIST_HEIGHT;
+
+ gdk_draw_rectangle(hist->pixmap, xsane.gc_backg, TRUE, 0, 0, HIST_WIDTH, HIST_HEIGHT);
+ gtk_widget_draw(hist->pixmapwid, &rect);
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_draw_histogram_with_points(XsanePixmap *hist,
+ SANE_Int *count, SANE_Int *count_red, SANE_Int *count_green, SANE_Int *count_blue,
+ int show_red, int show_green, int show_blue, int show_inten, double scale)
+{
+ GdkRectangle rect;
+ int i;
+ int inten, red, green, blue;
+
+ DBG(DBG_proc, "xsane_draw_histogram_with_points\n");
+
+#define XD 1
+#define YD 2
+
+ if(hist->pixmap)
+ {
+ rect.x=0;
+ rect.y=0;
+ rect.width = HIST_WIDTH;
+ rect.height = HIST_HEIGHT;
+
+ gdk_draw_rectangle(hist->pixmap, xsane.gc_backg, TRUE, 0, 0, HIST_WIDTH, HIST_HEIGHT);
+
+ red = 0;
+ green = 0;
+ blue = 0;
+
+ for (i=0; i < HIST_WIDTH; i++)
+ {
+ inten = show_inten * count[i] * scale;
+
+ if (xsane.xsane_colors > 1)
+ {
+ red = show_red * count_red[i] * scale;
+ green = show_green * count_green[i] * scale;
+ blue = show_blue * count_blue[i] * scale;
+ }
+
+ if (inten > HIST_HEIGHT)
+ inten = HIST_HEIGHT;
+
+ if (red > HIST_HEIGHT)
+ red = HIST_HEIGHT;
+
+ if (green > HIST_HEIGHT)
+ green = HIST_HEIGHT;
+
+ if (blue > HIST_HEIGHT)
+ blue = HIST_HEIGHT;
+
+
+ gdk_draw_rectangle(hist->pixmap, xsane.gc_red, TRUE, i, HIST_HEIGHT - red, XD, YD);
+ gdk_draw_rectangle(hist->pixmap, xsane.gc_green, TRUE, i, HIST_HEIGHT - green, XD, YD);
+ gdk_draw_rectangle(hist->pixmap, xsane.gc_blue, TRUE, i, HIST_HEIGHT - blue, XD, YD);
+ gdk_draw_rectangle(hist->pixmap, xsane.gc_black, TRUE, i, HIST_HEIGHT - inten, XD, YD);
+ }
+
+ gtk_widget_draw(hist->pixmapwid, &rect);
+ }
+}
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_draw_histogram_with_lines(XsanePixmap *hist,
+ SANE_Int *count, SANE_Int *count_red, SANE_Int *count_green, SANE_Int *count_blue,
+ int show_red, int show_green, int show_blue, int show_inten, double scale)
+{
+ GdkRectangle rect;
+ int i, j, k;
+ int inten, red, green, blue;
+ int inten0=0, red0=0, green0=0, blue0=0;
+ int val[4];
+ int val2[4];
+ int color[4];
+ int val_swap;
+ int color_swap;
+
+ DBG(DBG_proc, "xsane_draw_histogram_with_lines\n");
+
+ if (hist->pixmap)
+ {
+ rect.x=0;
+ rect.y=0;
+ rect.width = HIST_WIDTH;
+ rect.height = HIST_HEIGHT;
+
+ gdk_draw_rectangle(hist->pixmap, xsane.gc_backg, TRUE, 0, 0, HIST_WIDTH, HIST_HEIGHT);
+
+ red = 0;
+ green = 0;
+ blue = 0;
+
+ for (i=0; i < HIST_WIDTH; i++)
+ {
+ inten = show_inten * count[i] * scale;
+
+ if (xsane.xsane_colors > 1)
+ {
+ red = show_red * count_red[i] * scale;
+ green = show_green * count_green[i] * scale;
+ blue = show_blue * count_blue[i] * scale;
+ }
+
+ if (inten > HIST_HEIGHT)
+ {
+ inten = HIST_HEIGHT;
+ }
+
+ if (red > HIST_HEIGHT)
+ {
+ red = HIST_HEIGHT;
+ }
+
+ if (green > HIST_HEIGHT)
+ {
+ green = HIST_HEIGHT;
+ }
+
+ if (blue > HIST_HEIGHT)
+ {
+ blue = HIST_HEIGHT;
+ }
+
+ val[0] = red; color[0] = 0;
+ val[1] = green; color[1] = 1;
+ val[2] = blue; color[2] = 2;
+ val[3] = inten; color[3] = 3;
+
+ for (j = 0; j < 3; j++)
+ {
+ for (k = j + 1; k < 4; k++)
+ {
+ if (val[j] < val[k])
+ {
+ val_swap = val[j];
+ color_swap = color[j];
+ val[j] = val[k];
+ color[j] = color[k];
+ val[k] = val_swap;
+ color[k] = color_swap;
+ }
+ }
+ }
+ val2[0] = val[1] + 1;
+ val2[1] = val[2] + 1;
+ val2[2] = val[3] + 1;
+ val2[3] = 0;
+
+ for (j = 0; j < 4; j++)
+ {
+ switch(color[j])
+ {
+ case 0: red0 = val2[j];
+ break;
+ case 1: green0 = val2[j];
+ break;
+ case 2: blue0 = val2[j];
+ break;
+ case 3: inten0 = val2[j];
+ break;
+ }
+ }
+
+
+ gdk_draw_line(hist->pixmap, xsane.gc_red, i, HIST_HEIGHT - red, i, HIST_HEIGHT - red0);
+ gdk_draw_line(hist->pixmap, xsane.gc_green, i, HIST_HEIGHT - green, i, HIST_HEIGHT - green0);
+ gdk_draw_line(hist->pixmap, xsane.gc_blue, i, HIST_HEIGHT - blue, i, HIST_HEIGHT - blue0);
+ gdk_draw_line(hist->pixmap, xsane.gc_black, i, HIST_HEIGHT - inten, i, HIST_HEIGHT - inten0);
+ }
+
+ gtk_widget_draw(hist->pixmapwid, &rect);
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_establish_slider(XsaneSlider *slider)
+{
+ int x, y, pos, len;
+ guchar buf[XSANE_SLIDER_WIDTH*3];
+ GdkRectangle rect;
+
+ DBG(DBG_proc, "xsane_establish_slider\n");
+
+ buf[0] = buf[1] = buf[2] = 0;
+ buf[3+0] = buf[3+1] = buf[3+2]= 0;
+
+ for (x = 0; x < 256; x++)
+ {
+ buf[3*x+0+6] = x * slider->r;
+ buf[3*x+1+6] = x * slider->g;
+ buf[3*x+2+6] = x * slider->b;
+ }
+
+ buf[258*3+0] = 255 * slider->r;
+ buf[258*3+1] = 255 * slider->g;
+ buf[258*3+2] = 255 * slider->b;
+
+ buf[259*3+0] = 255 * slider->r;
+ buf[259*3+1] = 255 * slider->g;
+ buf[259*3+2] = 255 * slider->b;
+
+ for (y = 0; y < XSANE_SLIDER_HEIGHT; y++)
+ {
+ pos = slider->position[0]-y/2;
+ len = y;
+ if (pos<-2)
+ {
+ len = len + pos + 2;
+ pos = -2;
+ }
+ pos = pos * 3 + 6;
+
+ for (x = 0; x <= len; x++)
+ {
+ if ((x == 0) || (x == len) || (y == XSANE_SLIDER_HEIGHT-1))
+ {
+ buf[pos++] = 255;
+ buf[pos++] = 255;
+ buf[pos++] = 255;
+ }
+ else
+ {
+ buf[pos++] = 0;
+ buf[pos++] = 0;
+ buf[pos++] = 0;
+ }
+ }
+
+
+ pos = slider->position[1]-y/2;
+ len = y;
+ pos = pos * 3 + 6;
+
+ for (x = 0; x <= len; x++)
+ {
+ if ((x == 0) || (x == len) || (y == XSANE_SLIDER_HEIGHT-1))
+ {
+ buf[pos++] = 255;
+ buf[pos++] = 255;
+ buf[pos++] = 255;
+ }
+ else
+ {
+ buf[pos++] = 128;
+ buf[pos++] = 128;
+ buf[pos++] = 128;
+ }
+ }
+
+
+ pos = slider->position[2]-y/2;
+ len = y;
+ if (pos+len>257)
+ {
+ len = 257 - pos;
+ }
+ pos = pos * 3 + 6;
+
+ for (x=0; x<=len; x++)
+ {
+ if ((x == 0) || (x == len) || (y == XSANE_SLIDER_HEIGHT-1))
+ {
+ buf[pos++] = 0;
+ buf[pos++] = 0;
+ buf[pos++] = 0;
+ }
+ else
+ {
+ buf[pos++] = 255;
+ buf[pos++] = 255;
+ buf[pos++] = 255;
+ }
+ }
+
+ gtk_preview_draw_row(GTK_PREVIEW(slider->preview),buf, 0, y, XSANE_SLIDER_WIDTH);
+ }
+
+ rect.x=0;
+ rect.y=0;
+ rect.width = XSANE_SLIDER_WIDTH;
+ rect.height = XSANE_SLIDER_HEIGHT;
+
+ gtk_widget_draw(slider->preview, &rect);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_draw_slider_level(XsaneSlider *slider)
+{
+ int i;
+ guchar buf[XSANE_SLIDER_WIDTH*3];
+ GdkRectangle rect;
+
+ DBG(DBG_proc, "xsane_draw_slider_level\n");
+
+ buf[0] = buf[1] = buf[2] = 0;
+ buf[3+0] = buf[3+1] = buf[3+2]= 0;
+
+ for (i=0; i<256; i++)
+ {
+ buf[3*i+0+6] = i * slider->r;
+ buf[3*i+1+6] = i * slider->g;
+ buf[3*i+2+6] = i * slider->b;
+ }
+
+ buf[258*3+0] = 255 * slider->r;
+ buf[258*3+1] = 255 * slider->g;
+ buf[258*3+2] = 255 * slider->b;
+
+ buf[259*3+0] = 255 * slider->r;
+ buf[259*3+1] = 255 * slider->g;
+ buf[259*3+2] = 255 * slider->b;
+
+ for (i=0; i<XSANE_SLIDER_HEIGHT; i++)
+ {
+ gtk_preview_draw_row(GTK_PREVIEW(slider->preview),buf, 0, i, XSANE_SLIDER_WIDTH);
+ }
+
+ rect.x=0;
+ rect.y=0;
+ rect.width = XSANE_SLIDER_WIDTH;
+ rect.height = XSANE_SLIDER_HEIGHT;
+
+ gtk_widget_draw(slider->preview, &rect);
+}
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_set_slider(XsaneSlider *slider, double min, double mid, double max)
+{
+ DBG(DBG_proc, "xsane_set_slider\n");
+
+ slider->value[0] = min;
+ slider->value[1] = mid;
+ slider->value[2] = max;
+
+ slider->position[0] = min * 2.55;
+ slider->position[1] = mid * 2.55;
+ slider->position[2] = max * 2.55;
+
+ xsane_establish_slider(slider);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_update_slider(XsaneSlider *slider)
+{
+ DBG(DBG_proc, "xsane_update_slider\n");
+
+ slider->position[0] = 2.55 * slider->value[0];
+ slider->position[1] = 2.55 * slider->value[1];
+ slider->position[2] = 2.55 * slider->value[2];
+
+ xsane_establish_slider(slider);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_update_sliders()
+{
+ DBG(DBG_proc, "xsane_update_sliders\n");
+
+ xsane_update_slider(&xsane.slider_gray);
+
+ if ( (xsane.xsane_colors > 1) && (!xsane.enhancement_rgb_default) )
+ {
+ xsane_update_slider(&xsane.slider_red);
+ xsane_update_slider(&xsane.slider_green);
+ xsane_update_slider(&xsane.slider_blue);
+
+ xsane.slider_gray.active &= ~XSANE_SLIDER_INACTIVE; /* mark slider active */
+ xsane.slider_red.active &= ~XSANE_SLIDER_INACTIVE; /* mark slider active */
+ xsane.slider_green.active &= ~XSANE_SLIDER_INACTIVE; /* mark slider active */
+ xsane.slider_blue.active &= ~XSANE_SLIDER_INACTIVE; /* mark slider active */
+ }
+ else
+ {
+ xsane_draw_slider_level(&xsane.slider_red); /* remove slider */
+ xsane_draw_slider_level(&xsane.slider_green); /* remove slider */
+ xsane_draw_slider_level(&xsane.slider_blue); /* remove slider */
+
+ xsane.slider_red.active = XSANE_SLIDER_INACTIVE; /* mark slider inactive */
+ xsane.slider_green.active = XSANE_SLIDER_INACTIVE; /* mark slider inactive */
+ xsane.slider_blue.active = XSANE_SLIDER_INACTIVE; /* mark slider inactive */
+
+ if (xsane.param.depth == 1)
+ {
+ xsane_draw_slider_level(&xsane.slider_gray); /* remove slider */
+ xsane.slider_gray.active = XSANE_SLIDER_INACTIVE; /* mark slider inactive */
+ }
+ else
+ {
+ xsane.slider_gray.active &= ~XSANE_SLIDER_INACTIVE; /* mark slider active */
+ }
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static gint xsane_slider_hold_event()
+{
+ DBG(DBG_proc, "xsane_slider_hold_event\n");
+
+ xsane_enhancement_by_histogram(TRUE);
+
+ gtk_timeout_remove(xsane.slider_timer);
+ xsane.slider_timer = 0;
+
+ if (xsane.slider_timer_restart)
+ {
+ xsane.slider_timer = gtk_timeout_add(XSANE_CONTINUOUS_HOLD_TIME, xsane_slider_hold_event, 0);
+ xsane.slider_timer_restart = FALSE;
+ }
+
+ return FALSE;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static gint xsane_slider_callback(GtkWidget *widget, GdkEvent *event, XsaneSlider *slider)
+{
+ GdkEventButton *button_event;
+ GdkEventMotion *motion_event;
+ int distance;
+ int i = 0;
+ static int update = FALSE;
+ static int x;
+
+ DBG(DBG_proc, "xsane_slider_callback\n");
+
+ if (slider->active == XSANE_SLIDER_INACTIVE)
+ {
+ return 0;
+ }
+
+ switch(event->type)
+ {
+ case GDK_BUTTON_PRESS:
+ gtk_grab_add(widget);
+ button_event = (GdkEventButton *) event;
+
+ distance = G_MAXINT;
+ for (i=0; i<3; i++)
+ {
+ if (fabs(button_event->x - slider->position[i]) < distance)
+ {
+ slider->active = i + 1;
+ distance = fabs(button_event->x - slider->position[i]);
+ }
+ }
+ if (distance<10)
+ {
+ x = button_event->x;
+ update = TRUE;
+ }
+ else
+ {
+ slider->active = XSANE_SLIDER_ACTIVE;
+ }
+ break;
+
+ case GDK_BUTTON_RELEASE:
+ gtk_grab_remove(widget);
+ xsane_enhancement_by_histogram(TRUE); /* slider->active must be unchanged !!! */
+ slider->active = XSANE_SLIDER_ACTIVE; /* ok, now we can reset it */
+ break;
+
+ case GDK_MOTION_NOTIFY:
+
+ motion_event = (GdkEventMotion *) event;
+ gdk_window_get_pointer(widget->window, &x, 0, 0);
+ update = TRUE;
+ break;
+
+ default:
+ break;
+ }
+
+ if (update)
+ {
+ update = FALSE;
+ switch(slider->active)
+ {
+ case 1:
+ slider->value[0] = (x-XSANE_SLIDER_OFFSET) / 2.55;
+ xsane_bound_double(&slider->value[0], 0.0, slider->value[1] - 1);
+ break;
+
+ case 2:
+ slider->value[1] = (x-XSANE_SLIDER_OFFSET) / 2.55;
+ xsane_bound_double(&slider->value[1], slider->value[0] + 1, slider->value[2] - 1);
+ break;
+
+ case 3:
+ slider->value[2] = (x-XSANE_SLIDER_OFFSET) / 2.55;
+ xsane_bound_double(&slider->value[2], slider->value[1] + 1, 100.0);
+ break;
+
+ default:
+ break;
+ }
+ xsane_set_slider(slider, slider->value[0], slider->value[1], slider->value[2]);
+
+ if (preferences.gtk_update_policy == GTK_UPDATE_CONTINUOUS)
+ {
+ /* call xsane_enhancement_by_histogram by event handler */
+ if (!xsane.slider_timer)
+ {
+ xsane.slider_timer = gtk_timeout_add(XSANE_CONTINUOUS_HOLD_TIME, xsane_slider_hold_event, 0);
+ }
+ else
+ {
+ xsane.slider_timer_restart = TRUE;
+ }
+ }
+ else if (preferences.gtk_update_policy == GTK_UPDATE_DELAYED)
+ {
+ if (xsane.slider_timer) /* hold timer active? then remove it, we had a motion */
+ {
+ gtk_timeout_remove(xsane.slider_timer);
+ }
+ /* call xsane_slider_hold_event if mouse is not moved for ??? ms */
+ xsane.slider_timer = gtk_timeout_add(XSANE_HOLD_TIME, xsane_slider_hold_event, 0);
+ }
+ }
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_create_slider(XsaneSlider *slider)
+{
+ DBG(DBG_proc, "xsane_create_slider\n");
+
+ slider->preview = gtk_preview_new(GTK_PREVIEW_COLOR);
+ gtk_preview_size(GTK_PREVIEW(slider->preview), XSANE_SLIDER_WIDTH, XSANE_SLIDER_HEIGHT);
+ gtk_widget_set_events(slider->preview, XSANE_SLIDER_EVENTS);
+ gtk_signal_connect(GTK_OBJECT(slider->preview), "event", GTK_SIGNAL_FUNC(xsane_slider_callback), slider);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_create_histogram(GtkWidget *parent, const char *title, int width, int height, XsanePixmap *hist)
+{
+ GdkBitmap *mask=NULL;
+
+ DBG(DBG_proc, "xsane_create_histogram\n");
+
+ hist->frame = gtk_frame_new(title);
+ hist->pixmap = gdk_pixmap_new(xsane.histogram_dialog->window, width, height, -1);
+ hist->pixmapwid = gtk_pixmap_new(hist->pixmap, mask);
+ gtk_container_add(GTK_CONTAINER(hist->frame), hist->pixmapwid);
+ gdk_draw_rectangle(hist->pixmap, xsane.gc_backg, TRUE, 0, 0, width, height);
+
+ gtk_box_pack_start(GTK_BOX(parent), hist->frame, FALSE, FALSE, 2);
+ gtk_widget_show(hist->pixmapwid);
+ gtk_widget_show(hist->frame);
+ }
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_calculate_auto_enhancement(SANE_Int *count_raw,
+ SANE_Int *count_raw_red, SANE_Int *count_raw_green, SANE_Int *count_raw_blue)
+{ /* calculate white, medium and black values for auto enhancement */
+ int limit, limit_mid;
+ int points, points_mix, points_red, points_green, points_blue;
+ int min, mid, max;
+ int min_red, mid_red, max_red;
+ int min_green, mid_green, max_green;
+ int min_blue, mid_blue, max_blue;
+ int val;
+ int i;
+
+ DBG(DBG_proc, "xsane_calculate_auto_enhancement\n");
+
+ if (xsane.preview)
+ {
+ points = 0;
+ points_mix = 0;
+ points_red = 0;
+ points_green = 0;
+ points_blue = 0;
+
+ for (i=0; i<256; i++)
+ {
+ points += count_raw[i];
+ points_mix += 10 * log(1 + count_raw[i] + count_raw_red[i] + count_raw_green[i] + count_raw_blue[i]);
+ points_red += 10 * log(1 + count_raw_red[i]);
+ points_green += 10 * log(1 + count_raw_green[i]);
+ points_blue += 10 * log(1 + count_raw_blue[i]);
+ }
+
+ limit = 1 + points / 5000;
+
+ /* ----- gray ----- */
+
+ min = -1;
+ val = 0;
+ while ( (val/4 < limit) && (min < 253) )
+ {
+ min++;
+ val += count_raw[min] + count_raw_red[min] + count_raw_green[min] + count_raw_blue[min];
+ }
+
+ max = HIST_WIDTH;
+ val = 0;
+ while ( (val/4 < limit) && (max > min + 1) )
+ {
+ max--;
+ val += count_raw[max] + count_raw_red[max] + count_raw_green[max] + count_raw_blue[max];
+ }
+
+ limit_mid = points_mix / 2.0;
+
+ mid = 0;
+ val = 0;
+ while ( (val < limit_mid) && (mid < max - 1) )
+ {
+ mid++;
+ val += 10 * log(1 + count_raw[mid] + count_raw_red[mid] + count_raw_green[mid] + count_raw_blue[mid]);
+ }
+
+ xsane_bound_int(&mid, min, max);
+
+ /* ----- red ----- */
+
+ min_red = -1;
+ val = 0;
+ while ( (val < limit) && (min_red < 253) )
+ {
+ min_red++;
+ val += count_raw_red[min_red];
+ }
+
+ max_red = HIST_WIDTH;
+ val = 0;
+ while ( (val < limit) && (max_red > min_red + 1) )
+ {
+ max_red--;
+ val += count_raw_red[max_red];
+ }
+
+ limit_mid = points_red / 2.0;
+
+ mid_red = 0;
+ val = 0;
+ while ( (val < limit_mid) && (mid_red < max_red - 1) )
+ {
+ mid_red++;
+ val += 10 * log(1 + count_raw_red[mid_red]);
+ }
+
+ xsane_bound_int(&mid_red, min_red, max_red);
+
+ /* ----- green ----- */
+
+ min_green = -1;
+ val = 0;
+ while ( (val < limit) && (min_green < 253) )
+ {
+ min_green++;
+ val += count_raw_green[min_green];
+ }
+
+ max_green = HIST_WIDTH;
+ val = 0;
+ while ( (val < limit) && (max_green > min_green + 1) )
+ {
+ max_green--;
+ val += count_raw_green[max_green];
+ }
+
+ limit_mid = points_green / 2.0;
+
+ mid_green = 0;
+ val = 0;
+ while ( (val < limit_mid) && (mid_green < max_green - 1) )
+ {
+ mid_green++;
+ val += 10 * log(1 + count_raw_green[mid_green]);
+ }
+
+ xsane_bound_int(&mid_green, min_green, max_green);
+
+ /* ----- blue ----- */
+
+ min_blue = -1;
+ val = 0;
+ while ( (val < limit) && (min_blue < 253) )
+ {
+ min_blue++;
+ val += count_raw_blue[min_blue];
+ }
+
+ max_blue = HIST_WIDTH;
+ val = 0;
+ while ( (val < limit) && (max_blue > min_blue + 1) )
+ {
+ max_blue--;
+ val += count_raw_blue[max_blue];
+ }
+
+ limit_mid = points_blue / 2.0;
+
+ mid_blue = 0;
+ val = 0;
+ while ( (val < limit_mid) && (mid_blue < max_blue - 1) )
+ {
+ mid_blue++;
+ val += 10 * log(1 + count_raw_blue[mid_blue]);
+ }
+
+ xsane_bound_int(&mid_blue, min_blue, max_blue);
+
+ xsane.auto_white = max/2.55;
+ xsane.auto_gray = mid/2.55;
+ xsane.auto_black = min/2.55;
+
+ xsane.auto_white_red = max_red/2.55;
+ xsane.auto_gray_red = mid_red/2.55;
+ xsane.auto_black_red = min_red/2.55;
+
+ xsane.auto_white_green = max_green/2.55;
+ xsane.auto_gray_green = mid_green/2.55;
+ xsane.auto_black_green = min_green/2.55;
+
+ xsane.auto_white_blue = max_blue/2.55;
+ xsane.auto_gray_blue = mid_blue/2.55;
+ xsane.auto_black_blue = min_blue/2.55;
+ }
+
+ DBG(DBG_proc, "xsane.auto_white = %f\n", xsane.auto_white);
+ DBG(DBG_proc, "xsane.auto_gray = %f\n", xsane.auto_gray);
+ DBG(DBG_proc, "xsane.auto_black = %f\n", xsane.auto_black);
+ DBG(DBG_proc, "xsane.auto_white_red = %f\n", xsane.auto_white_red);
+ DBG(DBG_proc, "xsane.auto_gray_red = %f\n", xsane.auto_gray_red);
+ DBG(DBG_proc, "xsane.auto_black_red = %f\n", xsane.auto_black_red);
+ DBG(DBG_proc, "xsane.auto_white_green = %f\n", xsane.auto_white_green);
+ DBG(DBG_proc, "xsane.auto_gray_green = %f\n", xsane.auto_gray_green);
+ DBG(DBG_proc, "xsane.auto_black_green = %f\n", xsane.auto_black_green);
+ DBG(DBG_proc, "xsane.auto_white_blue = %f\n", xsane.auto_white_blue);
+ DBG(DBG_proc, "xsane.auto_gray_blue = %f\n", xsane.auto_gray_blue);
+ DBG(DBG_proc, "xsane.auto_black_blue = %f\n", xsane.auto_black_blue);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_calculate_raw_histogram(void)
+{
+ SANE_Int *count_raw;
+ SANE_Int *count_raw_red;
+ SANE_Int *count_raw_green;
+ SANE_Int *count_raw_blue;
+ int i;
+ int maxval_raw;
+ double scale_raw;
+
+ DBG(DBG_proc, "xsane_calculate_raw_histogram\n");
+
+ /* at first reset auto enhancement values */
+
+ xsane.auto_black = 0.0;
+ xsane.auto_gray = 50.0;
+ xsane.auto_white = 100.0;
+
+ xsane.auto_black_red = 0.0;
+ xsane.auto_gray_red = 50.0;
+ xsane.auto_white_red = 100.0;
+
+ xsane.auto_black_green = 0.0;
+ xsane.auto_gray_green = 50.0;
+ xsane.auto_white_green = 100.0;
+
+ xsane.auto_black_blue = 0.0;
+ xsane.auto_gray_blue = 50.0;
+ xsane.auto_white_blue = 100.0;
+
+ if (xsane.preview) /* preview window exists? */
+ {
+ count_raw = calloc(256, sizeof(SANE_Int));
+ count_raw_red = calloc(256, sizeof(SANE_Int));
+ count_raw_green = calloc(256, sizeof(SANE_Int));
+ count_raw_blue = calloc(256, sizeof(SANE_Int));
+
+ preview_calculate_raw_histogram(xsane.preview, count_raw, count_raw_red, count_raw_green, count_raw_blue);
+
+ if (xsane.param.depth > 1)
+ {
+ xsane_calculate_auto_enhancement(count_raw, count_raw_red, count_raw_green, count_raw_blue);
+ }
+
+ if (xsane.histogram_log) /* logarithmical display */
+ {
+ for (i=0; i<=255; i++)
+ {
+ count_raw[i] = (int) (50*log(1.0 + count_raw[i]));
+ count_raw_red[i] = (int) (50*log(1.0 + count_raw_red[i]));
+ count_raw_green[i] = (int) (50*log(1.0 + count_raw_green[i]));
+ count_raw_blue[i] = (int) (50*log(1.0 + count_raw_blue[i]));
+ }
+ }
+
+ maxval_raw = 1; /* we do not use 0 here because we divide through this varaible later */
+
+ /* first and last 10 values are not used for calculating maximum value */
+ for (i = 10 ; i < HIST_WIDTH - 10; i++)
+ {
+ if (count_raw[i] > maxval_raw) { maxval_raw = count_raw[i]; }
+ if (count_raw_red[i] > maxval_raw) { maxval_raw = count_raw_red[i]; }
+ if (count_raw_green[i] > maxval_raw) { maxval_raw = count_raw_green[i]; }
+ if (count_raw_blue[i] > maxval_raw) { maxval_raw = count_raw_blue[i]; }
+ }
+ scale_raw = 100.0/maxval_raw;
+
+ if (xsane.histogram_lines)
+ {
+ xsane_draw_histogram_with_lines(&xsane.histogram_raw,
+ count_raw, count_raw_red, count_raw_green, count_raw_blue,
+ xsane.histogram_red, xsane.histogram_green, xsane.histogram_blue,
+ xsane.histogram_int, scale_raw);
+ }
+ else
+ {
+ xsane_draw_histogram_with_points(&xsane.histogram_raw,
+ count_raw, count_raw_red, count_raw_green, count_raw_blue,
+ xsane.histogram_red, xsane.histogram_green, xsane.histogram_blue,
+ xsane.histogram_int, scale_raw);
+ }
+
+ free(count_raw_blue);
+ free(count_raw_green);
+ free(count_raw_red);
+ free(count_raw);
+ }
+ else
+ {
+ xsane_clear_histogram(&xsane.histogram_raw);
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_calculate_enh_histogram(void)
+{
+ SANE_Int *count_enh;
+ SANE_Int *count_enh_red;
+ SANE_Int *count_enh_green;
+ SANE_Int *count_enh_blue;
+ int i;
+ int maxval_enh;
+ double scale_enh;
+
+ DBG(DBG_proc, "xsane_calculate_enh_histogram\n");
+
+ if (xsane.preview) /* preview window exists? */
+ {
+ count_enh = calloc(256, sizeof(SANE_Int));
+ count_enh_red = calloc(256, sizeof(SANE_Int));
+ count_enh_green = calloc(256, sizeof(SANE_Int));
+ count_enh_blue = calloc(256, sizeof(SANE_Int));
+
+ preview_calculate_enh_histogram(xsane.preview, count_enh, count_enh_red, count_enh_green, count_enh_blue);
+
+ if (xsane.histogram_log) /* logarithmical display */
+ {
+ for (i=0; i<=255; i++)
+ {
+ count_enh[i] = (int) (50*log(1.0 + count_enh[i]));
+ count_enh_red[i] = (int) (50*log(1.0 + count_enh_red[i]));
+ count_enh_green[i] = (int) (50*log(1.0 + count_enh_green[i]));
+ count_enh_blue[i] = (int) (50*log(1.0 + count_enh_blue[i]));
+ }
+ }
+
+ maxval_enh = 1;
+
+ /* first and last 10 values are not used for calculating maximum value */
+ for (i = 10 ; i < HIST_WIDTH - 10; i++)
+ {
+ if (count_enh[i] > maxval_enh) { maxval_enh = count_enh[i]; }
+ if (count_enh_red[i] > maxval_enh) { maxval_enh = count_enh_red[i]; }
+ if (count_enh_green[i] > maxval_enh) { maxval_enh = count_enh_green[i]; }
+ if (count_enh_blue[i] > maxval_enh) { maxval_enh = count_enh_blue[i]; }
+ }
+ scale_enh = 100.0/maxval_enh;
+
+ if (xsane.histogram_lines)
+ {
+ xsane_draw_histogram_with_lines(&xsane.histogram_enh,
+ count_enh, count_enh_red, count_enh_green, count_enh_blue,
+ xsane.histogram_red, xsane.histogram_green, xsane.histogram_blue, xsane.histogram_int, scale_enh);
+ }
+ else
+ {
+ xsane_draw_histogram_with_points(&xsane.histogram_enh,
+ count_enh, count_enh_red, count_enh_green, count_enh_blue,
+ xsane.histogram_red, xsane.histogram_green, xsane.histogram_blue, xsane.histogram_int, scale_enh);
+ }
+
+ free(count_enh_blue);
+ free(count_enh_green);
+ free(count_enh_red);
+ free(count_enh);
+ }
+ else
+ {
+ xsane_clear_histogram(&xsane.histogram_enh);
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_update_histogram(int update_raw)
+{
+ DBG(DBG_proc, "xsane_update_histogram\n");
+
+ if (preferences.show_histogram)
+ {
+ if (update_raw)
+ {
+ xsane_calculate_raw_histogram();
+ }
+ xsane_calculate_enh_histogram();
+
+ gtk_widget_show(xsane.histogram_dialog);
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_histogram_toggle_button_callback(GtkWidget *widget, gpointer data)
+{
+ int *valuep = data;
+
+ DBG(DBG_proc, "xsane_histogram_toggle_button_callback\n");
+
+ *valuep = (GTK_TOGGLE_BUTTON(widget)->active != 0);
+ xsane_update_histogram(TRUE);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_create_preview_threshold_curve(u_char *gammadata, double threshold, int numbers)
+{
+ int i;
+ int maxin = numbers-1;
+ int threshold_level;
+
+ DBG(DBG_proc, "xsane_create_preview_threshold_curve\n");
+
+ xsane_bound_double(&threshold, 0.0, 100.0);
+ threshold_level = maxin * threshold / 100.0;
+
+ for (i=0; i < threshold_level; i++)
+ {
+ gammadata[i] = 0;
+ }
+
+ for (i=threshold_level; i <= maxin; i++)
+ {
+ gammadata[i] = 255;
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_create_preview_gamma_curve(u_char *gammadata, int negative, double gamma,
+ double brightness, double contrast,
+ double medium_shadow, double medium_highlight, double medium_gamma,
+ int numbers)
+{
+ int i;
+ double midin;
+ double val;
+ double m;
+ double b;
+ int maxin = numbers-1;
+ double medium_m;
+ double medium_mid;
+
+ medium_m = 100.0/(medium_highlight - medium_shadow);
+ medium_mid = (medium_shadow + medium_highlight)/200.0 * maxin;
+
+ DBG(DBG_proc, "xsane_create_preview_gamma_curve(neg=%d, gam=%3.2f, bri=%3.2f, ctr=%3.2f, nrs=%d)\n",
+ negative, gamma, brightness, contrast, numbers);
+
+ if (contrast < -100.0)
+ {
+ contrast = -100.0;
+ }
+
+ midin = (int)(numbers / 2.0);
+
+ m = 1.0 + contrast/100.0;
+ b = (1.0 + brightness/100.0) * midin;
+
+ if (negative)
+ {
+ for (i=0; i <= maxin; i++)
+ {
+ val = ((double) i);
+
+ /* medium correction */
+ val = (val - medium_mid) * medium_m + midin;
+ xsane_bound_double(&val, 0.0, maxin);
+ val = maxin - val; /* invert */
+ val = maxin * pow( val/maxin, (1.0/medium_gamma) );
+
+ val = val - midin;
+
+ /* user correction */
+ val = val * m + b;
+ xsane_bound_double(&val, 0.0, maxin);
+
+ gammadata[i] = (u_char) (255 * pow( val/maxin, (1.0/gamma) ));
+ }
+ }
+ else /* positive */
+ {
+ for (i=0; i <= maxin; i++)
+ {
+ val = ((double) i);
+
+ /* medium correction */
+ val = (val - medium_mid) * medium_m + midin;
+ xsane_bound_double(&val, 0.0, maxin);
+ val = maxin * pow( val/maxin, (1.0/medium_gamma) );
+
+ val = val - midin;
+
+ /* user correction */
+ val = val * m + b;
+ xsane_bound_double(&val, 0.0, maxin);
+
+ gammadata[i] = (u_char) (255 * pow( val/maxin, (1.0/gamma) ));
+ }
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_create_gamma_curve(SANE_Int *gammadata,
+ int negative, double gamma, double brightness, double contrast,
+ double medium_shadow, double medium_highlight, double medium_gamma,
+ int numbers, int maxout)
+{
+ int i;
+ double midin;
+ double val;
+ double m;
+ double b;
+ double medium_m;
+ double medium_mid;
+ int maxin = numbers-1;
+
+ DBG(DBG_proc, "xsane_create_gamma_curve(neg=%d, gam=%3.2f, bri=%3.2f, ctr=%3.2f, "
+ "mshd=%3.2f, mhig=%3.2f, mgam=%3.2f, "
+ "nrs=%d, max=%d)\n",
+ negative, gamma, brightness, contrast,
+ medium_shadow, medium_highlight, medium_gamma,
+ numbers, maxout);
+
+ midin = (int)(numbers / 2.0);
+
+ if (contrast < -100.0)
+ {
+ contrast = -100.0;
+ }
+
+ medium_m = 100.0/(medium_highlight - medium_shadow);
+ medium_mid = (medium_shadow + medium_highlight)/200.0 * maxin;
+
+ m = 1.0 + contrast/100.0;
+ b = (1.0 + brightness/100.0) * midin;
+
+ if (negative)
+ {
+ for (i=0; i <= maxin; i++)
+ {
+ val = ((double) i);
+
+ /* medium correction */
+ val = (val - medium_mid) * medium_m + midin;
+ xsane_bound_double(&val, 0.0, maxin);
+ val = maxin - val; /* invert */
+ val = maxin * pow( val/maxin, (1.0/medium_gamma) );
+
+ val = val - midin;
+
+ /* user correction */
+ val = val * m + b;
+ xsane_bound_double(&val, 0.0, maxin);
+ gammadata[i] = maxout * pow( val/maxin, (1.0/gamma) );
+ }
+ }
+ else /* positive */
+ {
+ for (i=0; i <= maxin; i++)
+ {
+ val = ((double) i);
+
+ /* medium correction */
+ val = (val - medium_mid) * medium_m + midin;
+ xsane_bound_double(&val, 0.0, maxin);
+ val = maxin * pow( val/maxin, (1.0/medium_gamma) );
+
+ val = val - midin;
+
+ /* user correction */
+ val = val * m + b;
+ xsane_bound_double(&val, 0.0, maxin);
+ gammadata[i] = maxout * pow( val/maxin, (1.0/gamma) );
+ }
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_update_gamma_curve(int update_raw)
+{
+ DBG(DBG_proc, "xsane_update_gamma_curve\n");
+
+ if (xsane.preview)
+ {
+ if (!xsane.preview_gamma_data_red)
+ {
+ xsane.preview_gamma_size = pow(2, preferences.preview_gamma_input_bits);
+
+ xsane.preview_gamma_data_red = malloc(xsane.preview_gamma_size);
+ xsane.preview_gamma_data_green = malloc(xsane.preview_gamma_size);
+ xsane.preview_gamma_data_blue = malloc(xsane.preview_gamma_size);
+
+ xsane.histogram_gamma_data_red = malloc(xsane.preview_gamma_size);
+ xsane.histogram_gamma_data_green = malloc(xsane.preview_gamma_size);
+ xsane.histogram_gamma_data_blue = malloc(xsane.preview_gamma_size);
+
+ xsane.histogram_medium_gamma_data_red = malloc(xsane.preview_gamma_size);
+ xsane.histogram_medium_gamma_data_green = malloc(xsane.preview_gamma_size);
+ xsane.histogram_medium_gamma_data_blue = malloc(xsane.preview_gamma_size);
+ }
+
+ if (xsane.preview->calibration)
+ {
+ double pgamma_red;
+ double pgamma_green;
+ double pgamma_blue;
+
+ pgamma_red = preferences.preview_gamma * preferences.preview_gamma_red;
+ pgamma_green = preferences.preview_gamma * preferences.preview_gamma_green;
+ pgamma_blue = preferences.preview_gamma * preferences.preview_gamma_blue;
+
+ xsane_create_preview_gamma_curve(xsane.preview_gamma_data_red, 0, pgamma_red,
+ 0.0, 0.0, 0.0, 100.0, 1.0, xsane.preview_gamma_size);
+ xsane_create_preview_gamma_curve(xsane.preview_gamma_data_green, 0, pgamma_green,
+ 0.0, 0.0, 0.0, 100.0, 1.0, xsane.preview_gamma_size);
+ xsane_create_preview_gamma_curve(xsane.preview_gamma_data_blue, 0, pgamma_blue,
+ 0.0, 0.0, 0.0, 100.0, 1.0, xsane.preview_gamma_size);
+ }
+ else if (xsane.param.depth == 1) /* for lineart mode with grayscale preview scan */
+ {
+ xsane_create_preview_threshold_curve(xsane.preview_gamma_data_red, xsane.threshold, xsane.preview_gamma_size);
+ xsane_create_preview_threshold_curve(xsane.preview_gamma_data_green, xsane.threshold, xsane.preview_gamma_size);
+ xsane_create_preview_threshold_curve(xsane.preview_gamma_data_blue, xsane.threshold, xsane.preview_gamma_size);
+
+ xsane_create_preview_threshold_curve(xsane.histogram_gamma_data_red, xsane.threshold, xsane.preview_gamma_size);
+ xsane_create_preview_threshold_curve(xsane.histogram_gamma_data_green, xsane.threshold, xsane.preview_gamma_size);
+ xsane_create_preview_threshold_curve(xsane.histogram_gamma_data_blue, xsane.threshold, xsane.preview_gamma_size);
+ }
+ else /* multi bit mode */
+ {
+ double pgamma_red = 1.0;
+ double pgamma_green = 1.0;
+ double pgamma_blue = 1.0;
+
+ if ((xsane.mode != XSANE_GIMP_EXTENSION) || (!preferences.disable_gimp_preview_gamma))
+ {
+ pgamma_red = preferences.preview_gamma * preferences.preview_gamma_red;
+ pgamma_green = preferences.preview_gamma * preferences.preview_gamma_green;
+ pgamma_blue = preferences.preview_gamma * preferences.preview_gamma_blue;
+ }
+
+
+#ifdef HAVE_WORKING_GTK_GAMMACURVE
+#if 1
+ gtk_curve_get_vector(GTK_CURVE(GTK_GAMMA_CURVE(xsane.gamma_curve_gray)->curve), 65536, xsane.free_gamma_data);
+#if 1
+{
+ int i;
+ for (i=0; i<100; i++)
+ {
+ printf("%1.6f ", xsane.free_gamma_data[i]);
+ if (i / 10.0 == i / 10)
+ {
+ printf("\n");
+ }
+ }
+ printf("\n");
+ for (i=65435; i<65536; i++)
+ {
+ printf("%1.6f ", xsane.free_gamma_data[i]);
+ if (i / 10.0 == i / 10)
+ {
+ printf("\n");
+ }
+ }
+ printf("\n");
+ printf("\n");
+}
+#endif
+ gtk_curve_get_vector(GTK_CURVE(GTK_GAMMA_CURVE(xsane.gamma_curve_red)->curve), 65536, xsane.free_gamma_data_red);
+ gtk_curve_get_vector(GTK_CURVE(GTK_GAMMA_CURVE(xsane.gamma_curve_green)->curve), 65536, xsane.free_gamma_data_green);
+ gtk_curve_get_vector(GTK_CURVE(GTK_GAMMA_CURVE(xsane.gamma_curve_blue)->curve), 65536, xsane.free_gamma_data_blue);
+#endif
+
+ xsane_get_free_gamma_curve(xsane.free_gamma_data_red, xsane.preview_gamma_data_red, xsane.negative,
+ xsane.gamma * xsane.gamma_red * pgamma_red,
+ xsane.brightness + xsane.brightness_red,
+ xsane.contrast + xsane.contrast_red, xsane.preview_gamma_size, 255);
+
+ xsane_get_free_gamma_curve(xsane.free_gamma_data_green, xsane.preview_gamma_data_green, xsane.negative,
+ xsane.gamma * xsane.gamma_green * pgamma_green,
+ xsane.brightness + xsane.brightness_green,
+ xsane.contrast + xsane.contrast_green, xsane.preview_gamma_size, 255);
+
+ xsane_get_free_gamma_curve(xsane.free_gamma_data_blue, xsane.preview_gamma_data_blue, xsane.negative,
+ xsane.gamma * xsane.gamma_blue * pgamma_blue,
+ xsane.brightness + xsane.brightness_blue,
+ xsane.contrast + xsane.contrast_blue , xsane.preview_gamma_size, 255);
+
+
+ xsane_get_free_gamma_curve(xsane.free_gamma_data_red, xsane.histogram_gamma_data_red, xsane.negative,
+ xsane.gamma * xsane.gamma_red,
+ xsane.brightness + xsane.brightness_red,
+ xsane.contrast + xsane.contrast_red, xsane.preview_gamma_size, 255);
+
+ xsane_get_free_gamma_curve(xsane.free_gamma_data_green, xsane.histogram_gamma_data_green, xsane.negative,
+ xsane.gamma * xsane.gamma_green,
+ xsane.brightness + xsane.brightness_green,
+ xsane.contrast + xsane.contrast_green, xsane.preview_gamma_size, 255);
+
+ xsane_get_free_gamma_curve(xsane.free_gamma_data_blue, xsane.histogram_gamma_data_blue, xsane.negative,
+ xsane.gamma * xsane.gamma_blue,
+ xsane.brightness + xsane.brightness_blue,
+ xsane.contrast + xsane.contrast_blue , xsane.preview_gamma_size, 255);
+#else
+ if ( ( ( (xsane.xsane_colors > 1) && xsane.scanner_gamma_color ) || /* color scan and gamma table for red, green and blue available */
+ xsane.scanner_gamma_gray ) && /* grayscale scan and gamma table for gray available */
+ (!xsane.no_preview_medium_gamma) ) /* do not use gamma table when disabled */
+ {
+ DBG(DBG_info, "creating preview gamma tables without medium correction\n");
+
+ xsane_create_preview_gamma_curve(xsane.preview_gamma_data_red, xsane.negative,
+ xsane.gamma * xsane.gamma_red * pgamma_red,
+ xsane.brightness + xsane.brightness_red,
+ xsane.contrast + xsane.contrast_red,
+ 0.0, 100.0, 1.0,
+ xsane.preview_gamma_size);
+
+ xsane_create_preview_gamma_curve(xsane.preview_gamma_data_green, xsane.negative,
+ xsane.gamma * xsane.gamma_green * pgamma_green,
+ xsane.brightness + xsane.brightness_green,
+ xsane.contrast + xsane.contrast_green,
+ 0.0, 100.0, 1.0,
+ xsane.preview_gamma_size);
+
+ xsane_create_preview_gamma_curve(xsane.preview_gamma_data_blue, xsane.negative,
+ xsane.gamma * xsane.gamma_blue * pgamma_blue,
+ xsane.brightness + xsane.brightness_blue,
+ xsane.contrast + xsane.contrast_blue,
+ 0.0, 100.0, 1.0,
+ xsane.preview_gamma_size);
+
+
+ xsane_create_preview_gamma_curve(xsane.histogram_gamma_data_red, xsane.negative,
+ xsane.gamma * xsane.gamma_red,
+ xsane.brightness + xsane.brightness_red,
+ xsane.contrast + xsane.contrast_red,
+ 0.0, 100.0, 1.0,
+ xsane.preview_gamma_size);
+
+ xsane_create_preview_gamma_curve(xsane.histogram_gamma_data_green, xsane.negative,
+ xsane.gamma * xsane.gamma_green,
+ xsane.brightness + xsane.brightness_green,
+ xsane.contrast + xsane.contrast_green,
+ 0.0, 100.0, 1.0,
+ xsane.preview_gamma_size);
+
+ xsane_create_preview_gamma_curve(xsane.histogram_gamma_data_blue, xsane.negative,
+ xsane.gamma * xsane.gamma_blue,
+ xsane.brightness + xsane.brightness_blue,
+ xsane.contrast + xsane.contrast_blue,
+ 0.0, 100.0, 1.0,
+ xsane.preview_gamma_size);
+
+ if (update_raw) /* to speed up things here */
+ {
+ xsane_create_preview_gamma_curve(xsane.histogram_medium_gamma_data_red, xsane.negative,
+ 1.0, 0.0, 0.0, 0.0, 100.0, 1.0,
+ xsane.preview_gamma_size);
+
+ xsane_create_preview_gamma_curve(xsane.histogram_medium_gamma_data_green, xsane.negative,
+ 1.0, 0.0, 0.0, 0.0, 100.0, 1.0,
+ xsane.preview_gamma_size);
+
+ xsane_create_preview_gamma_curve(xsane.histogram_medium_gamma_data_blue, xsane.negative,
+ 1.0, 0.0, 0.0, 0.0, 100.0, 1.0,
+ xsane.preview_gamma_size);
+ }
+ }
+ else if (xsane.xsane_colors > 1) /* color scan, no color scanner gamma tables available */
+ {
+ DBG(DBG_info, "creating preview gamma tables with medium correction\n");
+
+ xsane.medium_changed = FALSE;
+
+ preview_display_valid(xsane.preview);
+
+ xsane_create_preview_gamma_curve(xsane.preview_gamma_data_red, xsane.negative != xsane.medium_negative,
+ xsane.gamma * xsane.gamma_red * pgamma_red,
+ xsane.brightness + xsane.brightness_red,
+ xsane.contrast + xsane.contrast_red,
+ xsane.medium_shadow_red, xsane.medium_highlight_red, xsane.medium_gamma_red,
+ xsane.preview_gamma_size);
+
+ xsane_create_preview_gamma_curve(xsane.preview_gamma_data_green, xsane.negative != xsane.medium_negative,
+ xsane.gamma * xsane.gamma_green * pgamma_green,
+ xsane.brightness + xsane.brightness_green,
+ xsane.contrast + xsane.contrast_green,
+ xsane.medium_shadow_green, xsane.medium_highlight_green, xsane.medium_gamma_green,
+ xsane.preview_gamma_size);
+
+ xsane_create_preview_gamma_curve(xsane.preview_gamma_data_blue, xsane.negative != xsane.medium_negative,
+ xsane.gamma * xsane.gamma_blue * pgamma_blue,
+ xsane.brightness + xsane.brightness_blue,
+ xsane.contrast + xsane.contrast_blue,
+ xsane.medium_shadow_blue, xsane.medium_highlight_blue, xsane.medium_gamma_blue,
+ xsane.preview_gamma_size);
+
+
+ xsane_create_preview_gamma_curve(xsane.histogram_gamma_data_red, xsane.negative != xsane.medium_negative,
+ xsane.gamma * xsane.gamma_red,
+ xsane.brightness + xsane.brightness_red,
+ xsane.contrast + xsane.contrast_red,
+ xsane.medium_shadow_red, xsane.medium_highlight_red, xsane.medium_gamma_red,
+ xsane.preview_gamma_size);
+
+ xsane_create_preview_gamma_curve(xsane.histogram_gamma_data_green, xsane.negative != xsane.medium_negative,
+ xsane.gamma * xsane.gamma_green,
+ xsane.brightness + xsane.brightness_green,
+ xsane.contrast + xsane.contrast_green,
+ xsane.medium_shadow_green, xsane.medium_highlight_green, xsane.medium_gamma_green,
+ xsane.preview_gamma_size);
+
+ xsane_create_preview_gamma_curve(xsane.histogram_gamma_data_blue, xsane.negative != xsane.medium_negative,
+ xsane.gamma * xsane.gamma_blue,
+ xsane.brightness + xsane.brightness_blue,
+ xsane.contrast + xsane.contrast_blue,
+ xsane.medium_shadow_blue, xsane.medium_highlight_blue, xsane.medium_gamma_blue,
+ xsane.preview_gamma_size);
+
+
+ if (update_raw) /* to speed up things here */
+ {
+ xsane_create_preview_gamma_curve(xsane.histogram_medium_gamma_data_red, xsane.negative != xsane.medium_negative,
+ 1.0, 0.0, 0.0,
+ xsane.medium_shadow_red, xsane.medium_highlight_red, xsane.medium_gamma_red,
+ xsane.preview_gamma_size);
+
+ xsane_create_preview_gamma_curve(xsane.histogram_medium_gamma_data_green, xsane.negative != xsane.medium_negative,
+ 1.0, 0.0, 0.0,
+ xsane.medium_shadow_green, xsane.medium_highlight_green, xsane.medium_gamma_green,
+ xsane.preview_gamma_size);
+
+ xsane_create_preview_gamma_curve(xsane.histogram_medium_gamma_data_blue, xsane.negative != xsane.medium_negative,
+ 1.0, 0.0, 0.0,
+ xsane.medium_shadow_blue, xsane.medium_highlight_blue, xsane.medium_gamma_blue,
+ xsane.preview_gamma_size);
+ }
+ }
+ else /* grayscale scan, no gray scanner gamma table available */
+ {
+ DBG(DBG_info, "creating preview gamma tables with medium correction\n");
+
+ xsane.medium_changed = FALSE;
+
+ preview_display_valid(xsane.preview);
+
+ xsane_create_preview_gamma_curve(xsane.preview_gamma_data_red, xsane.negative != xsane.medium_negative,
+ xsane.gamma * xsane.gamma_red * pgamma_red,
+ xsane.brightness + xsane.brightness_red,
+ xsane.contrast + xsane.contrast_red,
+ xsane.medium_shadow_gray, xsane.medium_highlight_gray, xsane.medium_gamma_gray,
+ xsane.preview_gamma_size);
+
+ xsane_create_preview_gamma_curve(xsane.preview_gamma_data_green, xsane.negative != xsane.medium_negative,
+ xsane.gamma * xsane.gamma_green * pgamma_green,
+ xsane.brightness + xsane.brightness_green,
+ xsane.contrast + xsane.contrast_green,
+ xsane.medium_shadow_gray, xsane.medium_highlight_gray, xsane.medium_gamma_gray,
+ xsane.preview_gamma_size);
+
+ xsane_create_preview_gamma_curve(xsane.preview_gamma_data_blue, xsane.negative != xsane.medium_negative,
+ xsane.gamma * xsane.gamma_blue * pgamma_blue,
+ xsane.brightness + xsane.brightness_blue,
+ xsane.contrast + xsane.contrast_blue,
+ xsane.medium_shadow_gray, xsane.medium_highlight_gray, xsane.medium_gamma_gray,
+ xsane.preview_gamma_size);
+
+
+ xsane_create_preview_gamma_curve(xsane.histogram_gamma_data_red, xsane.negative != xsane.medium_negative,
+ xsane.gamma * xsane.gamma_red,
+ xsane.brightness + xsane.brightness_red,
+ xsane.contrast + xsane.contrast_red,
+ xsane.medium_shadow_gray, xsane.medium_highlight_gray, xsane.medium_gamma_gray,
+ xsane.preview_gamma_size);
+
+ xsane_create_preview_gamma_curve(xsane.histogram_gamma_data_green, xsane.negative != xsane.medium_negative,
+ xsane.gamma * xsane.gamma_green,
+ xsane.brightness + xsane.brightness_green,
+ xsane.contrast + xsane.contrast_green,
+ xsane.medium_shadow_gray, xsane.medium_highlight_gray, xsane.medium_gamma_gray,
+ xsane.preview_gamma_size);
+
+ xsane_create_preview_gamma_curve(xsane.histogram_gamma_data_blue, xsane.negative != xsane.medium_negative,
+ xsane.gamma * xsane.gamma_blue,
+ xsane.brightness + xsane.brightness_blue,
+ xsane.contrast + xsane.contrast_blue,
+ xsane.medium_shadow_gray, xsane.medium_highlight_gray, xsane.medium_gamma_gray,
+ xsane.preview_gamma_size);
+
+
+ if (update_raw) /* to speed up things here */
+ {
+ xsane_create_preview_gamma_curve(xsane.histogram_medium_gamma_data_red, xsane.negative != xsane.medium_negative,
+ 1.0, 0.0, 0.0,
+ xsane.medium_shadow_gray, xsane.medium_highlight_gray, xsane.medium_gamma_gray,
+ xsane.preview_gamma_size);
+
+ xsane_create_preview_gamma_curve(xsane.histogram_medium_gamma_data_green, xsane.negative != xsane.medium_negative,
+ 1.0, 0.0, 0.0,
+ xsane.medium_shadow_gray, xsane.medium_highlight_gray, xsane.medium_gamma_gray,
+ xsane.preview_gamma_size);
+
+ xsane_create_preview_gamma_curve(xsane.histogram_medium_gamma_data_blue, xsane.negative != xsane.medium_negative,
+ 1.0, 0.0, 0.0,
+ xsane.medium_shadow_gray, xsane.medium_highlight_gray, xsane.medium_gamma_gray,
+ xsane.preview_gamma_size);
+ }
+ }
+#endif
+ }
+
+ preview_gamma_correction(xsane.preview, preferences.preview_gamma_input_bits,
+ xsane.preview_gamma_data_red, xsane.preview_gamma_data_green, xsane.preview_gamma_data_blue,
+ xsane.histogram_gamma_data_red, xsane.histogram_gamma_data_green, xsane.histogram_gamma_data_blue,
+ xsane.histogram_medium_gamma_data_red, xsane.histogram_medium_gamma_data_green, xsane.histogram_medium_gamma_data_blue);
+
+ xsane_update_histogram(update_raw);
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_enhancement_update(void)
+{
+ guint sig_changed=0;
+
+ DBG(DBG_proc, "xsane_enhancement_update\n");
+
+ if (xsane.param.depth == 1) /* lineart? no gamma */
+ {
+ return;
+ }
+
+ sig_changed = gtk_signal_lookup("changed", GTK_OBJECT_TYPE(xsane.gamma_widget));
+
+ GTK_ADJUSTMENT(xsane.gamma_widget)->value = xsane.gamma;
+ GTK_ADJUSTMENT(xsane.brightness_widget)->value = xsane.brightness;
+ GTK_ADJUSTMENT(xsane.contrast_widget)->value = xsane.contrast;
+
+ if ( (xsane.xsane_colors > 1) && (!xsane.enhancement_rgb_default) )
+ {
+ GTK_ADJUSTMENT(xsane.gamma_red_widget)->value = xsane.gamma_red;
+ GTK_ADJUSTMENT(xsane.gamma_green_widget)->value = xsane.gamma_green;
+ GTK_ADJUSTMENT(xsane.gamma_blue_widget)->value = xsane.gamma_blue;
+
+ GTK_ADJUSTMENT(xsane.brightness_red_widget)->value = xsane.brightness_red;
+ GTK_ADJUSTMENT(xsane.brightness_green_widget)->value = xsane.brightness_green;
+ GTK_ADJUSTMENT(xsane.brightness_blue_widget)->value = xsane.brightness_blue;
+
+ GTK_ADJUSTMENT(xsane.contrast_red_widget)->value = xsane.contrast_red;
+ GTK_ADJUSTMENT(xsane.contrast_green_widget)->value = xsane.contrast_green;
+ GTK_ADJUSTMENT(xsane.contrast_blue_widget)->value = xsane.contrast_blue;
+
+ gtk_signal_emit(xsane.gamma_red_widget, sig_changed);
+ gtk_signal_emit(xsane.gamma_green_widget, sig_changed);
+ gtk_signal_emit(xsane.gamma_blue_widget, sig_changed);
+
+ gtk_signal_emit(xsane.brightness_red_widget, sig_changed);
+ gtk_signal_emit(xsane.brightness_green_widget, sig_changed);
+ gtk_signal_emit(xsane.brightness_blue_widget, sig_changed);
+
+ gtk_signal_emit(xsane.contrast_red_widget, sig_changed);
+ gtk_signal_emit(xsane.contrast_green_widget, sig_changed);
+ gtk_signal_emit(xsane.contrast_blue_widget, sig_changed);
+
+ }
+
+ gtk_signal_emit(xsane.gamma_widget, sig_changed);
+ gtk_signal_emit(xsane.brightness_widget, sig_changed);
+ gtk_signal_emit(xsane.contrast_widget, sig_changed);
+
+ xsane_update_sliders(); /* update histogram slider */
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_gamma_to_histogram(double *min, double *mid, double *max,
+ double contrast, double brightness, double gamma)
+{
+ double m;
+ double b;
+
+ DBG(DBG_proc, "xsane_gamma_to_histogram\n");
+
+ m = 1.0 + contrast/100.0;
+ b = (1.0 + brightness/100.0) * 50.0;
+
+ if (m > 0)
+ {
+ *min = 50.0 - b/m;
+ *mid = (100.0 * pow(0.5, gamma)-b) / m + 50.0;
+ *max = (100.0-b)/m + 50.0;
+ }
+ else
+ {
+ *min = 0.0;
+ *mid = 50.0;
+ *max = 100.0;
+ }
+
+ xsane_bound_double(min, 0.0, 98.0);
+ xsane_bound_double(max, *min+1, 100.0);
+ xsane_bound_double(mid, *min+1, *max-1);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_enhancement_by_gamma(void)
+{
+ double min, mid, max;
+ double contrast, brightness, gamma;
+
+ DBG(DBG_proc, "xsane_enhancement_by_gamma\n");
+
+ xsane_gamma_to_histogram(&min, &mid, &max, xsane.contrast, xsane.brightness, xsane.gamma);
+
+ xsane.slider_gray.value[0] = min;
+ xsane.slider_gray.value[1] = mid;
+ xsane.slider_gray.value[2] = max;
+
+
+ /* red */
+ contrast = xsane.contrast + xsane.contrast_red;
+ brightness = xsane.brightness + xsane.brightness_red;
+ gamma = xsane.gamma * xsane.gamma_red;
+
+ if (contrast < -100)
+ {
+ contrast = -100;
+ }
+
+ xsane_gamma_to_histogram(&min, &mid, &max, contrast, brightness, gamma);
+
+
+ xsane.slider_red.value[0] = min;
+ xsane.slider_red.value[1] = mid;
+ xsane.slider_red.value[2] = max;
+
+
+ /* green */
+ contrast = xsane.contrast + xsane.contrast_green;
+ brightness = xsane.brightness + xsane.brightness_green;
+ gamma = xsane.gamma * xsane.gamma_green;
+
+ if (contrast < -100)
+ {
+ contrast = -100;
+ }
+
+ xsane_gamma_to_histogram(&min, &mid, &max, contrast, brightness, gamma);
+
+ xsane.slider_green.value[0] = min;
+ xsane.slider_green.value[1] = mid;
+ xsane.slider_green.value[2] = max;
+
+
+ /* blue */
+ contrast = xsane.contrast + xsane.contrast_blue;
+ brightness = xsane.brightness + xsane.brightness_blue;
+ gamma = xsane.gamma * xsane.gamma_blue;
+
+ if (contrast < -100)
+ {
+ contrast = -100;
+ }
+
+ xsane_gamma_to_histogram(&min, &mid, &max, contrast, brightness, gamma);
+
+ xsane.slider_blue.value[0] = min;
+ xsane.slider_blue.value[1] = mid;
+ xsane.slider_blue.value[2] = max;
+
+
+ xsane_enhancement_update();
+ xsane_update_gamma_curve(FALSE);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_enhancement_restore_default()
+{
+ DBG(DBG_proc, "xsane_enhancement_restore_default\n");
+
+ xsane.gamma = 1.0;
+ xsane.gamma_red = 1.0;
+ xsane.gamma_green = 1.0;
+ xsane.gamma_blue = 1.0;
+
+ xsane.brightness = 0.0;
+ xsane.brightness_red = 0.0;
+ xsane.brightness_green = 0.0;
+ xsane.brightness_blue = 0.0;
+
+ xsane.contrast = 0.0;
+ xsane.contrast_red = 0.0;
+ xsane.contrast_green = 0.0;
+ xsane.contrast_blue = 0.0;
+
+ xsane_enhancement_by_gamma();
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_enhancement_restore()
+{
+ DBG(DBG_proc, "xsane_enhancement_restore\n");
+
+ xsane.gamma = preferences.xsane_gamma;
+ xsane.gamma_red = preferences.xsane_gamma_red;
+ xsane.gamma_green = preferences.xsane_gamma_green;
+ xsane.gamma_blue = preferences.xsane_gamma_blue;
+
+ xsane.brightness = preferences.xsane_brightness;
+ xsane.brightness_red = preferences.xsane_brightness_red;
+ xsane.brightness_green = preferences.xsane_brightness_green;
+ xsane.brightness_blue = preferences.xsane_brightness_blue;
+
+ xsane.contrast = preferences.xsane_contrast;
+ xsane.contrast_red = preferences.xsane_contrast_red;
+ xsane.contrast_green = preferences.xsane_contrast_green;
+ xsane.contrast_blue = preferences.xsane_contrast_blue;
+
+ xsane.enhancement_rgb_default = preferences.xsane_rgb_default;
+ xsane.negative = preferences.xsane_negative;
+
+ xsane_refresh_dialog();
+ xsane_enhancement_by_gamma();
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_enhancement_store()
+{
+ DBG(DBG_proc, "xsane_enhancement_store\n");
+
+ preferences.xsane_gamma = xsane.gamma;
+ preferences.xsane_gamma_red = xsane.gamma_red;
+ preferences.xsane_gamma_green = xsane.gamma_green;
+ preferences.xsane_gamma_blue = xsane.gamma_blue;
+
+ preferences.xsane_brightness = xsane.brightness;
+ preferences.xsane_brightness_red = xsane.brightness_red;
+ preferences.xsane_brightness_green = xsane.brightness_green;
+ preferences.xsane_brightness_blue = xsane.brightness_blue;
+
+ preferences.xsane_contrast = xsane.contrast;
+ preferences.xsane_contrast_red = xsane.contrast_red;
+ preferences.xsane_contrast_green = xsane.contrast_green;
+ preferences.xsane_contrast_blue = xsane.contrast_blue;
+
+ preferences.xsane_rgb_default = xsane.enhancement_rgb_default;
+ preferences.xsane_negative = xsane.negative;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static int xsane_histogram_to_gamma(XsaneSlider *slider,
+ double *contrast, double contrast_offset,
+ double *brightness, double brightness_offset,
+ double *gamma, double gamma_multiplier)
+{
+ double mid;
+ double range;
+ int correct_bound = ((slider->active == XSANE_SLIDER_ACTIVE) || (slider->active == XSANE_SLIDER_INACTIVE)); /* slider not moved */
+
+ DBG(DBG_proc, "xsane_histogram_to_gamma(correct_bound = %d)\n", correct_bound);
+
+ *contrast = (10000.0 / (slider->value[2] - slider->value[0]) - 100.0);
+ if (correct_bound)
+ {
+ xsane_bound_double(contrast, -100.0 + contrast_offset, xsane.contrast_max + contrast_offset);
+ }
+
+ *brightness = - (slider->value[0] - 50.0) * (*contrast + 100.0)/50.0 - 100.0;
+ if (correct_bound)
+ {
+ xsane_bound_double(brightness, xsane.brightness_min + brightness_offset, xsane.brightness_max + brightness_offset);
+ }
+
+ mid = slider->value[1] - slider->value[0];
+ range = slider->value[2] - slider->value[0];
+
+ *gamma = log(mid/range) / log(0.5);
+ if (correct_bound)
+ {
+ xsane_bound_double(gamma, XSANE_GAMMA_MIN * gamma_multiplier, XSANE_GAMMA_MAX * gamma_multiplier);
+ return 1; /* in bound */
+ }
+ else if (xsane_check_bound_double(*contrast, -100.0 + contrast_offset, xsane.contrast_max + contrast_offset) &&
+ xsane_check_bound_double(*brightness, XSANE_BRIGHTNESS_MIN + brightness_offset, xsane.brightness_max + brightness_offset) &&
+ xsane_check_bound_double(*gamma, XSANE_GAMMA_MIN * gamma_multiplier, XSANE_GAMMA_MAX * gamma_multiplier))
+ {
+ return 1; /* in bound */
+ }
+ return 0; /* out of bound */
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_enhancement_by_histogram(int update_gamma)
+{
+ double gray_brightness;
+ double gray_contrast;
+ double gray_gamma;
+ double brightness;
+ double contrast;
+ double gamma;
+
+ DBG(DBG_proc, "xsane_enhancement_by_histogram\n");
+
+ if (xsane_histogram_to_gamma(&xsane.slider_gray, &gray_contrast, 0, &gray_brightness, 0, &gray_gamma, 1.0))
+ {
+ if (update_gamma)
+ {
+ xsane.gamma = gray_gamma;
+ }
+
+ xsane.brightness = gray_brightness;
+ xsane.contrast = gray_contrast;
+ }
+
+ if ( (xsane.xsane_colors > 1) && (!xsane.enhancement_rgb_default) ) /* rgb sliders active */
+ {
+ if ((xsane.slider_gray.active == XSANE_SLIDER_ACTIVE) ||
+ (xsane.slider_gray.active == XSANE_SLIDER_INACTIVE)) /* gray slider not moved */
+ {
+ /* red */
+ if (xsane_histogram_to_gamma(&xsane.slider_red, &contrast, gray_contrast, &brightness, gray_brightness, &gamma, gray_gamma))
+ {
+ if (update_gamma)
+ {
+ xsane.gamma_red = gamma / gray_gamma;
+ }
+ xsane.brightness_red = brightness - gray_brightness;
+ xsane.contrast_red = contrast - gray_contrast;
+ }
+
+ /* green */
+ if (xsane_histogram_to_gamma(&xsane.slider_green, &contrast, gray_contrast, &brightness, gray_brightness, &gamma, gray_gamma))
+ {
+ if (update_gamma)
+ {
+ xsane.gamma_green = gamma / gray_gamma;
+ }
+ xsane.brightness_green = brightness - gray_brightness;
+ xsane.contrast_green = contrast - gray_contrast;
+ }
+
+ /* blue */
+ if (xsane_histogram_to_gamma(&xsane.slider_blue, &contrast, gray_contrast, &brightness, gray_brightness, &gamma, gray_gamma))
+ {
+ if (update_gamma)
+ {
+ xsane.gamma_blue = gamma / gray_gamma;
+ }
+ xsane.brightness_blue = brightness - gray_brightness;
+ xsane.contrast_blue = contrast - gray_contrast;
+ }
+
+ }
+ }
+
+ xsane_enhancement_by_gamma();
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static gint xsane_histogram_win_delete(GtkWidget *widget, gpointer data)
+{
+ DBG(DBG_proc, "xsane_histogram_win_delete\n");
+
+ gtk_widget_hide(widget);
+ preferences.show_histogram = FALSE;
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.show_histogram_widget), preferences.show_histogram);
+ return TRUE;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_create_histogram_dialog(const char *devicetext)
+{
+ char windowname[255];
+ GtkWidget *xsane_color_hbox;
+ GtkWidget *xsane_histogram_vbox;
+ GtkWidget *button;
+ GdkColor color_black;
+ GdkColor color_red;
+ GdkColor color_green;
+ GdkColor color_blue;
+ GdkColor color_backg;
+ GdkColormap *colormap;
+ GtkStyle *style;
+
+ DBG(DBG_proc, "xsane_create_histogram_dialog\n");
+
+ xsane.histogram_dialog = gtk_window_new(GTK_WINDOW_DIALOG);
+ gtk_window_set_policy(GTK_WINDOW(xsane.histogram_dialog), FALSE, FALSE, FALSE);
+ gtk_widget_set_uposition(xsane.histogram_dialog, XSANE_HISTOGRAM_POS_X, XSANE_HISTOGRAM_POS_Y);
+ gtk_signal_connect(GTK_OBJECT(xsane.histogram_dialog), "delete_event", GTK_SIGNAL_FUNC(xsane_histogram_win_delete), NULL);
+ sprintf(windowname, "%s %s", WINDOW_HISTOGRAM, devicetext);
+ gtk_window_set_title(GTK_WINDOW(xsane.histogram_dialog), windowname);
+ xsane_set_window_icon(xsane.histogram_dialog, 0);
+ gtk_accel_group_attach(xsane.accelerator_group, GTK_OBJECT(xsane.histogram_dialog));
+
+ xsane_histogram_vbox = gtk_vbox_new(FALSE, 0);
+ gtk_container_set_border_width(GTK_CONTAINER(xsane_histogram_vbox), 5);
+ gtk_container_add(GTK_CONTAINER(xsane.histogram_dialog), xsane_histogram_vbox);
+ gtk_widget_show(xsane_histogram_vbox);
+
+
+ /* set gc for histogram drawing */
+ gtk_widget_realize(xsane.histogram_dialog); /* realize dialog to get colors and style */
+
+ style = gtk_widget_get_style(xsane.histogram_dialog);
+/*
+ style = gtk_rc_get_style(xsane.histogram_dialog);
+ style = gtk_widget_get_default_style();
+*/
+
+ xsane.gc_trans = style->bg_gc[GTK_STATE_NORMAL];
+ xsane.bg_trans = &style->bg[GTK_STATE_NORMAL];
+
+ colormap = gdk_window_get_colormap(xsane.histogram_dialog->window);
+
+ xsane.gc_black = gdk_gc_new(xsane.histogram_dialog->window);
+ color_black.red = 0;
+ color_black.green = 0;
+ color_black.blue = 0;
+ gdk_color_alloc(colormap, &color_black);
+ gdk_gc_set_foreground(xsane.gc_black, &color_black);
+
+ xsane.gc_red = gdk_gc_new(xsane.histogram_dialog->window);
+ color_red.red = 40000;
+ color_red.green = 10000;
+ color_red.blue = 10000;
+ gdk_color_alloc(colormap, &color_red);
+ gdk_gc_set_foreground(xsane.gc_red, &color_red);
+
+ xsane.gc_green = gdk_gc_new(xsane.histogram_dialog->window);
+ color_green.red = 10000;
+ color_green.green = 40000;
+ color_green.blue = 10000;
+ gdk_color_alloc(colormap, &color_green);
+ gdk_gc_set_foreground(xsane.gc_green, &color_green);
+
+ xsane.gc_blue = gdk_gc_new(xsane.histogram_dialog->window);
+ color_blue.red = 10000;
+ color_blue.green = 10000;
+ color_blue.blue = 40000;
+ gdk_color_alloc(colormap, &color_blue);
+ gdk_gc_set_foreground(xsane.gc_blue, &color_blue);
+
+ xsane.gc_backg = gdk_gc_new(xsane.histogram_dialog->window);
+ color_backg.red = 50000;
+ color_backg.green = 50000;
+ color_backg.blue = 50000;
+ gdk_color_alloc(colormap, &color_backg);
+ gdk_gc_set_foreground(xsane.gc_backg, &color_backg);
+
+
+ /* add histogram images and sliders */
+
+ xsane_create_histogram(xsane_histogram_vbox, FRAME_RAW_IMAGE, 256, 100, &(xsane.histogram_raw));
+
+ xsane_separator_new(xsane_histogram_vbox, 0);
+
+ xsane.slider_gray.r = 1;
+ xsane.slider_gray.g = 1;
+ xsane.slider_gray.b = 1;
+ xsane.slider_gray.active = XSANE_SLIDER_ACTIVE;
+ xsane_create_slider(&xsane.slider_gray);
+ gtk_box_pack_start(GTK_BOX(xsane_histogram_vbox), xsane.slider_gray.preview, FALSE, FALSE, 0);
+ gtk_widget_show(xsane.slider_gray.preview);
+ gtk_widget_realize(xsane.slider_gray.preview);
+
+ xsane_separator_new(xsane_histogram_vbox, 0);
+
+ xsane.slider_red.r = 1;
+ xsane.slider_red.g = 0;
+ xsane.slider_red.b = 0;
+ xsane.slider_red.active = XSANE_SLIDER_ACTIVE;
+ xsane_create_slider(&xsane.slider_red);
+ gtk_box_pack_start(GTK_BOX(xsane_histogram_vbox), xsane.slider_red.preview, FALSE, FALSE, 0);
+ gtk_widget_show(xsane.slider_red.preview);
+ gtk_widget_realize(xsane.slider_red.preview);
+
+ xsane_separator_new(xsane_histogram_vbox, 0);
+
+ xsane.slider_green.r = 0;
+ xsane.slider_green.g = 1;
+ xsane.slider_green.b = 0;
+ xsane.slider_green.active = XSANE_SLIDER_ACTIVE;
+ xsane_create_slider(&xsane.slider_green);
+ gtk_box_pack_start(GTK_BOX(xsane_histogram_vbox), xsane.slider_green.preview, FALSE, FALSE, 0);
+ gtk_widget_show(xsane.slider_green.preview);
+ gtk_widget_realize(xsane.slider_green.preview);
+
+ xsane_separator_new(xsane_histogram_vbox, 0);
+
+ xsane.slider_blue.r = 0;
+ xsane.slider_blue.g = 0;
+ xsane.slider_blue.b = 1;
+ xsane.slider_blue.active = XSANE_SLIDER_ACTIVE;
+ xsane_create_slider(&xsane.slider_blue);
+ gtk_box_pack_start(GTK_BOX(xsane_histogram_vbox), xsane.slider_blue.preview, FALSE, FALSE, 0);
+ gtk_widget_show(xsane.slider_blue.preview);
+ gtk_widget_realize(xsane.slider_blue.preview);
+
+ xsane_draw_slider_level(&xsane.slider_gray);
+ xsane_draw_slider_level(&xsane.slider_red);
+ xsane_draw_slider_level(&xsane.slider_green);
+ xsane_draw_slider_level(&xsane.slider_blue);
+
+ xsane_separator_new(xsane_histogram_vbox, 0);
+
+ xsane_create_histogram(xsane_histogram_vbox, FRAME_ENHANCED_IMAGE, 256, 100, &(xsane.histogram_enh));
+
+ xsane_color_hbox = gtk_hbox_new(TRUE, 5);
+ gtk_container_set_border_width(GTK_CONTAINER(xsane_color_hbox), 5);
+ gtk_container_add(GTK_CONTAINER(xsane_histogram_vbox), xsane_color_hbox);
+ gtk_widget_show(xsane_color_hbox);
+
+ button = xsane_toggle_button_new_with_pixmap(xsane.histogram_dialog->window, xsane_color_hbox, intensity_xpm, DESC_HIST_INTENSITY,
+ &xsane.histogram_int, xsane_histogram_toggle_button_callback);
+ gtk_widget_add_accelerator(button, "clicked", xsane.accelerator_group, GDK_I, GDK_MOD1_MASK, GTK_ACCEL_LOCKED);
+
+ button = xsane_toggle_button_new_with_pixmap(xsane.histogram_dialog->window, xsane_color_hbox, red_xpm, DESC_HIST_RED,
+ &xsane.histogram_red, xsane_histogram_toggle_button_callback);
+ gtk_widget_add_accelerator(button, "clicked", xsane.accelerator_group, GDK_R, GDK_MOD1_MASK, GTK_ACCEL_LOCKED);
+
+ button = xsane_toggle_button_new_with_pixmap(xsane.histogram_dialog->window, xsane_color_hbox, green_xpm, DESC_HIST_GREEN,
+ &xsane.histogram_green, xsane_histogram_toggle_button_callback);
+ gtk_widget_add_accelerator(button, "clicked", xsane.accelerator_group, GDK_G, GDK_MOD1_MASK, GTK_ACCEL_LOCKED);
+
+ button = xsane_toggle_button_new_with_pixmap(xsane.histogram_dialog->window, xsane_color_hbox, blue_xpm, DESC_HIST_BLUE,
+ &xsane.histogram_blue, xsane_histogram_toggle_button_callback);
+ gtk_widget_add_accelerator(button, "clicked", xsane.accelerator_group, GDK_B, GDK_MOD1_MASK, GTK_ACCEL_LOCKED);
+
+ button = xsane_toggle_button_new_with_pixmap(xsane.histogram_dialog->window, xsane_color_hbox, pixel_xpm, DESC_HIST_PIXEL,
+ &xsane.histogram_lines, xsane_histogram_toggle_button_callback);
+ gtk_widget_add_accelerator(button, "clicked", xsane.accelerator_group, GDK_M, GDK_MOD1_MASK, GTK_ACCEL_LOCKED);
+
+ button = xsane_toggle_button_new_with_pixmap(xsane.histogram_dialog->window, xsane_color_hbox, log_xpm, DESC_HIST_LOG,
+ &xsane.histogram_log, xsane_histogram_toggle_button_callback);
+ gtk_widget_add_accelerator(button, "clicked", xsane.accelerator_group, GDK_L, GDK_MOD1_MASK, GTK_ACCEL_LOCKED);
+
+ gtk_widget_show(xsane_color_hbox);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+#ifdef HAVE_WORKING_GTK_GAMMACURVE
+/* xsane_get_free_gamma_curve transforms gamma table with 65536 entries and value range 0.0-1.0 to requested gamma table */
+/* it combines the color gamma table given by gamma_widget and the gray gamma table (xsane.gamma_curve_gray) */
+void xsane_get_free_gamma_curve(gfloat *free_color_gamma_data, SANE_Int *gammadata,
+ int negative, double gamma, double brightness, double contrast,
+ int len, int maxout)
+{
+ int i;
+ gfloat factor;
+ double midin;
+ double val;
+ double m;
+ double b;
+ int maxin = len-1;
+
+ DBG(DBG_proc, "xsane_get_free_gamma_curve\n");
+ DBG(DBG_proc, "xsane_get_free_gamma_curve(neg=%d, gam=%3.2f, bri=%3.2f, ctr=%3.2f, nrs=%d, max=%d\n",
+ negative, gamma, brightness, contrast, len, maxout);
+
+ if (contrast < -100.0)
+ {
+ contrast = -100.0;
+ }
+
+ midin = (int)(len / 2.0);
+
+ m = 1.0 + contrast/100.0;
+ b = (1.0 + brightness/100.0) * midin;
+
+ factor = 65536.0 / len;
+
+ if (1) /* xxxxxxxxxxxx colors available */
+ {
+ if (negative)
+ {
+ DBG(DBG_proc, "xsane_get_free_gamma_curve: color transformation, negative\n");
+
+ for (i=0; i <= maxin; i++)
+ {
+ val = ((double) (maxin - i)) - midin;
+ val = val * m + b;
+ xsane_bound_double(&val, 0.0, maxin);
+
+ val = maxout * xsane.free_gamma_data[(int) (65535 * free_color_gamma_data[(int) (val * factor)])];
+ val = 0.5 + maxout * pow( val/maxin, (1.0/gamma) );
+ gammadata[i] = val;
+ }
+ }
+ else /* positive */
+ {
+ DBG(DBG_proc, "xsane_get_free_gamma_curve: color transformation, positive\n");
+
+ for (i=0; i <= maxin; i++)
+ {
+ val = ((double) i) - midin;
+ val = val * m + b;
+ xsane_bound_double(&val, 0.0, maxin);
+
+ val = maxout * xsane.free_gamma_data[(int) (65535 * free_color_gamma_data[(int) (val * factor)])];
+ val = 0.5 + maxout * pow( val/maxin, (1.0/gamma) );
+ gammadata[i] = val;
+ }
+ }
+ }
+ else
+ {
+ if (negative)
+ {
+ DBG(DBG_proc, "xsane_get_free_gamma_curve: gray transformation, negative\n");
+
+ for (i=0; i <= maxin; i++)
+ {
+ val = ((double) (maxin - i)) - midin;
+ val = val * m + b;
+ xsane_bound_double(&val, 0.0, maxin);
+
+ val = maxout * xsane.free_gamma_data[(int) (val * factor)];
+ val = 0.5 + maxout * pow( val/maxin, (1.0/gamma) );
+ gammadata[i] = val;
+ }
+ }
+ else /* positive */
+ {
+ DBG(DBG_proc, "xsane_get_free_gamma_curve: gray transformation, positive\n");
+
+ for (i=0; i <= maxin; i++)
+ {
+ val = ((double) i) - midin;
+ val = val * m + b;
+ xsane_bound_double(&val, 0.0, maxin);
+
+ val = maxout * xsane.free_gamma_data[(int) (val * factor)];
+ val = 0.5 + maxout * pow( val/maxin, (1.0/gamma) );
+ gammadata[i] = val;
+ }
+ }
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static gint xsane_gamma_win_delete(GtkWidget *widget, gpointer data)
+{
+ DBG(DBG_proc, "xsane_gamma_win_delete\n");
+
+ gtk_widget_hide(widget);
+ preferences.show_gamma = FALSE;
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(xsane.show_gamma_widget), preferences.show_gamma);
+ return TRUE;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+/* xsane_gamma_curve_notebook_page_new creates a notebook page with a gamma curve
+ of 65536 entries and a value range from 0.0-1.0 */
+
+GtkWidget* xsane_gamma_curve_notebook_page_new(GtkWidget *notebook, char *title)
+{
+ gfloat fmin, fmax, *vector;
+ GtkWidget *curve, *gamma, *vbox, *label;
+ int optlen;
+
+ DBG(DBG_proc, "xsane_back_gtk_curve_new\n");
+
+ optlen = 65536;
+ fmin = 0.0;
+ fmax = 1.0;
+
+ label = gtk_label_new((char *) title);
+ vbox = gtk_vbox_new(/* homogeneous */ FALSE, 0);
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, label);
+ gtk_widget_show(vbox);
+ gtk_widget_show(label);
+
+ gamma = gtk_gamma_curve_new();
+ gtk_widget_set_usize(gamma, 0, 256);
+ curve = GTK_GAMMA_CURVE(gamma)->curve;
+
+ vector = alloca(optlen * sizeof(vector[0]));
+
+ gtk_curve_set_range(GTK_CURVE(curve), 0, optlen - 1, fmin, fmax);
+#if 1
+ gtk_curve_maintain_accuracy(GTK_CURVE(curve), 1.0);
+#endif
+
+ gtk_container_set_border_width(GTK_CONTAINER(gamma), 4);
+ gtk_box_pack_start(GTK_BOX(vbox), gamma, TRUE, TRUE, 0);
+ gtk_widget_show(gamma);
+
+ return gamma;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_create_gamma_dialog(const char *devicetext)
+{
+ char windowname[255];
+ GtkWidget *xsane_vbox_gamma, *notebook;
+
+ DBG(DBG_proc, "xsane_create_free_gamma_dialog\n");
+
+ xsane.free_gamma_data = calloc(65536, sizeof(xsane.free_gamma_data[0]));
+ xsane.free_gamma_data_red = calloc(65536, sizeof(xsane.free_gamma_data_red[0]));
+ xsane.free_gamma_data_green = calloc(65536, sizeof(xsane.free_gamma_data_green[0]));
+ xsane.free_gamma_data_blue = calloc(65536, sizeof(xsane.free_gamma_data_green[0]));
+
+ xsane.gamma_dialog = gtk_window_new(GTK_WINDOW_DIALOG);
+ gtk_window_set_policy(GTK_WINDOW(xsane.gamma_dialog), FALSE, FALSE, FALSE);
+ gtk_widget_set_uposition(xsane.gamma_dialog, XSANE_GAMMA_POS_X, XSANE_GAMMA_POS_Y);
+ gtk_signal_connect(GTK_OBJECT(xsane.gamma_dialog), "delete_event", GTK_SIGNAL_FUNC(xsane_gamma_win_delete), NULL);
+ sprintf(windowname, "%s %s", WINDOW_GAMMA, devicetext);
+ gtk_window_set_title(GTK_WINDOW(xsane.gamma_dialog), windowname);
+ xsane_set_window_icon(xsane.gamma_dialog, 0);
+ gtk_accel_group_attach(xsane.accelerator_group, GTK_OBJECT(xsane.gamma_dialog));
+
+ xsane_vbox_gamma = gtk_vbox_new(TRUE, 5);
+ gtk_container_set_border_width(GTK_CONTAINER(xsane_vbox_gamma), 5);
+ gtk_container_add(GTK_CONTAINER(xsane.gamma_dialog), xsane_vbox_gamma);
+ gtk_widget_show(xsane_vbox_gamma);
+
+ notebook = gtk_notebook_new();
+ gtk_container_set_border_width(GTK_CONTAINER(notebook), 4);
+ gtk_box_pack_start(GTK_BOX(xsane_vbox_gamma), notebook, TRUE, TRUE, 0);
+ gtk_widget_show(notebook);
+
+ xsane.gamma_curve_gray = xsane_gamma_curve_notebook_page_new(notebook, "Gamma gray");
+ xsane.gamma_curve_red = xsane_gamma_curve_notebook_page_new(notebook, "Gamma red");
+ xsane.gamma_curve_green = xsane_gamma_curve_notebook_page_new(notebook, "Gamma green");
+ xsane.gamma_curve_blue = xsane_gamma_curve_notebook_page_new(notebook, "Gamma blue");
+
+ gtk_curve_get_vector(GTK_CURVE(GTK_GAMMA_CURVE(xsane.gamma_curve_gray)->curve), 65536, xsane.free_gamma_data);
+ gtk_curve_get_vector(GTK_CURVE(GTK_GAMMA_CURVE(xsane.gamma_curve_red)->curve), 65536, xsane.free_gamma_data_red);
+ gtk_curve_get_vector(GTK_CURVE(GTK_GAMMA_CURVE(xsane.gamma_curve_green)->curve), 65536, xsane.free_gamma_data_green);
+ gtk_curve_get_vector(GTK_CURVE(GTK_GAMMA_CURVE(xsane.gamma_curve_blue)->curve), 65536, xsane.free_gamma_data_blue);
+
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_update_gamma_dialog()
+{
+ DBG(DBG_proc, "xsane_update_gamma_dialog\n");
+
+ if (preferences.show_gamma)
+ {
+ gtk_widget_show(xsane.gamma_dialog);
+ }
+}
+#endif
+
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_set_auto_enhancement()
+{
+ DBG(DBG_proc, "xsane_set_auto_enhancement\n");
+ xsane.slider_gray.value[0] = xsane.auto_black;
+ xsane.slider_gray.value[1] = xsane.auto_gray;
+ xsane.slider_gray.value[2] = xsane.auto_white;
+
+ if (xsane.enhancement_rgb_default) /* set same values for color components */
+ {
+ xsane.slider_red.value[0] = xsane.auto_black;
+ xsane.slider_red.value[1] = xsane.auto_gray;
+ xsane.slider_red.value[2] = xsane.auto_white;
+
+ xsane.slider_green.value[0] = xsane.auto_black;
+ xsane.slider_green.value[1] = xsane.auto_gray;
+ xsane.slider_green.value[2] = xsane.auto_white;
+
+ xsane.slider_blue.value[0] = xsane.auto_black;
+ xsane.slider_blue.value[1] = xsane.auto_gray;
+ xsane.slider_blue.value[2] = xsane.auto_white;
+ }
+ else /* set different values for each color component */
+ {
+ xsane.slider_red.value[0] = xsane.auto_black_red;
+ xsane.slider_red.value[1] = xsane.auto_gray_red;
+ xsane.slider_red.value[2] = xsane.auto_white_red;
+
+ xsane.slider_green.value[0] = xsane.auto_black_green;
+ xsane.slider_green.value[1] = xsane.auto_gray_green;
+ xsane.slider_green.value[2] = xsane.auto_white_green;
+
+ xsane.slider_blue.value[0] = xsane.auto_black_blue;
+ xsane.slider_blue.value[1] = xsane.auto_gray_blue;
+ xsane.slider_blue.value[2] = xsane.auto_white_blue;
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+void xsane_set_medium(Preferences_medium_t *medium)
+{
+ const SANE_Option_Descriptor *opt;
+ int shadow_gray, shadow_red, shadow_green, shadow_blue;
+ int highlight_gray, highlight_red, highlight_green, highlight_blue;
+
+
+ if (!medium)
+ {
+ DBG(DBG_proc, "xsane_set_medium: no medium given, using default values\n");
+
+ xsane.medium_gamma_gray = 1.0;
+ xsane.medium_gamma_red = 1.0;
+ xsane.medium_gamma_green = 1.0;
+ xsane.medium_gamma_blue = 1.0;
+
+ xsane.medium_shadow_gray = 0.0;
+ xsane.medium_shadow_red = 0.0;
+ xsane.medium_shadow_green = 0.0;
+ xsane.medium_shadow_blue = 0.0;
+
+ xsane.medium_highlight_gray = 100.0;
+ xsane.medium_highlight_red = 100.0;
+ xsane.medium_highlight_green = 100.0;
+ xsane.medium_highlight_blue = 100.0;
+
+ xsane.medium_negative = 0;
+
+ return;
+ }
+
+ DBG(DBG_proc, "xsane_set_medium: setting values for %s\n", medium->name);
+
+ xsane.medium_gamma_red = medium->gamma_red;
+ xsane.medium_gamma_green = medium->gamma_green;
+ xsane.medium_gamma_blue = medium->gamma_blue;
+
+ xsane.medium_shadow_red = medium->shadow_red;
+ xsane.medium_shadow_green = medium->shadow_green;
+ xsane.medium_shadow_blue = medium->shadow_blue;
+
+ xsane.medium_highlight_red = medium->highlight_red;
+ xsane.medium_highlight_green = medium->highlight_green;
+ xsane.medium_highlight_blue = medium->highlight_blue;
+
+ xsane.medium_gamma_gray = medium->gamma_gray;
+ xsane.medium_shadow_gray = medium->shadow_gray;
+ xsane.medium_highlight_gray = medium->highlight_gray;
+
+ xsane.medium_negative = medium->negative;
+
+#if 1
+return;
+#endif
+
+ opt = xsane_get_option_descriptor(xsane.dev, xsane.well_known.shadow);
+ if (!opt)
+ {
+ opt = xsane_get_option_descriptor(xsane.dev, xsane.well_known.shadow_r);
+ }
+ else if (!opt)
+ {
+ opt = xsane_get_option_descriptor(xsane.dev, xsane.well_known.highlight);
+ }
+ else if (!opt)
+ {
+ opt = xsane_get_option_descriptor(xsane.dev, xsane.well_known.highlight_r);
+ }
+ else if (!opt)
+ {
+ DBG(DBG_info, "xsane_set_medium_callback: no shadow/highlight values available\n");
+ return;
+ }
+
+ if (opt->type == SANE_TYPE_FIXED)
+ {
+ shadow_gray = SANE_FIX(medium->shadow_gray);
+ shadow_red = SANE_FIX(medium->shadow_red);
+ shadow_green = SANE_FIX(medium->shadow_green);
+ shadow_blue = SANE_FIX(medium->shadow_blue);
+ highlight_gray = SANE_FIX(medium->highlight_gray);
+ highlight_red = SANE_FIX(medium->highlight_red);
+ highlight_green = SANE_FIX(medium->highlight_green);
+ highlight_blue = SANE_FIX(medium->highlight_blue);
+ }
+ else if (opt->type == SANE_TYPE_INT)
+ {
+ shadow_gray = (int) medium->shadow_gray;
+ shadow_red = (int) medium->shadow_red;
+ shadow_green = (int) medium->shadow_green;
+ shadow_blue = (int) medium->shadow_blue;
+ highlight_gray = (int) medium->highlight_gray;
+ highlight_red = (int) medium->highlight_red;
+ highlight_green = (int) medium->highlight_green;
+ highlight_blue = (int) medium->highlight_blue;
+ }
+ else
+ {
+ DBG(DBG_info, "xsane_set_medium_callback: unknown type of shadow/highlight: %d\n", opt->type);
+ return;
+ }
+
+ /* shadow values */
+ if (!xsane_control_option(xsane.dev, xsane.well_known.shadow, SANE_ACTION_SET_VALUE, &shadow_gray, 0))
+ {
+ xsane.medium_shadow_gray = 0.0; /* we are using hardware shadow */
+ }
+
+ if (!xsane_control_option(xsane.dev, xsane.well_known.shadow_r, SANE_ACTION_SET_VALUE, &shadow_red, 0))
+ {
+ xsane.medium_shadow_red = 0.0; /* we are using hardware shadow */
+ }
+
+ if (!xsane_control_option(xsane.dev, xsane.well_known.shadow_g, SANE_ACTION_SET_VALUE, &shadow_green, 0))
+ {
+ xsane.medium_shadow_green = 0.0; /* we are using hardware shadow */
+ }
+
+ if (!xsane_control_option(xsane.dev, xsane.well_known.shadow_b, SANE_ACTION_SET_VALUE, &shadow_blue, 0))
+ {
+ xsane.medium_shadow_blue = 0.0; /* we are using hardware shadow */
+ }
+
+ /* highlight values */
+ if (!xsane_control_option(xsane.dev, xsane.well_known.highlight, SANE_ACTION_SET_VALUE, &highlight_gray, 0))
+ {
+ xsane.medium_highlight_gray = 100.0; /* we are using hardware highlight */
+ }
+
+ if (!xsane_control_option(xsane.dev, xsane.well_known.highlight_r, SANE_ACTION_SET_VALUE, &highlight_red, 0))
+ {
+ xsane.medium_highlight_red = 100.0; /* we are using hardware highlight */
+ }
+
+ if (!xsane_control_option(xsane.dev, xsane.well_known.highlight_g, SANE_ACTION_SET_VALUE, &highlight_green, 0))
+ {
+ xsane.medium_highlight_green = 100.0; /* we are using hardware highlight */
+ }
+
+ if (!xsane_control_option(xsane.dev, xsane.well_known.highlight_b, SANE_ACTION_SET_VALUE, &highlight_blue, 0))
+ {
+ xsane.medium_highlight_blue = 100.0; /* we are using hardware highlight */
+ }
+
+ xsane_back_gtk_refresh_dialog();
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */