1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* Color Context module
20 * Copyright 1994,1995 John L. Cwikla
21 * Copyright (C) 1997 by Ripley Software Development
22 * Copyright (C) 1997 by Federico Mena (port to Gtk/Gdk)
25 /* Copyright 1994,1995 John L. Cwikla
27 * Permission to use, copy, modify, distribute, and sell this software
28 * and its documentation for any purpose is hereby granted without fee,
29 * provided that the above copyright notice appears in all copies and that
30 * both that copyright notice and this permission notice appear in
31 * supporting documentation, and that the name of John L. Cwikla or
32 * Wolfram Research, Inc not be used in advertising or publicity
33 * pertaining to distribution of the software without specific, written
34 * prior permission. John L. Cwikla and Wolfram Research, Inc make no
35 * representations about the suitability of this software for any
36 * purpose. It is provided "as is" without express or implied warranty.
38 * John L. Cwikla and Wolfram Research, Inc disclaim all warranties with
39 * regard to this software, including all implied warranties of
40 * merchantability and fitness, in no event shall John L. Cwikla or
41 * Wolfram Research, Inc be liable for any special, indirect or
42 * consequential damages or any damages whatsoever resulting from loss of
43 * use, data or profits, whether in an action of contract, negligence or
44 * other tortious action, arising out of or in connection with the use or
45 * performance of this software.
50 * Wolfram Research Inc.
60 #include "gdkprivate.h"
64 #define MAX_IMAGE_COLORS 256
68 hash_color (gpointer key)
70 GdkColor *color = key;
72 return (color->red * 33023 + color->green * 30013 + color->blue * 27011);
76 compare_colors (gpointer a,
82 return ((aa->red == bb->red) && (aa->green == bb->green) && (aa->blue == bb->blue));
86 free_hash_entry (gpointer key,
90 g_free (key); /* key and value are the same GdkColor */
94 pixel_sort (const void *a, const void *b)
96 return ((GdkColor *) a)->pixel - ((GdkColor *) b)->pixel;
99 /* XXX: This function does an XQueryColors() the hard way, because there is
100 * no corresponding function in Gdk.
104 my_x_query_colors (GdkColormap *colormap,
111 xcolors = g_new (XColor, ncolors);
112 for (i = 0; i < ncolors; i++)
113 xcolors[i].pixel = colors[i].pixel;
115 XQueryColors (gdk_display, GDK_COLORMAP_XCOLORMAP (colormap), xcolors, ncolors);
117 for (i = 0; i < ncolors; i++)
119 colors[i].red = xcolors[i].red;
120 colors[i].green = xcolors[i].green;
121 colors[i].blue = xcolors[i].blue;
128 query_colors (GdkColorContext *cc)
131 GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
132 cc->cmap = g_new (GdkColor, cc->num_colors);
134 for (i = 0; i < cc->num_colors; i++)
135 cc->cmap[i].pixel = cc->clut ? cc->clut[i] : ccp->std_cmap.base_pixel + i;
137 my_x_query_colors (cc->colormap, cc->cmap, cc->num_colors);
139 qsort (cc->cmap, cc->num_colors, sizeof (GdkColor), pixel_sort);
143 init_bw (GdkColorContext *cc)
147 g_warning ("init_bw: failed to allocate colors, falling back to black and white");
149 cc->mode = GDK_CC_MODE_BW;
151 color.red = color.green = color.blue = 0;
153 if (!gdk_color_alloc (cc->colormap, &color))
156 cc->black_pixel = color.pixel;
158 color.red = color.green = color.blue = 0xffff;
160 if (!gdk_color_alloc (cc->colormap, &color))
161 cc->white_pixel = cc->black_pixel ? 0 : 1;
163 cc->white_pixel = color.pixel;
169 init_gray (GdkColorContext *cc)
171 GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
172 GdkColor *clrs, *cstart;
176 cc->num_colors = GDK_VISUAL_XVISUAL (cc->visual)->map_entries;
178 cc->clut = g_new (gulong, cc->num_colors);
179 cstart = g_new (GdkColor, cc->num_colors);
183 dinc = 65535.0 / (cc->num_colors - 1);
187 for (i = 0; i < cc->num_colors; i++)
189 clrs->red = clrs->green = clrs->blue = dinc * i;
191 if (!gdk_color_alloc (cc->colormap, clrs))
193 gdk_colors_free (cc->colormap, cc->clut, i, 0);
197 if (cc->num_colors > 1)
209 cc->clut[i] = clrs++->pixel;
214 /* XXX: is this the right thing to do? */
215 ccp->std_cmap.colormap = GDK_COLORMAP_XCOLORMAP (cc->colormap);
216 ccp->std_cmap.base_pixel = 0;
217 ccp->std_cmap.red_max = cc->num_colors - 1;
218 ccp->std_cmap.green_max = 0;
219 ccp->std_cmap.blue_max = 0;
220 ccp->std_cmap.red_mult = 1;
221 ccp->std_cmap.green_mult = 0;
222 ccp->std_cmap.blue_mult = 0;
224 cc->white_pixel = WhitePixel (ccp->xdisplay, gdk_screen);
225 cc->black_pixel = BlackPixel (ccp->xdisplay, gdk_screen);
229 cc->mode = GDK_CC_MODE_MY_GRAY;
233 init_color (GdkColorContext *cc)
235 GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
239 while ((cubeval * cubeval * cubeval) < GDK_VISUAL_XVISUAL (cc->visual)->map_entries)
243 cc->num_colors = cubeval * cubeval * cubeval;
245 ccp->std_cmap.red_max = cubeval - 1;
246 ccp->std_cmap.green_max = cubeval - 1;
247 ccp->std_cmap.blue_max = cubeval - 1;
248 ccp->std_cmap.red_mult = cubeval * cubeval;
249 ccp->std_cmap.green_mult = cubeval;
250 ccp->std_cmap.blue_mult = 1;
251 ccp->std_cmap.base_pixel = 0;
253 cc->white_pixel = WhitePixel (ccp->xdisplay, gdk_screen);
254 cc->black_pixel = BlackPixel (ccp->xdisplay, gdk_screen);
255 cc->num_colors = DisplayCells (ccp->xdisplay, gdk_screen);
257 /* a CLUT for storing allocated pixel indices */
259 cc->max_colors = cc->num_colors;
260 cc->clut = g_new (gulong, cc->max_colors);
262 for (cubeval = 0; cubeval < cc->max_colors; cubeval++)
263 cc->clut[cubeval] = cubeval;
267 cc->mode = GDK_CC_MODE_STD_CMAP;
272 init_true_color (GdkColorContext *cc)
274 GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
275 gulong rmask, gmask, bmask;
277 cc->mode = GDK_CC_MODE_TRUE;
281 rmask = cc->masks.red = cc->visual->red_mask;
300 gmask = cc->masks.green = cc->visual->green_mask;
302 cc->shifts.green = 0;
319 bmask = cc->masks.blue = cc->visual->blue_mask;
336 cc->num_colors = (cc->visual->red_mask | cc->visual->green_mask | cc->visual->blue_mask) + 1;
337 cc->white_pixel = WhitePixel (ccp->xdisplay, gdk_screen);
338 cc->black_pixel = BlackPixel (ccp->xdisplay, gdk_screen);
342 init_direct_color (GdkColorContext *cc)
345 GdkColor *clrs, *cstart;
346 gulong rval, gval, bval;
352 init_true_color (cc); /* for shift stuff */
354 rval = cc->visual->red_mask >> cc->shifts.red;
355 gval = cc->visual->green_mask >> cc->shifts.green;
356 bval = cc->visual->blue_mask >> cc->shifts.blue;
358 rtable = g_new (gulong, rval + 1);
359 gtable = g_new (gulong, gval + 1);
360 btable = g_new (gulong, bval + 1);
362 cc->max_entry = MAX (rval, gval);
363 cc->max_entry = MAX (cc->max_entry, bval);
365 cstart = g_new (GdkColor, cc->max_entry + 1);
366 cc->clut = g_new (gulong, cc->max_entry + 1);
370 for (n = 0; n < rval; n++)
371 rtable[n] = rval ? (65535.0 / rval * n) : 0;
373 for (n = 0; n < gval; n++)
374 gtable[n] = gval ? (65535.0 / gval * n) : 0;
376 for (n = 0; n < bval; n++)
377 btable[n] = bval ? (65535.0 / bval * n) : 0;
379 cc->max_entry = MAX (rval, gval);
380 cc->max_entry = MAX (cc->max_entry, bval);
384 cc->num_colors = (rval + 1) * (gval + 1) * (bval + 1);
386 for (n = 0; n < cc->max_entry; n++)
388 dinc = (double) n / cc->max_entry;
390 clrs->red = rtable[(int) (dinc * rval)];
391 clrs->green = gtable[(int) (dinc * gval)];
392 clrs->blue = btable[(int) (dinc * bval)];
394 if (gdk_color_alloc (cc->colormap, clrs))
396 cc->clut[count++] = clrs->pixel;
401 gdk_colors_free (cc->colormap, cc->clut, count, 0);
407 cc->masks.red = (cc->masks.red >> 1) & cc->visual->red_mask;
408 cc->masks.green = (cc->masks.green >> 1) & cc->visual->green_mask;
409 cc->masks.blue = (cc->masks.blue >> 1) & cc->visual->blue_mask;
419 cc->num_colors = (rval + 1) * (gval + 1) * (bval + 1);
421 if (cc->num_colors >1)
433 /* Update allocated color count; original num_colors is max_entry, which
434 * is not necessarily the same as the really allocated number of colors.
437 cc->num_colors = count;
446 init_palette (GdkColorContext *cc)
448 /* restore correct mode for this cc */
450 switch (cc->visual->type)
452 case GDK_VISUAL_STATIC_GRAY:
453 case GDK_VISUAL_GRAYSCALE:
454 if (GDK_VISUAL_XVISUAL (cc->visual)->map_entries == 2)
455 cc->mode = GDK_CC_MODE_BW;
457 cc->mode = GDK_CC_MODE_MY_GRAY;
460 case GDK_VISUAL_TRUE_COLOR:
461 case GDK_VISUAL_DIRECT_COLOR:
462 cc->mode = GDK_CC_MODE_TRUE;
465 case GDK_VISUAL_STATIC_COLOR:
466 case GDK_VISUAL_PSEUDO_COLOR:
467 cc->mode = GDK_CC_MODE_STD_CMAP;
471 cc->mode = GDK_CC_MODE_UNDEFINED;
475 /* previous palette */
478 g_free (cc->palette);
481 g_free (cc->fast_dither);
483 /* clear hash table if present */
487 /* XXX: quick-and-dirty way to remove everything */
489 g_hash_table_destroy (cc->color_hash);
490 cc->color_hash = g_hash_table_new (hash_color, compare_colors);
495 cc->fast_dither = NULL;
499 gdk_color_context_new (GdkVisual *visual,
500 GdkColormap *colormap)
502 GdkColorContextPrivate *ccp;
503 gint use_private_colormap = FALSE; /* XXX: maybe restore full functionality later? */
506 GdkColormap *default_colormap;
508 g_assert (visual != NULL);
509 g_assert (colormap != NULL);
511 ccp = g_new (GdkColorContextPrivate, 1);
512 cc = (GdkColorContext *) ccp;
513 ccp->xdisplay = gdk_display;
515 cc->colormap = colormap;
518 cc->mode = GDK_CC_MODE_UNDEFINED;
519 cc->need_to_free_colormap = FALSE;
521 cc->color_hash = NULL;
524 cc->fast_dither = NULL;
526 default_colormap = gdk_colormap_get_system ();
530 while (retry_count < 2)
532 /* Only create a private colormap if the visual found isn't equal
533 * to the default visual and we don't have a private colormap,
534 * -or- if we are instructed to create a private colormap (which
535 * never is the case for XmHTML).
538 if (use_private_colormap
539 || ((cc->visual != gdk_visual_get_system ()) /* default visual? */
540 && (GDK_COLORMAP_XCOLORMAP (colormap) == GDK_COLORMAP_XCOLORMAP (default_colormap))))
542 g_warning ("gdk_color_context_new: non-default visual detected, "
543 "using private colormap");
545 cc->colormap = gdk_colormap_new (cc->visual, FALSE);
547 cc->need_to_free_colormap = (GDK_COLORMAP_XCOLORMAP (colormap)
548 != GDK_COLORMAP_XCOLORMAP (default_colormap));
551 switch (visual->type)
553 case GDK_VISUAL_STATIC_GRAY:
554 case GDK_VISUAL_GRAYSCALE:
555 GDK_NOTE (COLOR_CONTEXT,
556 g_print ("gdk_color_context_new: visual class is %s\n",
557 (visual->type == GDK_VISUAL_STATIC_GRAY) ?
558 "GDK_VISUAL_STATIC_GRAY" :
559 "GDK_VISUAL_GRAYSCALE"));
561 if (GDK_VISUAL_XVISUAL (cc->visual)->map_entries == 2)
568 case GDK_VISUAL_TRUE_COLOR: /* shifts */
569 GDK_NOTE (COLOR_CONTEXT,
570 g_print ("gdk_color_context_new: visual class is GDK_VISUAL_TRUE_COLOR\n"));
572 init_true_color (cc);
575 case GDK_VISUAL_DIRECT_COLOR: /* shifts and fake CLUT */
576 GDK_NOTE (COLOR_CONTEXT,
577 g_print ("gdk_color_context_new: visual class is GDK_VISUAL_DIRECT_COLOR\n"));
579 init_direct_color (cc);
582 case GDK_VISUAL_STATIC_COLOR:
583 case GDK_VISUAL_PSEUDO_COLOR:
584 GDK_NOTE (COLOR_CONTEXT,
585 g_print ("gdk_color_context_new: visual class is %s\n",
586 (visual->type == GDK_VISUAL_STATIC_COLOR) ?
587 "GDK_VISUAL_STATIC_COLOR" :
588 "GDK_VISUAL_PSEUDO_COLOR"));
594 g_assert_not_reached ();
597 if ((cc->mode == GDK_CC_MODE_BW) && (cc->visual->depth > 1))
599 use_private_colormap = TRUE;
606 /* no. of colors allocated yet */
608 cc->num_allocated = 0;
610 GDK_NOTE (COLOR_CONTEXT,
611 g_print ("gdk_color_context_new: screen depth is %i, no. of colors is %i\n",
612 cc->visual->depth, cc->num_colors));
614 /* check if we need to initialize a hash table */
616 if ((cc->mode == GDK_CC_MODE_STD_CMAP) || (cc->mode == GDK_CC_MODE_UNDEFINED))
617 cc->color_hash = g_hash_table_new (hash_color, compare_colors);
619 return (GdkColorContext *) cc;
623 gdk_color_context_new_mono (GdkVisual *visual,
624 GdkColormap *colormap)
626 GdkColorContextPrivate *ccp;
629 g_assert (visual != NULL);
630 g_assert (colormap != NULL);
632 cc = g_new (GdkColorContext, 1);
633 ccp = (GdkColorContextPrivate *) cc;
634 ccp->xdisplay = gdk_display;
636 cc->colormap = colormap;
639 cc->mode = GDK_CC_MODE_UNDEFINED;
640 cc->need_to_free_colormap = FALSE;
644 return (GdkColorContext *) cc;
647 /* This doesn't currently free black/white, hmm... */
650 gdk_color_context_free (GdkColorContext *cc)
652 g_assert (cc != NULL);
654 if ((cc->visual->type == GDK_VISUAL_STATIC_COLOR)
655 || (cc->visual->type == GDK_VISUAL_PSEUDO_COLOR))
657 gdk_colors_free (cc->colormap, cc->clut, cc->num_allocated, 0);
660 else if (cc->clut != NULL)
662 gdk_colors_free (cc->colormap, cc->clut, cc->num_colors, 0);
666 if (cc->cmap != NULL)
669 if (cc->need_to_free_colormap)
670 gdk_colormap_unref (cc->colormap);
672 /* free any palette that has been associated with this GdkColorContext */
678 g_hash_table_foreach (cc->color_hash,
681 g_hash_table_destroy (cc->color_hash);
688 gdk_color_context_get_pixel (GdkColorContext *cc,
694 GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
695 g_assert (cc != NULL);
696 g_assert (failed != NULL);
706 value = (red / 65535.0 * 0.30
707 + green / 65535.0 * 0.59
708 + blue / 65535.0 * 0.11);
711 return cc->white_pixel;
713 return cc->black_pixel;
716 case GDK_CC_MODE_MY_GRAY:
718 gulong ired, igreen, iblue;
720 red = red * 0.30 + green * 0.59 + blue * 0.11;
724 if ((ired = red * (ccp->std_cmap.red_max + 1) / 0xffff) > ccp->std_cmap.red_max)
725 ired = ccp->std_cmap.red_max;
727 ired *= ccp->std_cmap.red_mult;
729 if ((igreen = green * (ccp->std_cmap.green_max + 1) / 0xffff) > ccp->std_cmap.green_max)
730 igreen = ccp->std_cmap.green_max;
732 igreen *= ccp->std_cmap.green_mult;
734 if ((iblue = blue * (ccp->std_cmap.blue_max + 1) / 0xffff) > ccp->std_cmap.blue_max)
735 iblue = ccp->std_cmap.blue_max;
737 iblue *= ccp->std_cmap.blue_mult;
739 if (cc->clut != NULL)
740 return cc->clut[ccp->std_cmap.base_pixel + ired + igreen + iblue];
742 return ccp->std_cmap.base_pixel + ired + igreen + iblue;
745 case GDK_CC_MODE_TRUE:
747 gulong ired, igreen, iblue;
749 if (cc->clut == NULL)
751 red >>= 16 - cc->bits.red;
752 green >>= 16 - cc->bits.green;
753 blue >>= 16 - cc->bits.blue;
755 ired = (red << cc->shifts.red) & cc->masks.red;
756 igreen = (green << cc->shifts.green) & cc->masks.green;
757 iblue = (blue << cc->shifts.blue) & cc->masks.blue;
759 return ired | igreen | iblue;
762 ired = cc->clut[red * cc->max_entry / 65535] & cc->masks.red;
763 igreen = cc->clut[green * cc->max_entry / 65535] & cc->masks.green;
764 iblue = cc->clut[blue * cc->max_entry / 65535] & cc->masks.blue;
766 return ired | igreen | iblue;
769 case GDK_CC_MODE_PALETTE:
770 return gdk_color_context_get_pixel_from_palette (cc, &red, &green, &blue, failed);
772 case GDK_CC_MODE_STD_CMAP:
782 result = g_hash_table_lookup (cc->color_hash, &color);
791 if (!gdk_color_alloc (cc->colormap, &color))
797 /* XXX: the following comment comes directly from
798 * XCC.c. I don't know if it is relevant for
799 * gdk_color_alloc() as it is for XAllocColor()
803 * I can't figure this out entirely, but it *is* possible
804 * that XAllocColor succeeds, even if the number of
805 * allocations we've made exceeds the number of available
806 * colors in the current colormap. And therefore it
807 * might be necessary for us to resize the CLUT.
810 if (cc->num_allocated == cc->max_colors)
814 GDK_NOTE (COLOR_CONTEXT,
815 g_print ("gdk_color_context_get_pixel: "
816 "resizing CLUT to %i entries\n",
819 cc->clut = g_realloc (cc->clut,
820 cc->max_colors * sizeof (gulong));
823 /* Key and value are the same color structure */
825 cnew = g_new (GdkColor, 1);
827 g_hash_table_insert (cc->color_hash, cnew, cnew);
829 cc->clut[cc->num_allocated] = color.pixel;
835 return result->pixel;
841 gdk_color_context_get_pixels (GdkColorContext *cc,
850 gint cmapsize, ncols = 0, nopen = 0, counter = 0;
851 gint bad_alloc = FALSE;
852 gint failed[MAX_IMAGE_COLORS], allocated[MAX_IMAGE_COLORS];
853 GdkColor defs[MAX_IMAGE_COLORS], cmap[MAX_IMAGE_COLORS];
854 #ifdef G_ENABLE_DEBUG
855 gint exact_col = 0, subst_col = 0, close_col = 0, black_col = 0;
857 g_assert (cc != NULL);
858 g_assert (reds != NULL);
859 g_assert (greens != NULL);
860 g_assert (blues != NULL);
861 g_assert (colors != NULL);
862 g_assert (nallocated != NULL);
864 memset (defs, 0, MAX_IMAGE_COLORS * sizeof (GdkColor));
865 memset (failed, 0, MAX_IMAGE_COLORS * sizeof (gint));
866 memset (allocated, 0, MAX_IMAGE_COLORS * sizeof (gint));
868 /* Will only have a value if used by the progressive image loader */
874 /* First allocate all pixels */
876 for (i = 0; i < ncolors; i++)
878 /* colors[i] is only zero if the pixel at that location hasn't
879 * been allocated yet. This is a sanity check required for proper
880 * color allocation by the progressive image loader
885 defs[i].red = reds[i];
886 defs[i].green = greens[i];
887 defs[i].blue = blues[i];
889 colors[i] = gdk_color_context_get_pixel (cc, reds[i], greens[i], blues[i],
892 /* successfully allocated, store it */
896 defs[i].pixel = colors[i];
897 allocated[ncols++] = colors[i];
906 /* all colors available, all done */
908 if ((ncols == ncolors) || (nopen == 0))
910 GDK_NOTE (COLOR_CONTEXT,
911 g_print ("gdk_color_context_get_pixels: got all %i colors; "
912 "(%i colors allocated so far)\n", ncolors, cc->num_allocated));
917 /* The fun part. We now try to allocate the colors we couldn't allocate
918 * directly. The first step will map a color onto its nearest color
919 * that has been allocated (either by us or someone else). If any colors
920 * remain unallocated, we map these onto the colors that we have allocated
924 /* read up to MAX_IMAGE_COLORS colors of the current colormap */
926 cmapsize = MIN (cc->num_colors, MAX_IMAGE_COLORS);
928 /* see if the colormap has any colors to read */
932 g_warning ("gdk_color_context_get_pixels: oops! no colors available, "
933 "your images will look *really* ugly.");
938 #ifdef G_ENABLE_DEBUG
942 /* initialize pixels */
944 for (i = 0; i < cmapsize; i++)
947 cmap[i].red = cmap[i].green = cmap[i].blue = 0;
950 /* read the colormap */
952 my_x_query_colors (cc->colormap, cmap, cmapsize);
954 /* get a close match for any unallocated colors */
962 gint d, j, mdist, close, ri, gi, bi;
970 /* Store these vals. Small performance increase as this skips three
971 * indexing operations in the loop code.
978 /* Walk all colors in the colormap and see which one is the
979 * closest. Uses plain least squares.
982 for (j = 0; (j < cmapsize) && (mdist != 0); j++)
984 /* Don't replace these by shifts; the sign may get clobbered */
986 rd = (ri - cmap[j].red) / 256;
987 gd = (gi - cmap[j].green) / 256;
988 bd = (bi - cmap[j].blue) / 256;
990 d = rd * rd + gd * gd + bd * bd;
1001 rd = cmap[close].red;
1002 gd = cmap[close].green;
1003 bd = cmap[close].blue;
1007 colors[i] = gdk_color_context_get_pixel (cc, rd, gd, bd, &bad_alloc);
1013 defs[i] = cmap[close];
1014 defs[i].pixel = colors[i];
1015 allocated[ncols++] = colors[i];
1016 #ifdef G_ENABLE_DEBUG
1020 failed[nopen++] = i;
1022 failed[nopen++] = i;
1023 /* deal with in next stage if allocation failed */
1025 while (++idx < counter);
1027 *nallocated = ncols;
1029 /* This is the maximum no. of allocated colors. See also the nopen == 0
1033 if ((ncols == ncolors) || (nopen == 0))
1035 GDK_NOTE (COLOR_CONTEXT,
1036 g_print ("gdk_color_context_get_pixels: got %i colors, %i exact and "
1037 "%i close (%i colors allocated so far)\n",
1038 ncolors, exact_col, close_col, cc->num_allocated));
1043 /* Now map any remaining unallocated pixels into the colors we did get */
1049 gint d, mdist, close, ri, gi, bi;
1063 /* search allocated colors */
1065 for (j = 0; (j < ncols) && (mdist != 0); j++)
1069 /* Don't replace these by shifts; the sign may get clobbered */
1071 rd = (ri - defs[k].red) / 256;
1072 gd = (gi - defs[k].green) / 256;
1073 bd = (bi - defs[k].blue) / 256;
1075 d = rd * rd + gd * gd + bd * bd;
1086 /* too bad, map to black */
1088 defs[i].pixel = cc->black_pixel;
1089 defs[i].red = defs[i].green = defs[i].blue = 0;
1090 #ifdef G_ENABLE_DEBUG
1096 defs[i] = defs[close];
1097 #ifdef G_ENABLE_DEBUG
1102 colors[i] = defs[i].pixel;
1104 while (++idx < nopen);
1106 GDK_NOTE (COLOR_CONTEXT,
1107 g_print ("gdk_color_context_get_pixels: got %i colors, %i exact, %i close, "
1108 "%i substituted, %i to black (%i colors allocated so far)\n",
1109 ncolors, exact_col, close_col, subst_col, black_col, cc->num_allocated));
1113 gdk_color_context_get_pixels_incremental (GdkColorContext *cc,
1123 gint cmapsize, ncols = 0, nopen = 0, counter = 0;
1124 gint bad_alloc = FALSE;
1125 gint failed[MAX_IMAGE_COLORS], allocated[MAX_IMAGE_COLORS];
1126 GdkColor defs[MAX_IMAGE_COLORS], cmap[MAX_IMAGE_COLORS];
1127 #ifdef G_ENABLE_DEBUG
1128 gint exact_col = 0, subst_col = 0, close_col = 0, black_col = 0;
1131 g_assert (cc != NULL);
1132 g_assert (reds != NULL);
1133 g_assert (greens != NULL);
1134 g_assert (blues != NULL);
1135 g_assert (used != NULL);
1136 g_assert (colors != NULL);
1137 g_assert (nallocated != NULL);
1139 memset (defs, 0, MAX_IMAGE_COLORS * sizeof (GdkColor));
1140 memset (failed, 0, MAX_IMAGE_COLORS * sizeof (gint));
1141 memset (allocated, 0, MAX_IMAGE_COLORS * sizeof (gint));
1143 /* Will only have a value if used by the progressive image loader */
1145 ncols = *nallocated;
1149 /* First allocate all pixels */
1151 for (i = 0; i < ncolors; i++)
1153 /* used[i] is only -1 if the pixel at that location hasn't
1154 * been allocated yet. This is a sanity check required for proper
1155 * color allocation by the progressive image loader.
1156 * When colors[i] == 0 it indicates the slot is available for
1160 if (used[i] != FALSE)
1164 defs[i].red = reds[i];
1165 defs[i].green = greens[i];
1166 defs[i].blue = blues[i];
1168 colors[i] = gdk_color_context_get_pixel (cc, reds[i], greens[i], blues[i], &bad_alloc);
1170 /* successfully allocated, store it */
1174 defs[i].pixel = colors[i];
1175 allocated[ncols++] = colors[i];
1178 failed[nopen++] = i;
1182 GDK_NOTE (COLOR_CONTEXT,
1183 g_print ("gdk_color_context_get_pixels_incremental: "
1184 "pixel at slot %i already allocated, skipping\n", i));
1189 *nallocated = ncols;
1191 if ((ncols == ncolors) || (nopen == 0))
1193 GDK_NOTE (COLOR_CONTEXT,
1194 g_print ("gdk_color_context_get_pixels_incremental: got all %i colors "
1195 "(%i colors allocated so far)\n",
1196 ncolors, cc->num_allocated));
1201 cmapsize = MIN (cc->num_colors, MAX_IMAGE_COLORS);
1205 g_warning ("gdk_color_context_get_pixels_incremental: oops! "
1206 "No colors available images will look *really* ugly.");
1210 #ifdef G_ENABLE_DEBUG
1214 /* initialize pixels */
1216 for (i = 0; i < cmapsize; i++)
1219 cmap[i].red = cmap[i].green = cmap[i].blue = 0;
1224 my_x_query_colors (cc->colormap, cmap, cmapsize);
1226 /* now match any unallocated colors */
1234 gint d, j, mdist, close, ri, gi, bi;
1248 for (j = 0; (j < cmapsize) && (mdist != 0); j++)
1250 /* Don't replace these by shifts; the sign may get clobbered */
1252 rd = (ri - cmap[j].red) / 256;
1253 gd = (gi - cmap[j].green) / 256;
1254 bd = (bi - cmap[j].blue) / 256;
1256 d = rd * rd + gd * gd + bd * bd;
1267 rd = cmap[close].red;
1268 gd = cmap[close].green;
1269 bd = cmap[close].blue;
1273 colors[i] = gdk_color_context_get_pixel (cc, rd, gd, bd, &bad_alloc);
1279 defs[i] = cmap[close];
1280 defs[i].pixel = colors[i];
1281 allocated[ncols++] = colors[i];
1282 #ifdef G_ENABLE_DEBUG
1287 failed[nopen++] = i;
1290 failed[nopen++] = i;
1291 /* deal with in next stage if allocation failed */
1293 while (++idx < counter);
1295 *nallocated = ncols;
1297 if ((ncols == ncolors) || (nopen == 0))
1299 GDK_NOTE (COLOR_CONTEXT,
1300 g_print ("gdk_color_context_get_pixels_incremental: "
1301 "got %i colors, %i exact and %i close "
1302 "(%i colors allocated so far)\n",
1303 ncolors, exact_col, close_col, cc->num_allocated));
1308 /* map remaining unallocated pixels into colors we did get */
1314 gint d, mdist, close, ri, gi, bi;
1326 /* search allocated colors */
1328 for (j = 0; (j < ncols) && (mdist != 0); j++)
1333 /* Don't replace these by shifts; the sign may get clobbered */
1335 rd = (ri - defs[k].red) / 256;
1336 gd = (gi - defs[k].green) / 256;
1337 bd = (bi - defs[k].blue) / 256;
1339 d = rd * rd + gd * gd + bd * bd;
1350 /* too bad, map to black */
1352 defs[i].pixel = cc->black_pixel;
1353 defs[i].red = defs[i].green = defs[i].blue = 0;
1354 #ifdef G_ENABLE_DEBUG
1360 defs[i] = defs[close];
1361 #ifdef G_ENABLE_DEBUG
1366 colors[i] = defs[i].pixel;
1368 while (++idx < nopen);
1370 GDK_NOTE (COLOR_CONTEXT,
1371 g_print ("gdk_color_context_get_pixels_incremental: "
1372 "got %i colors, %i exact, %i close, %i substituted, %i to black "
1373 "(%i colors allocated so far)\n",
1374 ncolors, exact_col, close_col, subst_col, black_col, cc->num_allocated));
1378 gdk_color_context_query_color (GdkColorContext *cc,
1381 return gdk_color_context_query_colors (cc, color, 1);
1385 gdk_color_context_query_colors (GdkColorContext *cc,
1392 g_assert (cc != NULL);
1393 g_assert (colors != NULL);
1397 case GDK_CC_MODE_BW:
1398 for (i = 0, tc = colors; i < num_colors; i++, tc++)
1400 if (tc->pixel == cc->white_pixel)
1401 tc->red = tc->green = tc->blue = 65535;
1403 tc->red = tc->green = tc->blue = 0;
1407 case GDK_CC_MODE_TRUE:
1408 if (cc->clut == NULL)
1409 for (i = 0, tc = colors; i < num_colors; i++, tc++)
1411 tc->red = ((tc->pixel & cc->masks.red) >> cc->shifts.red) << (16 - cc->bits.red);
1412 tc->green = ((tc->pixel & cc->masks.green) >> cc->shifts.green) << (16 - cc->bits.green);
1413 tc->blue = ((tc->pixel & cc->masks.blue) >> cc->shifts.blue) << (16 - cc->bits.blue);
1417 my_x_query_colors (cc->colormap, colors, num_colors);
1422 case GDK_CC_MODE_STD_CMAP:
1424 if (cc->cmap == NULL)
1426 my_x_query_colors (cc->colormap, colors, num_colors);
1431 gint first, last, half;
1434 for (i = 0, tc = colors; i < num_colors; i++)
1437 last = cc->num_colors - 1;
1439 while (first <= last)
1441 half = (first + last) / 2;
1442 half_pixel = cc->cmap[half].pixel;
1444 if (tc->pixel == half_pixel)
1446 tc->red = cc->cmap[half].red;
1447 tc->green = cc->cmap[half].green;
1448 tc->blue = cc->cmap[half].blue;
1449 first = last + 1; /* false break */
1453 if (tc->pixel > half_pixel)
1468 gdk_color_context_add_palette (GdkColorContext *cc,
1476 g_assert (cc != NULL);
1478 /* initialize this palette (will also erase previous palette as well) */
1482 /* restore previous mode if we aren't adding a new palette */
1484 if (num_palette == 0)
1486 /* GDK_CC_MODE_STD_CMAP uses a hash table, so we'd better initialize one */
1488 /* XXX: here, the hash table is already initialized */
1493 /* Initialize a hash table for this palette (we need one for allocating
1494 * the pixels in the palette using the current settings)
1497 if (cc->color_hash == NULL)
1498 cc->color_hash = g_hash_table_new (hash_color, compare_colors);
1500 /* copy incoming palette */
1502 cc->palette = g_new0(GdkColor, num_palette);
1506 for (i = 0; i < num_palette; i++)
1511 /* try to allocate this color */
1514 g = palette[i].green;
1515 b = palette[i].blue;
1517 gdk_color_context_get_pixels (cc, &r, &g, &b, 1, pixel, &erg);
1519 /* only store if we succeed */
1523 /* store in palette */
1525 cc->palette[j].red = r;
1526 cc->palette[j].green = g;
1527 cc->palette[j].blue = b;
1528 cc->palette[j].pixel = pixel[0];
1530 /* move to next slot */
1538 if (j != num_palette)
1539 cc->palette = g_realloc (cc->palette, j * sizeof (GdkColor));
1541 /* clear the hash table, we don't use it when dithering */
1545 g_hash_table_destroy (cc->color_hash);
1546 cc->color_hash = NULL;
1549 /* store real palette size */
1551 cc->num_palette = j;
1553 /* switch to palette mode */
1555 cc->mode = GDK_CC_MODE_PALETTE;
1559 qsort (cc->palette, cc->num_palette, sizeof (GdkColor), pixel_sort);
1561 cc->fast_dither = NULL;
1567 gdk_color_context_init_dither (GdkColorContext *cc)
1569 gint rr, gg, bb, err, erg, erb;
1570 gint success = FALSE;
1572 g_assert (cc != NULL);
1574 /* now we can initialize the fast dither matrix */
1576 if (cc->fast_dither == NULL)
1577 cc->fast_dither = g_new (GdkColorContextDither, 1);
1579 /* Fill it. We ignore unsuccessful allocations, they are just mapped
1580 * to black instead */
1582 for (rr = 0; rr < 32; rr++)
1583 for (gg = 0; gg < 32; gg++)
1584 for (bb = 0; bb < 32; bb++)
1586 err = (rr << 3) | (rr >> 2);
1587 erg = (gg << 3) | (gg >> 2);
1588 erb = (bb << 3) | (bb >> 2);
1590 cc->fast_dither->fast_rgb[rr][gg][bb] =
1591 gdk_color_context_get_index_from_palette (cc, &err, &erg, &erb, &success);
1592 cc->fast_dither->fast_err[rr][gg][bb] = err;
1593 cc->fast_dither->fast_erg[rr][gg][bb] = erg;
1594 cc->fast_dither->fast_erb[rr][gg][bb] = erb;
1599 gdk_color_context_free_dither (GdkColorContext *cc)
1601 g_assert (cc != NULL);
1603 if (cc->fast_dither)
1604 g_free (cc->fast_dither);
1606 cc->fast_dither = NULL;
1610 gdk_color_context_get_pixel_from_palette (GdkColorContext *cc,
1617 gint dif, dr, dg, db, j = -1;
1618 gint mindif = 0x7fffffff;
1619 gint err = 0, erg = 0, erb = 0;
1622 g_assert (cc != NULL);
1623 g_assert (red != NULL);
1624 g_assert (green != NULL);
1625 g_assert (blue != NULL);
1626 g_assert (failed != NULL);
1630 for (i = 0; i < cc->num_palette; i++)
1632 dr = *red - cc->palette[i].red;
1633 dg = *green - cc->palette[i].green;
1634 db = *blue - cc->palette[i].blue;
1636 dif = dr * dr + dg * dg + db * db;
1642 pixel = cc->palette[i].pixel;
1652 /* we failed to map onto a color */
1667 gdk_color_context_get_index_from_palette (GdkColorContext *cc,
1673 gint dif, dr, dg, db, j = -1;
1674 gint mindif = 0x7fffffff;
1675 gint err = 0, erg = 0, erb = 0;
1678 g_assert (cc != NULL);
1679 g_assert (red != NULL);
1680 g_assert (green != NULL);
1681 g_assert (blue != NULL);
1682 g_assert (failed != NULL);
1686 for (i = 0; i < cc->num_palette; i++)
1688 dr = *red - cc->palette[i].red;
1689 dg = *green - cc->palette[i].green;
1690 db = *blue - cc->palette[i].blue;
1692 dif = dr * dr + dg * dg + db * db;
1707 /* we failed to map onto a color */
1716 /* return error fractions */