1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
22 #include <sys/types.h>
23 #include <sys/param.h>
25 #include "gtkpreview.h"
26 #include "gtksignal.h"
29 #define IMAGE_SIZE 256
30 #define PREVIEW_CLASS(w) GTK_PREVIEW_CLASS (GTK_OBJECT (w)->klass)
31 #define COLOR_COMPOSE(r,g,b) (lookup_red[r] | lookup_green[g] | lookup_blue[b])
34 typedef struct _GtkPreviewProp GtkPreviewProp;
35 typedef void (*GtkTransferFunc) (guchar *dest, guchar *src, gint count);
37 struct _GtkPreviewProp
41 guint16 ngreen_shades;
47 static void gtk_preview_class_init (GtkPreviewClass *klass);
48 static void gtk_preview_init (GtkPreview *preview);
49 static void gtk_preview_finalize (GtkObject *object);
50 static void gtk_preview_realize (GtkWidget *widget);
51 static gint gtk_preview_expose (GtkWidget *widget,
52 GdkEventExpose *event);
53 static void gtk_preview_make_buffer (GtkPreview *preview);
54 static void gtk_preview_get_visuals (GtkPreviewClass *klass);
55 static void gtk_preview_get_cmaps (GtkPreviewClass *klass);
56 static void gtk_preview_dither_init (GtkPreviewClass *klass);
57 static void gtk_fill_lookup_array (gulong *array,
61 static void gtk_trim_cmap (GtkPreviewClass *klass);
62 static void gtk_create_8_bit (GtkPreviewClass *klass);
64 static void gtk_color_8 (guchar *src,
69 static void gtk_color_16 (guchar *src,
72 static void gtk_color_24 (guchar *src,
75 static void gtk_grayscale_8 (guchar *src,
80 static void gtk_grayscale_16 (guchar *src,
83 static void gtk_grayscale_24 (guchar *src,
87 static gint gtk_get_preview_prop (guint *nred,
91 static void gtk_set_preview_prop (guint nred,
96 /* transfer functions:
97 * destination byte order/source bpp/destination bpp
99 static void gtk_lsbmsb_1_1 (guchar *dest,
102 static void gtk_lsb_2_2 (guchar *dest,
105 static void gtk_msb_2_2 (guchar *dest,
108 static void gtk_lsb_3_3 (guchar *dest,
111 static void gtk_msb_3_3 (guchar *dest,
114 static void gtk_lsb_3_4 (guchar *dest,
117 static void gtk_msb_3_4 (guchar *dest,
122 static GtkWidgetClass *parent_class = NULL;
123 static GtkPreviewClass *preview_class = NULL;
124 static GtkPreviewInfo *preview_info = NULL;
125 static gint install_cmap = FALSE;
129 gtk_preview_get_type (void)
131 static guint preview_type = 0;
135 GtkTypeInfo preview_info =
139 sizeof (GtkPreviewClass),
140 (GtkClassInitFunc) gtk_preview_class_init,
141 (GtkObjectInitFunc) gtk_preview_init,
142 /* reversed_1 */ NULL,
143 /* reversed_2 */ NULL,
144 (GtkClassInitFunc) NULL,
147 preview_type = gtk_type_unique (gtk_widget_get_type (), &preview_info);
154 gtk_preview_class_init (GtkPreviewClass *klass)
156 GtkObjectClass *object_class;
157 GtkWidgetClass *widget_class;
159 object_class = (GtkObjectClass*) klass;
160 widget_class = (GtkWidgetClass*) klass;
162 parent_class = gtk_type_class (gtk_widget_get_type ());
163 preview_class = klass;
165 object_class->finalize = gtk_preview_finalize;
167 widget_class->realize = gtk_preview_realize;
168 widget_class->expose_event = gtk_preview_expose;
171 klass->info = *preview_info;
174 klass->info.visual = NULL;
175 klass->info.cmap = NULL;
177 klass->info.color_pixels = NULL;
178 klass->info.gray_pixels = NULL;
179 klass->info.reserved_pixels = NULL;
181 klass->info.lookup_red = NULL;
182 klass->info.lookup_green = NULL;
183 klass->info.lookup_blue = NULL;
185 klass->info.dither_red = NULL;
186 klass->info.dither_green = NULL;
187 klass->info.dither_blue = NULL;
188 klass->info.dither_gray = NULL;
189 klass->info.dither_matrix = NULL;
191 klass->info.nred_shades = 6;
192 klass->info.ngreen_shades = 6;
193 klass->info.nblue_shades = 4;
194 klass->info.ngray_shades = 24;
195 klass->info.nreserved = 0;
198 klass->info.cmap_alloced = FALSE;
199 klass->info.gamma = 1.0;
204 gtk_preview_get_visuals (klass);
205 gtk_preview_get_cmaps (klass);
206 gtk_preview_dither_init (klass);
210 gtk_preview_reset (void)
212 GtkPreviewInfo *info;
214 if (!preview_class || !preview_info)
217 info = &preview_class->info;
219 gtk_preview_uninit();
221 if (info->color_pixels)
223 gdk_colors_free (info->cmap,
226 info->ngreen_shades *
230 gdk_colors_free (info->cmap,
232 info->ngray_shades, 0);
234 g_free (info->color_pixels);
235 g_free (info->gray_pixels);
238 if (info->reserved_pixels)
240 gdk_colors_free (info->cmap,
241 info->reserved_pixels,
243 g_free (info->reserved_pixels);
246 if (info->cmap && info->cmap_alloced)
247 gdk_colormap_unref (info->cmap);
249 if (info->lookup_red)
251 g_free (info->lookup_red);
252 g_free (info->lookup_green);
253 g_free (info->lookup_blue);
256 if (info->dither_matrix)
260 for (i= 0 ; i < 8 ; i++)
262 for (j = 0; j < 8 ; j++)
263 g_free (info->dither_matrix[i][j]);
264 g_free (info->dither_matrix[i]);
266 g_free (info->dither_matrix);
267 g_free (info->dither_red);
268 g_free (info->dither_green);
269 g_free (info->dither_blue);
272 preview_class->info = *preview_info;
274 gtk_preview_get_visuals (preview_class);
275 gtk_preview_get_cmaps (preview_class);
276 gtk_preview_dither_init (preview_class);
280 gtk_preview_init (GtkPreview *preview)
282 GTK_WIDGET_SET_FLAGS (preview, GTK_BASIC);
284 preview->buffer = NULL;
285 preview->buffer_width = 0;
286 preview->buffer_height = 0;
287 preview->expand = FALSE;
291 gtk_preview_uninit (void)
293 GtkPreviewProp *prop;
296 /* FIXME: need to grab the server here to prevent a race condition */
298 if (preview_class && !install_cmap && preview_class->info.visual &&
299 (preview_class->info.visual->type != GDK_VISUAL_TRUE_COLOR) &&
300 (preview_class->info.visual->type != GDK_VISUAL_DIRECT_COLOR))
302 property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE);
304 if (gdk_property_get (NULL, property, property,
305 0, sizeof (GtkPreviewProp), FALSE,
306 NULL, NULL, NULL, (guchar**) &prop))
308 prop->ref_count = prop->ref_count - 1;
309 if (prop->ref_count == 0)
311 gdk_property_delete (NULL, property);
315 gdk_property_change (NULL, property, property, 16,
316 GDK_PROP_MODE_REPLACE,
324 gtk_preview_new (GtkPreviewType type)
328 preview = gtk_type_new (gtk_preview_get_type ());
329 preview->type = type;
331 return GTK_WIDGET (preview);
335 gtk_preview_size (GtkPreview *preview,
339 g_return_if_fail (preview != NULL);
340 g_return_if_fail (GTK_IS_PREVIEW (preview));
342 if ((width != GTK_WIDGET (preview)->requisition.width) ||
343 (height != GTK_WIDGET (preview)->requisition.height))
345 GTK_WIDGET (preview)->requisition.width = width;
346 GTK_WIDGET (preview)->requisition.height = height;
349 g_free (preview->buffer);
350 preview->buffer = NULL;
355 gtk_preview_put (GtkPreview *preview,
367 GdkRectangle r1, r2, r3;
368 GtkTransferFunc transfer_func;
373 guint dest_rowstride;
378 g_return_if_fail (preview != NULL);
379 g_return_if_fail (GTK_IS_PREVIEW (preview));
380 g_return_if_fail (window != NULL);
382 if (!preview->buffer)
385 widget = GTK_WIDGET (preview);
389 r1.width = preview->buffer_width;
390 r1.height = preview->buffer_height;
397 if (!gdk_rectangle_intersect (&r1, &r2, &r3))
400 x2 = r3.x + r3.width;
401 y2 = r3.y + r3.height;
403 if (!preview_class->image)
404 preview_class->image = gdk_image_new (GDK_IMAGE_FASTEST,
405 preview_class->info.visual,
406 IMAGE_SIZE, IMAGE_SIZE);
407 image = preview_class->image;
408 src_bpp = preview_class->info.bpp;
410 image_mem = image->mem;
411 dest_bpp = image->bpp;
412 dest_rowstride = image->bpl;
414 transfer_func = NULL;
422 transfer_func = gtk_lsbmsb_1_1;
430 if (image->byte_order == GDK_MSB_FIRST)
431 transfer_func = gtk_msb_2_2;
433 transfer_func = gtk_lsb_2_2;
443 if (image->byte_order == GDK_MSB_FIRST)
444 transfer_func = gtk_msb_3_3;
446 transfer_func = gtk_lsb_3_3;
454 if (image->byte_order == GDK_MSB_FIRST)
455 transfer_func = gtk_msb_3_4;
457 transfer_func = gtk_lsb_3_4;
465 g_warning ("unsupported byte order/src bpp/dest bpp combination: %s:%d:%d",
466 (image->byte_order == GDK_MSB_FIRST) ? "msb" : "lsb", src_bpp, dest_bpp);
470 for (y = r3.y; y < y2; y += IMAGE_SIZE)
472 for (x = r3.x; x < x2; x += IMAGE_SIZE)
482 for (i = y; i < ye; i++)
484 src = preview->buffer + (((gulong) (i - r1.y) * (gulong) preview->buffer_width) +
485 (x - r1.x)) * (gulong) src_bpp;
486 dest = image_mem + ((gulong) (i - y) * dest_rowstride);
489 (* transfer_func) (dest, src, xe - x);
492 gdk_draw_image (window, gc,
494 destx + (r3.x - srcx) + (x - r3.x),
495 desty + (r3.y - srcy) + (y - r3.y),
503 gtk_preview_put_row (GtkPreview *preview,
510 g_return_if_fail (preview != NULL);
511 g_return_if_fail (GTK_IS_PREVIEW (preview));
512 g_return_if_fail (src != NULL);
513 g_return_if_fail (dest != NULL);
515 switch (preview->type)
517 case GTK_PREVIEW_COLOR:
518 switch (preview_class->info.visual->depth)
521 gtk_color_8 (src, dest, x, y, w);
525 gtk_color_16 (src, dest, w);
529 gtk_color_24 (src, dest, w);
533 case GTK_PREVIEW_GRAYSCALE:
534 switch (preview_class->info.visual->depth)
537 gtk_grayscale_8 (src, dest, x, y, w);
541 gtk_grayscale_16 (src, dest, w);
545 gtk_grayscale_24 (src, dest, w);
553 gtk_preview_draw_row (GtkPreview *preview,
561 g_return_if_fail (preview != NULL);
562 g_return_if_fail (GTK_IS_PREVIEW (preview));
563 g_return_if_fail (data != NULL);
564 g_return_if_fail (preview_class->info.visual != NULL);
566 if ((w <= 0) || (y < 0))
569 g_return_if_fail (data != NULL);
571 gtk_preview_make_buffer (preview);
573 if (y >= preview->buffer_height)
576 switch (preview->type)
578 case GTK_PREVIEW_COLOR:
579 switch (preview_class->info.visual->depth)
582 dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x);
583 gtk_color_8 (data, dest, x, y, w);
587 dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 2;
588 gtk_color_16 (data, dest, w);
592 dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 3;
593 gtk_color_24 (data, dest, w);
597 case GTK_PREVIEW_GRAYSCALE:
598 switch (preview_class->info.visual->depth)
601 dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x);
602 gtk_grayscale_8 (data, dest, x, y, w);
606 dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 2;
607 gtk_grayscale_16 (data, dest, w);
611 dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 3;
612 gtk_grayscale_24 (data, dest, w);
620 gtk_preview_set_expand (GtkPreview *preview,
623 g_return_if_fail (preview != NULL);
624 g_return_if_fail (GTK_IS_PREVIEW (preview));
626 preview->expand = (expand != FALSE);
630 gtk_preview_set_gamma (double _gamma)
634 preview_info = g_new0 (GtkPreviewInfo, 1);
635 preview_info->nred_shades = 6;
636 preview_info->ngreen_shades = 6;
637 preview_info->nblue_shades = 4;
638 preview_info->ngray_shades = 24;
641 preview_info->gamma = _gamma;
645 gtk_preview_set_color_cube (guint nred_shades,
652 preview_info = g_new0 (GtkPreviewInfo, 1);
653 preview_info->gamma = 1.0;
656 preview_info->nred_shades = nred_shades;
657 preview_info->ngreen_shades = ngreen_shades;
658 preview_info->nblue_shades = nblue_shades;
659 preview_info->ngray_shades = ngray_shades;
663 gtk_preview_set_install_cmap (gint _install_cmap)
665 install_cmap = _install_cmap;
669 gtk_preview_set_reserved (gint nreserved)
672 preview_info = g_new0 (GtkPreviewInfo, 1);
674 preview_info->nreserved = nreserved;
678 gtk_preview_get_visual (void)
681 preview_class = gtk_type_class (gtk_preview_get_type ());
683 return preview_class->info.visual;
687 gtk_preview_get_cmap (void)
690 preview_class = gtk_type_class (gtk_preview_get_type ());
692 return preview_class->info.cmap;
696 gtk_preview_get_info (void)
699 preview_class = gtk_type_class (gtk_preview_get_type ());
701 return &preview_class->info;
706 gtk_preview_finalize (GtkObject *object)
710 g_return_if_fail (object != NULL);
711 g_return_if_fail (GTK_IS_PREVIEW (object));
713 preview = GTK_PREVIEW (object);
715 g_free (preview->buffer);
716 preview->type = (GtkPreviewType) -1;
718 (* GTK_OBJECT_CLASS (parent_class)->finalize) (object);
722 gtk_preview_realize (GtkWidget *widget)
725 GdkWindowAttr attributes;
726 gint attributes_mask;
728 g_return_if_fail (widget != NULL);
729 g_return_if_fail (GTK_IS_PREVIEW (widget));
731 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
732 preview = GTK_PREVIEW (widget);
734 attributes.window_type = GDK_WINDOW_CHILD;
735 attributes.x = widget->allocation.x;
736 attributes.y = widget->allocation.y;
737 attributes.width = widget->allocation.width;
738 attributes.height = widget->allocation.height;
739 attributes.wclass = GDK_INPUT_OUTPUT;
740 attributes.visual = preview_class->info.visual;
741 attributes.colormap = preview_class->info.cmap;
742 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
743 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
745 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
746 gdk_window_set_user_data (widget->window, widget);
748 widget->style = gtk_style_attach (widget->style, widget->window);
749 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
753 gtk_preview_expose (GtkWidget *widget,
754 GdkEventExpose *event)
758 g_return_val_if_fail (widget != NULL, FALSE);
759 g_return_val_if_fail (GTK_IS_PREVIEW (widget), FALSE);
760 g_return_val_if_fail (event != NULL, FALSE);
762 if (GTK_WIDGET_DRAWABLE (widget))
764 preview = GTK_PREVIEW (widget);
766 gtk_preview_put (GTK_PREVIEW (widget),
767 widget->window, widget->style->black_gc,
769 (widget->allocation.width - preview->buffer_width)/2,
771 (widget->allocation.height - preview->buffer_height)/2,
772 event->area.x, event->area.y,
773 event->area.width, event->area.height);
780 gtk_preview_make_buffer (GtkPreview *preview)
786 g_return_if_fail (preview != NULL);
787 g_return_if_fail (GTK_IS_PREVIEW (preview));
789 widget = GTK_WIDGET (preview);
791 if (preview->expand &&
792 (widget->allocation.width != 0) &&
793 (widget->allocation.height != 0))
795 width = widget->allocation.width;
796 height = widget->allocation.height;
800 width = widget->requisition.width;
801 height = widget->requisition.height;
804 if (!preview->buffer ||
805 (preview->buffer_width != width) ||
806 (preview->buffer_height != height))
809 g_free (preview->buffer);
811 preview->buffer_width = width;
812 preview->buffer_height = height;
814 preview->buffer = g_new0 (guchar,
815 preview->buffer_width *
816 preview->buffer_height *
817 preview_class->info.bpp);
822 gtk_preview_get_visuals (GtkPreviewClass *klass)
824 static GdkVisualType types[] =
826 GDK_VISUAL_TRUE_COLOR,
827 GDK_VISUAL_DIRECT_COLOR,
828 GDK_VISUAL_TRUE_COLOR,
829 GDK_VISUAL_DIRECT_COLOR,
830 GDK_VISUAL_TRUE_COLOR,
831 GDK_VISUAL_DIRECT_COLOR,
832 GDK_VISUAL_TRUE_COLOR,
833 GDK_VISUAL_DIRECT_COLOR,
834 GDK_VISUAL_PSEUDO_COLOR
836 static gint depths[] = { 24, 24, 32, 32, 16, 16, 15, 15, 8 };
837 static gint nvisual_types = sizeof (types) / sizeof (types[0]);
841 g_return_if_fail (klass != NULL);
843 if (!klass->info.visual)
844 for (i = 0; i < nvisual_types; i++)
845 if ((klass->info.visual = gdk_visual_get_best_with_both (depths[i], types[i])))
847 if ((klass->info.visual->type == GDK_VISUAL_TRUE_COLOR) ||
848 (klass->info.visual->type == GDK_VISUAL_DIRECT_COLOR))
850 klass->info.lookup_red = g_new (gulong, 256);
851 klass->info.lookup_green = g_new (gulong, 256);
852 klass->info.lookup_blue = g_new (gulong, 256);
854 gtk_fill_lookup_array (klass->info.lookup_red,
855 klass->info.visual->depth,
856 klass->info.visual->red_shift,
857 8 - klass->info.visual->red_prec);
858 gtk_fill_lookup_array (klass->info.lookup_green,
859 klass->info.visual->depth,
860 klass->info.visual->green_shift,
861 8 - klass->info.visual->green_prec);
862 gtk_fill_lookup_array (klass->info.lookup_blue,
863 klass->info.visual->depth,
864 klass->info.visual->blue_shift,
865 8 - klass->info.visual->blue_prec);
870 if (!klass->info.visual)
872 g_warning ("unable to find a suitable visual for color image display.\n");
876 /* If we are _not_ running with an installed cmap, we must run
877 * with the system visual. Otherwise, we let GDK pick the visual,
878 * and it makes some effort to pick a non-default visual, which
879 * will hopefully provide minimum color flashing.
881 if ((klass->info.visual->depth == gdk_visual_get_system()->depth) &&
882 (klass->info.visual->type == gdk_visual_get_system()->type) &&
885 klass->info.visual = gdk_visual_get_system();
888 switch (klass->info.visual->depth)
905 gtk_preview_get_cmaps (GtkPreviewClass *klass)
907 g_return_if_fail (klass != NULL);
908 g_return_if_fail (klass->info.visual != NULL);
910 if ((klass->info.visual->type != GDK_VISUAL_TRUE_COLOR) &&
911 (klass->info.visual->type != GDK_VISUAL_DIRECT_COLOR))
915 klass->info.cmap = gdk_colormap_new (klass->info.visual, FALSE);
916 klass->info.cmap_alloced = install_cmap;
918 gtk_trim_cmap (klass);
919 gtk_create_8_bit (klass);
929 klass->info.cmap = gdk_colormap_get_system ();
932 if (gtk_get_preview_prop (&nred, &ngreen, &nblue, &ngray))
936 klass->info.nred_shades = nred;
937 klass->info.ngreen_shades = ngreen;
938 klass->info.nblue_shades = nblue;
939 klass->info.ngray_shades = ngray;
941 if (klass->info.nreserved)
943 klass->info.reserved_pixels = g_new (gulong, klass->info.nreserved);
944 if (!gdk_colors_alloc (klass->info.cmap, 0, NULL, 0,
945 klass->info.reserved_pixels,
946 klass->info.nreserved))
948 g_free (klass->info.reserved_pixels);
949 klass->info.reserved_pixels = NULL;
955 gtk_trim_cmap (klass);
958 gtk_create_8_bit (klass);
961 gtk_set_preview_prop (klass->info.nred_shades,
962 klass->info.ngreen_shades,
963 klass->info.nblue_shades,
964 klass->info.ngray_shades);
969 if (klass->info.visual == gdk_visual_get_system ())
970 klass->info.cmap = gdk_colormap_get_system ();
973 klass->info.cmap = gdk_colormap_new (klass->info.visual, FALSE);
974 klass->info.cmap_alloced = TRUE;
977 klass->info.nred_shades = 0;
978 klass->info.ngreen_shades = 0;
979 klass->info.nblue_shades = 0;
980 klass->info.ngray_shades = 0;
985 gtk_preview_dither_init (GtkPreviewClass *klass)
988 unsigned char low_shade, high_shade;
989 unsigned short index;
990 long red_mult, green_mult;
991 double red_matrix_width;
992 double green_matrix_width;
993 double blue_matrix_width;
994 double gray_matrix_width;
995 double red_colors_per_shade;
996 double green_colors_per_shade;
997 double blue_colors_per_shade;
998 double gray_colors_per_shade;
1000 gint shades_r, shades_g, shades_b, shades_gray;
1001 GtkDitherInfo *red_ordered_dither;
1002 GtkDitherInfo *green_ordered_dither;
1003 GtkDitherInfo *blue_ordered_dither;
1004 GtkDitherInfo *gray_ordered_dither;
1005 guchar ***dither_matrix;
1008 { 0, 32, 8, 40, 2, 34, 10, 42 },
1009 { 48, 16, 56, 24, 50, 18, 58, 26 },
1010 { 12, 44, 4, 36, 14, 46, 6, 38 },
1011 { 60, 28, 52, 20, 62, 30, 54, 22 },
1012 { 3, 35, 11, 43, 1, 33, 9, 41 },
1013 { 51, 19, 59, 27, 49, 17, 57, 25 },
1014 { 15, 47, 7, 39, 13, 45, 5, 37 },
1015 { 63, 31, 55, 23, 61, 29, 53, 21 }
1018 if (!klass->info.visual || klass->info.visual->type != GDK_VISUAL_PSEUDO_COLOR)
1021 shades_r = klass->info.nred_shades;
1022 shades_g = klass->info.ngreen_shades;
1023 shades_b = klass->info.nblue_shades;
1024 shades_gray = klass->info.ngray_shades;
1026 red_mult = shades_g * shades_b;
1027 green_mult = shades_b;
1029 red_colors_per_shade = 255.0 / (shades_r - 1);
1030 red_matrix_width = red_colors_per_shade / 64;
1032 green_colors_per_shade = 255.0 / (shades_g - 1);
1033 green_matrix_width = green_colors_per_shade / 64;
1035 blue_colors_per_shade = 255.0 / (shades_b - 1);
1036 blue_matrix_width = blue_colors_per_shade / 64;
1038 gray_colors_per_shade = 255.0 / (shades_gray - 1);
1039 gray_matrix_width = gray_colors_per_shade / 64;
1041 /* alloc the ordered dither arrays for accelerated dithering */
1043 klass->info.dither_red = g_new (GtkDitherInfo, 256);
1044 klass->info.dither_green = g_new (GtkDitherInfo, 256);
1045 klass->info.dither_blue = g_new (GtkDitherInfo, 256);
1046 klass->info.dither_gray = g_new (GtkDitherInfo, 256);
1048 red_ordered_dither = klass->info.dither_red;
1049 green_ordered_dither = klass->info.dither_green;
1050 blue_ordered_dither = klass->info.dither_blue;
1051 gray_ordered_dither = klass->info.dither_gray;
1053 dither_matrix = g_new (guchar**, 8);
1054 for (i = 0; i < 8; i++)
1056 dither_matrix[i] = g_new (guchar*, 8);
1057 for (j = 0; j < 8; j++)
1058 dither_matrix[i][j] = g_new (guchar, 65);
1061 klass->info.dither_matrix = dither_matrix;
1063 /* setup the ordered_dither_matrices */
1065 for (i = 0; i < 8; i++)
1066 for (j = 0; j < 8; j++)
1067 for (k = 0; k <= 64; k++)
1068 dither_matrix[i][j][k] = (DM[i][j] < k) ? 1 : 0;
1070 /* setup arrays containing three bytes of information for red, green, & blue */
1071 /* the arrays contain :
1072 * 1st byte: low end shade value
1073 * 2nd byte: high end shade value
1074 * 3rd & 4th bytes: ordered dither matrix index
1077 gray_pixels = klass->info.gray_pixels;
1079 for (i = 0; i < 256; i++)
1082 /* setup the red information */
1084 low_shade = (unsigned char) (i / red_colors_per_shade);
1085 if (low_shade == (shades_r - 1))
1087 high_shade = low_shade + 1;
1089 index = (unsigned short)
1090 (((double) i - low_shade * red_colors_per_shade) /
1093 low_shade *= red_mult;
1094 high_shade *= red_mult;
1096 red_ordered_dither[i].s[1] = index;
1097 red_ordered_dither[i].c[0] = low_shade;
1098 red_ordered_dither[i].c[1] = high_shade;
1102 /* setup the green information */
1104 low_shade = (unsigned char) (i / green_colors_per_shade);
1105 if (low_shade == (shades_g - 1))
1107 high_shade = low_shade + 1;
1109 index = (unsigned short)
1110 (((double) i - low_shade * green_colors_per_shade) /
1111 green_matrix_width);
1113 low_shade *= green_mult;
1114 high_shade *= green_mult;
1116 green_ordered_dither[i].s[1] = index;
1117 green_ordered_dither[i].c[0] = low_shade;
1118 green_ordered_dither[i].c[1] = high_shade;
1122 /* setup the blue information */
1124 low_shade = (unsigned char) (i / blue_colors_per_shade);
1125 if (low_shade == (shades_b - 1))
1127 high_shade = low_shade + 1;
1129 index = (unsigned short)
1130 (((double) i - low_shade * blue_colors_per_shade) /
1133 blue_ordered_dither[i].s[1] = index;
1134 blue_ordered_dither[i].c[0] = low_shade;
1135 blue_ordered_dither[i].c[1] = high_shade;
1139 /* setup the gray information */
1141 low_shade = (unsigned char) (i / gray_colors_per_shade);
1142 if (low_shade == (shades_gray - 1))
1144 high_shade = low_shade + 1;
1146 index = (unsigned short)
1147 (((double) i - low_shade * gray_colors_per_shade) /
1150 gray_ordered_dither[i].s[1] = index;
1151 gray_ordered_dither[i].c[0] = gray_pixels[low_shade];
1152 gray_ordered_dither[i].c[1] = gray_pixels[high_shade];
1158 gtk_fill_lookup_array (gulong *array,
1163 double one_over_gamma;
1168 if (preview_class->info.gamma != 0.0)
1169 one_over_gamma = 1.0 / preview_class->info.gamma;
1171 one_over_gamma = 1.0;
1173 for (i = 0; i < 256; i++)
1175 if (one_over_gamma == 1.0)
1176 array[i] = ((i >> prec) << shift);
1179 ind = (double) i / 255.0;
1180 val = (int) (255 * pow (ind, one_over_gamma));
1181 array[i] = ((val >> prec) << shift);
1187 gtk_trim_cmap (GtkPreviewClass *klass)
1199 nred = klass->info.nred_shades;
1200 ngreen = klass->info.ngreen_shades;
1201 nblue = klass->info.nblue_shades;
1202 ngray = klass->info.ngray_shades;
1203 nreserved = klass->info.nreserved;
1208 total = nred * ngreen * nblue + ngray + nreserved;
1212 if ((nred < 2) || (ngreen < 2) || (nblue < 2) || (ngray < 2))
1216 success = gdk_colors_alloc (klass->info.cmap, 0, NULL, 0, pixels, total);
1221 klass->info.reserved_pixels = g_new (gulong, nreserved);
1222 memcpy (klass->info.reserved_pixels, pixels, sizeof (gulong) * nreserved);
1223 gdk_colors_free (klass->info.cmap, &pixels[nreserved],
1224 total - nreserved, 0);
1228 gdk_colors_free (klass->info.cmap, pixels, total, 0);
1236 if ((nblue >= nred) && (nblue >= ngreen))
1238 else if ((nred >= ngreen) && (nred >= nblue))
1242 tmp = log ((gdouble)ngray) / log (2.0);
1245 ngreen = ngreen - 1;
1252 if ((nred < 2) || (ngreen < 2) || (nblue < 2) || (ngray < 2))
1254 g_print ("Unable to allocate sufficient colormap entries.\n");
1255 g_print ("Try exiting other color intensive applications.\n");
1259 /* If any of the shade values has changed, issue a warning */
1260 if ((nred != klass->info.nred_shades) ||
1261 (ngreen != klass->info.ngreen_shades) ||
1262 (nblue != klass->info.nblue_shades) ||
1263 (ngray != klass->info.ngray_shades))
1265 g_print ("Not enough colors to satisfy requested color cube.\n");
1266 g_print ("Reduced color cube shades from\n");
1267 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",
1268 klass->info.nred_shades, klass->info.ngreen_shades,
1269 klass->info.nblue_shades, klass->info.ngray_shades,
1270 nred, ngreen, nblue, ngray);
1273 klass->info.nred_shades = nred;
1274 klass->info.ngreen_shades = ngreen;
1275 klass->info.nblue_shades = nblue;
1276 klass->info.ngray_shades = ngray;
1280 gtk_create_8_bit (GtkPreviewClass *klass)
1282 unsigned int r, g, b;
1283 unsigned int rv, gv, bv;
1284 unsigned int dr, dg, db, dgray;
1287 double one_over_gamma;
1290 if (!klass->info.color_pixels)
1291 klass->info.color_pixels = g_new (gulong, 256);
1293 if (!klass->info.gray_pixels)
1294 klass->info.gray_pixels = g_new (gulong, 256);
1296 if (klass->info.gamma != 0.0)
1297 one_over_gamma = 1.0 / klass->info.gamma;
1299 one_over_gamma = 1.0;
1301 dr = klass->info.nred_shades - 1;
1302 dg = klass->info.ngreen_shades - 1;
1303 db = klass->info.nblue_shades - 1;
1304 dgray = klass->info.ngray_shades - 1;
1306 pixels = klass->info.color_pixels;
1308 for (r = 0, i = 0; r <= dr; r++)
1309 for (g = 0; g <= dg; g++)
1310 for (b = 0; b <= db; b++, i++)
1312 rv = (unsigned int) ((r * klass->info.visual->colormap_size) / dr);
1313 gv = (unsigned int) ((g * klass->info.visual->colormap_size) / dg);
1314 bv = (unsigned int) ((b * klass->info.visual->colormap_size) / db);
1315 color.red = ((int) (255 * pow ((double) rv / 256.0, one_over_gamma))) * 257;
1316 color.green = ((int) (255 * pow ((double) gv / 256.0, one_over_gamma))) * 257;
1317 color.blue = ((int) (255 * pow ((double) bv / 256.0, one_over_gamma))) * 257;
1319 if (!gdk_color_alloc (klass->info.cmap, &color))
1321 g_error ("could not initialize 8-bit combined colormap");
1325 pixels[i] = color.pixel;
1329 pixels = klass->info.gray_pixels;
1331 for (i = 0; i < (int) klass->info.ngray_shades; i++)
1333 color.red = (i * klass->info.visual->colormap_size) / dgray;
1334 color.red = ((int) (255 * pow ((double) color.red / 256.0, one_over_gamma))) * 257;
1335 color.green = color.red;
1336 color.blue = color.red;
1338 if (!gdk_color_alloc (klass->info.cmap, &color))
1340 g_error ("could not initialize 8-bit combined colormap");
1344 pixels[i] = color.pixel;
1350 gtk_color_8 (guchar *src,
1357 GtkDitherInfo *dither_red;
1358 GtkDitherInfo *dither_green;
1359 GtkDitherInfo *dither_blue;
1360 GtkDitherInfo r, g, b;
1361 guchar **dither_matrix;
1364 colors = preview_class->info.color_pixels;
1365 dither_red = preview_class->info.dither_red;
1366 dither_green = preview_class->info.dither_green;
1367 dither_blue = preview_class->info.dither_blue;
1368 dither_matrix = preview_class->info.dither_matrix[y & 0x7];
1372 r = dither_red[src[0]];
1373 g = dither_green[src[1]];
1374 b = dither_blue[src[2]];
1377 matrix = dither_matrix[x++ & 0x7];
1378 *dest++ = colors[(r.c[matrix[r.s[1]]] +
1379 g.c[matrix[g.s[1]]] +
1380 b.c[matrix[b.s[1]]])];
1385 gtk_color_16 (guchar *src,
1390 gulong *lookup_green;
1391 gulong *lookup_blue;
1394 lookup_red = preview_class->info.lookup_red;
1395 lookup_green = preview_class->info.lookup_green;
1396 lookup_blue = preview_class->info.lookup_blue;
1400 val = COLOR_COMPOSE (src[0], src[1], src[2]);
1409 gtk_color_24 (guchar *src,
1414 gulong *lookup_green;
1415 gulong *lookup_blue;
1418 lookup_red = preview_class->info.lookup_red;
1419 lookup_green = preview_class->info.lookup_green;
1420 lookup_blue = preview_class->info.lookup_blue;
1424 val = COLOR_COMPOSE (src[0], src[1], src[2]);
1427 dest[2] = val >> 16;
1434 gtk_grayscale_8 (guchar *src,
1440 GtkDitherInfo *dither_gray;
1442 guchar **dither_matrix;
1445 dither_gray = preview_class->info.dither_gray;
1446 dither_matrix = preview_class->info.dither_matrix[y & 0x7];
1450 gray = dither_gray[*src++];
1451 matrix = dither_matrix[x++ & 0x7];
1452 *dest++ = gray.c[matrix[gray.s[1]]];
1457 gtk_grayscale_16 (guchar *src,
1462 gulong *lookup_green;
1463 gulong *lookup_blue;
1466 lookup_red = preview_class->info.lookup_red;
1467 lookup_green = preview_class->info.lookup_green;
1468 lookup_blue = preview_class->info.lookup_blue;
1472 val = COLOR_COMPOSE (*src, *src, *src);
1481 gtk_grayscale_24 (guchar *src,
1486 gulong *lookup_green;
1487 gulong *lookup_blue;
1490 lookup_red = preview_class->info.lookup_red;
1491 lookup_green = preview_class->info.lookup_green;
1492 lookup_blue = preview_class->info.lookup_blue;
1496 val = COLOR_COMPOSE (*src, *src, *src);
1499 dest[2] = val >> 16;
1507 gtk_get_preview_prop (guint *nred,
1512 GtkPreviewProp *prop;
1515 /* FIXME: need to grab the server here to prevent a race condition */
1517 property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE);
1519 if (gdk_property_get (NULL, property, property,
1520 0, sizeof (GtkPreviewProp), FALSE,
1521 NULL, NULL, NULL, (guchar**) &prop))
1523 *nred = prop->nred_shades;
1524 *ngreen = prop->ngreen_shades;
1525 *nblue = prop->nblue_shades;
1526 *ngray = prop->ngray_shades;
1528 prop->ref_count = prop->ref_count + 1;
1529 gdk_property_change (NULL, property, property, 16,
1530 GDK_PROP_MODE_REPLACE,
1540 gtk_set_preview_prop (guint nred,
1545 GtkPreviewProp prop;
1548 property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE);
1551 prop.nred_shades = nred;
1552 prop.ngreen_shades = ngreen;
1553 prop.nblue_shades = nblue;
1554 prop.ngray_shades = ngray;
1556 gdk_property_change (NULL, property, property, 16,
1557 GDK_PROP_MODE_REPLACE,
1558 (guchar*) &prop, 5);
1563 gtk_lsbmsb_1_1 (guchar *dest,
1567 memcpy (dest, src, count);
1571 gtk_lsb_2_2 (guchar *dest,
1575 memcpy (dest, src, count * 2);
1579 gtk_msb_2_2 (guchar *dest,
1593 gtk_lsb_3_3 (guchar *dest,
1597 memcpy (dest, src, count * 3);
1601 gtk_msb_3_3 (guchar *dest,
1616 gtk_lsb_3_4 (guchar *dest,
1631 gtk_msb_3_4 (guchar *dest,