1572 lines
		
	
	
		
			38 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1572 lines
		
	
	
		
			38 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* 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;
 | |
|     }
 | |
| }
 | 
