]> Pileus Git - ~andy/gtk/blob - gtk/gtkpreview.c
fix behavior of gtk_preview_put() with srcx/srcy != 0,
[~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 &&
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
493   if ((w <= 0) || (y < 0))
494     return;
495
496   g_return_if_fail (data != NULL);
497
498   gtk_preview_make_buffer (preview);
499
500   if (y >= preview->buffer_height)
501     return;
502
503   switch (preview->type)
504     {
505     case GTK_PREVIEW_COLOR:
506       switch (preview_class->info.visual->depth)
507         {
508         case 8:
509           dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x);
510           gtk_color_8 (data, dest, x, y, w);
511           break;
512         case 15:
513         case 16:
514           dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 2;
515           gtk_color_16 (data, dest, w);
516           break;
517         case 24:
518         case 32:
519           dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 3;
520           gtk_color_24 (data, dest, w);
521           break;
522         }
523       break;
524     case GTK_PREVIEW_GRAYSCALE:
525       switch (preview_class->info.visual->depth)
526         {
527         case 8:
528           dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x);
529           gtk_grayscale_8 (data, dest, x, y, w);
530           break;
531         case 15:
532         case 16:
533           dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 2;
534           gtk_grayscale_16 (data, dest, w);
535           break;
536         case 24:
537         case 32:
538           dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 3;
539           gtk_grayscale_24 (data, dest, w);
540           break;
541         }
542       break;
543     }
544 }
545
546 void
547 gtk_preview_set_expand (GtkPreview *preview,
548                         gint        expand)
549 {
550   g_return_if_fail (preview != NULL);
551   g_return_if_fail (GTK_IS_PREVIEW (preview));
552
553   preview->expand = (expand != FALSE);
554 }
555
556 void
557 gtk_preview_set_gamma (double _gamma)
558 {
559   g_return_if_fail (preview_class == NULL);
560
561   if (!preview_info)
562     {
563       preview_info = g_new0 (GtkPreviewInfo, 1);
564       preview_info->nred_shades = 6;
565       preview_info->ngreen_shades = 6;
566       preview_info->nblue_shades = 4;
567       preview_info->ngray_shades = 24;
568     }
569
570   preview_info->gamma = _gamma;
571 }
572
573 void
574 gtk_preview_set_color_cube (guint nred_shades,
575                             guint ngreen_shades,
576                             guint nblue_shades,
577                             guint ngray_shades)
578 {
579   g_return_if_fail (preview_class == NULL);
580
581   if (!preview_info)
582     {
583       preview_info = g_new0 (GtkPreviewInfo, 1);
584       preview_info->gamma = 1.0;
585     }
586
587   preview_info->nred_shades = nred_shades;
588   preview_info->ngreen_shades = ngreen_shades;
589   preview_info->nblue_shades = nblue_shades;
590   preview_info->ngray_shades = ngray_shades;
591 }
592
593 void
594 gtk_preview_set_install_cmap (gint _install_cmap)
595 {
596   /* g_return_if_fail (preview_class == NULL); */
597
598   install_cmap = _install_cmap;
599 }
600
601 void
602 gtk_preview_set_reserved (gint nreserved)
603 {
604   if (!preview_info)
605     preview_info = g_new0 (GtkPreviewInfo, 1);
606
607   preview_info->nreserved = nreserved;
608 }
609
610 GdkVisual*
611 gtk_preview_get_visual ()
612 {
613   if (!preview_class)
614     preview_class = gtk_type_class (gtk_preview_get_type ());
615
616   return preview_class->info.visual;
617 }
618
619 GdkColormap*
620 gtk_preview_get_cmap ()
621 {
622   if (!preview_class)
623     preview_class = gtk_type_class (gtk_preview_get_type ());
624
625   return preview_class->info.cmap;
626 }
627
628 GtkPreviewInfo*
629 gtk_preview_get_info ()
630 {
631   if (!preview_class)
632     preview_class = gtk_type_class (gtk_preview_get_type ());
633
634   return &preview_class->info;
635 }
636
637
638 static void
639 gtk_preview_finalize (GtkObject *object)
640 {
641   GtkPreview *preview;
642
643   g_return_if_fail (object != NULL);
644   g_return_if_fail (GTK_IS_PREVIEW (object));
645
646   preview = GTK_PREVIEW (object);
647   if (preview->buffer)
648     g_free (preview->buffer);
649   preview->type = (GtkPreviewType) -1;
650
651   (* GTK_OBJECT_CLASS (parent_class)->finalize) (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 (gtk_widget_get_parent_window (widget), &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 gint
686 gtk_preview_expose (GtkWidget      *widget,
687                     GdkEventExpose *event)
688 {
689   GtkPreview *preview;
690
691   g_return_val_if_fail (widget != NULL, FALSE);
692   g_return_val_if_fail (GTK_IS_PREVIEW (widget), FALSE);
693   g_return_val_if_fail (event != NULL, FALSE);
694
695   if (GTK_WIDGET_DRAWABLE (widget))
696     {
697       preview = GTK_PREVIEW (widget);
698       
699       gtk_preview_put (GTK_PREVIEW (widget),
700                        widget->window, widget->style->black_gc,
701                        event->area.x -
702                        (widget->allocation.width - preview->buffer_width)/2,
703                        event->area.y -
704                        (widget->allocation.height - preview->buffer_height)/2,
705                        event->area.x, event->area.y,
706                        event->area.width, event->area.height);
707     }
708   
709   return FALSE;
710 }
711
712 static void
713 gtk_preview_make_buffer (GtkPreview *preview)
714 {
715   GtkWidget *widget;
716   gint width;
717   gint height;
718
719   g_return_if_fail (preview != NULL);
720   g_return_if_fail (GTK_IS_PREVIEW (preview));
721
722   widget = GTK_WIDGET (preview);
723
724   if (preview->expand &&
725       (widget->allocation.width != 0) &&
726       (widget->allocation.height != 0))
727     {
728       width = widget->allocation.width;
729       height = widget->allocation.height;
730     }
731   else
732     {
733       width = widget->requisition.width;
734       height = widget->requisition.height;
735     }
736
737   if (!preview->buffer ||
738       (preview->buffer_width != width) ||
739       (preview->buffer_height != height))
740     {
741       if (preview->buffer)
742         g_free (preview->buffer);
743
744       preview->buffer_width = width;
745       preview->buffer_height = height;
746
747       preview->buffer = g_new0 (guchar,
748                                 preview->buffer_width *
749                                 preview->buffer_height *
750                                 preview_class->info.bpp);
751     }
752 }
753
754 static void
755 gtk_preview_get_visuals (GtkPreviewClass *klass)
756 {
757   static GdkVisualType types[] =
758   {
759     GDK_VISUAL_TRUE_COLOR,
760     GDK_VISUAL_DIRECT_COLOR,
761     GDK_VISUAL_TRUE_COLOR,
762     GDK_VISUAL_DIRECT_COLOR,
763     GDK_VISUAL_TRUE_COLOR,
764     GDK_VISUAL_DIRECT_COLOR,
765     GDK_VISUAL_TRUE_COLOR,
766     GDK_VISUAL_DIRECT_COLOR,
767     GDK_VISUAL_PSEUDO_COLOR
768   };
769   static gint depths[] = { 24, 24, 32, 32, 16, 16, 15, 15, 8 };
770   static gint nvisual_types = sizeof (types) / sizeof (types[0]);
771
772   int i;
773
774   g_return_if_fail (klass != NULL);
775
776   if (!klass->info.visual)
777     for (i = 0; i < nvisual_types; i++)
778       if ((klass->info.visual = gdk_visual_get_best_with_both (depths[i], types[i])))
779         {
780           if ((klass->info.visual->type == GDK_VISUAL_TRUE_COLOR) ||
781               (klass->info.visual->type == GDK_VISUAL_DIRECT_COLOR))
782             {
783               klass->info.lookup_red = g_new (gulong, 256);
784               klass->info.lookup_green = g_new (gulong, 256);
785               klass->info.lookup_blue = g_new (gulong, 256);
786
787               gtk_fill_lookup_array (klass->info.lookup_red,
788                                      klass->info.visual->depth,
789                                      klass->info.visual->red_shift,
790                                      8 - klass->info.visual->red_prec);
791               gtk_fill_lookup_array (klass->info.lookup_green,
792                                      klass->info.visual->depth,
793                                      klass->info.visual->green_shift,
794                                      8 - klass->info.visual->green_prec);
795               gtk_fill_lookup_array (klass->info.lookup_blue,
796                                      klass->info.visual->depth,
797                                      klass->info.visual->blue_shift,
798                                      8 - klass->info.visual->blue_prec);
799             }
800           break;
801         }
802
803   if (!klass->info.visual)
804     {
805       g_warning ("unable to find a suitable visual for color image display.\n");
806       return;
807     }
808
809   switch (klass->info.visual->depth)
810     {
811     case 8:
812       klass->info.bpp = 1;
813       break;
814     case 15:
815     case 16:
816       klass->info.bpp = 2;
817       break;
818     case 24:
819     case 32:
820       klass->info.bpp = 3;
821       break;
822     }
823 }
824
825 static void
826 gtk_preview_get_cmaps (GtkPreviewClass *klass)
827 {
828   g_return_if_fail (klass != NULL);
829   g_return_if_fail (klass->info.visual != NULL);
830
831   if ((klass->info.visual->type != GDK_VISUAL_TRUE_COLOR) &&
832       (klass->info.visual->type != GDK_VISUAL_DIRECT_COLOR))
833     {
834       if (install_cmap)
835         {
836           klass->info.cmap = gdk_colormap_new (klass->info.visual, FALSE);
837           klass->info.cmap_alloced = install_cmap;
838
839           gtk_trim_cmap (klass);
840           gtk_create_8_bit (klass);
841         }
842       else
843         {
844           guint nred;
845           guint ngreen;
846           guint nblue;
847           guint ngray;
848           gint set_prop;
849
850           klass->info.cmap = gdk_colormap_get_system ();
851
852           set_prop = TRUE;
853           if (gtk_get_preview_prop (&nred, &ngreen, &nblue, &ngray))
854             {
855               set_prop = FALSE;
856
857               klass->info.nred_shades = nred;
858               klass->info.ngreen_shades = ngreen;
859               klass->info.nblue_shades = nblue;
860               klass->info.ngray_shades = ngray;
861
862               if (klass->info.nreserved)
863                 {
864                   klass->info.reserved_pixels = g_new (gulong, klass->info.nreserved);
865                   if (!gdk_colors_alloc (klass->info.cmap, 0, NULL, 0,
866                                          klass->info.reserved_pixels,
867                                          klass->info.nreserved))
868                     {
869                       g_free (klass->info.reserved_pixels);
870                       klass->info.reserved_pixels = NULL;
871                     }
872                 }
873             }
874           else
875             {
876               gtk_trim_cmap (klass);
877             }
878
879           gtk_create_8_bit (klass);
880
881           if (set_prop)
882             gtk_set_preview_prop (klass->info.nred_shades,
883                                   klass->info.ngreen_shades,
884                                   klass->info.nblue_shades,
885                                   klass->info.ngray_shades);
886         }
887     }
888   else
889     {
890       if (klass->info.visual == gdk_visual_get_system ())
891         klass->info.cmap = gdk_colormap_get_system ();
892       else
893         klass->info.cmap = gdk_colormap_new (klass->info.visual, FALSE);
894       klass->info.cmap_alloced = TRUE;
895
896       klass->info.nred_shades = 0;
897       klass->info.ngreen_shades = 0;
898       klass->info.nblue_shades = 0;
899       klass->info.ngray_shades = 0;
900     }
901 }
902
903 static void
904 gtk_preview_dither_init (GtkPreviewClass *klass)
905 {
906   int i, j, k;
907   unsigned char low_shade, high_shade;
908   unsigned short index;
909   long red_mult, green_mult;
910   double red_matrix_width;
911   double green_matrix_width;
912   double blue_matrix_width;
913   double gray_matrix_width;
914   double red_colors_per_shade;
915   double green_colors_per_shade;
916   double blue_colors_per_shade;
917   double gray_colors_per_shade;
918   gulong *gray_pixels;
919   gint shades_r, shades_g, shades_b, shades_gray;
920   GtkDitherInfo *red_ordered_dither;
921   GtkDitherInfo *green_ordered_dither;
922   GtkDitherInfo *blue_ordered_dither;
923   GtkDitherInfo *gray_ordered_dither;
924   guchar ***dither_matrix;
925   guchar DM[8][8] =
926   {
927     { 0,  32, 8,  40, 2,  34, 10, 42 },
928     { 48, 16, 56, 24, 50, 18, 58, 26 },
929     { 12, 44, 4,  36, 14, 46, 6,  38 },
930     { 60, 28, 52, 20, 62, 30, 54, 22 },
931     { 3,  35, 11, 43, 1,  33, 9,  41 },
932     { 51, 19, 59, 27, 49, 17, 57, 25 },
933     { 15, 47, 7,  39, 13, 45, 5,  37 },
934     { 63, 31, 55, 23, 61, 29, 53, 21 }
935   };
936
937   if (klass->info.visual->type != GDK_VISUAL_PSEUDO_COLOR)
938     return;
939
940   shades_r = klass->info.nred_shades;
941   shades_g = klass->info.ngreen_shades;
942   shades_b = klass->info.nblue_shades;
943   shades_gray = klass->info.ngray_shades;
944
945   red_mult = shades_g * shades_b;
946   green_mult = shades_b;
947
948   red_colors_per_shade = 255.0 / (shades_r - 1);
949   red_matrix_width = red_colors_per_shade / 64;
950
951   green_colors_per_shade = 255.0 / (shades_g - 1);
952   green_matrix_width = green_colors_per_shade / 64;
953
954   blue_colors_per_shade = 255.0 / (shades_b - 1);
955   blue_matrix_width = blue_colors_per_shade / 64;
956
957   gray_colors_per_shade = 255.0 / (shades_gray - 1);
958   gray_matrix_width = gray_colors_per_shade / 64;
959
960   /*  alloc the ordered dither arrays for accelerated dithering  */
961
962   klass->info.dither_red = g_new (GtkDitherInfo, 256);
963   klass->info.dither_green = g_new (GtkDitherInfo, 256);
964   klass->info.dither_blue = g_new (GtkDitherInfo, 256);
965   klass->info.dither_gray = g_new (GtkDitherInfo, 256);
966
967   red_ordered_dither = klass->info.dither_red;
968   green_ordered_dither = klass->info.dither_green;
969   blue_ordered_dither = klass->info.dither_blue;
970   gray_ordered_dither = klass->info.dither_gray;
971
972   dither_matrix = g_new (guchar**, 8);
973   for (i = 0; i < 8; i++)
974     {
975       dither_matrix[i] = g_new (guchar*, 8);
976       for (j = 0; j < 8; j++)
977         dither_matrix[i][j] = g_new (guchar, 65);
978     }
979
980   klass->info.dither_matrix = dither_matrix;
981
982   /*  setup the ordered_dither_matrices  */
983
984   for (i = 0; i < 8; i++)
985     for (j = 0; j < 8; j++)
986       for (k = 0; k <= 64; k++)
987         dither_matrix[i][j][k] = (DM[i][j] < k) ? 1 : 0;
988
989   /*  setup arrays containing three bytes of information for red, green, & blue  */
990   /*  the arrays contain :
991    *    1st byte:    low end shade value
992    *    2nd byte:    high end shade value
993    *    3rd & 4th bytes:    ordered dither matrix index
994    */
995
996   gray_pixels = klass->info.gray_pixels;
997
998   for (i = 0; i < 256; i++)
999     {
1000
1001       /*  setup the red information  */
1002       {
1003         low_shade = (unsigned char) (i / red_colors_per_shade);
1004         if (low_shade == (shades_r - 1))
1005           low_shade--;
1006         high_shade = low_shade + 1;
1007
1008         index = (unsigned short)
1009           (((double) i - low_shade * red_colors_per_shade) /
1010            red_matrix_width);
1011
1012         low_shade *= red_mult;
1013         high_shade *= red_mult;
1014
1015         red_ordered_dither[i].s[1] = index;
1016         red_ordered_dither[i].c[0] = low_shade;
1017         red_ordered_dither[i].c[1] = high_shade;
1018       }
1019
1020
1021       /*  setup the green information  */
1022       {
1023         low_shade = (unsigned char) (i / green_colors_per_shade);
1024         if (low_shade == (shades_g - 1))
1025           low_shade--;
1026         high_shade = low_shade + 1;
1027
1028         index = (unsigned short)
1029           (((double) i - low_shade * green_colors_per_shade) /
1030            green_matrix_width);
1031
1032         low_shade *= green_mult;
1033         high_shade *= green_mult;
1034
1035         green_ordered_dither[i].s[1] = index;
1036         green_ordered_dither[i].c[0] = low_shade;
1037         green_ordered_dither[i].c[1] = high_shade;
1038       }
1039
1040
1041       /*  setup the blue information  */
1042       {
1043         low_shade = (unsigned char) (i / blue_colors_per_shade);
1044         if (low_shade == (shades_b - 1))
1045           low_shade--;
1046         high_shade = low_shade + 1;
1047
1048         index = (unsigned short)
1049           (((double) i - low_shade * blue_colors_per_shade) /
1050            blue_matrix_width);
1051
1052         blue_ordered_dither[i].s[1] = index;
1053         blue_ordered_dither[i].c[0] = low_shade;
1054         blue_ordered_dither[i].c[1] = high_shade;
1055       }
1056
1057
1058       /*  setup the gray information */
1059       {
1060         low_shade = (unsigned char) (i / gray_colors_per_shade);
1061         if (low_shade == (shades_gray - 1))
1062           low_shade--;
1063         high_shade = low_shade + 1;
1064
1065         index = (unsigned short)
1066           (((double) i - low_shade * gray_colors_per_shade) /
1067            gray_matrix_width);
1068
1069         gray_ordered_dither[i].s[1] = index;
1070         gray_ordered_dither[i].c[0] = gray_pixels[low_shade];
1071         gray_ordered_dither[i].c[1] = gray_pixels[high_shade];
1072       }
1073     }
1074 }
1075
1076 static void
1077 gtk_fill_lookup_array (gulong *array,
1078                        int     depth,
1079                        int     shift,
1080                        int     prec)
1081 {
1082   double one_over_gamma;
1083   double ind;
1084   int val;
1085   int i;
1086
1087   if (preview_class->info.gamma != 0.0)
1088     one_over_gamma = 1.0 / preview_class->info.gamma;
1089   else
1090     one_over_gamma = 1.0;
1091
1092   for (i = 0; i < 256; i++)
1093     {
1094       if (one_over_gamma == 1.0)
1095         array[i] = ((i >> prec) << shift);
1096       else
1097         {
1098           ind = (double) i / 255.0;
1099           val = (int) (255 * pow (ind, one_over_gamma));
1100           array[i] = ((val >> prec) << shift);
1101         }
1102     }
1103 }
1104
1105 static void
1106 gtk_trim_cmap (GtkPreviewClass *klass)
1107 {
1108   gulong pixels[256];
1109   guint nred;
1110   guint ngreen;
1111   guint nblue;
1112   guint ngray;
1113   guint nreserved;
1114   guint total;
1115   guint tmp;
1116   gint success;
1117
1118   nred = klass->info.nred_shades;
1119   ngreen = klass->info.ngreen_shades;
1120   nblue = klass->info.nblue_shades;
1121   ngray = klass->info.ngray_shades;
1122   nreserved = klass->info.nreserved;
1123
1124   success = FALSE;
1125   while (!success)
1126     {
1127       total = nred * ngreen * nblue + ngray + nreserved;
1128
1129       if (total <= 256)
1130         {
1131           if ((nred < 2) || (ngreen < 2) || (nblue < 2) || (ngray < 2))
1132             success = TRUE;
1133           else
1134             {
1135               success = gdk_colors_alloc (klass->info.cmap, 0, NULL, 0, pixels, total);
1136               if (success)
1137                 {
1138                   if (nreserved > 0)
1139                     {
1140                       klass->info.reserved_pixels = g_new (gulong, nreserved);
1141                       memcpy (klass->info.reserved_pixels, pixels, sizeof (gulong) * nreserved);
1142                       gdk_colors_free (klass->info.cmap, &pixels[nreserved],
1143                                        total - nreserved, 0);
1144                     }
1145                   else
1146                     {
1147                       gdk_colors_free (klass->info.cmap, pixels, total, 0);
1148                     }
1149                 }
1150             }
1151         }
1152
1153       if (!success)
1154         {
1155           if ((nblue >= nred) && (nblue >= ngreen))
1156             nblue = nblue - 1;
1157           else if ((nred >= ngreen) && (nred >= nblue))
1158             nred = nred - 1;
1159           else
1160             {
1161               tmp = log (ngray) / log (2);
1162
1163               if (ngreen >= tmp)
1164                 ngreen = ngreen - 1;
1165               else
1166                 ngray -= 1;
1167             }
1168         }
1169     }
1170
1171   if ((nred < 2) || (ngreen < 2) || (nblue < 2) || (ngray < 2))
1172     {
1173       g_print ("Unable to allocate sufficient colormap entries.\n");
1174       g_print ("Try exiting other color intensive applications.\n");
1175       return;
1176     }
1177
1178   /*  If any of the shade values has changed, issue a warning  */
1179   if ((nred != klass->info.nred_shades) ||
1180       (ngreen != klass->info.ngreen_shades) ||
1181       (nblue != klass->info.nblue_shades) ||
1182       (ngray != klass->info.ngray_shades))
1183     {
1184       g_print ("Not enough colors to satisfy requested color cube.\n");
1185       g_print ("Reduced color cube shades from\n");
1186       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",
1187                klass->info.nred_shades, klass->info.ngreen_shades,
1188                klass->info.nblue_shades, klass->info.ngray_shades,
1189                nred, ngreen, nblue, ngray);
1190     }
1191
1192   klass->info.nred_shades = nred;
1193   klass->info.ngreen_shades = ngreen;
1194   klass->info.nblue_shades = nblue;
1195   klass->info.ngray_shades = ngray;
1196 }
1197
1198 static void
1199 gtk_create_8_bit (GtkPreviewClass *klass)
1200 {
1201   unsigned int r, g, b;
1202   unsigned int rv, gv, bv;
1203   unsigned int dr, dg, db, dgray;
1204   GdkColor color;
1205   gulong *pixels;
1206   double one_over_gamma;
1207   int i;
1208
1209   if (!klass->info.color_pixels)
1210     klass->info.color_pixels = g_new (gulong, 256);
1211
1212   if (!klass->info.gray_pixels)
1213     klass->info.gray_pixels = g_new (gulong, 256);
1214
1215   if (klass->info.gamma != 0.0)
1216     one_over_gamma = 1.0 / klass->info.gamma;
1217   else
1218     one_over_gamma = 1.0;
1219
1220   dr = klass->info.nred_shades - 1;
1221   dg = klass->info.ngreen_shades - 1;
1222   db = klass->info.nblue_shades - 1;
1223   dgray = klass->info.ngray_shades - 1;
1224
1225   pixels = klass->info.color_pixels;
1226
1227   for (r = 0, i = 0; r <= dr; r++)
1228     for (g = 0; g <= dg; g++)
1229       for (b = 0; b <= db; b++, i++)
1230         {
1231           rv = (unsigned int) ((r * klass->info.visual->colormap_size) / dr);
1232           gv = (unsigned int) ((g * klass->info.visual->colormap_size) / dg);
1233           bv = (unsigned int) ((b * klass->info.visual->colormap_size) / db);
1234           color.red = ((int) (255 * pow ((double) rv / 256.0, one_over_gamma))) * 257;
1235           color.green = ((int) (255 * pow ((double) gv / 256.0, one_over_gamma))) * 257;
1236           color.blue = ((int) (255 * pow ((double) bv / 256.0, one_over_gamma))) * 257;
1237
1238           if (!gdk_color_alloc (klass->info.cmap, &color))
1239             {
1240               g_error ("could not initialize 8-bit combined colormap");
1241               return;
1242             }
1243
1244           pixels[i] = color.pixel;
1245         }
1246
1247   pixels = klass->info.gray_pixels;
1248
1249   for (i = 0; i < (int) klass->info.ngray_shades; i++)
1250     {
1251       color.red = (i * klass->info.visual->colormap_size) / dgray;
1252       color.red = ((int) (255 * pow ((double) color.red / 256.0, one_over_gamma))) * 257;
1253       color.green = color.red;
1254       color.blue = color.red;
1255
1256       if (!gdk_color_alloc (klass->info.cmap, &color))
1257         {
1258           g_error ("could not initialize 8-bit combined colormap");
1259           return;
1260         }
1261
1262       pixels[i] = color.pixel;
1263     }
1264 }
1265
1266
1267 static void
1268 gtk_color_8 (guchar *src,
1269              guchar *dest,
1270              gint    x,
1271              gint    y,
1272              gulong  width)
1273 {
1274   gulong *colors;
1275   GtkDitherInfo *dither_red;
1276   GtkDitherInfo *dither_green;
1277   GtkDitherInfo *dither_blue;
1278   GtkDitherInfo r, g, b;
1279   guchar **dither_matrix;
1280   guchar *matrix;
1281
1282   colors = preview_class->info.color_pixels;
1283   dither_red = preview_class->info.dither_red;
1284   dither_green = preview_class->info.dither_green;
1285   dither_blue = preview_class->info.dither_blue;
1286   dither_matrix = preview_class->info.dither_matrix[y & 0x7];
1287
1288   while (width--)
1289     {
1290       r = dither_red[src[0]];
1291       g = dither_green[src[1]];
1292       b = dither_blue[src[2]];
1293       src += 3;
1294
1295       matrix = dither_matrix[x++ & 0x7];
1296       *dest++ = colors[(r.c[matrix[r.s[1]]] +
1297                         g.c[matrix[g.s[1]]] +
1298                         b.c[matrix[b.s[1]]])];
1299     }
1300 }
1301
1302 static void
1303 gtk_color_16 (guchar *src,
1304               guchar *dest,
1305               gulong  width)
1306 {
1307   gulong *lookup_red;
1308   gulong *lookup_green;
1309   gulong *lookup_blue;
1310   gulong val;
1311
1312   lookup_red = preview_class->info.lookup_red;
1313   lookup_green = preview_class->info.lookup_green;
1314   lookup_blue = preview_class->info.lookup_blue;
1315
1316   while (width--)
1317     {
1318       val = COLOR_COMPOSE (src[0], src[1], src[2]);
1319       dest[0] = val;
1320       dest[1] = val >> 8;
1321       dest += 2;
1322       src += 3;
1323     }
1324 }
1325
1326 static void
1327 gtk_color_24 (guchar *src,
1328               guchar *dest,
1329               gulong  width)
1330 {
1331   gulong *lookup_red;
1332   gulong *lookup_green;
1333   gulong *lookup_blue;
1334   gulong val;
1335
1336   lookup_red = preview_class->info.lookup_red;
1337   lookup_green = preview_class->info.lookup_green;
1338   lookup_blue = preview_class->info.lookup_blue;
1339
1340   while (width--)
1341     {
1342       val = COLOR_COMPOSE (src[0], src[1], src[2]);
1343       dest[0] = val;
1344       dest[1] = val >> 8;
1345       dest[2] = val >> 16;
1346       dest += 3;
1347       src += 3;
1348     }
1349 }
1350
1351 static void
1352 gtk_grayscale_8 (guchar *src,
1353                  guchar *dest,
1354                  gint    x,
1355                  gint    y,
1356                  gulong  width)
1357 {
1358   GtkDitherInfo *dither_gray;
1359   GtkDitherInfo gray;
1360   guchar **dither_matrix;
1361   guchar *matrix;
1362
1363   dither_gray = preview_class->info.dither_gray;
1364   dither_matrix = preview_class->info.dither_matrix[y & 0x7];
1365
1366   while (width--)
1367     {
1368       gray = dither_gray[*src++];
1369       matrix = dither_matrix[x++ & 0x7];
1370       *dest++ = gray.c[matrix[gray.s[1]]];
1371     }
1372 }
1373
1374 static void
1375 gtk_grayscale_16 (guchar *src,
1376                   guchar *dest,
1377                   gulong  width)
1378 {
1379   gulong *lookup_red;
1380   gulong *lookup_green;
1381   gulong *lookup_blue;
1382   gulong val;
1383
1384   lookup_red = preview_class->info.lookup_red;
1385   lookup_green = preview_class->info.lookup_green;
1386   lookup_blue = preview_class->info.lookup_blue;
1387
1388   while (width--)
1389     {
1390       val = COLOR_COMPOSE (*src, *src, *src);
1391       dest[0] = val;
1392       dest[1] = val >> 8;
1393       dest += 2;
1394       src += 1;
1395     }
1396 }
1397
1398 static void
1399 gtk_grayscale_24 (guchar  *src,
1400                   guchar  *dest,
1401                   gulong   width)
1402 {
1403   gulong *lookup_red;
1404   gulong *lookup_green;
1405   gulong *lookup_blue;
1406   gulong val;
1407
1408   lookup_red = preview_class->info.lookup_red;
1409   lookup_green = preview_class->info.lookup_green;
1410   lookup_blue = preview_class->info.lookup_blue;
1411
1412   while (width--)
1413     {
1414       val = COLOR_COMPOSE (*src, *src, *src);
1415       dest[0] = val;
1416       dest[1] = val >> 8;
1417       dest[2] = val >> 16;
1418       dest += 3;
1419       src += 1;
1420     }
1421 }
1422
1423
1424 static gint
1425 gtk_get_preview_prop (guint *nred,
1426                       guint *ngreen,
1427                       guint *nblue,
1428                       guint *ngray)
1429 {
1430   GtkPreviewProp *prop;
1431   GdkAtom property;
1432
1433   property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE);
1434
1435   if (gdk_property_get (NULL, property, property,
1436                         0, sizeof (GtkPreviewProp), FALSE,
1437                         NULL, NULL, NULL, (guchar**) &prop))
1438     {
1439       *nred = ntohs (prop->nred_shades);
1440       *ngreen = ntohs (prop->ngreen_shades);
1441       *nblue = ntohs (prop->nblue_shades);
1442       *ngray = ntohs (prop->ngray_shades);
1443
1444       prop->ref_count = htons (ntohs (prop->ref_count) + 1);
1445       gdk_property_change (NULL, property, property, 16,
1446                            GDK_PROP_MODE_REPLACE,
1447                            (guchar*) prop, 5);
1448
1449       return TRUE;
1450     }
1451
1452   return FALSE;
1453 }
1454
1455 static void
1456 gtk_set_preview_prop (guint nred,
1457                       guint ngreen,
1458                       guint nblue,
1459                       guint ngray)
1460 {
1461   GtkPreviewProp prop;
1462   GdkAtom property;
1463
1464   property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE);
1465
1466   prop.ref_count = htons (1);
1467   prop.nred_shades = htons (nred);
1468   prop.ngreen_shades = htons (ngreen);
1469   prop.nblue_shades = htons (nblue);
1470   prop.ngray_shades = htons (ngray);
1471
1472   gdk_property_change (NULL, property, property, 16,
1473                        GDK_PROP_MODE_REPLACE,
1474                        (guchar*) &prop, 5);
1475 }
1476
1477
1478 static void
1479 gtk_lsbmsb_1_1 (guchar *dest,
1480                 guchar *src,
1481                 gint    count)
1482 {
1483   memcpy (dest, src, count);
1484 }
1485
1486 static void
1487 gtk_lsb_2_2 (guchar *dest,
1488              guchar *src,
1489              gint    count)
1490 {
1491   memcpy (dest, src, count * 2);
1492 }
1493
1494 static void
1495 gtk_msb_2_2 (guchar *dest,
1496              guchar *src,
1497              gint    count)
1498 {
1499   while (count--)
1500     {
1501       dest[0] = src[1];
1502       dest[1] = src[0];
1503       dest += 2;
1504       src += 2;
1505     }
1506 }
1507
1508 static void
1509 gtk_lsb_3_3 (guchar *dest,
1510              guchar *src,
1511              gint    count)
1512 {
1513   memcpy (dest, src, count * 3);
1514 }
1515
1516 static void
1517 gtk_msb_3_3 (guchar *dest,
1518              guchar *src,
1519              gint    count)
1520 {
1521   while (count--)
1522     {
1523       dest[0] = src[2];
1524       dest[1] = src[1];
1525       dest[2] = src[0];
1526       dest += 3;
1527       src += 3;
1528     }
1529 }
1530
1531 static void
1532 gtk_lsb_3_4 (guchar *dest,
1533              guchar *src,
1534              gint    count)
1535 {
1536   while (count--)
1537     {
1538       dest[0] = src[0];
1539       dest[1] = src[1];
1540       dest[2] = src[2];
1541       dest += 4;
1542       src += 3;
1543     }
1544 }
1545
1546 static void
1547 gtk_msb_3_4 (guchar *dest,
1548              guchar *src,
1549              gint    count)
1550 {
1551   while (count--)
1552     {
1553       dest[1] = src[2];
1554       dest[2] = src[1];
1555       dest[3] = src[0];
1556       dest += 4;
1557       src += 3;
1558     }
1559 }