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 Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include <sys/types.h>
22 #include <sys/param.h>
24 #include "gtkpreview.h"
25 #include "gtksignal.h"
28 #define IMAGE_SIZE 256
29 #define PREVIEW_CLASS(w) GTK_PREVIEW_CLASS (GTK_OBJECT (w)->klass)
30 #define COLOR_COMPOSE(r,g,b) (lookup_red[r] | lookup_green[g] | lookup_blue[b])
33 typedef struct _GtkPreviewProp GtkPreviewProp;
34 typedef void (*GtkTransferFunc) (guchar *dest, guchar *src, gint count);
36 struct _GtkPreviewProp
40 guint16 ngreen_shades;
46 static void gtk_preview_class_init (GtkPreviewClass *klass);
47 static void gtk_preview_init (GtkPreview *preview);
48 static void gtk_preview_finalize (GtkObject *object);
49 static void gtk_preview_realize (GtkWidget *widget);
50 static gint gtk_preview_expose (GtkWidget *widget,
51 GdkEventExpose *event);
52 static void gtk_preview_make_buffer (GtkPreview *preview);
53 static void gtk_preview_get_visuals (GtkPreviewClass *klass);
54 static void gtk_preview_get_cmaps (GtkPreviewClass *klass);
55 static void gtk_preview_dither_init (GtkPreviewClass *klass);
56 static void gtk_fill_lookup_array (gulong *array,
60 static void gtk_trim_cmap (GtkPreviewClass *klass);
61 static void gtk_create_8_bit (GtkPreviewClass *klass);
63 static void gtk_color_8 (guchar *src,
68 static void gtk_color_16 (guchar *src,
71 static void gtk_color_24 (guchar *src,
74 static void gtk_grayscale_8 (guchar *src,
79 static void gtk_grayscale_16 (guchar *src,
82 static void gtk_grayscale_24 (guchar *src,
86 static gint gtk_get_preview_prop (guint *nred,
90 static void gtk_set_preview_prop (guint nred,
95 /* transfer functions:
96 * destination byte order/source bpp/destination bpp
98 static void gtk_lsbmsb_1_1 (guchar *dest,
101 static void gtk_lsb_2_2 (guchar *dest,
104 static void gtk_msb_2_2 (guchar *dest,
107 static void gtk_lsb_3_3 (guchar *dest,
110 static void gtk_msb_3_3 (guchar *dest,
113 static void gtk_lsb_3_4 (guchar *dest,
116 static void gtk_msb_3_4 (guchar *dest,
121 static GtkWidgetClass *parent_class = NULL;
122 static GtkPreviewClass *preview_class = NULL;
123 static GtkPreviewInfo *preview_info = NULL;
124 static gint install_cmap = FALSE;
128 gtk_preview_get_type ()
130 static guint preview_type = 0;
134 GtkTypeInfo preview_info =
138 sizeof (GtkPreviewClass),
139 (GtkClassInitFunc) gtk_preview_class_init,
140 (GtkObjectInitFunc) gtk_preview_init,
141 (GtkArgSetFunc) NULL,
142 (GtkArgGetFunc) NULL,
145 preview_type = gtk_type_unique (gtk_widget_get_type (), &preview_info);
152 gtk_preview_class_init (GtkPreviewClass *klass)
154 GtkObjectClass *object_class;
155 GtkWidgetClass *widget_class;
157 object_class = (GtkObjectClass*) klass;
158 widget_class = (GtkWidgetClass*) klass;
160 parent_class = gtk_type_class (gtk_widget_get_type ());
161 preview_class = klass;
163 object_class->finalize = gtk_preview_finalize;
165 widget_class->realize = gtk_preview_realize;
166 widget_class->expose_event = gtk_preview_expose;
169 klass->info = *preview_info;
172 klass->info.visual = NULL;
173 klass->info.cmap = NULL;
175 klass->info.color_pixels = NULL;
176 klass->info.gray_pixels = NULL;
177 klass->info.reserved_pixels = NULL;
179 klass->info.lookup_red = NULL;
180 klass->info.lookup_green = NULL;
181 klass->info.lookup_blue = NULL;
183 klass->info.dither_red = NULL;
184 klass->info.dither_green = NULL;
185 klass->info.dither_blue = NULL;
186 klass->info.dither_gray = NULL;
187 klass->info.dither_matrix = NULL;
189 klass->info.nred_shades = 6;
190 klass->info.ngreen_shades = 6;
191 klass->info.nblue_shades = 4;
192 klass->info.ngray_shades = 24;
193 klass->info.nreserved = 0;
196 klass->info.cmap_alloced = FALSE;
197 klass->info.gamma = 1.0;
202 gtk_preview_get_visuals (klass);
203 gtk_preview_get_cmaps (klass);
204 gtk_preview_dither_init (klass);
208 gtk_preview_reset (void)
210 GtkPreviewInfo *info;
212 if (!preview_class || !preview_info)
215 info = &preview_class->info;
217 gtk_preview_uninit();
219 if (info->color_pixels)
221 gdk_colors_free (info->cmap,
224 info->ngreen_shades *
228 gdk_colors_free (info->cmap,
230 info->ngray_shades, 0);
232 g_free (info->color_pixels);
233 g_free (info->gray_pixels);
236 if (info->reserved_pixels)
238 gdk_colors_free (info->cmap,
239 info->reserved_pixels,
241 g_free (info->reserved_pixels);
244 if (info->cmap && info->cmap_alloced)
245 gdk_colormap_unref (info->cmap);
247 if (info->lookup_red)
249 g_free (info->lookup_red);
250 g_free (info->lookup_green);
251 g_free (info->lookup_blue);
254 if (info->dither_matrix)
258 for (i= 0 ; i < 8 ; i++)
260 for (j = 0; j < 8 ; j++)
261 g_free (info->dither_matrix[i][j]);
262 g_free (info->dither_matrix[i]);
264 g_free (info->dither_matrix);
265 g_free (info->dither_red);
266 g_free (info->dither_green);
267 g_free (info->dither_blue);
270 preview_class->info = *preview_info;
272 gtk_preview_get_visuals (preview_class);
273 gtk_preview_get_cmaps (preview_class);
274 gtk_preview_dither_init (preview_class);
278 gtk_preview_init (GtkPreview *preview)
280 GTK_WIDGET_SET_FLAGS (preview, GTK_BASIC);
282 preview->buffer = NULL;
283 preview->buffer_width = 0;
284 preview->buffer_height = 0;
285 preview->expand = FALSE;
289 gtk_preview_uninit ()
291 GtkPreviewProp *prop;
294 /* FIXME: need to grab the server here to prevent a race condition */
296 if (preview_class && !install_cmap && preview_class->info.visual &&
297 (preview_class->info.visual->type != GDK_VISUAL_TRUE_COLOR) &&
298 (preview_class->info.visual->type != GDK_VISUAL_DIRECT_COLOR))
300 property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE);
302 if (gdk_property_get (NULL, property, property,
303 0, sizeof (GtkPreviewProp), FALSE,
304 NULL, NULL, NULL, (guchar**) &prop))
306 prop->ref_count = prop->ref_count - 1;
307 if (prop->ref_count == 0)
309 gdk_property_delete (NULL, property);
313 gdk_property_change (NULL, property, property, 16,
314 GDK_PROP_MODE_REPLACE,
322 gtk_preview_new (GtkPreviewType type)
326 preview = gtk_type_new (gtk_preview_get_type ());
327 preview->type = type;
329 return GTK_WIDGET (preview);
333 gtk_preview_size (GtkPreview *preview,
337 g_return_if_fail (preview != NULL);
338 g_return_if_fail (GTK_IS_PREVIEW (preview));
340 if ((width != GTK_WIDGET (preview)->requisition.width) ||
341 (height != GTK_WIDGET (preview)->requisition.height))
343 GTK_WIDGET (preview)->requisition.width = width;
344 GTK_WIDGET (preview)->requisition.height = height;
347 g_free (preview->buffer);
348 preview->buffer = NULL;
353 gtk_preview_put (GtkPreview *preview,
365 GdkRectangle r1, r2, r3;
366 GtkTransferFunc transfer_func;
371 guint dest_rowstride;
376 g_return_if_fail (preview != NULL);
377 g_return_if_fail (GTK_IS_PREVIEW (preview));
378 g_return_if_fail (window != NULL);
380 if (!preview->buffer)
383 widget = GTK_WIDGET (preview);
387 r1.width = preview->buffer_width;
388 r1.height = preview->buffer_height;
395 if (!gdk_rectangle_intersect (&r1, &r2, &r3))
398 x2 = r3.x + r3.width;
399 y2 = r3.y + r3.height;
401 if (!preview_class->image)
402 preview_class->image = gdk_image_new (GDK_IMAGE_FASTEST,
403 preview_class->info.visual,
404 IMAGE_SIZE, IMAGE_SIZE);
405 image = preview_class->image;
406 src_bpp = preview_class->info.bpp;
408 image_mem = image->mem;
409 dest_bpp = image->bpp;
410 dest_rowstride = image->bpl;
412 transfer_func = NULL;
420 transfer_func = gtk_lsbmsb_1_1;
428 if (image->byte_order == GDK_MSB_FIRST)
429 transfer_func = gtk_msb_2_2;
431 transfer_func = gtk_lsb_2_2;
441 if (image->byte_order == GDK_MSB_FIRST)
442 transfer_func = gtk_msb_3_3;
444 transfer_func = gtk_lsb_3_3;
452 if (image->byte_order == GDK_MSB_FIRST)
453 transfer_func = gtk_msb_3_4;
455 transfer_func = gtk_lsb_3_4;
463 g_warning ("unsupported byte order/src bpp/dest bpp combination: %s:%d:%d",
464 (image->byte_order == GDK_MSB_FIRST) ? "msb" : "lsb", src_bpp, dest_bpp);
468 for (y = r3.y; y < y2; y += IMAGE_SIZE)
470 for (x = r3.x; x < x2; x += IMAGE_SIZE)
480 for (i = y; i < ye; i++)
482 src = preview->buffer + (((gulong) (i - r1.y) * (gulong) preview->buffer_width) +
483 (x - r1.x)) * (gulong) src_bpp;
484 dest = image_mem + ((gulong) (i - y) * dest_rowstride);
487 (* transfer_func) (dest, src, xe - x);
490 gdk_draw_image (window, gc,
492 destx + (r3.x - srcx) + (x - r3.x),
493 desty + (r3.y - srcy) + (y - r3.y),
501 gtk_preview_put_row (GtkPreview *preview,
508 g_return_if_fail (preview != NULL);
509 g_return_if_fail (GTK_IS_PREVIEW (preview));
510 g_return_if_fail (src != NULL);
511 g_return_if_fail (dest != NULL);
513 switch (preview->type)
515 case GTK_PREVIEW_COLOR:
516 switch (preview_class->info.visual->depth)
519 gtk_color_8 (src, dest, x, y, w);
523 gtk_color_16 (src, dest, w);
527 gtk_color_24 (src, dest, w);
531 case GTK_PREVIEW_GRAYSCALE:
532 switch (preview_class->info.visual->depth)
535 gtk_grayscale_8 (src, dest, x, y, w);
539 gtk_grayscale_16 (src, dest, w);
543 gtk_grayscale_24 (src, dest, w);
551 gtk_preview_draw_row (GtkPreview *preview,
559 g_return_if_fail (preview != NULL);
560 g_return_if_fail (GTK_IS_PREVIEW (preview));
561 g_return_if_fail (data != NULL);
562 g_return_if_fail (preview_class->info.visual != NULL);
564 if ((w <= 0) || (y < 0))
567 g_return_if_fail (data != NULL);
569 gtk_preview_make_buffer (preview);
571 if (y >= preview->buffer_height)
574 switch (preview->type)
576 case GTK_PREVIEW_COLOR:
577 switch (preview_class->info.visual->depth)
580 dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x);
581 gtk_color_8 (data, dest, x, y, w);
585 dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 2;
586 gtk_color_16 (data, dest, w);
590 dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 3;
591 gtk_color_24 (data, dest, w);
595 case GTK_PREVIEW_GRAYSCALE:
596 switch (preview_class->info.visual->depth)
599 dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x);
600 gtk_grayscale_8 (data, dest, x, y, w);
604 dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 2;
605 gtk_grayscale_16 (data, dest, w);
609 dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 3;
610 gtk_grayscale_24 (data, dest, w);
618 gtk_preview_set_expand (GtkPreview *preview,
621 g_return_if_fail (preview != NULL);
622 g_return_if_fail (GTK_IS_PREVIEW (preview));
624 preview->expand = (expand != FALSE);
628 gtk_preview_set_gamma (double _gamma)
632 preview_info = g_new0 (GtkPreviewInfo, 1);
633 preview_info->nred_shades = 6;
634 preview_info->ngreen_shades = 6;
635 preview_info->nblue_shades = 4;
636 preview_info->ngray_shades = 24;
639 preview_info->gamma = _gamma;
643 gtk_preview_set_color_cube (guint nred_shades,
650 preview_info = g_new0 (GtkPreviewInfo, 1);
651 preview_info->gamma = 1.0;
654 preview_info->nred_shades = nred_shades;
655 preview_info->ngreen_shades = ngreen_shades;
656 preview_info->nblue_shades = nblue_shades;
657 preview_info->ngray_shades = ngray_shades;
661 gtk_preview_set_install_cmap (gint _install_cmap)
663 install_cmap = _install_cmap;
667 gtk_preview_set_reserved (gint nreserved)
670 preview_info = g_new0 (GtkPreviewInfo, 1);
672 preview_info->nreserved = nreserved;
676 gtk_preview_get_visual ()
679 preview_class = gtk_type_class (gtk_preview_get_type ());
681 return preview_class->info.visual;
685 gtk_preview_get_cmap ()
688 preview_class = gtk_type_class (gtk_preview_get_type ());
690 return preview_class->info.cmap;
694 gtk_preview_get_info ()
697 preview_class = gtk_type_class (gtk_preview_get_type ());
699 return &preview_class->info;
704 gtk_preview_finalize (GtkObject *object)
708 g_return_if_fail (object != NULL);
709 g_return_if_fail (GTK_IS_PREVIEW (object));
711 preview = GTK_PREVIEW (object);
713 g_free (preview->buffer);
714 preview->type = (GtkPreviewType) -1;
716 (* GTK_OBJECT_CLASS (parent_class)->finalize) (object);
720 gtk_preview_realize (GtkWidget *widget)
723 GdkWindowAttr attributes;
724 gint attributes_mask;
726 g_return_if_fail (widget != NULL);
727 g_return_if_fail (GTK_IS_PREVIEW (widget));
729 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
730 preview = GTK_PREVIEW (widget);
732 attributes.window_type = GDK_WINDOW_CHILD;
733 attributes.x = widget->allocation.x;
734 attributes.y = widget->allocation.y;
735 attributes.width = widget->allocation.width;
736 attributes.height = widget->allocation.height;
737 attributes.wclass = GDK_INPUT_OUTPUT;
738 attributes.visual = gtk_widget_get_visual (widget);
739 attributes.colormap = gtk_widget_get_colormap (widget);
740 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
741 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
743 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
744 gdk_window_set_user_data (widget->window, widget);
746 widget->style = gtk_style_attach (widget->style, widget->window);
747 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
751 gtk_preview_expose (GtkWidget *widget,
752 GdkEventExpose *event)
756 g_return_val_if_fail (widget != NULL, FALSE);
757 g_return_val_if_fail (GTK_IS_PREVIEW (widget), FALSE);
758 g_return_val_if_fail (event != NULL, FALSE);
760 if (GTK_WIDGET_DRAWABLE (widget))
762 preview = GTK_PREVIEW (widget);
764 gtk_preview_put (GTK_PREVIEW (widget),
765 widget->window, widget->style->black_gc,
767 (widget->allocation.width - preview->buffer_width)/2,
769 (widget->allocation.height - preview->buffer_height)/2,
770 event->area.x, event->area.y,
771 event->area.width, event->area.height);
778 gtk_preview_make_buffer (GtkPreview *preview)
784 g_return_if_fail (preview != NULL);
785 g_return_if_fail (GTK_IS_PREVIEW (preview));
787 widget = GTK_WIDGET (preview);
789 if (preview->expand &&
790 (widget->allocation.width != 0) &&
791 (widget->allocation.height != 0))
793 width = widget->allocation.width;
794 height = widget->allocation.height;
798 width = widget->requisition.width;
799 height = widget->requisition.height;
802 if (!preview->buffer ||
803 (preview->buffer_width != width) ||
804 (preview->buffer_height != height))
807 g_free (preview->buffer);
809 preview->buffer_width = width;
810 preview->buffer_height = height;
812 preview->buffer = g_new0 (guchar,
813 preview->buffer_width *
814 preview->buffer_height *
815 preview_class->info.bpp);
820 gtk_preview_get_visuals (GtkPreviewClass *klass)
822 static GdkVisualType types[] =
824 GDK_VISUAL_TRUE_COLOR,
825 GDK_VISUAL_DIRECT_COLOR,
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_PSEUDO_COLOR
834 static gint depths[] = { 24, 24, 32, 32, 16, 16, 15, 15, 8 };
835 static gint nvisual_types = sizeof (types) / sizeof (types[0]);
839 g_return_if_fail (klass != NULL);
841 if (!klass->info.visual)
842 for (i = 0; i < nvisual_types; i++)
843 if ((klass->info.visual = gdk_visual_get_best_with_both (depths[i], types[i])))
845 if ((klass->info.visual->type == GDK_VISUAL_TRUE_COLOR) ||
846 (klass->info.visual->type == GDK_VISUAL_DIRECT_COLOR))
848 klass->info.lookup_red = g_new (gulong, 256);
849 klass->info.lookup_green = g_new (gulong, 256);
850 klass->info.lookup_blue = g_new (gulong, 256);
852 gtk_fill_lookup_array (klass->info.lookup_red,
853 klass->info.visual->depth,
854 klass->info.visual->red_shift,
855 8 - klass->info.visual->red_prec);
856 gtk_fill_lookup_array (klass->info.lookup_green,
857 klass->info.visual->depth,
858 klass->info.visual->green_shift,
859 8 - klass->info.visual->green_prec);
860 gtk_fill_lookup_array (klass->info.lookup_blue,
861 klass->info.visual->depth,
862 klass->info.visual->blue_shift,
863 8 - klass->info.visual->blue_prec);
868 if (!klass->info.visual)
870 g_warning ("unable to find a suitable visual for color image display.\n");
874 switch (klass->info.visual->depth)
891 gtk_preview_get_cmaps (GtkPreviewClass *klass)
893 g_return_if_fail (klass != NULL);
894 g_return_if_fail (klass->info.visual != NULL);
896 if ((klass->info.visual->type != GDK_VISUAL_TRUE_COLOR) &&
897 (klass->info.visual->type != GDK_VISUAL_DIRECT_COLOR))
901 klass->info.cmap = gdk_colormap_new (klass->info.visual, FALSE);
902 klass->info.cmap_alloced = install_cmap;
904 gtk_trim_cmap (klass);
905 gtk_create_8_bit (klass);
915 klass->info.cmap = gdk_colormap_get_system ();
918 if (gtk_get_preview_prop (&nred, &ngreen, &nblue, &ngray))
922 klass->info.nred_shades = nred;
923 klass->info.ngreen_shades = ngreen;
924 klass->info.nblue_shades = nblue;
925 klass->info.ngray_shades = ngray;
927 if (klass->info.nreserved)
929 klass->info.reserved_pixels = g_new (gulong, klass->info.nreserved);
930 if (!gdk_colors_alloc (klass->info.cmap, 0, NULL, 0,
931 klass->info.reserved_pixels,
932 klass->info.nreserved))
934 g_free (klass->info.reserved_pixels);
935 klass->info.reserved_pixels = NULL;
941 gtk_trim_cmap (klass);
944 gtk_create_8_bit (klass);
947 gtk_set_preview_prop (klass->info.nred_shades,
948 klass->info.ngreen_shades,
949 klass->info.nblue_shades,
950 klass->info.ngray_shades);
955 if (klass->info.visual == gdk_visual_get_system ())
956 klass->info.cmap = gdk_colormap_get_system ();
959 klass->info.cmap = gdk_colormap_new (klass->info.visual, FALSE);
960 klass->info.cmap_alloced = TRUE;
963 klass->info.nred_shades = 0;
964 klass->info.ngreen_shades = 0;
965 klass->info.nblue_shades = 0;
966 klass->info.ngray_shades = 0;
971 gtk_preview_dither_init (GtkPreviewClass *klass)
974 unsigned char low_shade, high_shade;
975 unsigned short index;
976 long red_mult, green_mult;
977 double red_matrix_width;
978 double green_matrix_width;
979 double blue_matrix_width;
980 double gray_matrix_width;
981 double red_colors_per_shade;
982 double green_colors_per_shade;
983 double blue_colors_per_shade;
984 double gray_colors_per_shade;
986 gint shades_r, shades_g, shades_b, shades_gray;
987 GtkDitherInfo *red_ordered_dither;
988 GtkDitherInfo *green_ordered_dither;
989 GtkDitherInfo *blue_ordered_dither;
990 GtkDitherInfo *gray_ordered_dither;
991 guchar ***dither_matrix;
994 { 0, 32, 8, 40, 2, 34, 10, 42 },
995 { 48, 16, 56, 24, 50, 18, 58, 26 },
996 { 12, 44, 4, 36, 14, 46, 6, 38 },
997 { 60, 28, 52, 20, 62, 30, 54, 22 },
998 { 3, 35, 11, 43, 1, 33, 9, 41 },
999 { 51, 19, 59, 27, 49, 17, 57, 25 },
1000 { 15, 47, 7, 39, 13, 45, 5, 37 },
1001 { 63, 31, 55, 23, 61, 29, 53, 21 }
1004 if (!klass->info.visual || klass->info.visual->type != GDK_VISUAL_PSEUDO_COLOR)
1007 shades_r = klass->info.nred_shades;
1008 shades_g = klass->info.ngreen_shades;
1009 shades_b = klass->info.nblue_shades;
1010 shades_gray = klass->info.ngray_shades;
1012 red_mult = shades_g * shades_b;
1013 green_mult = shades_b;
1015 red_colors_per_shade = 255.0 / (shades_r - 1);
1016 red_matrix_width = red_colors_per_shade / 64;
1018 green_colors_per_shade = 255.0 / (shades_g - 1);
1019 green_matrix_width = green_colors_per_shade / 64;
1021 blue_colors_per_shade = 255.0 / (shades_b - 1);
1022 blue_matrix_width = blue_colors_per_shade / 64;
1024 gray_colors_per_shade = 255.0 / (shades_gray - 1);
1025 gray_matrix_width = gray_colors_per_shade / 64;
1027 /* alloc the ordered dither arrays for accelerated dithering */
1029 klass->info.dither_red = g_new (GtkDitherInfo, 256);
1030 klass->info.dither_green = g_new (GtkDitherInfo, 256);
1031 klass->info.dither_blue = g_new (GtkDitherInfo, 256);
1032 klass->info.dither_gray = g_new (GtkDitherInfo, 256);
1034 red_ordered_dither = klass->info.dither_red;
1035 green_ordered_dither = klass->info.dither_green;
1036 blue_ordered_dither = klass->info.dither_blue;
1037 gray_ordered_dither = klass->info.dither_gray;
1039 dither_matrix = g_new (guchar**, 8);
1040 for (i = 0; i < 8; i++)
1042 dither_matrix[i] = g_new (guchar*, 8);
1043 for (j = 0; j < 8; j++)
1044 dither_matrix[i][j] = g_new (guchar, 65);
1047 klass->info.dither_matrix = dither_matrix;
1049 /* setup the ordered_dither_matrices */
1051 for (i = 0; i < 8; i++)
1052 for (j = 0; j < 8; j++)
1053 for (k = 0; k <= 64; k++)
1054 dither_matrix[i][j][k] = (DM[i][j] < k) ? 1 : 0;
1056 /* setup arrays containing three bytes of information for red, green, & blue */
1057 /* the arrays contain :
1058 * 1st byte: low end shade value
1059 * 2nd byte: high end shade value
1060 * 3rd & 4th bytes: ordered dither matrix index
1063 gray_pixels = klass->info.gray_pixels;
1065 for (i = 0; i < 256; i++)
1068 /* setup the red information */
1070 low_shade = (unsigned char) (i / red_colors_per_shade);
1071 if (low_shade == (shades_r - 1))
1073 high_shade = low_shade + 1;
1075 index = (unsigned short)
1076 (((double) i - low_shade * red_colors_per_shade) /
1079 low_shade *= red_mult;
1080 high_shade *= red_mult;
1082 red_ordered_dither[i].s[1] = index;
1083 red_ordered_dither[i].c[0] = low_shade;
1084 red_ordered_dither[i].c[1] = high_shade;
1088 /* setup the green information */
1090 low_shade = (unsigned char) (i / green_colors_per_shade);
1091 if (low_shade == (shades_g - 1))
1093 high_shade = low_shade + 1;
1095 index = (unsigned short)
1096 (((double) i - low_shade * green_colors_per_shade) /
1097 green_matrix_width);
1099 low_shade *= green_mult;
1100 high_shade *= green_mult;
1102 green_ordered_dither[i].s[1] = index;
1103 green_ordered_dither[i].c[0] = low_shade;
1104 green_ordered_dither[i].c[1] = high_shade;
1108 /* setup the blue information */
1110 low_shade = (unsigned char) (i / blue_colors_per_shade);
1111 if (low_shade == (shades_b - 1))
1113 high_shade = low_shade + 1;
1115 index = (unsigned short)
1116 (((double) i - low_shade * blue_colors_per_shade) /
1119 blue_ordered_dither[i].s[1] = index;
1120 blue_ordered_dither[i].c[0] = low_shade;
1121 blue_ordered_dither[i].c[1] = high_shade;
1125 /* setup the gray information */
1127 low_shade = (unsigned char) (i / gray_colors_per_shade);
1128 if (low_shade == (shades_gray - 1))
1130 high_shade = low_shade + 1;
1132 index = (unsigned short)
1133 (((double) i - low_shade * gray_colors_per_shade) /
1136 gray_ordered_dither[i].s[1] = index;
1137 gray_ordered_dither[i].c[0] = gray_pixels[low_shade];
1138 gray_ordered_dither[i].c[1] = gray_pixels[high_shade];
1144 gtk_fill_lookup_array (gulong *array,
1149 double one_over_gamma;
1154 if (preview_class->info.gamma != 0.0)
1155 one_over_gamma = 1.0 / preview_class->info.gamma;
1157 one_over_gamma = 1.0;
1159 for (i = 0; i < 256; i++)
1161 if (one_over_gamma == 1.0)
1162 array[i] = ((i >> prec) << shift);
1165 ind = (double) i / 255.0;
1166 val = (int) (255 * pow (ind, one_over_gamma));
1167 array[i] = ((val >> prec) << shift);
1173 gtk_trim_cmap (GtkPreviewClass *klass)
1185 nred = klass->info.nred_shades;
1186 ngreen = klass->info.ngreen_shades;
1187 nblue = klass->info.nblue_shades;
1188 ngray = klass->info.ngray_shades;
1189 nreserved = klass->info.nreserved;
1194 total = nred * ngreen * nblue + ngray + nreserved;
1198 if ((nred < 2) || (ngreen < 2) || (nblue < 2) || (ngray < 2))
1202 success = gdk_colors_alloc (klass->info.cmap, 0, NULL, 0, pixels, total);
1207 klass->info.reserved_pixels = g_new (gulong, nreserved);
1208 memcpy (klass->info.reserved_pixels, pixels, sizeof (gulong) * nreserved);
1209 gdk_colors_free (klass->info.cmap, &pixels[nreserved],
1210 total - nreserved, 0);
1214 gdk_colors_free (klass->info.cmap, pixels, total, 0);
1222 if ((nblue >= nred) && (nblue >= ngreen))
1224 else if ((nred >= ngreen) && (nred >= nblue))
1228 tmp = log (ngray) / log (2);
1231 ngreen = ngreen - 1;
1238 if ((nred < 2) || (ngreen < 2) || (nblue < 2) || (ngray < 2))
1240 g_print ("Unable to allocate sufficient colormap entries.\n");
1241 g_print ("Try exiting other color intensive applications.\n");
1245 /* If any of the shade values has changed, issue a warning */
1246 if ((nred != klass->info.nred_shades) ||
1247 (ngreen != klass->info.ngreen_shades) ||
1248 (nblue != klass->info.nblue_shades) ||
1249 (ngray != klass->info.ngray_shades))
1251 g_print ("Not enough colors to satisfy requested color cube.\n");
1252 g_print ("Reduced color cube shades from\n");
1253 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",
1254 klass->info.nred_shades, klass->info.ngreen_shades,
1255 klass->info.nblue_shades, klass->info.ngray_shades,
1256 nred, ngreen, nblue, ngray);
1259 klass->info.nred_shades = nred;
1260 klass->info.ngreen_shades = ngreen;
1261 klass->info.nblue_shades = nblue;
1262 klass->info.ngray_shades = ngray;
1266 gtk_create_8_bit (GtkPreviewClass *klass)
1268 unsigned int r, g, b;
1269 unsigned int rv, gv, bv;
1270 unsigned int dr, dg, db, dgray;
1273 double one_over_gamma;
1276 if (!klass->info.color_pixels)
1277 klass->info.color_pixels = g_new (gulong, 256);
1279 if (!klass->info.gray_pixels)
1280 klass->info.gray_pixels = g_new (gulong, 256);
1282 if (klass->info.gamma != 0.0)
1283 one_over_gamma = 1.0 / klass->info.gamma;
1285 one_over_gamma = 1.0;
1287 dr = klass->info.nred_shades - 1;
1288 dg = klass->info.ngreen_shades - 1;
1289 db = klass->info.nblue_shades - 1;
1290 dgray = klass->info.ngray_shades - 1;
1292 pixels = klass->info.color_pixels;
1294 for (r = 0, i = 0; r <= dr; r++)
1295 for (g = 0; g <= dg; g++)
1296 for (b = 0; b <= db; b++, i++)
1298 rv = (unsigned int) ((r * klass->info.visual->colormap_size) / dr);
1299 gv = (unsigned int) ((g * klass->info.visual->colormap_size) / dg);
1300 bv = (unsigned int) ((b * klass->info.visual->colormap_size) / db);
1301 color.red = ((int) (255 * pow ((double) rv / 256.0, one_over_gamma))) * 257;
1302 color.green = ((int) (255 * pow ((double) gv / 256.0, one_over_gamma))) * 257;
1303 color.blue = ((int) (255 * pow ((double) bv / 256.0, one_over_gamma))) * 257;
1305 if (!gdk_color_alloc (klass->info.cmap, &color))
1307 g_error ("could not initialize 8-bit combined colormap");
1311 pixels[i] = color.pixel;
1315 pixels = klass->info.gray_pixels;
1317 for (i = 0; i < (int) klass->info.ngray_shades; i++)
1319 color.red = (i * klass->info.visual->colormap_size) / dgray;
1320 color.red = ((int) (255 * pow ((double) color.red / 256.0, one_over_gamma))) * 257;
1321 color.green = color.red;
1322 color.blue = color.red;
1324 if (!gdk_color_alloc (klass->info.cmap, &color))
1326 g_error ("could not initialize 8-bit combined colormap");
1330 pixels[i] = color.pixel;
1336 gtk_color_8 (guchar *src,
1343 GtkDitherInfo *dither_red;
1344 GtkDitherInfo *dither_green;
1345 GtkDitherInfo *dither_blue;
1346 GtkDitherInfo r, g, b;
1347 guchar **dither_matrix;
1350 colors = preview_class->info.color_pixels;
1351 dither_red = preview_class->info.dither_red;
1352 dither_green = preview_class->info.dither_green;
1353 dither_blue = preview_class->info.dither_blue;
1354 dither_matrix = preview_class->info.dither_matrix[y & 0x7];
1358 r = dither_red[src[0]];
1359 g = dither_green[src[1]];
1360 b = dither_blue[src[2]];
1363 matrix = dither_matrix[x++ & 0x7];
1364 *dest++ = colors[(r.c[matrix[r.s[1]]] +
1365 g.c[matrix[g.s[1]]] +
1366 b.c[matrix[b.s[1]]])];
1371 gtk_color_16 (guchar *src,
1376 gulong *lookup_green;
1377 gulong *lookup_blue;
1380 lookup_red = preview_class->info.lookup_red;
1381 lookup_green = preview_class->info.lookup_green;
1382 lookup_blue = preview_class->info.lookup_blue;
1386 val = COLOR_COMPOSE (src[0], src[1], src[2]);
1395 gtk_color_24 (guchar *src,
1400 gulong *lookup_green;
1401 gulong *lookup_blue;
1404 lookup_red = preview_class->info.lookup_red;
1405 lookup_green = preview_class->info.lookup_green;
1406 lookup_blue = preview_class->info.lookup_blue;
1410 val = COLOR_COMPOSE (src[0], src[1], src[2]);
1413 dest[2] = val >> 16;
1420 gtk_grayscale_8 (guchar *src,
1426 GtkDitherInfo *dither_gray;
1428 guchar **dither_matrix;
1431 dither_gray = preview_class->info.dither_gray;
1432 dither_matrix = preview_class->info.dither_matrix[y & 0x7];
1436 gray = dither_gray[*src++];
1437 matrix = dither_matrix[x++ & 0x7];
1438 *dest++ = gray.c[matrix[gray.s[1]]];
1443 gtk_grayscale_16 (guchar *src,
1448 gulong *lookup_green;
1449 gulong *lookup_blue;
1452 lookup_red = preview_class->info.lookup_red;
1453 lookup_green = preview_class->info.lookup_green;
1454 lookup_blue = preview_class->info.lookup_blue;
1458 val = COLOR_COMPOSE (*src, *src, *src);
1467 gtk_grayscale_24 (guchar *src,
1472 gulong *lookup_green;
1473 gulong *lookup_blue;
1476 lookup_red = preview_class->info.lookup_red;
1477 lookup_green = preview_class->info.lookup_green;
1478 lookup_blue = preview_class->info.lookup_blue;
1482 val = COLOR_COMPOSE (*src, *src, *src);
1485 dest[2] = val >> 16;
1493 gtk_get_preview_prop (guint *nred,
1498 GtkPreviewProp *prop;
1501 /* FIXME: need to grab the server here to prevent a race condition */
1503 property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE);
1505 if (gdk_property_get (NULL, property, property,
1506 0, sizeof (GtkPreviewProp), FALSE,
1507 NULL, NULL, NULL, (guchar**) &prop))
1509 *nred = prop->nred_shades;
1510 *ngreen = prop->ngreen_shades;
1511 *nblue = prop->nblue_shades;
1512 *ngray = prop->ngray_shades;
1514 prop->ref_count = prop->ref_count + 1;
1515 gdk_property_change (NULL, property, property, 16,
1516 GDK_PROP_MODE_REPLACE,
1526 gtk_set_preview_prop (guint nred,
1531 GtkPreviewProp prop;
1534 property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE);
1537 prop.nred_shades = nred;
1538 prop.ngreen_shades = ngreen;
1539 prop.nblue_shades = nblue;
1540 prop.ngray_shades = ngray;
1542 gdk_property_change (NULL, property, property, 16,
1543 GDK_PROP_MODE_REPLACE,
1544 (guchar*) &prop, 5);
1549 gtk_lsbmsb_1_1 (guchar *dest,
1553 memcpy (dest, src, count);
1557 gtk_lsb_2_2 (guchar *dest,
1561 memcpy (dest, src, count * 2);
1565 gtk_msb_2_2 (guchar *dest,
1579 gtk_lsb_3_3 (guchar *dest,
1583 memcpy (dest, src, count * 3);
1587 gtk_msb_3_3 (guchar *dest,
1602 gtk_lsb_3_4 (guchar *dest,
1617 gtk_msb_3_4 (guchar *dest,