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