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