]> Pileus Git - ~andy/gtk/blob - gtk/gtkpreview.c
gtkbutton.c gtkclist.c gtkdrawingarea.c gtkentry.c gtkeventbox.c
[~andy/gtk] / gtk / gtkpreview.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
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.
8  *
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.
13  *
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.
17  */
18
19 #include <math.h>
20 #include <string.h>
21 #include <sys/types.h>
22 #include <sys/param.h>
23 #include <netinet/in.h>
24 #include "gdk/gdkx.h"
25 #include "gtkpreview.h"
26 #include "gtksignal.h"
27
28
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])
32
33
34 typedef struct _GtkPreviewProp  GtkPreviewProp;
35 typedef void (*GtkTransferFunc) (guchar *dest, guchar *src, gint count);
36
37 struct _GtkPreviewProp
38 {
39   guint16 ref_count;
40   guint16 nred_shades;
41   guint16 ngreen_shades;
42   guint16 nblue_shades;
43   guint16 ngray_shades;
44 };
45
46
47 static void   gtk_preview_class_init    (GtkPreviewClass  *klass);
48 static void   gtk_preview_init          (GtkPreview       *preview);
49 static void   gtk_preview_destroy       (GtkObject        *object);
50 static void   gtk_preview_realize       (GtkWidget        *widget);
51 static void   gtk_preview_unrealize     (GtkWidget        *widget);
52 static gint   gtk_preview_expose        (GtkWidget        *widget,
53                                          GdkEventExpose   *event);
54 static void   gtk_preview_make_buffer   (GtkPreview       *preview);
55 static void   gtk_preview_get_visuals   (GtkPreviewClass  *klass);
56 static void   gtk_preview_get_cmaps     (GtkPreviewClass  *klass);
57 static void   gtk_preview_dither_init   (GtkPreviewClass  *klass);
58 static void   gtk_fill_lookup_array     (gulong           *array,
59                                          int               depth,
60                                          int               shift,
61                                          int               prec);
62 static void   gtk_trim_cmap             (GtkPreviewClass  *klass);
63 static void   gtk_create_8_bit          (GtkPreviewClass  *klass);
64
65 static void   gtk_color_8               (guchar           *src,
66                                          guchar           *data,
67                                          gint              x,
68                                          gint              y,
69                                          gulong            width);
70 static void   gtk_color_16              (guchar           *src,
71                                          guchar           *data,
72                                          gulong            width);
73 static void   gtk_color_24              (guchar           *src,
74                                          guchar           *data,
75                                          gulong            width);
76 static void   gtk_grayscale_8           (guchar           *src,
77                                          guchar           *data,
78                                          gint              x,
79                                          gint              y,
80                                          gulong            width);
81 static void   gtk_grayscale_16          (guchar           *src,
82                                          guchar           *data,
83                                          gulong            width);
84 static void   gtk_grayscale_24          (guchar           *src,
85                                          guchar           *data,
86                                          gulong            width);
87
88 static gint   gtk_get_preview_prop      (guint            *nred,
89                                          guint            *nblue,
90                                          guint            *ngreen,
91                                          guint            *ngray);
92 static void   gtk_set_preview_prop      (guint             nred,
93                                          guint             ngreen,
94                                          guint             nblue,
95                                          guint             ngray);
96
97 /* transfer functions:
98  *  destination byte order/source bpp/destination bpp
99  */
100 static void   gtk_lsbmsb_1_1            (guchar           *dest,
101                                          guchar           *src,
102                                          gint              count);
103 static void   gtk_lsb_2_2               (guchar           *dest,
104                                          guchar           *src,
105                                          gint              count);
106 static void   gtk_msb_2_2               (guchar           *dest,
107                                          guchar           *src,
108                                          gint              count);
109 static void   gtk_lsb_3_3               (guchar           *dest,
110                                          guchar           *src,
111                                          gint              count);
112 static void   gtk_msb_3_3               (guchar           *dest,
113                                          guchar           *src,
114                                          gint              count);
115 static void   gtk_lsb_3_4               (guchar           *dest,
116                                          guchar           *src,
117                                          gint              count);
118 static void   gtk_msb_3_4               (guchar           *dest,
119                                          guchar           *src,
120                                          gint              count);
121
122
123 static GtkWidgetClass *parent_class = NULL;
124 static GtkPreviewClass *preview_class = NULL;
125 static GtkPreviewInfo *preview_info = NULL;
126 static gint install_cmap = FALSE;
127
128
129 guint
130 gtk_preview_get_type ()
131 {
132   static guint preview_type = 0;
133
134   if (!preview_type)
135     {
136       GtkTypeInfo preview_info =
137       {
138         "GtkPreview",
139         sizeof (GtkPreview),
140         sizeof (GtkPreviewClass),
141         (GtkClassInitFunc) gtk_preview_class_init,
142         (GtkObjectInitFunc) gtk_preview_init,
143         (GtkArgSetFunc) NULL,
144         (GtkArgGetFunc) NULL,
145       };
146
147       preview_type = gtk_type_unique (gtk_widget_get_type (), &preview_info);
148     }
149
150   return preview_type;
151 }
152
153 static void
154 gtk_preview_class_init (GtkPreviewClass *klass)
155 {
156   GtkObjectClass *object_class;
157   GtkWidgetClass *widget_class;
158
159   object_class = (GtkObjectClass*) klass;
160   widget_class = (GtkWidgetClass*) klass;
161
162   parent_class = gtk_type_class (gtk_widget_get_type ());
163   preview_class = klass;
164
165   object_class->destroy = gtk_preview_destroy;
166
167   widget_class->realize = gtk_preview_realize;
168   widget_class->unrealize = gtk_preview_unrealize;
169   widget_class->expose_event = gtk_preview_expose;
170
171   if (preview_info)
172     klass->info = *preview_info;
173   else
174     {
175       klass->info.visual = NULL;
176       klass->info.cmap = NULL;
177
178       klass->info.color_pixels = NULL;
179       klass->info.gray_pixels = NULL;
180       klass->info.reserved_pixels = NULL;
181
182       klass->info.lookup_red = NULL;
183       klass->info.lookup_green = NULL;
184       klass->info.lookup_blue = NULL;
185
186       klass->info.dither_red = NULL;
187       klass->info.dither_green = NULL;
188       klass->info.dither_blue = NULL;
189       klass->info.dither_gray = NULL;
190       klass->info.dither_matrix = NULL;
191
192       klass->info.nred_shades = 6;
193       klass->info.ngreen_shades = 6;
194       klass->info.nblue_shades = 4;
195       klass->info.ngray_shades = 24;
196       klass->info.nreserved = 0;
197
198       klass->info.bpp = 0;
199       klass->info.cmap_alloced = FALSE;
200       klass->info.gamma = 1.0;
201     }
202
203   klass->image = NULL;
204
205   gtk_preview_get_visuals (klass);
206   gtk_preview_get_cmaps (klass);
207   gtk_preview_dither_init (klass);
208 }
209
210 static void
211 gtk_preview_init (GtkPreview *preview)
212 {
213   GTK_WIDGET_SET_FLAGS (preview, GTK_BASIC);
214
215   preview->buffer = NULL;
216   preview->buffer_width = 0;
217   preview->buffer_height = 0;
218   preview->expand = FALSE;
219 }
220
221 void
222 gtk_preview_uninit ()
223 {
224   GtkPreviewProp *prop;
225   GdkAtom property;
226
227   if (preview_class && !install_cmap &&
228       (preview_class->info.visual->type != GDK_VISUAL_TRUE_COLOR) &&
229       (preview_class->info.visual->type != GDK_VISUAL_DIRECT_COLOR))
230     {
231       property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE);
232
233       if (gdk_property_get (NULL, property, property,
234                             0, sizeof (GtkPreviewProp), FALSE,
235                             NULL, NULL, NULL, (guchar**) &prop))
236         {
237           prop->ref_count = ntohs (prop->ref_count) - 1;
238           if (prop->ref_count == 0)
239             {
240               gdk_property_delete (NULL, property);
241             }
242           else
243             {
244               prop->ref_count = htons (prop->ref_count);
245               gdk_property_change (NULL, property, property, 16,
246                                    GDK_PROP_MODE_REPLACE,
247                                    (guchar*) prop, 5);
248             }
249         }
250     }
251 }
252
253 GtkWidget*
254 gtk_preview_new (GtkPreviewType type)
255 {
256   GtkPreview *preview;
257
258   preview = gtk_type_new (gtk_preview_get_type ());
259   preview->type = type;
260
261   return GTK_WIDGET (preview);
262 }
263
264 void
265 gtk_preview_size (GtkPreview *preview,
266                   gint        width,
267                   gint        height)
268 {
269   g_return_if_fail (preview != NULL);
270   g_return_if_fail (GTK_IS_PREVIEW (preview));
271
272   if ((width != GTK_WIDGET (preview)->requisition.width) ||
273       (height != GTK_WIDGET (preview)->requisition.height))
274     {
275       GTK_WIDGET (preview)->requisition.width = width;
276       GTK_WIDGET (preview)->requisition.height = height;
277
278       if (preview->buffer)
279         g_free (preview->buffer);
280       preview->buffer = NULL;
281     }
282 }
283
284 void
285 gtk_preview_put (GtkPreview   *preview,
286                  GdkWindow    *window,
287                  GdkGC        *gc,
288                  gint          srcx,
289                  gint          srcy,
290                  gint          destx,
291                  gint          desty,
292                  gint          width,
293                  gint          height)
294 {
295   GtkWidget *widget;
296   GdkImage *image;
297   GdkRectangle r1, r2, r3;
298   GtkTransferFunc transfer_func;
299   guchar *image_mem;
300   guchar *src, *dest;
301   gint x, xe, x2;
302   gint y, ye, y2;
303   guint dest_rowstride;
304   guint src_bpp;
305   guint dest_bpp;
306   gint i;
307
308   g_return_if_fail (preview != NULL);
309   g_return_if_fail (GTK_IS_PREVIEW (preview));
310   g_return_if_fail (window != NULL);
311
312   if (!preview->buffer)
313     return;
314
315   widget = GTK_WIDGET (preview);
316
317   r1.x = srcx;
318   r1.y = srcy;
319   r1.width = preview->buffer_width;
320   r1.height = preview->buffer_height;
321
322   r2.x = destx;
323   r2.y = desty;
324   r2.width = width;
325   r2.height = height;
326
327   if (!gdk_rectangle_intersect (&r1, &r2, &r3))
328     return;
329
330   x2 = r3.x + r3.width;
331   y2 = r3.y + r3.height;
332
333   if (!preview_class->image)
334     preview_class->image = gdk_image_new (GDK_IMAGE_FASTEST,
335                                           preview_class->info.visual,
336                                           IMAGE_SIZE, IMAGE_SIZE);
337   image = preview_class->image;
338   src_bpp = preview_class->info.bpp;
339
340   image_mem = image->mem;
341   dest_bpp = image->bpp;
342   dest_rowstride = image->bpl;
343
344   transfer_func = NULL;
345
346   switch (dest_bpp)
347     {
348     case 1:
349       switch (src_bpp)
350         {
351         case 1:
352           transfer_func = gtk_lsbmsb_1_1;
353           break;
354         }
355       break;
356     case 2:
357       switch (src_bpp)
358         {
359         case 2:
360           if (image->byte_order == GDK_MSB_FIRST)
361             transfer_func = gtk_msb_2_2;
362           else
363             transfer_func = gtk_lsb_2_2;
364           break;
365         case 3:
366           break;
367         }
368       break;
369     case 3:
370       switch (src_bpp)
371         {
372         case 3:
373           if (image->byte_order == GDK_MSB_FIRST)
374             transfer_func = gtk_msb_3_3;
375           else
376             transfer_func = gtk_lsb_3_3;
377           break;
378         }
379       break;
380     case 4:
381       switch (src_bpp)
382         {
383         case 3:
384           if (image->byte_order == GDK_MSB_FIRST)
385             transfer_func = gtk_msb_3_4;
386           else
387             transfer_func = gtk_lsb_3_4;
388           break;
389         }
390       break;
391     }
392
393   if (!transfer_func)
394     {
395       g_warning ("unsupported byte order/src bpp/dest bpp combination: %s:%d:%d",
396                  (image->byte_order == GDK_MSB_FIRST) ? "msb" : "lsb", src_bpp, dest_bpp);
397       return;
398     }
399
400   for (y = r3.y; y < y2; y += IMAGE_SIZE)
401     {
402       for (x = r3.x; x < x2; x += IMAGE_SIZE)
403         {
404           xe = x + IMAGE_SIZE;
405           if (xe > x2)
406             xe = x2;
407
408           ye = y + IMAGE_SIZE;
409           if (ye > y2)
410             ye = y2;
411
412           for (i = y; i < ye; i++)
413             {
414               src = preview->buffer + (((gulong) (i - r1.y) * (gulong) preview->buffer_width) +
415                                        (x - r1.x)) * (gulong) src_bpp;
416               dest = image_mem + ((gulong) (i - y) * dest_rowstride);
417
418               if (xe > x)
419                 (* transfer_func) (dest, src, xe - x);
420             }
421
422           gdk_draw_image (window, gc,
423                           image, 0, 0, x, y,
424                           xe - x, ye - y);
425           gdk_flush ();
426         }
427     }
428 }
429
430 void
431 gtk_preview_put_row (GtkPreview *preview,
432                      guchar     *src,
433                      guchar     *dest,
434                      gint        x,
435                      gint        y,
436                      gint        w)
437 {
438   g_return_if_fail (preview != NULL);
439   g_return_if_fail (GTK_IS_PREVIEW (preview));
440   g_return_if_fail (src != NULL);
441   g_return_if_fail (dest != NULL);
442
443   switch (preview->type)
444     {
445     case GTK_PREVIEW_COLOR:
446       switch (preview_class->info.visual->depth)
447         {
448         case 8:
449           gtk_color_8 (src, dest, x, y, w);
450           break;
451         case 15:
452         case 16:
453           gtk_color_16 (src, dest, w);
454           break;
455         case 24:
456         case 32:
457           gtk_color_24 (src, dest, w);
458           break;
459         }
460       break;
461     case GTK_PREVIEW_GRAYSCALE:
462       switch (preview_class->info.visual->depth)
463         {
464         case 8:
465           gtk_grayscale_8 (src, dest, x, y, w);
466           break;
467         case 15:
468         case 16:
469           gtk_grayscale_16 (src, dest, w);
470           break;
471         case 24:
472         case 32:
473           gtk_grayscale_24 (src, dest, w);
474           break;
475         }
476       break;
477     }
478 }
479
480 void
481 gtk_preview_draw_row (GtkPreview *preview,
482                       guchar     *data,
483                       gint        x,
484                       gint        y,
485                       gint        w)
486 {
487   guchar *dest;
488
489   g_return_if_fail (preview != NULL);
490   g_return_if_fail (GTK_IS_PREVIEW (preview));
491   g_return_if_fail (data != NULL);
492
493   if ((w <= 0) || (y < 0))
494     return;
495
496   g_return_if_fail (data != NULL);
497
498   gtk_preview_make_buffer (preview);
499
500   if (y >= preview->buffer_height)
501     return;
502
503   switch (preview->type)
504     {
505     case GTK_PREVIEW_COLOR:
506       switch (preview_class->info.visual->depth)
507         {
508         case 8:
509           dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x);
510           gtk_color_8 (data, dest, x, y, w);
511           break;
512         case 15:
513         case 16:
514           dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 2;
515           gtk_color_16 (data, dest, w);
516           break;
517         case 24:
518         case 32:
519           dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 3;
520           gtk_color_24 (data, dest, w);
521           break;
522         }
523       break;
524     case GTK_PREVIEW_GRAYSCALE:
525       switch (preview_class->info.visual->depth)
526         {
527         case 8:
528           dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x);
529           gtk_grayscale_8 (data, dest, x, y, w);
530           break;
531         case 15:
532         case 16:
533           dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 2;
534           gtk_grayscale_16 (data, dest, w);
535           break;
536         case 24:
537         case 32:
538           dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 3;
539           gtk_grayscale_24 (data, dest, w);
540           break;
541         }
542       break;
543     }
544 }
545
546 void
547 gtk_preview_set_expand (GtkPreview *preview,
548                         gint        expand)
549 {
550   g_return_if_fail (preview != NULL);
551   g_return_if_fail (GTK_IS_PREVIEW (preview));
552
553   preview->expand = (expand != FALSE);
554 }
555
556 void
557 gtk_preview_set_gamma (double _gamma)
558 {
559   g_return_if_fail (preview_class == NULL);
560
561   if (!preview_info)
562     {
563       preview_info = g_new0 (GtkPreviewInfo, 1);
564       preview_info->nred_shades = 6;
565       preview_info->ngreen_shades = 6;
566       preview_info->nblue_shades = 4;
567       preview_info->ngray_shades = 24;
568     }
569
570   preview_info->gamma = _gamma;
571 }
572
573 void
574 gtk_preview_set_color_cube (guint nred_shades,
575                             guint ngreen_shades,
576                             guint nblue_shades,
577                             guint ngray_shades)
578 {
579   g_return_if_fail (preview_class == NULL);
580
581   if (!preview_info)
582     {
583       preview_info = g_new0 (GtkPreviewInfo, 1);
584       preview_info->gamma = 1.0;
585     }
586
587   preview_info->nred_shades = nred_shades;
588   preview_info->ngreen_shades = ngreen_shades;
589   preview_info->nblue_shades = nblue_shades;
590   preview_info->ngray_shades = ngray_shades;
591 }
592
593 void
594 gtk_preview_set_install_cmap (gint _install_cmap)
595 {
596   /* g_return_if_fail (preview_class == NULL); */
597
598   install_cmap = _install_cmap;
599 }
600
601 void
602 gtk_preview_set_reserved (gint nreserved)
603 {
604   if (!preview_info)
605     preview_info = g_new0 (GtkPreviewInfo, 1);
606
607   preview_info->nreserved = nreserved;
608 }
609
610 GdkVisual*
611 gtk_preview_get_visual ()
612 {
613   if (!preview_class)
614     preview_class = gtk_type_class (gtk_preview_get_type ());
615
616   return preview_class->info.visual;
617 }
618
619 GdkColormap*
620 gtk_preview_get_cmap ()
621 {
622   if (!preview_class)
623     preview_class = gtk_type_class (gtk_preview_get_type ());
624
625   return preview_class->info.cmap;
626 }
627
628 GtkPreviewInfo*
629 gtk_preview_get_info ()
630 {
631   if (!preview_class)
632     preview_class = gtk_type_class (gtk_preview_get_type ());
633
634   return &preview_class->info;
635 }
636
637
638 static void
639 gtk_preview_destroy (GtkObject *object)
640 {
641   GtkPreview *preview;
642
643   g_return_if_fail (object != NULL);
644   g_return_if_fail (GTK_IS_PREVIEW (object));
645
646   preview = GTK_PREVIEW (object);
647   if (preview->buffer)
648     g_free (preview->buffer);
649   preview->type = (GtkPreviewType) -1;
650
651   if (GTK_OBJECT_CLASS (parent_class)->destroy)
652     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
653 }
654
655 static void
656 gtk_preview_realize (GtkWidget *widget)
657 {
658   GtkPreview *preview;
659   GdkWindowAttr attributes;
660   gint attributes_mask;
661
662   g_return_if_fail (widget != NULL);
663   g_return_if_fail (GTK_IS_PREVIEW (widget));
664
665   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
666   preview = GTK_PREVIEW (widget);
667
668   attributes.window_type = GDK_WINDOW_CHILD;
669   attributes.x = widget->allocation.x;
670   attributes.y = widget->allocation.y;
671   attributes.width = widget->allocation.width;
672   attributes.height = widget->allocation.height;
673   attributes.wclass = GDK_INPUT_OUTPUT;
674   attributes.visual = gtk_widget_get_visual (widget);
675   attributes.colormap = gtk_widget_get_colormap (widget);
676   attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
677   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
678
679   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
680   gdk_window_set_user_data (widget->window, widget);
681
682   widget->style = gtk_style_attach (widget->style, widget->window);
683   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
684 }
685
686 static void
687 gtk_preview_unrealize (GtkWidget *widget)
688 {
689   GtkPreview *preview;
690
691   g_return_if_fail (widget != NULL);
692   g_return_if_fail (GTK_IS_PREVIEW (widget));
693
694   preview = GTK_PREVIEW (widget);
695
696   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
697     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
698 }
699
700 static gint
701 gtk_preview_expose (GtkWidget      *widget,
702                     GdkEventExpose *event)
703 {
704   GtkPreview *preview;
705
706   g_return_val_if_fail (widget != NULL, FALSE);
707   g_return_val_if_fail (GTK_IS_PREVIEW (widget), FALSE);
708   g_return_val_if_fail (event != NULL, FALSE);
709
710   if (GTK_WIDGET_DRAWABLE (widget))
711     {
712       preview = GTK_PREVIEW (widget);
713
714       gtk_preview_put (GTK_PREVIEW (widget),
715                        widget->window, widget->style->black_gc,
716                        (widget->allocation.width - preview->buffer_width) / 2,
717                        (widget->allocation.height - preview->buffer_height) / 2,
718                        event->area.x, event->area.y,
719                        event->area.width, event->area.height);
720     }
721
722   return FALSE;
723 }
724
725 static void
726 gtk_preview_make_buffer (GtkPreview *preview)
727 {
728   GtkWidget *widget;
729   gint width;
730   gint height;
731
732   g_return_if_fail (preview != NULL);
733   g_return_if_fail (GTK_IS_PREVIEW (preview));
734
735   widget = GTK_WIDGET (preview);
736
737   if (preview->expand &&
738       (widget->allocation.width != 0) &&
739       (widget->allocation.height != 0))
740     {
741       width = widget->allocation.width;
742       height = widget->allocation.height;
743     }
744   else
745     {
746       width = widget->requisition.width;
747       height = widget->requisition.height;
748     }
749
750   if (!preview->buffer ||
751       (preview->buffer_width != width) ||
752       (preview->buffer_height != height))
753     {
754       if (preview->buffer)
755         g_free (preview->buffer);
756
757       preview->buffer_width = width;
758       preview->buffer_height = height;
759
760       preview->buffer = g_new0 (guchar,
761                                 preview->buffer_width *
762                                 preview->buffer_height *
763                                 preview_class->info.bpp);
764     }
765 }
766
767 static void
768 gtk_preview_get_visuals (GtkPreviewClass *klass)
769 {
770   static GdkVisualType types[] =
771   {
772     GDK_VISUAL_TRUE_COLOR,
773     GDK_VISUAL_DIRECT_COLOR,
774     GDK_VISUAL_TRUE_COLOR,
775     GDK_VISUAL_DIRECT_COLOR,
776     GDK_VISUAL_TRUE_COLOR,
777     GDK_VISUAL_DIRECT_COLOR,
778     GDK_VISUAL_TRUE_COLOR,
779     GDK_VISUAL_DIRECT_COLOR,
780     GDK_VISUAL_PSEUDO_COLOR
781   };
782   static gint depths[] = { 24, 24, 32, 32, 16, 16, 15, 15, 8 };
783   static gint nvisual_types = sizeof (types) / sizeof (types[0]);
784
785   int i;
786
787   g_return_if_fail (klass != NULL);
788
789   if (!klass->info.visual)
790     for (i = 0; i < nvisual_types; i++)
791       if ((klass->info.visual = gdk_visual_get_best_with_both (depths[i], types[i])))
792         {
793           if ((klass->info.visual->type == GDK_VISUAL_TRUE_COLOR) ||
794               (klass->info.visual->type == GDK_VISUAL_DIRECT_COLOR))
795             {
796               klass->info.lookup_red = g_new (gulong, 256);
797               klass->info.lookup_green = g_new (gulong, 256);
798               klass->info.lookup_blue = g_new (gulong, 256);
799
800               gtk_fill_lookup_array (klass->info.lookup_red,
801                                      klass->info.visual->depth,
802                                      klass->info.visual->red_shift,
803                                      8 - klass->info.visual->red_prec);
804               gtk_fill_lookup_array (klass->info.lookup_green,
805                                      klass->info.visual->depth,
806                                      klass->info.visual->green_shift,
807                                      8 - klass->info.visual->green_prec);
808               gtk_fill_lookup_array (klass->info.lookup_blue,
809                                      klass->info.visual->depth,
810                                      klass->info.visual->blue_shift,
811                                      8 - klass->info.visual->blue_prec);
812             }
813           break;
814         }
815
816   if (!klass->info.visual)
817     {
818       g_warning ("unable to find a suitable visual for color image display.\n");
819       return;
820     }
821
822   switch (klass->info.visual->depth)
823     {
824     case 8:
825       klass->info.bpp = 1;
826       break;
827     case 15:
828     case 16:
829       klass->info.bpp = 2;
830       break;
831     case 24:
832     case 32:
833       klass->info.bpp = 3;
834       break;
835     }
836 }
837
838 static void
839 gtk_preview_get_cmaps (GtkPreviewClass *klass)
840 {
841   g_return_if_fail (klass != NULL);
842   g_return_if_fail (klass->info.visual != NULL);
843
844   if ((klass->info.visual->type != GDK_VISUAL_TRUE_COLOR) &&
845       (klass->info.visual->type != GDK_VISUAL_DIRECT_COLOR))
846     {
847       if (install_cmap)
848         {
849           klass->info.cmap = gdk_colormap_new (klass->info.visual, FALSE);
850           klass->info.cmap_alloced = install_cmap;
851
852           gtk_trim_cmap (klass);
853           gtk_create_8_bit (klass);
854         }
855       else
856         {
857           guint nred;
858           guint ngreen;
859           guint nblue;
860           guint ngray;
861           gint set_prop;
862
863           klass->info.cmap = gdk_colormap_get_system ();
864
865           set_prop = TRUE;
866           if (gtk_get_preview_prop (&nred, &ngreen, &nblue, &ngray))
867             {
868               set_prop = FALSE;
869
870               klass->info.nred_shades = nred;
871               klass->info.ngreen_shades = ngreen;
872               klass->info.nblue_shades = nblue;
873               klass->info.ngray_shades = ngray;
874
875               if (klass->info.nreserved)
876                 {
877                   klass->info.reserved_pixels = g_new (gulong, klass->info.nreserved);
878                   if (!gdk_colors_alloc (klass->info.cmap, 0, NULL, 0,
879                                          klass->info.reserved_pixels,
880                                          klass->info.nreserved))
881                     {
882                       g_free (klass->info.reserved_pixels);
883                       klass->info.reserved_pixels = NULL;
884                     }
885                 }
886             }
887           else
888             {
889               gtk_trim_cmap (klass);
890             }
891
892           gtk_create_8_bit (klass);
893
894           if (set_prop)
895             gtk_set_preview_prop (klass->info.nred_shades,
896                                   klass->info.ngreen_shades,
897                                   klass->info.nblue_shades,
898                                   klass->info.ngray_shades);
899         }
900     }
901   else
902     {
903       if (klass->info.visual == gdk_visual_get_system ())
904         klass->info.cmap = gdk_colormap_get_system ();
905       else
906         klass->info.cmap = gdk_colormap_new (klass->info.visual, FALSE);
907       klass->info.cmap_alloced = TRUE;
908
909       klass->info.nred_shades = 0;
910       klass->info.ngreen_shades = 0;
911       klass->info.nblue_shades = 0;
912       klass->info.ngray_shades = 0;
913     }
914 }
915
916 static void
917 gtk_preview_dither_init (GtkPreviewClass *klass)
918 {
919   int i, j, k;
920   unsigned char low_shade, high_shade;
921   unsigned short index;
922   long red_mult, green_mult;
923   double red_matrix_width;
924   double green_matrix_width;
925   double blue_matrix_width;
926   double gray_matrix_width;
927   double red_colors_per_shade;
928   double green_colors_per_shade;
929   double blue_colors_per_shade;
930   double gray_colors_per_shade;
931   gulong *gray_pixels;
932   gint shades_r, shades_g, shades_b, shades_gray;
933   GtkDitherInfo *red_ordered_dither;
934   GtkDitherInfo *green_ordered_dither;
935   GtkDitherInfo *blue_ordered_dither;
936   GtkDitherInfo *gray_ordered_dither;
937   guchar ***dither_matrix;
938   guchar DM[8][8] =
939   {
940     { 0,  32, 8,  40, 2,  34, 10, 42 },
941     { 48, 16, 56, 24, 50, 18, 58, 26 },
942     { 12, 44, 4,  36, 14, 46, 6,  38 },
943     { 60, 28, 52, 20, 62, 30, 54, 22 },
944     { 3,  35, 11, 43, 1,  33, 9,  41 },
945     { 51, 19, 59, 27, 49, 17, 57, 25 },
946     { 15, 47, 7,  39, 13, 45, 5,  37 },
947     { 63, 31, 55, 23, 61, 29, 53, 21 }
948   };
949
950   if (klass->info.visual->type != GDK_VISUAL_PSEUDO_COLOR)
951     return;
952
953   shades_r = klass->info.nred_shades;
954   shades_g = klass->info.ngreen_shades;
955   shades_b = klass->info.nblue_shades;
956   shades_gray = klass->info.ngray_shades;
957
958   red_mult = shades_g * shades_b;
959   green_mult = shades_b;
960
961   red_colors_per_shade = 255.0 / (shades_r - 1);
962   red_matrix_width = red_colors_per_shade / 64;
963
964   green_colors_per_shade = 255.0 / (shades_g - 1);
965   green_matrix_width = green_colors_per_shade / 64;
966
967   blue_colors_per_shade = 255.0 / (shades_b - 1);
968   blue_matrix_width = blue_colors_per_shade / 64;
969
970   gray_colors_per_shade = 255.0 / (shades_gray - 1);
971   gray_matrix_width = gray_colors_per_shade / 64;
972
973   /*  alloc the ordered dither arrays for accelerated dithering  */
974
975   klass->info.dither_red = g_new (GtkDitherInfo, 256);
976   klass->info.dither_green = g_new (GtkDitherInfo, 256);
977   klass->info.dither_blue = g_new (GtkDitherInfo, 256);
978   klass->info.dither_gray = g_new (GtkDitherInfo, 256);
979
980   red_ordered_dither = klass->info.dither_red;
981   green_ordered_dither = klass->info.dither_green;
982   blue_ordered_dither = klass->info.dither_blue;
983   gray_ordered_dither = klass->info.dither_gray;
984
985   dither_matrix = g_new (guchar**, 8);
986   for (i = 0; i < 8; i++)
987     {
988       dither_matrix[i] = g_new (guchar*, 8);
989       for (j = 0; j < 8; j++)
990         dither_matrix[i][j] = g_new (guchar, 65);
991     }
992
993   klass->info.dither_matrix = dither_matrix;
994
995   /*  setup the ordered_dither_matrices  */
996
997   for (i = 0; i < 8; i++)
998     for (j = 0; j < 8; j++)
999       for (k = 0; k <= 64; k++)
1000         dither_matrix[i][j][k] = (DM[i][j] < k) ? 1 : 0;
1001
1002   /*  setup arrays containing three bytes of information for red, green, & blue  */
1003   /*  the arrays contain :
1004    *    1st byte:    low end shade value
1005    *    2nd byte:    high end shade value
1006    *    3rd & 4th bytes:    ordered dither matrix index
1007    */
1008
1009   gray_pixels = klass->info.gray_pixels;
1010
1011   for (i = 0; i < 256; i++)
1012     {
1013
1014       /*  setup the red information  */
1015       {
1016         low_shade = (unsigned char) (i / red_colors_per_shade);
1017         if (low_shade == (shades_r - 1))
1018           low_shade--;
1019         high_shade = low_shade + 1;
1020
1021         index = (unsigned short)
1022           (((double) i - low_shade * red_colors_per_shade) /
1023            red_matrix_width);
1024
1025         low_shade *= red_mult;
1026         high_shade *= red_mult;
1027
1028         red_ordered_dither[i].s[1] = index;
1029         red_ordered_dither[i].c[0] = low_shade;
1030         red_ordered_dither[i].c[1] = high_shade;
1031       }
1032
1033
1034       /*  setup the green information  */
1035       {
1036         low_shade = (unsigned char) (i / green_colors_per_shade);
1037         if (low_shade == (shades_g - 1))
1038           low_shade--;
1039         high_shade = low_shade + 1;
1040
1041         index = (unsigned short)
1042           (((double) i - low_shade * green_colors_per_shade) /
1043            green_matrix_width);
1044
1045         low_shade *= green_mult;
1046         high_shade *= green_mult;
1047
1048         green_ordered_dither[i].s[1] = index;
1049         green_ordered_dither[i].c[0] = low_shade;
1050         green_ordered_dither[i].c[1] = high_shade;
1051       }
1052
1053
1054       /*  setup the blue information  */
1055       {
1056         low_shade = (unsigned char) (i / blue_colors_per_shade);
1057         if (low_shade == (shades_b - 1))
1058           low_shade--;
1059         high_shade = low_shade + 1;
1060
1061         index = (unsigned short)
1062           (((double) i - low_shade * blue_colors_per_shade) /
1063            blue_matrix_width);
1064
1065         blue_ordered_dither[i].s[1] = index;
1066         blue_ordered_dither[i].c[0] = low_shade;
1067         blue_ordered_dither[i].c[1] = high_shade;
1068       }
1069
1070
1071       /*  setup the gray information */
1072       {
1073         low_shade = (unsigned char) (i / gray_colors_per_shade);
1074         if (low_shade == (shades_gray - 1))
1075           low_shade--;
1076         high_shade = low_shade + 1;
1077
1078         index = (unsigned short)
1079           (((double) i - low_shade * gray_colors_per_shade) /
1080            gray_matrix_width);
1081
1082         gray_ordered_dither[i].s[1] = index;
1083         gray_ordered_dither[i].c[0] = gray_pixels[low_shade];
1084         gray_ordered_dither[i].c[1] = gray_pixels[high_shade];
1085       }
1086     }
1087 }
1088
1089 static void
1090 gtk_fill_lookup_array (gulong *array,
1091                        int     depth,
1092                        int     shift,
1093                        int     prec)
1094 {
1095   double one_over_gamma;
1096   double ind;
1097   int val;
1098   int i;
1099
1100   if (preview_class->info.gamma != 0.0)
1101     one_over_gamma = 1.0 / preview_class->info.gamma;
1102   else
1103     one_over_gamma = 1.0;
1104
1105   for (i = 0; i < 256; i++)
1106     {
1107       if (one_over_gamma == 1.0)
1108         array[i] = ((i >> prec) << shift);
1109       else
1110         {
1111           ind = (double) i / 255.0;
1112           val = (int) (255 * pow (ind, one_over_gamma));
1113           array[i] = ((val >> prec) << shift);
1114         }
1115     }
1116 }
1117
1118 static void
1119 gtk_trim_cmap (GtkPreviewClass *klass)
1120 {
1121   gulong pixels[256];
1122   guint nred;
1123   guint ngreen;
1124   guint nblue;
1125   guint ngray;
1126   guint nreserved;
1127   guint total;
1128   guint tmp;
1129   gint success;
1130
1131   nred = klass->info.nred_shades;
1132   ngreen = klass->info.ngreen_shades;
1133   nblue = klass->info.nblue_shades;
1134   ngray = klass->info.ngray_shades;
1135   nreserved = klass->info.nreserved;
1136
1137   success = FALSE;
1138   while (!success)
1139     {
1140       total = nred * ngreen * nblue + ngray + nreserved;
1141
1142       if (total <= 256)
1143         {
1144           if ((nred < 2) || (ngreen < 2) || (nblue < 2) || (ngray < 2))
1145             success = TRUE;
1146           else
1147             {
1148               success = gdk_colors_alloc (klass->info.cmap, 0, NULL, 0, pixels, total);
1149               if (success)
1150                 {
1151                   if (nreserved > 0)
1152                     {
1153                       klass->info.reserved_pixels = g_new (gulong, nreserved);
1154                       memcpy (klass->info.reserved_pixels, pixels, sizeof (gulong) * nreserved);
1155                       gdk_colors_free (klass->info.cmap, &pixels[nreserved],
1156                                        total - nreserved, 0);
1157                     }
1158                   else
1159                     {
1160                       gdk_colors_free (klass->info.cmap, pixels, total, 0);
1161                     }
1162                 }
1163             }
1164         }
1165
1166       if (!success)
1167         {
1168           if ((nblue >= nred) && (nblue >= ngreen))
1169             nblue = nblue - 1;
1170           else if ((nred >= ngreen) && (nred >= nblue))
1171             nred = nred - 1;
1172           else
1173             {
1174               tmp = log (ngray) / log (2);
1175
1176               if (ngreen >= tmp)
1177                 ngreen = ngreen - 1;
1178               else
1179                 ngray -= 1;
1180             }
1181         }
1182     }
1183
1184   if ((nred < 2) || (ngreen < 2) || (nblue < 2) || (ngray < 2))
1185     {
1186       g_print ("Unable to allocate sufficient colormap entries.\n");
1187       g_print ("Try exiting other color intensive applications.\n");
1188       return;
1189     }
1190
1191   /*  If any of the shade values has changed, issue a warning  */
1192   if ((nred != klass->info.nred_shades) ||
1193       (ngreen != klass->info.ngreen_shades) ||
1194       (nblue != klass->info.nblue_shades) ||
1195       (ngray != klass->info.ngray_shades))
1196     {
1197       g_print ("Not enough colors to satisfy requested color cube.\n");
1198       g_print ("Reduced color cube shades from\n");
1199       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",
1200                klass->info.nred_shades, klass->info.ngreen_shades,
1201                klass->info.nblue_shades, klass->info.ngray_shades,
1202                nred, ngreen, nblue, ngray);
1203     }
1204
1205   klass->info.nred_shades = nred;
1206   klass->info.ngreen_shades = ngreen;
1207   klass->info.nblue_shades = nblue;
1208   klass->info.ngray_shades = ngray;
1209 }
1210
1211 static void
1212 gtk_create_8_bit (GtkPreviewClass *klass)
1213 {
1214   unsigned int r, g, b;
1215   unsigned int rv, gv, bv;
1216   unsigned int dr, dg, db, dgray;
1217   GdkColor color;
1218   gulong *pixels;
1219   double one_over_gamma;
1220   int i;
1221
1222   if (!klass->info.color_pixels)
1223     klass->info.color_pixels = g_new (gulong, 256);
1224
1225   if (!klass->info.gray_pixels)
1226     klass->info.gray_pixels = g_new (gulong, 256);
1227
1228   if (klass->info.gamma != 0.0)
1229     one_over_gamma = 1.0 / klass->info.gamma;
1230   else
1231     one_over_gamma = 1.0;
1232
1233   dr = klass->info.nred_shades - 1;
1234   dg = klass->info.ngreen_shades - 1;
1235   db = klass->info.nblue_shades - 1;
1236   dgray = klass->info.ngray_shades - 1;
1237
1238   pixels = klass->info.color_pixels;
1239
1240   for (r = 0, i = 0; r <= dr; r++)
1241     for (g = 0; g <= dg; g++)
1242       for (b = 0; b <= db; b++, i++)
1243         {
1244           rv = (unsigned int) ((r * klass->info.visual->colormap_size) / dr);
1245           gv = (unsigned int) ((g * klass->info.visual->colormap_size) / dg);
1246           bv = (unsigned int) ((b * klass->info.visual->colormap_size) / db);
1247           color.red = ((int) (255 * pow ((double) rv / 256.0, one_over_gamma))) * 257;
1248           color.green = ((int) (255 * pow ((double) gv / 256.0, one_over_gamma))) * 257;
1249           color.blue = ((int) (255 * pow ((double) bv / 256.0, one_over_gamma))) * 257;
1250
1251           if (!gdk_color_alloc (klass->info.cmap, &color))
1252             {
1253               g_error ("could not initialize 8-bit combined colormap");
1254               return;
1255             }
1256
1257           pixels[i] = color.pixel;
1258         }
1259
1260   pixels = klass->info.gray_pixels;
1261
1262   for (i = 0; i < (int) klass->info.ngray_shades; i++)
1263     {
1264       color.red = (i * klass->info.visual->colormap_size) / dgray;
1265       color.red = ((int) (255 * pow ((double) color.red / 256.0, one_over_gamma))) * 257;
1266       color.green = color.red;
1267       color.blue = color.red;
1268
1269       if (!gdk_color_alloc (klass->info.cmap, &color))
1270         {
1271           g_error ("could not initialize 8-bit combined colormap");
1272           return;
1273         }
1274
1275       pixels[i] = color.pixel;
1276     }
1277 }
1278
1279
1280 static void
1281 gtk_color_8 (guchar *src,
1282              guchar *dest,
1283              gint    x,
1284              gint    y,
1285              gulong  width)
1286 {
1287   gulong *colors;
1288   GtkDitherInfo *dither_red;
1289   GtkDitherInfo *dither_green;
1290   GtkDitherInfo *dither_blue;
1291   GtkDitherInfo r, g, b;
1292   guchar **dither_matrix;
1293   guchar *matrix;
1294
1295   colors = preview_class->info.color_pixels;
1296   dither_red = preview_class->info.dither_red;
1297   dither_green = preview_class->info.dither_green;
1298   dither_blue = preview_class->info.dither_blue;
1299   dither_matrix = preview_class->info.dither_matrix[y & 0x7];
1300
1301   while (width--)
1302     {
1303       r = dither_red[src[0]];
1304       g = dither_green[src[1]];
1305       b = dither_blue[src[2]];
1306       src += 3;
1307
1308       matrix = dither_matrix[x++ & 0x7];
1309       *dest++ = colors[(r.c[matrix[r.s[1]]] +
1310                         g.c[matrix[g.s[1]]] +
1311                         b.c[matrix[b.s[1]]])];
1312     }
1313 }
1314
1315 static void
1316 gtk_color_16 (guchar *src,
1317               guchar *dest,
1318               gulong  width)
1319 {
1320   gulong *lookup_red;
1321   gulong *lookup_green;
1322   gulong *lookup_blue;
1323   gulong val;
1324
1325   lookup_red = preview_class->info.lookup_red;
1326   lookup_green = preview_class->info.lookup_green;
1327   lookup_blue = preview_class->info.lookup_blue;
1328
1329   while (width--)
1330     {
1331       val = COLOR_COMPOSE (src[0], src[1], src[2]);
1332       dest[0] = val;
1333       dest[1] = val >> 8;
1334       dest += 2;
1335       src += 3;
1336     }
1337 }
1338
1339 static void
1340 gtk_color_24 (guchar *src,
1341               guchar *dest,
1342               gulong  width)
1343 {
1344   gulong *lookup_red;
1345   gulong *lookup_green;
1346   gulong *lookup_blue;
1347   gulong val;
1348
1349   lookup_red = preview_class->info.lookup_red;
1350   lookup_green = preview_class->info.lookup_green;
1351   lookup_blue = preview_class->info.lookup_blue;
1352
1353   while (width--)
1354     {
1355       val = COLOR_COMPOSE (src[0], src[1], src[2]);
1356       dest[0] = val;
1357       dest[1] = val >> 8;
1358       dest[2] = val >> 16;
1359       dest += 3;
1360       src += 3;
1361     }
1362 }
1363
1364 static void
1365 gtk_grayscale_8 (guchar *src,
1366                  guchar *dest,
1367                  gint    x,
1368                  gint    y,
1369                  gulong  width)
1370 {
1371   GtkDitherInfo *dither_gray;
1372   GtkDitherInfo gray;
1373   guchar **dither_matrix;
1374   guchar *matrix;
1375
1376   dither_gray = preview_class->info.dither_gray;
1377   dither_matrix = preview_class->info.dither_matrix[y & 0x7];
1378
1379   while (width--)
1380     {
1381       gray = dither_gray[*src++];
1382       matrix = dither_matrix[x++ & 0x7];
1383       *dest++ = gray.c[matrix[gray.s[1]]];
1384     }
1385 }
1386
1387 static void
1388 gtk_grayscale_16 (guchar *src,
1389                   guchar *dest,
1390                   gulong  width)
1391 {
1392   gulong *lookup_red;
1393   gulong *lookup_green;
1394   gulong *lookup_blue;
1395   gulong val;
1396
1397   lookup_red = preview_class->info.lookup_red;
1398   lookup_green = preview_class->info.lookup_green;
1399   lookup_blue = preview_class->info.lookup_blue;
1400
1401   while (width--)
1402     {
1403       val = COLOR_COMPOSE (*src, *src, *src);
1404       dest[0] = val;
1405       dest[1] = val >> 8;
1406       dest += 2;
1407       src += 1;
1408     }
1409 }
1410
1411 static void
1412 gtk_grayscale_24 (guchar  *src,
1413                   guchar  *dest,
1414                   gulong   width)
1415 {
1416   gulong *lookup_red;
1417   gulong *lookup_green;
1418   gulong *lookup_blue;
1419   gulong val;
1420
1421   lookup_red = preview_class->info.lookup_red;
1422   lookup_green = preview_class->info.lookup_green;
1423   lookup_blue = preview_class->info.lookup_blue;
1424
1425   while (width--)
1426     {
1427       val = COLOR_COMPOSE (*src, *src, *src);
1428       dest[0] = val;
1429       dest[1] = val >> 8;
1430       dest[2] = val >> 16;
1431       dest += 3;
1432       src += 1;
1433     }
1434 }
1435
1436
1437 static gint
1438 gtk_get_preview_prop (guint *nred,
1439                       guint *ngreen,
1440                       guint *nblue,
1441                       guint *ngray)
1442 {
1443   GtkPreviewProp *prop;
1444   GdkAtom property;
1445
1446   property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE);
1447
1448   if (gdk_property_get (NULL, property, property,
1449                         0, sizeof (GtkPreviewProp), FALSE,
1450                         NULL, NULL, NULL, (guchar**) &prop))
1451     {
1452       *nred = ntohs (prop->nred_shades);
1453       *ngreen = ntohs (prop->ngreen_shades);
1454       *nblue = ntohs (prop->nblue_shades);
1455       *ngray = ntohs (prop->ngray_shades);
1456
1457       prop->ref_count = htons (ntohs (prop->ref_count) + 1);
1458       gdk_property_change (NULL, property, property, 16,
1459                            GDK_PROP_MODE_REPLACE,
1460                            (guchar*) prop, 5);
1461
1462       return TRUE;
1463     }
1464
1465   return FALSE;
1466 }
1467
1468 static void
1469 gtk_set_preview_prop (guint nred,
1470                       guint ngreen,
1471                       guint nblue,
1472                       guint ngray)
1473 {
1474   GtkPreviewProp prop;
1475   GdkAtom property;
1476
1477   property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE);
1478
1479   prop.ref_count = htons (1);
1480   prop.nred_shades = htons (nred);
1481   prop.ngreen_shades = htons (ngreen);
1482   prop.nblue_shades = htons (nblue);
1483   prop.ngray_shades = htons (ngray);
1484
1485   gdk_property_change (NULL, property, property, 16,
1486                        GDK_PROP_MODE_REPLACE,
1487                        (guchar*) &prop, 5);
1488 }
1489
1490
1491 static void
1492 gtk_lsbmsb_1_1 (guchar *dest,
1493                 guchar *src,
1494                 gint    count)
1495 {
1496   memcpy (dest, src, count);
1497 }
1498
1499 static void
1500 gtk_lsb_2_2 (guchar *dest,
1501              guchar *src,
1502              gint    count)
1503 {
1504   memcpy (dest, src, count * 2);
1505 }
1506
1507 static void
1508 gtk_msb_2_2 (guchar *dest,
1509              guchar *src,
1510              gint    count)
1511 {
1512   while (count--)
1513     {
1514       dest[0] = src[1];
1515       dest[1] = src[0];
1516       dest += 2;
1517       src += 2;
1518     }
1519 }
1520
1521 static void
1522 gtk_lsb_3_3 (guchar *dest,
1523              guchar *src,
1524              gint    count)
1525 {
1526   memcpy (dest, src, count * 3);
1527 }
1528
1529 static void
1530 gtk_msb_3_3 (guchar *dest,
1531              guchar *src,
1532              gint    count)
1533 {
1534   while (count--)
1535     {
1536       dest[0] = src[2];
1537       dest[1] = src[1];
1538       dest[2] = src[0];
1539       dest += 3;
1540       src += 3;
1541     }
1542 }
1543
1544 static void
1545 gtk_lsb_3_4 (guchar *dest,
1546              guchar *src,
1547              gint    count)
1548 {
1549   while (count--)
1550     {
1551       dest[0] = src[0];
1552       dest[1] = src[1];
1553       dest[2] = src[2];
1554       dest += 4;
1555       src += 3;
1556     }
1557 }
1558
1559 static void
1560 gtk_msb_3_4 (guchar *dest,
1561              guchar *src,
1562              gint    count)
1563 {
1564   while (count--)
1565     {
1566       dest[1] = src[2];
1567       dest[2] = src[1];
1568       dest[3] = src[0];
1569       dest += 4;
1570       src += 3;
1571     }
1572 }