summaryrefslogtreecommitdiff
path: root/gtk/gtkpreview.c
diff options
context:
space:
mode:
Diffstat (limited to 'gtk/gtkpreview.c')
-rw-r--r--gtk/gtkpreview.c1571
1 files changed, 1571 insertions, 0 deletions
diff --git a/gtk/gtkpreview.c b/gtk/gtkpreview.c
new file mode 100644
index 0000000000..4246a321ab
--- /dev/null
+++ b/gtk/gtkpreview.c
@@ -0,0 +1,1571 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <math.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include "gdk/gdkx.h"
+#include "gtkpreview.h"
+#include "gtksignal.h"
+
+
+#define IMAGE_SIZE 256
+#define PREVIEW_CLASS(w) GTK_PREVIEW_CLASS (GTK_OBJECT (w)->klass)
+#define COLOR_COMPOSE(r,g,b) (lookup_red[r] | lookup_green[g] | lookup_blue[b])
+
+
+typedef struct _GtkPreviewProp GtkPreviewProp;
+typedef void (*GtkTransferFunc) (guchar *dest, guchar *src, gint count);
+
+struct _GtkPreviewProp
+{
+ guint16 ref_count;
+ guint16 nred_shades;
+ guint16 ngreen_shades;
+ guint16 nblue_shades;
+ guint16 ngray_shades;
+};
+
+
+static void gtk_preview_class_init (GtkPreviewClass *klass);
+static void gtk_preview_init (GtkPreview *preview);
+static void gtk_preview_destroy (GtkObject *object);
+static void gtk_preview_realize (GtkWidget *widget);
+static void gtk_preview_unrealize (GtkWidget *widget);
+static gint gtk_preview_expose (GtkWidget *widget,
+ GdkEventExpose *event);
+static void gtk_preview_make_buffer (GtkPreview *preview);
+static void gtk_preview_get_visuals (GtkPreviewClass *klass);
+static void gtk_preview_get_cmaps (GtkPreviewClass *klass);
+static void gtk_preview_dither_init (GtkPreviewClass *klass);
+static void gtk_fill_lookup_array (gulong *array,
+ int depth,
+ int shift,
+ int prec);
+static void gtk_trim_cmap (GtkPreviewClass *klass);
+static void gtk_create_8_bit (GtkPreviewClass *klass);
+
+static void gtk_color_8 (guchar *src,
+ guchar *data,
+ gint x,
+ gint y,
+ gulong width);
+static void gtk_color_16 (guchar *src,
+ guchar *data,
+ gulong width);
+static void gtk_color_24 (guchar *src,
+ guchar *data,
+ gulong width);
+static void gtk_grayscale_8 (guchar *src,
+ guchar *data,
+ gint x,
+ gint y,
+ gulong width);
+static void gtk_grayscale_16 (guchar *src,
+ guchar *data,
+ gulong width);
+static void gtk_grayscale_24 (guchar *src,
+ guchar *data,
+ gulong width);
+
+static gint gtk_get_preview_prop (guint *nred,
+ guint *nblue,
+ guint *ngreen,
+ guint *ngray);
+static void gtk_set_preview_prop (guint nred,
+ guint ngreen,
+ guint nblue,
+ guint ngray);
+
+/* transfer functions:
+ * destination byte order/source bpp/destination bpp
+ */
+static void gtk_lsbmsb_1_1 (guchar *dest,
+ guchar *src,
+ gint count);
+static void gtk_lsb_2_2 (guchar *dest,
+ guchar *src,
+ gint count);
+static void gtk_msb_2_2 (guchar *dest,
+ guchar *src,
+ gint count);
+static void gtk_lsb_3_3 (guchar *dest,
+ guchar *src,
+ gint count);
+static void gtk_msb_3_3 (guchar *dest,
+ guchar *src,
+ gint count);
+static void gtk_lsb_3_4 (guchar *dest,
+ guchar *src,
+ gint count);
+static void gtk_msb_3_4 (guchar *dest,
+ guchar *src,
+ gint count);
+
+
+static GtkWidgetClass *parent_class = NULL;
+static GtkPreviewClass *preview_class = NULL;
+static GtkPreviewInfo *preview_info = NULL;
+static gint install_cmap = FALSE;
+
+
+guint
+gtk_preview_get_type ()
+{
+ static guint preview_type = 0;
+
+ if (!preview_type)
+ {
+ GtkTypeInfo preview_info =
+ {
+ "GtkPreview",
+ sizeof (GtkPreview),
+ sizeof (GtkPreviewClass),
+ (GtkClassInitFunc) gtk_preview_class_init,
+ (GtkObjectInitFunc) gtk_preview_init,
+ (GtkArgFunc) NULL,
+ };
+
+ preview_type = gtk_type_unique (gtk_widget_get_type (), &preview_info);
+ }
+
+ return preview_type;
+}
+
+static void
+gtk_preview_class_init (GtkPreviewClass *klass)
+{
+ GtkObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+
+ object_class = (GtkObjectClass*) klass;
+ widget_class = (GtkWidgetClass*) klass;
+
+ parent_class = gtk_type_class (gtk_widget_get_type ());
+ preview_class = klass;
+
+ object_class->destroy = gtk_preview_destroy;
+
+ widget_class->realize = gtk_preview_realize;
+ widget_class->unrealize = gtk_preview_unrealize;
+ widget_class->expose_event = gtk_preview_expose;
+
+ if (preview_info)
+ klass->info = *preview_info;
+ else
+ {
+ klass->info.visual = NULL;
+ klass->info.cmap = NULL;
+
+ klass->info.color_pixels = NULL;
+ klass->info.gray_pixels = NULL;
+ klass->info.reserved_pixels = NULL;
+
+ klass->info.lookup_red = NULL;
+ klass->info.lookup_green = NULL;
+ klass->info.lookup_blue = NULL;
+
+ klass->info.dither_red = NULL;
+ klass->info.dither_green = NULL;
+ klass->info.dither_blue = NULL;
+ klass->info.dither_gray = NULL;
+ klass->info.dither_matrix = NULL;
+
+ klass->info.nred_shades = 6;
+ klass->info.ngreen_shades = 6;
+ klass->info.nblue_shades = 4;
+ klass->info.ngray_shades = 24;
+ klass->info.nreserved = 0;
+
+ klass->info.bpp = 0;
+ klass->info.cmap_alloced = FALSE;
+ klass->info.gamma = 1.0;
+ }
+
+ klass->image = NULL;
+
+ gtk_preview_get_visuals (klass);
+ gtk_preview_get_cmaps (klass);
+ gtk_preview_dither_init (klass);
+}
+
+static void
+gtk_preview_init (GtkPreview *preview)
+{
+ GTK_WIDGET_SET_FLAGS (preview, GTK_BASIC);
+
+ preview->buffer = NULL;
+ preview->buffer_width = 0;
+ preview->buffer_height = 0;
+ preview->expand = FALSE;
+}
+
+void
+gtk_preview_uninit ()
+{
+ GtkPreviewProp *prop;
+ GdkAtom property;
+
+ if (preview_class && !install_cmap &&
+ (preview_class->info.visual->type != GDK_VISUAL_TRUE_COLOR) &&
+ (preview_class->info.visual->type != GDK_VISUAL_DIRECT_COLOR))
+ {
+ property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE);
+
+ if (gdk_property_get (NULL, property, property,
+ 0, sizeof (GtkPreviewProp), FALSE,
+ NULL, NULL, NULL, (guchar**) &prop))
+ {
+ prop->ref_count = ntohs (prop->ref_count) - 1;
+ if (prop->ref_count == 0)
+ {
+ gdk_property_delete (NULL, property);
+ }
+ else
+ {
+ prop->ref_count = htons (prop->ref_count);
+ gdk_property_change (NULL, property, property, 16,
+ GDK_PROP_MODE_REPLACE,
+ (guchar*) prop, 5);
+ }
+ }
+ }
+}
+
+GtkWidget*
+gtk_preview_new (GtkPreviewType type)
+{
+ GtkPreview *preview;
+
+ preview = gtk_type_new (gtk_preview_get_type ());
+ preview->type = type;
+
+ return GTK_WIDGET (preview);
+}
+
+void
+gtk_preview_size (GtkPreview *preview,
+ gint width,
+ gint height)
+{
+ g_return_if_fail (preview != NULL);
+ g_return_if_fail (GTK_IS_PREVIEW (preview));
+
+ if ((width != GTK_WIDGET (preview)->requisition.width) ||
+ (height != GTK_WIDGET (preview)->requisition.height))
+ {
+ GTK_WIDGET (preview)->requisition.width = width;
+ GTK_WIDGET (preview)->requisition.height = height;
+
+ if (preview->buffer)
+ g_free (preview->buffer);
+ preview->buffer = NULL;
+ }
+}
+
+void
+gtk_preview_put (GtkPreview *preview,
+ GdkWindow *window,
+ GdkGC *gc,
+ gint srcx,
+ gint srcy,
+ gint destx,
+ gint desty,
+ gint width,
+ gint height)
+{
+ GtkWidget *widget;
+ GdkImage *image;
+ GdkRectangle r1, r2, r3;
+ GtkTransferFunc transfer_func;
+ guchar *image_mem;
+ guchar *src, *dest;
+ gint x, xe, x2;
+ gint y, ye, y2;
+ guint dest_rowstride;
+ guint src_bpp;
+ guint dest_bpp;
+ gint i;
+
+ g_return_if_fail (preview != NULL);
+ g_return_if_fail (GTK_IS_PREVIEW (preview));
+ g_return_if_fail (window != NULL);
+
+ if (!preview->buffer)
+ return;
+
+ widget = GTK_WIDGET (preview);
+
+ r1.x = srcx;
+ r1.y = srcy;
+ r1.width = preview->buffer_width;
+ r1.height = preview->buffer_height;
+
+ r2.x = destx;
+ r2.y = desty;
+ r2.width = width;
+ r2.height = height;
+
+ if (!gdk_rectangle_intersect (&r1, &r2, &r3))
+ return;
+
+ x2 = r3.x + r3.width;
+ y2 = r3.y + r3.height;
+
+ if (!preview_class->image)
+ preview_class->image = gdk_image_new (GDK_IMAGE_FASTEST,
+ preview_class->info.visual,
+ IMAGE_SIZE, IMAGE_SIZE);
+ image = preview_class->image;
+ src_bpp = preview_class->info.bpp;
+
+ image_mem = image->mem;
+ dest_bpp = image->bpp;
+ dest_rowstride = image->bpl;
+
+ transfer_func = NULL;
+
+ switch (dest_bpp)
+ {
+ case 1:
+ switch (src_bpp)
+ {
+ case 1:
+ transfer_func = gtk_lsbmsb_1_1;
+ break;
+ }
+ break;
+ case 2:
+ switch (src_bpp)
+ {
+ case 2:
+ if (image->byte_order == GDK_MSB_FIRST)
+ transfer_func = gtk_msb_2_2;
+ else
+ transfer_func = gtk_lsb_2_2;
+ break;
+ case 3:
+ break;
+ }
+ break;
+ case 3:
+ switch (src_bpp)
+ {
+ case 3:
+ if (image->byte_order == GDK_MSB_FIRST)
+ transfer_func = gtk_msb_3_3;
+ else
+ transfer_func = gtk_lsb_3_3;
+ break;
+ }
+ break;
+ case 4:
+ switch (src_bpp)
+ {
+ case 3:
+ if (image->byte_order == GDK_MSB_FIRST)
+ transfer_func = gtk_msb_3_4;
+ else
+ transfer_func = gtk_lsb_3_4;
+ break;
+ }
+ break;
+ }
+
+ if (!transfer_func)
+ {
+ g_warning ("unsupported byte order/src bpp/dest bpp combination: %s:%d:%d",
+ (image->byte_order == GDK_MSB_FIRST) ? "msb" : "lsb", src_bpp, dest_bpp);
+ return;
+ }
+
+ for (y = r3.y; y < y2; y += IMAGE_SIZE)
+ {
+ for (x = r3.x; x < x2; x += IMAGE_SIZE)
+ {
+ xe = x + IMAGE_SIZE;
+ if (xe > x2)
+ xe = x2;
+
+ ye = y + IMAGE_SIZE;
+ if (ye > y2)
+ ye = y2;
+
+ for (i = y; i < ye; i++)
+ {
+ src = preview->buffer + (((gulong) (i - r1.y) * (gulong) preview->buffer_width) +
+ (x - r1.x)) * (gulong) src_bpp;
+ dest = image_mem + ((gulong) (i - y) * dest_rowstride);
+
+ if (xe > x)
+ (* transfer_func) (dest, src, xe - x);
+ }
+
+ gdk_draw_image (window, gc,
+ image, 0, 0, x, y,
+ xe - x, ye - y);
+ gdk_flush ();
+ }
+ }
+}
+
+void
+gtk_preview_put_row (GtkPreview *preview,
+ guchar *src,
+ guchar *dest,
+ gint x,
+ gint y,
+ gint w)
+{
+ g_return_if_fail (preview != NULL);
+ g_return_if_fail (GTK_IS_PREVIEW (preview));
+ g_return_if_fail (src != NULL);
+ g_return_if_fail (dest != NULL);
+
+ switch (preview->type)
+ {
+ case GTK_PREVIEW_COLOR:
+ switch (preview_class->info.visual->depth)
+ {
+ case 8:
+ gtk_color_8 (src, dest, x, y, w);
+ break;
+ case 15:
+ case 16:
+ gtk_color_16 (src, dest, w);
+ break;
+ case 24:
+ case 32:
+ gtk_color_24 (src, dest, w);
+ break;
+ }
+ break;
+ case GTK_PREVIEW_GRAYSCALE:
+ switch (preview_class->info.visual->depth)
+ {
+ case 8:
+ gtk_grayscale_8 (src, dest, x, y, w);
+ break;
+ case 15:
+ case 16:
+ gtk_grayscale_16 (src, dest, w);
+ break;
+ case 24:
+ case 32:
+ gtk_grayscale_24 (src, dest, w);
+ break;
+ }
+ break;
+ }
+}
+
+void
+gtk_preview_draw_row (GtkPreview *preview,
+ guchar *data,
+ gint x,
+ gint y,
+ gint w)
+{
+ guchar *dest;
+
+ g_return_if_fail (preview != NULL);
+ g_return_if_fail (GTK_IS_PREVIEW (preview));
+ g_return_if_fail (data != NULL);
+
+ if ((w <= 0) || (y < 0))
+ return;
+
+ g_return_if_fail (data != NULL);
+
+ gtk_preview_make_buffer (preview);
+
+ if (y >= preview->buffer_height)
+ return;
+
+ switch (preview->type)
+ {
+ case GTK_PREVIEW_COLOR:
+ switch (preview_class->info.visual->depth)
+ {
+ case 8:
+ dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x);
+ gtk_color_8 (data, dest, x, y, w);
+ break;
+ case 15:
+ case 16:
+ dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 2;
+ gtk_color_16 (data, dest, w);
+ break;
+ case 24:
+ case 32:
+ dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 3;
+ gtk_color_24 (data, dest, w);
+ break;
+ }
+ break;
+ case GTK_PREVIEW_GRAYSCALE:
+ switch (preview_class->info.visual->depth)
+ {
+ case 8:
+ dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x);
+ gtk_grayscale_8 (data, dest, x, y, w);
+ break;
+ case 15:
+ case 16:
+ dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 2;
+ gtk_grayscale_16 (data, dest, w);
+ break;
+ case 24:
+ case 32:
+ dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 3;
+ gtk_grayscale_24 (data, dest, w);
+ break;
+ }
+ break;
+ }
+}
+
+void
+gtk_preview_set_expand (GtkPreview *preview,
+ gint expand)
+{
+ g_return_if_fail (preview != NULL);
+ g_return_if_fail (GTK_IS_PREVIEW (preview));
+
+ preview->expand = (expand != FALSE);
+}
+
+void
+gtk_preview_set_gamma (double _gamma)
+{
+ g_return_if_fail (preview_class == NULL);
+
+ if (!preview_info)
+ {
+ preview_info = g_new0 (GtkPreviewInfo, 1);
+ preview_info->nred_shades = 6;
+ preview_info->ngreen_shades = 6;
+ preview_info->nblue_shades = 4;
+ preview_info->ngray_shades = 24;
+ }
+
+ preview_info->gamma = _gamma;
+}
+
+void
+gtk_preview_set_color_cube (guint nred_shades,
+ guint ngreen_shades,
+ guint nblue_shades,
+ guint ngray_shades)
+{
+ g_return_if_fail (preview_class == NULL);
+
+ if (!preview_info)
+ {
+ preview_info = g_new0 (GtkPreviewInfo, 1);
+ preview_info->gamma = 1.0;
+ }
+
+ preview_info->nred_shades = nred_shades;
+ preview_info->ngreen_shades = ngreen_shades;
+ preview_info->nblue_shades = nblue_shades;
+ preview_info->ngray_shades = ngray_shades;
+}
+
+void
+gtk_preview_set_install_cmap (gint _install_cmap)
+{
+ /* g_return_if_fail (preview_class == NULL); */
+
+ install_cmap = _install_cmap;
+}
+
+void
+gtk_preview_set_reserved (gint nreserved)
+{
+ if (!preview_info)
+ preview_info = g_new0 (GtkPreviewInfo, 1);
+
+ preview_info->nreserved = nreserved;
+}
+
+GdkVisual*
+gtk_preview_get_visual ()
+{
+ if (!preview_class)
+ preview_class = gtk_type_class (gtk_preview_get_type ());
+
+ return preview_class->info.visual;
+}
+
+GdkColormap*
+gtk_preview_get_cmap ()
+{
+ if (!preview_class)
+ preview_class = gtk_type_class (gtk_preview_get_type ());
+
+ return preview_class->info.cmap;
+}
+
+GtkPreviewInfo*
+gtk_preview_get_info ()
+{
+ if (!preview_class)
+ preview_class = gtk_type_class (gtk_preview_get_type ());
+
+ return &preview_class->info;
+}
+
+
+static void
+gtk_preview_destroy (GtkObject *object)
+{
+ GtkPreview *preview;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GTK_IS_PREVIEW (object));
+
+ preview = GTK_PREVIEW (object);
+ if (preview->buffer)
+ g_free (preview->buffer);
+ preview->type = (GtkPreviewType) -1;
+
+ if (GTK_OBJECT_CLASS (parent_class)->destroy)
+ (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+
+static void
+gtk_preview_realize (GtkWidget *widget)
+{
+ GtkPreview *preview;
+ GdkWindowAttr attributes;
+ gint attributes_mask;
+
+ g_return_if_fail (widget != NULL);
+ g_return_if_fail (GTK_IS_PREVIEW (widget));
+
+ GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+ preview = GTK_PREVIEW (widget);
+
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.x = widget->allocation.x;
+ attributes.y = widget->allocation.y;
+ attributes.width = widget->allocation.width;
+ attributes.height = widget->allocation.height;
+ attributes.wclass = GDK_INPUT_OUTPUT;
+ attributes.visual = gtk_widget_get_visual (widget);
+ attributes.colormap = gtk_widget_get_colormap (widget);
+ attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
+ attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+
+ widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
+ gdk_window_set_user_data (widget->window, widget);
+
+ widget->style = gtk_style_attach (widget->style, widget->window);
+ gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
+}
+
+static void
+gtk_preview_unrealize (GtkWidget *widget)
+{
+ GtkPreview *preview;
+
+ g_return_if_fail (widget != NULL);
+ g_return_if_fail (GTK_IS_PREVIEW (widget));
+
+ preview = GTK_PREVIEW (widget);
+
+ if (GTK_WIDGET_CLASS (parent_class)->unrealize)
+ (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
+}
+
+static gint
+gtk_preview_expose (GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ GtkPreview *preview;
+
+ g_return_val_if_fail (widget != NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_PREVIEW (widget), FALSE);
+ g_return_val_if_fail (event != NULL, FALSE);
+
+ if (GTK_WIDGET_DRAWABLE (widget))
+ {
+ preview = GTK_PREVIEW (widget);
+
+ gtk_preview_put (GTK_PREVIEW (widget),
+ widget->window, widget->style->black_gc,
+ (widget->allocation.width - preview->buffer_width) / 2,
+ (widget->allocation.height - preview->buffer_height) / 2,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+ }
+
+ return FALSE;
+}
+
+static void
+gtk_preview_make_buffer (GtkPreview *preview)
+{
+ GtkWidget *widget;
+ gint width;
+ gint height;
+
+ g_return_if_fail (preview != NULL);
+ g_return_if_fail (GTK_IS_PREVIEW (preview));
+
+ widget = GTK_WIDGET (preview);
+
+ if (preview->expand &&
+ (widget->allocation.width != 0) &&
+ (widget->allocation.height != 0))
+ {
+ width = widget->allocation.width;
+ height = widget->allocation.height;
+ }
+ else
+ {
+ width = widget->requisition.width;
+ height = widget->requisition.height;
+ }
+
+ if (!preview->buffer ||
+ (preview->buffer_width != width) ||
+ (preview->buffer_height != height))
+ {
+ if (preview->buffer)
+ g_free (preview->buffer);
+
+ preview->buffer_width = width;
+ preview->buffer_height = height;
+
+ preview->buffer = g_new0 (guchar,
+ preview->buffer_width *
+ preview->buffer_height *
+ preview_class->info.bpp);
+ }
+}
+
+static void
+gtk_preview_get_visuals (GtkPreviewClass *klass)
+{
+ static GdkVisualType types[] =
+ {
+ GDK_VISUAL_TRUE_COLOR,
+ GDK_VISUAL_DIRECT_COLOR,
+ GDK_VISUAL_TRUE_COLOR,
+ GDK_VISUAL_DIRECT_COLOR,
+ GDK_VISUAL_TRUE_COLOR,
+ GDK_VISUAL_DIRECT_COLOR,
+ GDK_VISUAL_TRUE_COLOR,
+ GDK_VISUAL_DIRECT_COLOR,
+ GDK_VISUAL_PSEUDO_COLOR
+ };
+ static gint depths[] = { 24, 24, 32, 32, 16, 16, 15, 15, 8 };
+ static gint nvisual_types = sizeof (types) / sizeof (types[0]);
+
+ int i;
+
+ g_return_if_fail (klass != NULL);
+
+ if (!klass->info.visual)
+ for (i = 0; i < nvisual_types; i++)
+ if ((klass->info.visual = gdk_visual_get_best_with_both (depths[i], types[i])))
+ {
+ if ((klass->info.visual->type == GDK_VISUAL_TRUE_COLOR) ||
+ (klass->info.visual->type == GDK_VISUAL_DIRECT_COLOR))
+ {
+ klass->info.lookup_red = g_new (gulong, 256);
+ klass->info.lookup_green = g_new (gulong, 256);
+ klass->info.lookup_blue = g_new (gulong, 256);
+
+ gtk_fill_lookup_array (klass->info.lookup_red,
+ klass->info.visual->depth,
+ klass->info.visual->red_shift,
+ 8 - klass->info.visual->red_prec);
+ gtk_fill_lookup_array (klass->info.lookup_green,
+ klass->info.visual->depth,
+ klass->info.visual->green_shift,
+ 8 - klass->info.visual->green_prec);
+ gtk_fill_lookup_array (klass->info.lookup_blue,
+ klass->info.visual->depth,
+ klass->info.visual->blue_shift,
+ 8 - klass->info.visual->blue_prec);
+ }
+ break;
+ }
+
+ if (!klass->info.visual)
+ {
+ g_warning ("unable to find a suitable visual for color image display.\n");
+ return;
+ }
+
+ switch (klass->info.visual->depth)
+ {
+ case 8:
+ klass->info.bpp = 1;
+ break;
+ case 15:
+ case 16:
+ klass->info.bpp = 2;
+ break;
+ case 24:
+ case 32:
+ klass->info.bpp = 3;
+ break;
+ }
+}
+
+static void
+gtk_preview_get_cmaps (GtkPreviewClass *klass)
+{
+ g_return_if_fail (klass != NULL);
+ g_return_if_fail (klass->info.visual != NULL);
+
+ if ((klass->info.visual->type != GDK_VISUAL_TRUE_COLOR) &&
+ (klass->info.visual->type != GDK_VISUAL_DIRECT_COLOR))
+ {
+ if (install_cmap)
+ {
+ klass->info.cmap = gdk_colormap_new (klass->info.visual, FALSE);
+ klass->info.cmap_alloced = install_cmap;
+
+ gtk_trim_cmap (klass);
+ gtk_create_8_bit (klass);
+ }
+ else
+ {
+ guint nred;
+ guint ngreen;
+ guint nblue;
+ guint ngray;
+ gint set_prop;
+
+ klass->info.cmap = gdk_colormap_get_system ();
+
+ set_prop = TRUE;
+ if (gtk_get_preview_prop (&nred, &ngreen, &nblue, &ngray))
+ {
+ set_prop = FALSE;
+
+ klass->info.nred_shades = nred;
+ klass->info.ngreen_shades = ngreen;
+ klass->info.nblue_shades = nblue;
+ klass->info.ngray_shades = ngray;
+
+ if (klass->info.nreserved)
+ {
+ klass->info.reserved_pixels = g_new (gulong, klass->info.nreserved);
+ if (!gdk_colors_alloc (klass->info.cmap, 0, NULL, 0,
+ klass->info.reserved_pixels,
+ klass->info.nreserved))
+ {
+ g_free (klass->info.reserved_pixels);
+ klass->info.reserved_pixels = NULL;
+ }
+ }
+ }
+ else
+ {
+ gtk_trim_cmap (klass);
+ }
+
+ gtk_create_8_bit (klass);
+
+ if (set_prop)
+ gtk_set_preview_prop (klass->info.nred_shades,
+ klass->info.ngreen_shades,
+ klass->info.nblue_shades,
+ klass->info.ngray_shades);
+ }
+ }
+ else
+ {
+ if (klass->info.visual == gdk_visual_get_system ())
+ klass->info.cmap = gdk_colormap_get_system ();
+ else
+ klass->info.cmap = gdk_colormap_new (klass->info.visual, FALSE);
+ klass->info.cmap_alloced = TRUE;
+
+ klass->info.nred_shades = 0;
+ klass->info.ngreen_shades = 0;
+ klass->info.nblue_shades = 0;
+ klass->info.ngray_shades = 0;
+ }
+}
+
+static void
+gtk_preview_dither_init (GtkPreviewClass *klass)
+{
+ int i, j, k;
+ unsigned char low_shade, high_shade;
+ unsigned short index;
+ long red_mult, green_mult;
+ double red_matrix_width;
+ double green_matrix_width;
+ double blue_matrix_width;
+ double gray_matrix_width;
+ double red_colors_per_shade;
+ double green_colors_per_shade;
+ double blue_colors_per_shade;
+ double gray_colors_per_shade;
+ gulong *gray_pixels;
+ gint shades_r, shades_g, shades_b, shades_gray;
+ GtkDitherInfo *red_ordered_dither;
+ GtkDitherInfo *green_ordered_dither;
+ GtkDitherInfo *blue_ordered_dither;
+ GtkDitherInfo *gray_ordered_dither;
+ guchar ***dither_matrix;
+ guchar DM[8][8] =
+ {
+ { 0, 32, 8, 40, 2, 34, 10, 42 },
+ { 48, 16, 56, 24, 50, 18, 58, 26 },
+ { 12, 44, 4, 36, 14, 46, 6, 38 },
+ { 60, 28, 52, 20, 62, 30, 54, 22 },
+ { 3, 35, 11, 43, 1, 33, 9, 41 },
+ { 51, 19, 59, 27, 49, 17, 57, 25 },
+ { 15, 47, 7, 39, 13, 45, 5, 37 },
+ { 63, 31, 55, 23, 61, 29, 53, 21 }
+ };
+
+ if (klass->info.visual->type != GDK_VISUAL_PSEUDO_COLOR)
+ return;
+
+ shades_r = klass->info.nred_shades;
+ shades_g = klass->info.ngreen_shades;
+ shades_b = klass->info.nblue_shades;
+ shades_gray = klass->info.ngray_shades;
+
+ red_mult = shades_g * shades_b;
+ green_mult = shades_b;
+
+ red_colors_per_shade = 255.0 / (shades_r - 1);
+ red_matrix_width = red_colors_per_shade / 64;
+
+ green_colors_per_shade = 255.0 / (shades_g - 1);
+ green_matrix_width = green_colors_per_shade / 64;
+
+ blue_colors_per_shade = 255.0 / (shades_b - 1);
+ blue_matrix_width = blue_colors_per_shade / 64;
+
+ gray_colors_per_shade = 255.0 / (shades_gray - 1);
+ gray_matrix_width = gray_colors_per_shade / 64;
+
+ /* alloc the ordered dither arrays for accelerated dithering */
+
+ klass->info.dither_red = g_new (GtkDitherInfo, 256);
+ klass->info.dither_green = g_new (GtkDitherInfo, 256);
+ klass->info.dither_blue = g_new (GtkDitherInfo, 256);
+ klass->info.dither_gray = g_new (GtkDitherInfo, 256);
+
+ red_ordered_dither = klass->info.dither_red;
+ green_ordered_dither = klass->info.dither_green;
+ blue_ordered_dither = klass->info.dither_blue;
+ gray_ordered_dither = klass->info.dither_gray;
+
+ dither_matrix = g_new (guchar**, 8);
+ for (i = 0; i < 8; i++)
+ {
+ dither_matrix[i] = g_new (guchar*, 8);
+ for (j = 0; j < 8; j++)
+ dither_matrix[i][j] = g_new (guchar, 65);
+ }
+
+ klass->info.dither_matrix = dither_matrix;
+
+ /* setup the ordered_dither_matrices */
+
+ for (i = 0; i < 8; i++)
+ for (j = 0; j < 8; j++)
+ for (k = 0; k <= 64; k++)
+ dither_matrix[i][j][k] = (DM[i][j] < k) ? 1 : 0;
+
+ /* setup arrays containing three bytes of information for red, green, & blue */
+ /* the arrays contain :
+ * 1st byte: low end shade value
+ * 2nd byte: high end shade value
+ * 3rd & 4th bytes: ordered dither matrix index
+ */
+
+ gray_pixels = klass->info.gray_pixels;
+
+ for (i = 0; i < 256; i++)
+ {
+
+ /* setup the red information */
+ {
+ low_shade = (unsigned char) (i / red_colors_per_shade);
+ if (low_shade == (shades_r - 1))
+ low_shade--;
+ high_shade = low_shade + 1;
+
+ index = (unsigned short)
+ (((double) i - low_shade * red_colors_per_shade) /
+ red_matrix_width);
+
+ low_shade *= red_mult;
+ high_shade *= red_mult;
+
+ red_ordered_dither[i].s[1] = index;
+ red_ordered_dither[i].c[0] = low_shade;
+ red_ordered_dither[i].c[1] = high_shade;
+ }
+
+
+ /* setup the green information */
+ {
+ low_shade = (unsigned char) (i / green_colors_per_shade);
+ if (low_shade == (shades_g - 1))
+ low_shade--;
+ high_shade = low_shade + 1;
+
+ index = (unsigned short)
+ (((double) i - low_shade * green_colors_per_shade) /
+ green_matrix_width);
+
+ low_shade *= green_mult;
+ high_shade *= green_mult;
+
+ green_ordered_dither[i].s[1] = index;
+ green_ordered_dither[i].c[0] = low_shade;
+ green_ordered_dither[i].c[1] = high_shade;
+ }
+
+
+ /* setup the blue information */
+ {
+ low_shade = (unsigned char) (i / blue_colors_per_shade);
+ if (low_shade == (shades_b - 1))
+ low_shade--;
+ high_shade = low_shade + 1;
+
+ index = (unsigned short)
+ (((double) i - low_shade * blue_colors_per_shade) /
+ blue_matrix_width);
+
+ blue_ordered_dither[i].s[1] = index;
+ blue_ordered_dither[i].c[0] = low_shade;
+ blue_ordered_dither[i].c[1] = high_shade;
+ }
+
+
+ /* setup the gray information */
+ {
+ low_shade = (unsigned char) (i / gray_colors_per_shade);
+ if (low_shade == (shades_gray - 1))
+ low_shade--;
+ high_shade = low_shade + 1;
+
+ index = (unsigned short)
+ (((double) i - low_shade * gray_colors_per_shade) /
+ gray_matrix_width);
+
+ gray_ordered_dither[i].s[1] = index;
+ gray_ordered_dither[i].c[0] = gray_pixels[low_shade];
+ gray_ordered_dither[i].c[1] = gray_pixels[high_shade];
+ }
+ }
+}
+
+static void
+gtk_fill_lookup_array (gulong *array,
+ int depth,
+ int shift,
+ int prec)
+{
+ double one_over_gamma;
+ double ind;
+ int val;
+ int i;
+
+ if (preview_class->info.gamma != 0.0)
+ one_over_gamma = 1.0 / preview_class->info.gamma;
+ else
+ one_over_gamma = 1.0;
+
+ for (i = 0; i < 256; i++)
+ {
+ if (one_over_gamma == 1.0)
+ array[i] = ((i >> prec) << shift);
+ else
+ {
+ ind = (double) i / 255.0;
+ val = (int) (255 * pow (ind, one_over_gamma));
+ array[i] = ((val >> prec) << shift);
+ }
+ }
+}
+
+static void
+gtk_trim_cmap (GtkPreviewClass *klass)
+{
+ gulong pixels[256];
+ guint nred;
+ guint ngreen;
+ guint nblue;
+ guint ngray;
+ guint nreserved;
+ guint total;
+ guint tmp;
+ gint success;
+
+ nred = klass->info.nred_shades;
+ ngreen = klass->info.ngreen_shades;
+ nblue = klass->info.nblue_shades;
+ ngray = klass->info.ngray_shades;
+ nreserved = klass->info.nreserved;
+
+ success = FALSE;
+ while (!success)
+ {
+ total = nred * ngreen * nblue + ngray + nreserved;
+
+ if (total <= 256)
+ {
+ if ((nred < 2) || (ngreen < 2) || (nblue < 2) || (ngray < 2))
+ success = TRUE;
+ else
+ {
+ success = gdk_colors_alloc (klass->info.cmap, 0, NULL, 0, pixels, total);
+ if (success)
+ {
+ if (nreserved > 0)
+ {
+ klass->info.reserved_pixels = g_new (gulong, nreserved);
+ memcpy (klass->info.reserved_pixels, pixels, sizeof (gulong) * nreserved);
+ gdk_colors_free (klass->info.cmap, &pixels[nreserved],
+ total - nreserved, 0);
+ }
+ else
+ {
+ gdk_colors_free (klass->info.cmap, pixels, total, 0);
+ }
+ }
+ }
+ }
+
+ if (!success)
+ {
+ if ((nblue >= nred) && (nblue >= ngreen))
+ nblue = nblue - 1;
+ else if ((nred >= ngreen) && (nred >= nblue))
+ nred = nred - 1;
+ else
+ {
+ tmp = log (ngray) / log (2);
+
+ if (ngreen >= tmp)
+ ngreen = ngreen - 1;
+ else
+ ngray -= 1;
+ }
+ }
+ }
+
+ if ((nred < 2) || (ngreen < 2) || (nblue < 2) || (ngray < 2))
+ {
+ g_print ("Unable to allocate sufficient colormap entries.\n");
+ g_print ("Try exiting other color intensive applications.\n");
+ return;
+ }
+
+ /* If any of the shade values has changed, issue a warning */
+ if ((nred != klass->info.nred_shades) ||
+ (ngreen != klass->info.ngreen_shades) ||
+ (nblue != klass->info.nblue_shades) ||
+ (ngray != klass->info.ngray_shades))
+ {
+ g_print ("Not enough colors to satisfy requested color cube.\n");
+ g_print ("Reduced color cube shades from\n");
+ g_print ("[%d of Red, %d of Green, %d of Blue, %d of Gray] ==> [%d of Red, %d of Green, %d of Blue, %d of Gray]\n",
+ klass->info.nred_shades, klass->info.ngreen_shades,
+ klass->info.nblue_shades, klass->info.ngray_shades,
+ nred, ngreen, nblue, ngray);
+ }
+
+ klass->info.nred_shades = nred;
+ klass->info.ngreen_shades = ngreen;
+ klass->info.nblue_shades = nblue;
+ klass->info.ngray_shades = ngray;
+}
+
+static void
+gtk_create_8_bit (GtkPreviewClass *klass)
+{
+ unsigned int r, g, b;
+ unsigned int rv, gv, bv;
+ unsigned int dr, dg, db, dgray;
+ GdkColor color;
+ gulong *pixels;
+ double one_over_gamma;
+ int i;
+
+ if (!klass->info.color_pixels)
+ klass->info.color_pixels = g_new (gulong, 256);
+
+ if (!klass->info.gray_pixels)
+ klass->info.gray_pixels = g_new (gulong, 256);
+
+ if (klass->info.gamma != 0.0)
+ one_over_gamma = 1.0 / klass->info.gamma;
+ else
+ one_over_gamma = 1.0;
+
+ dr = klass->info.nred_shades - 1;
+ dg = klass->info.ngreen_shades - 1;
+ db = klass->info.nblue_shades - 1;
+ dgray = klass->info.ngray_shades - 1;
+
+ pixels = klass->info.color_pixels;
+
+ for (r = 0, i = 0; r <= dr; r++)
+ for (g = 0; g <= dg; g++)
+ for (b = 0; b <= db; b++, i++)
+ {
+ rv = (unsigned int) ((r * klass->info.visual->colormap_size) / dr);
+ gv = (unsigned int) ((g * klass->info.visual->colormap_size) / dg);
+ bv = (unsigned int) ((b * klass->info.visual->colormap_size) / db);
+ color.red = ((int) (255 * pow ((double) rv / 256.0, one_over_gamma))) * 257;
+ color.green = ((int) (255 * pow ((double) gv / 256.0, one_over_gamma))) * 257;
+ color.blue = ((int) (255 * pow ((double) bv / 256.0, one_over_gamma))) * 257;
+
+ if (!gdk_color_alloc (klass->info.cmap, &color))
+ {
+ g_error ("could not initialize 8-bit combined colormap");
+ return;
+ }
+
+ pixels[i] = color.pixel;
+ }
+
+ pixels = klass->info.gray_pixels;
+
+ for (i = 0; i < (int) klass->info.ngray_shades; i++)
+ {
+ color.red = (i * klass->info.visual->colormap_size) / dgray;
+ color.red = ((int) (255 * pow ((double) color.red / 256.0, one_over_gamma))) * 257;
+ color.green = color.red;
+ color.blue = color.red;
+
+ if (!gdk_color_alloc (klass->info.cmap, &color))
+ {
+ g_error ("could not initialize 8-bit combined colormap");
+ return;
+ }
+
+ pixels[i] = color.pixel;
+ }
+}
+
+
+static void
+gtk_color_8 (guchar *src,
+ guchar *dest,
+ gint x,
+ gint y,
+ gulong width)
+{
+ gulong *colors;
+ GtkDitherInfo *dither_red;
+ GtkDitherInfo *dither_green;
+ GtkDitherInfo *dither_blue;
+ GtkDitherInfo r, g, b;
+ guchar **dither_matrix;
+ guchar *matrix;
+
+ colors = preview_class->info.color_pixels;
+ dither_red = preview_class->info.dither_red;
+ dither_green = preview_class->info.dither_green;
+ dither_blue = preview_class->info.dither_blue;
+ dither_matrix = preview_class->info.dither_matrix[y & 0x7];
+
+ while (width--)
+ {
+ r = dither_red[src[0]];
+ g = dither_green[src[1]];
+ b = dither_blue[src[2]];
+ src += 3;
+
+ matrix = dither_matrix[x++ & 0x7];
+ *dest++ = colors[(r.c[matrix[r.s[1]]] +
+ g.c[matrix[g.s[1]]] +
+ b.c[matrix[b.s[1]]])];
+ }
+}
+
+static void
+gtk_color_16 (guchar *src,
+ guchar *dest,
+ gulong width)
+{
+ gulong *lookup_red;
+ gulong *lookup_green;
+ gulong *lookup_blue;
+ gulong val;
+
+ lookup_red = preview_class->info.lookup_red;
+ lookup_green = preview_class->info.lookup_green;
+ lookup_blue = preview_class->info.lookup_blue;
+
+ while (width--)
+ {
+ val = COLOR_COMPOSE (src[0], src[1], src[2]);
+ dest[0] = val;
+ dest[1] = val >> 8;
+ dest += 2;
+ src += 3;
+ }
+}
+
+static void
+gtk_color_24 (guchar *src,
+ guchar *dest,
+ gulong width)
+{
+ gulong *lookup_red;
+ gulong *lookup_green;
+ gulong *lookup_blue;
+ gulong val;
+
+ lookup_red = preview_class->info.lookup_red;
+ lookup_green = preview_class->info.lookup_green;
+ lookup_blue = preview_class->info.lookup_blue;
+
+ while (width--)
+ {
+ val = COLOR_COMPOSE (src[0], src[1], src[2]);
+ dest[0] = val;
+ dest[1] = val >> 8;
+ dest[2] = val >> 16;
+ dest += 3;
+ src += 3;
+ }
+}
+
+static void
+gtk_grayscale_8 (guchar *src,
+ guchar *dest,
+ gint x,
+ gint y,
+ gulong width)
+{
+ GtkDitherInfo *dither_gray;
+ GtkDitherInfo gray;
+ guchar **dither_matrix;
+ guchar *matrix;
+
+ dither_gray = preview_class->info.dither_gray;
+ dither_matrix = preview_class->info.dither_matrix[y & 0x7];
+
+ while (width--)
+ {
+ gray = dither_gray[*src++];
+ matrix = dither_matrix[x++ & 0x7];
+ *dest++ = gray.c[matrix[gray.s[1]]];
+ }
+}
+
+static void
+gtk_grayscale_16 (guchar *src,
+ guchar *dest,
+ gulong width)
+{
+ gulong *lookup_red;
+ gulong *lookup_green;
+ gulong *lookup_blue;
+ gulong val;
+
+ lookup_red = preview_class->info.lookup_red;
+ lookup_green = preview_class->info.lookup_green;
+ lookup_blue = preview_class->info.lookup_blue;
+
+ while (width--)
+ {
+ val = COLOR_COMPOSE (*src, *src, *src);
+ dest[0] = val;
+ dest[1] = val >> 8;
+ dest += 2;
+ src += 1;
+ }
+}
+
+static void
+gtk_grayscale_24 (guchar *src,
+ guchar *dest,
+ gulong width)
+{
+ gulong *lookup_red;
+ gulong *lookup_green;
+ gulong *lookup_blue;
+ gulong val;
+
+ lookup_red = preview_class->info.lookup_red;
+ lookup_green = preview_class->info.lookup_green;
+ lookup_blue = preview_class->info.lookup_blue;
+
+ while (width--)
+ {
+ val = COLOR_COMPOSE (*src, *src, *src);
+ dest[0] = val;
+ dest[1] = val >> 8;
+ dest[2] = val >> 16;
+ dest += 3;
+ src += 1;
+ }
+}
+
+
+static gint
+gtk_get_preview_prop (guint *nred,
+ guint *ngreen,
+ guint *nblue,
+ guint *ngray)
+{
+ GtkPreviewProp *prop;
+ GdkAtom property;
+
+ property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE);
+
+ if (gdk_property_get (NULL, property, property,
+ 0, sizeof (GtkPreviewProp), FALSE,
+ NULL, NULL, NULL, (guchar**) &prop))
+ {
+ *nred = ntohs (prop->nred_shades);
+ *ngreen = ntohs (prop->ngreen_shades);
+ *nblue = ntohs (prop->nblue_shades);
+ *ngray = ntohs (prop->ngray_shades);
+
+ prop->ref_count = htons (ntohs (prop->ref_count) + 1);
+ gdk_property_change (NULL, property, property, 16,
+ GDK_PROP_MODE_REPLACE,
+ (guchar*) prop, 5);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+gtk_set_preview_prop (guint nred,
+ guint ngreen,
+ guint nblue,
+ guint ngray)
+{
+ GtkPreviewProp prop;
+ GdkAtom property;
+
+ property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE);
+
+ prop.ref_count = htons (1);
+ prop.nred_shades = htons (nred);
+ prop.ngreen_shades = htons (ngreen);
+ prop.nblue_shades = htons (nblue);
+ prop.ngray_shades = htons (ngray);
+
+ gdk_property_change (NULL, property, property, 16,
+ GDK_PROP_MODE_REPLACE,
+ (guchar*) &prop, 5);
+}
+
+
+static void
+gtk_lsbmsb_1_1 (guchar *dest,
+ guchar *src,
+ gint count)
+{
+ memcpy (dest, src, count);
+}
+
+static void
+gtk_lsb_2_2 (guchar *dest,
+ guchar *src,
+ gint count)
+{
+ memcpy (dest, src, count * 2);
+}
+
+static void
+gtk_msb_2_2 (guchar *dest,
+ guchar *src,
+ gint count)
+{
+ while (count--)
+ {
+ dest[0] = src[1];
+ dest[1] = src[0];
+ dest += 2;
+ src += 2;
+ }
+}
+
+static void
+gtk_lsb_3_3 (guchar *dest,
+ guchar *src,
+ gint count)
+{
+ memcpy (dest, src, count * 3);
+}
+
+static void
+gtk_msb_3_3 (guchar *dest,
+ guchar *src,
+ gint count)
+{
+ while (count--)
+ {
+ dest[0] = src[2];
+ dest[1] = src[1];
+ dest[2] = src[0];
+ dest += 3;
+ src += 3;
+ }
+}
+
+static void
+gtk_lsb_3_4 (guchar *dest,
+ guchar *src,
+ gint count)
+{
+ while (count--)
+ {
+ dest[0] = src[0];
+ dest[1] = src[1];
+ dest[2] = src[2];
+ dest += 4;
+ src += 3;
+ }
+}
+
+static void
+gtk_msb_3_4 (guchar *dest,
+ guchar *src,
+ gint count)
+{
+ while (count--)
+ {
+ dest[1] = src[2];
+ dest[2] = src[1];
+ dest[3] = src[0];
+ dest += 4;
+ src += 3;
+ }
+}