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
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
20 /* Color Context module
21 * Copyright 1994,1995 John L. Cwikla
22 * Copyright (C) 1997 by Ripley Software Development
23 * Copyright (C) 1997 by Federico Mena (port to Gtk/Gdk)
26 /* Copyright 1994,1995 John L. Cwikla
28 * Permission to use, copy, modify, distribute, and sell this software
29 * and its documentation for any purpose is hereby granted without fee,
30 * provided that the above copyright notice appears in all copies and that
31 * both that copyright notice and this permission notice appear in
32 * supporting documentation, and that the name of John L. Cwikla or
33 * Wolfram Research, Inc not be used in advertising or publicity
34 * pertaining to distribution of the software without specific, written
35 * prior permission. John L. Cwikla and Wolfram Research, Inc make no
36 * representations about the suitability of this software for any
37 * purpose. It is provided "as is" without express or implied warranty.
39 * John L. Cwikla and Wolfram Research, Inc disclaim all warranties with
40 * regard to this software, including all implied warranties of
41 * merchantability and fitness, in no event shall John L. Cwikla or
42 * Wolfram Research, Inc be liable for any special, indirect or
43 * consequential damages or any damages whatsoever resulting from loss of
44 * use, data or profits, whether in an action of contract, negligence or
45 * other tortious action, arising out of or in connection with the use or
46 * performance of this software.
51 * Wolfram Research Inc.
57 * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
58 * file for a list of people on the GTK+ Team. See the ChangeLog
59 * files for a list of changes. These files are distributed with
60 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
70 #define MAX_IMAGE_COLORS 256
74 hash_color (gconstpointer key)
76 const GdkColor *color = key;
78 return (color->red * 33023 + color->green * 30013 + color->blue * 27011);
82 compare_colors (gconstpointer a,
85 const GdkColor *aa = a;
86 const GdkColor *bb = b;
88 return ((aa->red == bb->red) && (aa->green == bb->green) && (aa->blue == bb->blue));
92 free_hash_entry (gpointer key,
96 g_free (key); /* key and value are the same GdkColor */
100 pixel_sort (const void *a, const void *b)
102 return ((GdkColor *) a)->pixel - ((GdkColor *) b)->pixel;
105 /* XXX: This function does an XQueryColors() the hard way, because there is
106 * no corresponding function in Gdk.
110 my_x_query_colors (GdkColormap *colormap,
117 for (i = 0; i < ncolors; i++)
119 PALETTEENTRY palentry;
121 GetPaletteEntries (GDK_COLORMAP_XCOLORMAP (colormap)->palette, colors[i].pixel, 1, &palentry);
122 colors[i].red = (palentry.peRed * 65536) / 255;
123 colors[i].green = (palentry.peGreen * 65536) / 255;
124 colors[i].blue = (palentry.peBlue * 65536) / 255;
129 query_colors (GdkColorContext *cc)
132 GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
133 cc->cmap = g_new (GdkColor, cc->num_colors);
135 for (i = 0; i < cc->num_colors; i++)
136 cc->cmap[i].pixel = cc->clut ? cc->clut[i] : ccp->std_cmap.base_pixel + i;
138 my_x_query_colors (cc->colormap, cc->cmap, cc->num_colors);
140 qsort (cc->cmap, cc->num_colors, sizeof (GdkColor), pixel_sort);
144 init_bw (GdkColorContext *cc)
148 g_warning ("init_bw: failed to allocate colors, falling back to black and white");
150 cc->mode = GDK_CC_MODE_BW;
152 color.red = color.green = color.blue = 0;
154 if (!gdk_color_alloc (cc->colormap, &color))
157 cc->black_pixel = color.pixel;
159 color.red = color.green = color.blue = 0xffff;
161 if (!gdk_color_alloc (cc->colormap, &color))
162 cc->white_pixel = cc->black_pixel ? 0 : 1;
164 cc->white_pixel = color.pixel;
170 init_gray (GdkColorContext *cc)
172 GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
173 GdkColor *clrs, *cstart;
177 cc->num_colors = 256; /* Bogus, but will never get here anyway? */
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 = 255;
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 = 255; /* ??? */
254 cc->black_pixel = 0; /* ??? */
256 /* a CLUT for storing allocated pixel indices */
258 cc->max_colors = cc->num_colors;
259 cc->clut = g_new (gulong, cc->max_colors);
261 for (cubeval = 0; cubeval < cc->max_colors; cubeval++)
262 cc->clut[cubeval] = cubeval;
266 cc->mode = GDK_CC_MODE_STD_CMAP;
271 init_true_color (GdkColorContext *cc)
273 GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
274 gulong rmask, gmask, bmask;
276 cc->mode = GDK_CC_MODE_TRUE;
280 rmask = cc->masks.red = cc->visual->red_mask;
299 gmask = cc->masks.green = cc->visual->green_mask;
301 cc->shifts.green = 0;
318 bmask = cc->masks.blue = cc->visual->blue_mask;
335 cc->num_colors = (cc->visual->red_mask | cc->visual->green_mask | cc->visual->blue_mask) + 1;
337 cc->white_pixel = 0xffffff;
342 init_palette (GdkColorContext *cc)
344 /* restore correct mode for this cc */
346 switch (cc->visual->type)
348 case GDK_VISUAL_STATIC_GRAY:
349 case GDK_VISUAL_GRAYSCALE:
350 if (GDK_VISUAL_XVISUAL (cc->visual)->map_entries == 2)
351 cc->mode = GDK_CC_MODE_BW;
353 cc->mode = GDK_CC_MODE_MY_GRAY;
356 case GDK_VISUAL_TRUE_COLOR:
357 cc->mode = GDK_CC_MODE_TRUE;
360 case GDK_VISUAL_STATIC_COLOR:
361 case GDK_VISUAL_PSEUDO_COLOR:
362 cc->mode = GDK_CC_MODE_STD_CMAP;
366 cc->mode = GDK_CC_MODE_UNDEFINED;
370 /* previous palette */
373 g_free (cc->palette);
376 g_free (cc->fast_dither);
378 /* clear hash table if present */
382 /* XXX: quick-and-dirty way to remove everything */
384 g_hash_table_destroy (cc->color_hash);
385 cc->color_hash = g_hash_table_new (hash_color, compare_colors);
390 cc->fast_dither = NULL;
394 gdk_color_context_new (GdkVisual *visual,
395 GdkColormap *colormap)
397 GdkColorContextPrivate *ccp;
398 gint use_private_colormap = FALSE; /* XXX: maybe restore full functionality later? */
401 GdkColormap *default_colormap;
403 g_assert (visual != NULL);
404 g_assert (colormap != NULL);
406 ccp = g_new (GdkColorContextPrivate, 1);
407 cc = (GdkColorContext *) ccp;
409 cc->colormap = colormap;
412 cc->mode = GDK_CC_MODE_UNDEFINED;
413 cc->need_to_free_colormap = FALSE;
415 cc->color_hash = NULL;
418 cc->fast_dither = NULL;
420 default_colormap = gdk_colormap_get_system ();
424 while (retry_count < 2)
426 /* Only create a private colormap if the visual found isn't equal
427 * to the default visual and we don't have a private colormap,
428 * -or- if we are instructed to create a private colormap (which
429 * never is the case for XmHTML).
432 if (use_private_colormap
433 || ((cc->visual != gdk_visual_get_system ()) /* default visual? */
434 && (GDK_COLORMAP_XCOLORMAP (colormap) == GDK_COLORMAP_XCOLORMAP (default_colormap))))
436 g_warning ("gdk_color_context_new: non-default visual detected, "
437 "using private colormap");
439 cc->colormap = gdk_colormap_new (cc->visual, FALSE);
441 cc->need_to_free_colormap = (GDK_COLORMAP_XCOLORMAP (colormap)
442 != GDK_COLORMAP_XCOLORMAP (default_colormap));
445 switch (visual->type)
447 case GDK_VISUAL_STATIC_GRAY:
448 case GDK_VISUAL_GRAYSCALE:
449 GDK_NOTE (COLOR_CONTEXT,
450 g_message ("gdk_color_context_new: visual class is %s\n",
451 (visual->type == GDK_VISUAL_STATIC_GRAY) ?
452 "GDK_VISUAL_STATIC_GRAY" :
453 "GDK_VISUAL_GRAYSCALE"));
455 if (GDK_VISUAL_XVISUAL (cc->visual)->map_entries == 2)
461 case GDK_VISUAL_TRUE_COLOR: /* shifts */
462 GDK_NOTE (COLOR_CONTEXT,
463 g_message ("gdk_color_context_new: visual class is GDK_VISUAL_TRUE_COLOR\n"));
465 init_true_color (cc);
468 case GDK_VISUAL_STATIC_COLOR:
469 case GDK_VISUAL_PSEUDO_COLOR:
470 GDK_NOTE (COLOR_CONTEXT,
471 g_message ("gdk_color_context_new: visual class is %s\n",
472 (visual->type == GDK_VISUAL_STATIC_COLOR) ?
473 "GDK_VISUAL_STATIC_COLOR" :
474 "GDK_VISUAL_PSEUDO_COLOR"));
480 g_assert_not_reached ();
483 if ((cc->mode == GDK_CC_MODE_BW) && (cc->visual->depth > 1))
485 use_private_colormap = TRUE;
492 /* no. of colors allocated yet */
494 cc->num_allocated = 0;
496 GDK_NOTE (COLOR_CONTEXT,
497 g_message ("gdk_color_context_new: screen depth is %i, no. of colors is %i\n",
498 cc->visual->depth, cc->num_colors));
500 /* check if we need to initialize a hash table */
502 if ((cc->mode == GDK_CC_MODE_STD_CMAP) || (cc->mode == GDK_CC_MODE_UNDEFINED))
503 cc->color_hash = g_hash_table_new (hash_color, compare_colors);
505 return (GdkColorContext *) cc;
509 gdk_color_context_new_mono (GdkVisual *visual,
510 GdkColormap *colormap)
512 GdkColorContextPrivate *ccp;
515 g_assert (visual != NULL);
516 g_assert (colormap != NULL);
518 cc = g_new (GdkColorContext, 1);
519 ccp = (GdkColorContextPrivate *) cc;
521 cc->colormap = colormap;
524 cc->mode = GDK_CC_MODE_UNDEFINED;
525 cc->need_to_free_colormap = FALSE;
529 return (GdkColorContext *) cc;
532 /* This doesn't currently free black/white, hmm... */
535 gdk_color_context_free (GdkColorContext *cc)
537 g_assert (cc != NULL);
539 if ((cc->visual->type == GDK_VISUAL_STATIC_COLOR)
540 || (cc->visual->type == GDK_VISUAL_PSEUDO_COLOR))
542 gdk_colors_free (cc->colormap, cc->clut, cc->num_allocated, 0);
545 else if (cc->clut != NULL)
547 gdk_colors_free (cc->colormap, cc->clut, cc->num_colors, 0);
551 if (cc->cmap != NULL)
554 if (cc->need_to_free_colormap)
555 gdk_colormap_unref (cc->colormap);
557 /* free any palette that has been associated with this GdkColorContext */
563 g_hash_table_foreach (cc->color_hash,
566 g_hash_table_destroy (cc->color_hash);
573 gdk_color_context_get_pixel (GdkColorContext *cc,
579 GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
580 g_assert (cc != NULL);
581 g_assert (failed != NULL);
591 value = (red / 65535.0 * 0.30
592 + green / 65535.0 * 0.59
593 + blue / 65535.0 * 0.11);
596 return cc->white_pixel;
598 return cc->black_pixel;
601 case GDK_CC_MODE_MY_GRAY:
603 gulong ired, igreen, iblue;
605 red = red * 0.30 + green * 0.59 + blue * 0.11;
609 if ((ired = red * (ccp->std_cmap.red_max + 1) / 0xffff) > ccp->std_cmap.red_max)
610 ired = ccp->std_cmap.red_max;
612 ired *= ccp->std_cmap.red_mult;
614 if ((igreen = green * (ccp->std_cmap.green_max + 1) / 0xffff) > ccp->std_cmap.green_max)
615 igreen = ccp->std_cmap.green_max;
617 igreen *= ccp->std_cmap.green_mult;
619 if ((iblue = blue * (ccp->std_cmap.blue_max + 1) / 0xffff) > ccp->std_cmap.blue_max)
620 iblue = ccp->std_cmap.blue_max;
622 iblue *= ccp->std_cmap.blue_mult;
624 if (cc->clut != NULL)
625 return cc->clut[ccp->std_cmap.base_pixel + ired + igreen + iblue];
627 return ccp->std_cmap.base_pixel + ired + igreen + iblue;
630 case GDK_CC_MODE_TRUE:
632 gulong ired, igreen, iblue;
634 if (cc->clut == NULL)
636 red >>= 16 - cc->bits.red;
637 green >>= 16 - cc->bits.green;
638 blue >>= 16 - cc->bits.blue;
640 ired = (red << cc->shifts.red) & cc->masks.red;
641 igreen = (green << cc->shifts.green) & cc->masks.green;
642 iblue = (blue << cc->shifts.blue) & cc->masks.blue;
644 return ired | igreen | iblue;
647 ired = cc->clut[red * cc->max_entry / 65535] & cc->masks.red;
648 igreen = cc->clut[green * cc->max_entry / 65535] & cc->masks.green;
649 iblue = cc->clut[blue * cc->max_entry / 65535] & cc->masks.blue;
651 return ired | igreen | iblue;
654 case GDK_CC_MODE_PALETTE:
655 return gdk_color_context_get_pixel_from_palette (cc, &red, &green, &blue, failed);
657 case GDK_CC_MODE_STD_CMAP:
667 result = g_hash_table_lookup (cc->color_hash, &color);
676 if (!gdk_color_alloc (cc->colormap, &color))
682 /* XXX: the following comment comes directly from
683 * XCC.c. I don't know if it is relevant for
684 * gdk_color_alloc() as it is for XAllocColor()
688 * I can't figure this out entirely, but it *is* possible
689 * that XAllocColor succeeds, even if the number of
690 * allocations we've made exceeds the number of available
691 * colors in the current colormap. And therefore it
692 * might be necessary for us to resize the CLUT.
695 if (cc->num_allocated == cc->max_colors)
699 GDK_NOTE (COLOR_CONTEXT,
700 g_message ("gdk_color_context_get_pixel: "
701 "resizing CLUT to %i entries\n",
704 cc->clut = g_realloc (cc->clut,
705 cc->max_colors * sizeof (gulong));
708 /* Key and value are the same color structure */
710 cnew = g_new (GdkColor, 1);
712 g_hash_table_insert (cc->color_hash, cnew, cnew);
714 cc->clut[cc->num_allocated] = color.pixel;
720 return result->pixel;
726 gdk_color_context_get_pixels (GdkColorContext *cc,
735 gint cmapsize, ncols = 0, nopen = 0, counter = 0;
736 gint bad_alloc = FALSE;
737 gint failed[MAX_IMAGE_COLORS], allocated[MAX_IMAGE_COLORS];
738 GdkColor defs[MAX_IMAGE_COLORS], cmap[MAX_IMAGE_COLORS];
739 #ifdef G_ENABLE_DEBUG
740 gint exact_col = 0, subst_col = 0, close_col = 0, black_col = 0;
742 g_assert (cc != NULL);
743 g_assert (reds != NULL);
744 g_assert (greens != NULL);
745 g_assert (blues != NULL);
746 g_assert (colors != NULL);
747 g_assert (nallocated != NULL);
749 memset (defs, 0, MAX_IMAGE_COLORS * sizeof (GdkColor));
750 memset (failed, 0, MAX_IMAGE_COLORS * sizeof (gint));
751 memset (allocated, 0, MAX_IMAGE_COLORS * sizeof (gint));
753 /* Will only have a value if used by the progressive image loader */
759 /* First allocate all pixels */
761 for (i = 0; i < ncolors; i++)
763 /* colors[i] is only zero if the pixel at that location hasn't
764 * been allocated yet. This is a sanity check required for proper
765 * color allocation by the progressive image loader
770 defs[i].red = reds[i];
771 defs[i].green = greens[i];
772 defs[i].blue = blues[i];
774 colors[i] = gdk_color_context_get_pixel (cc, reds[i], greens[i], blues[i],
777 /* successfully allocated, store it */
781 defs[i].pixel = colors[i];
782 allocated[ncols++] = colors[i];
791 /* all colors available, all done */
793 if ((ncols == ncolors) || (nopen == 0))
795 GDK_NOTE (COLOR_CONTEXT,
796 g_message ("gdk_color_context_get_pixels: got all %i colors; "
797 "(%i colors allocated so far)\n", ncolors, cc->num_allocated));
802 /* The fun part. We now try to allocate the colors we couldn't allocate
803 * directly. The first step will map a color onto its nearest color
804 * that has been allocated (either by us or someone else). If any colors
805 * remain unallocated, we map these onto the colors that we have allocated
809 /* read up to MAX_IMAGE_COLORS colors of the current colormap */
811 cmapsize = MIN (cc->num_colors, MAX_IMAGE_COLORS);
813 /* see if the colormap has any colors to read */
817 g_warning ("gdk_color_context_get_pixels: oops! no colors available, "
818 "your images will look *really* ugly.");
823 #ifdef G_ENABLE_DEBUG
827 /* initialize pixels */
829 for (i = 0; i < cmapsize; i++)
832 cmap[i].red = cmap[i].green = cmap[i].blue = 0;
835 /* read the colormap */
837 my_x_query_colors (cc->colormap, cmap, cmapsize);
839 /* get a close match for any unallocated colors */
847 gint d, j, mdist, close, ri, gi, bi;
855 /* Store these vals. Small performance increase as this skips three
856 * indexing operations in the loop code.
863 /* Walk all colors in the colormap and see which one is the
864 * closest. Uses plain least squares.
867 for (j = 0; (j < cmapsize) && (mdist != 0); j++)
869 /* Don't replace these by shifts; the sign may get clobbered */
871 rd = (ri - cmap[j].red) / 256;
872 gd = (gi - cmap[j].green) / 256;
873 bd = (bi - cmap[j].blue) / 256;
875 d = rd * rd + gd * gd + bd * bd;
886 rd = cmap[close].red;
887 gd = cmap[close].green;
888 bd = cmap[close].blue;
892 colors[i] = gdk_color_context_get_pixel (cc, rd, gd, bd, &bad_alloc);
898 defs[i] = cmap[close];
899 defs[i].pixel = colors[i];
900 allocated[ncols++] = colors[i];
901 #ifdef G_ENABLE_DEBUG
908 /* deal with in next stage if allocation failed */
910 while (++idx < counter);
914 /* This is the maximum no. of allocated colors. See also the nopen == 0
918 if ((ncols == ncolors) || (nopen == 0))
920 GDK_NOTE (COLOR_CONTEXT,
921 g_message ("gdk_color_context_get_pixels: got %i colors, %i exact and "
922 "%i close (%i colors allocated so far)\n",
923 ncolors, exact_col, close_col, cc->num_allocated));
928 /* Now map any remaining unallocated pixels into the colors we did get */
934 gint d, mdist, close, ri, gi, bi;
948 /* search allocated colors */
950 for (j = 0; (j < ncols) && (mdist != 0); j++)
954 /* Don't replace these by shifts; the sign may get clobbered */
956 rd = (ri - defs[k].red) / 256;
957 gd = (gi - defs[k].green) / 256;
958 bd = (bi - defs[k].blue) / 256;
960 d = rd * rd + gd * gd + bd * bd;
971 /* too bad, map to black */
973 defs[i].pixel = cc->black_pixel;
974 defs[i].red = defs[i].green = defs[i].blue = 0;
975 #ifdef G_ENABLE_DEBUG
981 defs[i] = defs[close];
982 #ifdef G_ENABLE_DEBUG
987 colors[i] = defs[i].pixel;
989 while (++idx < nopen);
991 GDK_NOTE (COLOR_CONTEXT,
992 g_message ("gdk_color_context_get_pixels: got %i colors, %i exact, %i close, "
993 "%i substituted, %i to black (%i colors allocated so far)\n",
994 ncolors, exact_col, close_col, subst_col, black_col, cc->num_allocated));
998 gdk_color_context_get_pixels_incremental (GdkColorContext *cc,
1008 gint cmapsize, ncols = 0, nopen = 0, counter = 0;
1009 gint bad_alloc = FALSE;
1010 gint failed[MAX_IMAGE_COLORS], allocated[MAX_IMAGE_COLORS];
1011 GdkColor defs[MAX_IMAGE_COLORS], cmap[MAX_IMAGE_COLORS];
1012 #ifdef G_ENABLE_DEBUG
1013 gint exact_col = 0, subst_col = 0, close_col = 0, black_col = 0;
1016 g_assert (cc != NULL);
1017 g_assert (reds != NULL);
1018 g_assert (greens != NULL);
1019 g_assert (blues != NULL);
1020 g_assert (used != NULL);
1021 g_assert (colors != NULL);
1022 g_assert (nallocated != NULL);
1024 memset (defs, 0, MAX_IMAGE_COLORS * sizeof (GdkColor));
1025 memset (failed, 0, MAX_IMAGE_COLORS * sizeof (gint));
1026 memset (allocated, 0, MAX_IMAGE_COLORS * sizeof (gint));
1028 /* Will only have a value if used by the progressive image loader */
1030 ncols = *nallocated;
1034 /* First allocate all pixels */
1036 for (i = 0; i < ncolors; i++)
1038 /* used[i] is only -1 if the pixel at that location hasn't
1039 * been allocated yet. This is a sanity check required for proper
1040 * color allocation by the progressive image loader.
1041 * When colors[i] == 0 it indicates the slot is available for
1045 if (used[i] != FALSE)
1049 defs[i].red = reds[i];
1050 defs[i].green = greens[i];
1051 defs[i].blue = blues[i];
1053 colors[i] = gdk_color_context_get_pixel (cc, reds[i], greens[i], blues[i], &bad_alloc);
1055 /* successfully allocated, store it */
1059 defs[i].pixel = colors[i];
1060 allocated[ncols++] = colors[i];
1063 failed[nopen++] = i;
1067 GDK_NOTE (COLOR_CONTEXT,
1068 g_message ("gdk_color_context_get_pixels_incremental: "
1069 "pixel at slot %i already allocated, skipping\n", i));
1074 *nallocated = ncols;
1076 if ((ncols == ncolors) || (nopen == 0))
1078 GDK_NOTE (COLOR_CONTEXT,
1079 g_message ("gdk_color_context_get_pixels_incremental: got all %i colors "
1080 "(%i colors allocated so far)\n",
1081 ncolors, cc->num_allocated));
1086 cmapsize = MIN (cc->num_colors, MAX_IMAGE_COLORS);
1090 g_warning ("gdk_color_context_get_pixels_incremental: oops! "
1091 "No colors available images will look *really* ugly.");
1095 #ifdef G_ENABLE_DEBUG
1099 /* initialize pixels */
1101 for (i = 0; i < cmapsize; i++)
1104 cmap[i].red = cmap[i].green = cmap[i].blue = 0;
1109 my_x_query_colors (cc->colormap, cmap, cmapsize);
1111 /* now match any unallocated colors */
1119 gint d, j, mdist, close, ri, gi, bi;
1133 for (j = 0; (j < cmapsize) && (mdist != 0); j++)
1135 /* Don't replace these by shifts; the sign may get clobbered */
1137 rd = (ri - cmap[j].red) / 256;
1138 gd = (gi - cmap[j].green) / 256;
1139 bd = (bi - cmap[j].blue) / 256;
1141 d = rd * rd + gd * gd + bd * bd;
1152 rd = cmap[close].red;
1153 gd = cmap[close].green;
1154 bd = cmap[close].blue;
1158 colors[i] = gdk_color_context_get_pixel (cc, rd, gd, bd, &bad_alloc);
1164 defs[i] = cmap[close];
1165 defs[i].pixel = colors[i];
1166 allocated[ncols++] = colors[i];
1167 #ifdef G_ENABLE_DEBUG
1172 failed[nopen++] = i;
1175 failed[nopen++] = i;
1176 /* deal with in next stage if allocation failed */
1178 while (++idx < counter);
1180 *nallocated = ncols;
1182 if ((ncols == ncolors) || (nopen == 0))
1184 GDK_NOTE (COLOR_CONTEXT,
1185 g_message ("gdk_color_context_get_pixels_incremental: "
1186 "got %i colors, %i exact and %i close "
1187 "(%i colors allocated so far)\n",
1188 ncolors, exact_col, close_col, cc->num_allocated));
1193 /* map remaining unallocated pixels into colors we did get */
1199 gint d, mdist, close, ri, gi, bi;
1211 /* search allocated colors */
1213 for (j = 0; (j < ncols) && (mdist != 0); j++)
1218 /* Don't replace these by shifts; the sign may get clobbered */
1220 rd = (ri - defs[k].red) / 256;
1221 gd = (gi - defs[k].green) / 256;
1222 bd = (bi - defs[k].blue) / 256;
1224 d = rd * rd + gd * gd + bd * bd;
1235 /* too bad, map to black */
1237 defs[i].pixel = cc->black_pixel;
1238 defs[i].red = defs[i].green = defs[i].blue = 0;
1239 #ifdef G_ENABLE_DEBUG
1245 defs[i] = defs[close];
1246 #ifdef G_ENABLE_DEBUG
1251 colors[i] = defs[i].pixel;
1253 while (++idx < nopen);
1255 GDK_NOTE (COLOR_CONTEXT,
1256 g_message ("gdk_color_context_get_pixels_incremental: "
1257 "got %i colors, %i exact, %i close, %i substituted, %i to black "
1258 "(%i colors allocated so far)\n",
1259 ncolors, exact_col, close_col, subst_col, black_col, cc->num_allocated));
1263 gdk_color_context_query_color (GdkColorContext *cc,
1266 return gdk_color_context_query_colors (cc, color, 1);
1270 gdk_color_context_query_colors (GdkColorContext *cc,
1277 g_assert (cc != NULL);
1278 g_assert (colors != NULL);
1282 case GDK_CC_MODE_BW:
1283 for (i = 0, tc = colors; i < num_colors; i++, tc++)
1285 if (tc->pixel == cc->white_pixel)
1286 tc->red = tc->green = tc->blue = 65535;
1288 tc->red = tc->green = tc->blue = 0;
1292 case GDK_CC_MODE_TRUE:
1293 if (cc->clut == NULL)
1294 for (i = 0, tc = colors; i < num_colors; i++, tc++)
1296 tc->red = ((tc->pixel & cc->masks.red) >> cc->shifts.red) << (16 - cc->bits.red);
1297 tc->green = ((tc->pixel & cc->masks.green) >> cc->shifts.green) << (16 - cc->bits.green);
1298 tc->blue = ((tc->pixel & cc->masks.blue) >> cc->shifts.blue) << (16 - cc->bits.blue);
1302 my_x_query_colors (cc->colormap, colors, num_colors);
1307 case GDK_CC_MODE_STD_CMAP:
1309 if (cc->cmap == NULL)
1311 my_x_query_colors (cc->colormap, colors, num_colors);
1316 gint first, last, half;
1319 for (i = 0, tc = colors; i < num_colors; i++)
1322 last = cc->num_colors - 1;
1324 while (first <= last)
1326 half = (first + last) / 2;
1327 half_pixel = cc->cmap[half].pixel;
1329 if (tc->pixel == half_pixel)
1331 tc->red = cc->cmap[half].red;
1332 tc->green = cc->cmap[half].green;
1333 tc->blue = cc->cmap[half].blue;
1334 first = last + 1; /* false break */
1338 if (tc->pixel > half_pixel)
1353 gdk_color_context_add_palette (GdkColorContext *cc,
1361 g_assert (cc != NULL);
1363 /* initialize this palette (will also erase previous palette as well) */
1367 /* restore previous mode if we aren't adding a new palette */
1369 if (num_palette == 0)
1371 /* GDK_CC_MODE_STD_CMAP uses a hash table, so we'd better initialize one */
1373 /* XXX: here, the hash table is already initialized */
1378 /* Initialize a hash table for this palette (we need one for allocating
1379 * the pixels in the palette using the current settings)
1382 if (cc->color_hash == NULL)
1383 cc->color_hash = g_hash_table_new (hash_color, compare_colors);
1385 /* copy incoming palette */
1387 cc->palette = g_new0(GdkColor, num_palette);
1391 for (i = 0; i < num_palette; i++)
1396 /* try to allocate this color */
1399 g = palette[i].green;
1400 b = palette[i].blue;
1402 gdk_color_context_get_pixels (cc, &r, &g, &b, 1, pixel, &erg);
1404 /* only store if we succeed */
1408 /* store in palette */
1410 cc->palette[j].red = r;
1411 cc->palette[j].green = g;
1412 cc->palette[j].blue = b;
1413 cc->palette[j].pixel = pixel[0];
1415 /* move to next slot */
1423 if (j != num_palette)
1424 cc->palette = g_realloc (cc->palette, j * sizeof (GdkColor));
1426 /* clear the hash table, we don't use it when dithering */
1430 g_hash_table_destroy (cc->color_hash);
1431 cc->color_hash = NULL;
1434 /* store real palette size */
1436 cc->num_palette = j;
1438 /* switch to palette mode */
1440 cc->mode = GDK_CC_MODE_PALETTE;
1444 qsort (cc->palette, cc->num_palette, sizeof (GdkColor), pixel_sort);
1446 cc->fast_dither = NULL;
1452 gdk_color_context_init_dither (GdkColorContext *cc)
1454 gint rr, gg, bb, err, erg, erb;
1455 gint success = FALSE;
1457 g_assert (cc != NULL);
1459 /* now we can initialize the fast dither matrix */
1461 if (cc->fast_dither == NULL)
1462 cc->fast_dither = g_new (GdkColorContextDither, 1);
1464 /* Fill it. We ignore unsuccessful allocations, they are just mapped
1465 * to black instead */
1467 for (rr = 0; rr < 32; rr++)
1468 for (gg = 0; gg < 32; gg++)
1469 for (bb = 0; bb < 32; bb++)
1471 err = (rr << 3) | (rr >> 2);
1472 erg = (gg << 3) | (gg >> 2);
1473 erb = (bb << 3) | (bb >> 2);
1475 cc->fast_dither->fast_rgb[rr][gg][bb] =
1476 gdk_color_context_get_index_from_palette (cc, &err, &erg, &erb, &success);
1477 cc->fast_dither->fast_err[rr][gg][bb] = err;
1478 cc->fast_dither->fast_erg[rr][gg][bb] = erg;
1479 cc->fast_dither->fast_erb[rr][gg][bb] = erb;
1484 gdk_color_context_free_dither (GdkColorContext *cc)
1486 g_assert (cc != NULL);
1488 if (cc->fast_dither)
1489 g_free (cc->fast_dither);
1491 cc->fast_dither = NULL;
1495 gdk_color_context_get_pixel_from_palette (GdkColorContext *cc,
1502 gint dif, dr, dg, db, j = -1;
1503 gint mindif = 0x7fffffff;
1504 gint err = 0, erg = 0, erb = 0;
1507 g_assert (cc != NULL);
1508 g_assert (red != NULL);
1509 g_assert (green != NULL);
1510 g_assert (blue != NULL);
1511 g_assert (failed != NULL);
1515 for (i = 0; i < cc->num_palette; i++)
1517 dr = *red - cc->palette[i].red;
1518 dg = *green - cc->palette[i].green;
1519 db = *blue - cc->palette[i].blue;
1521 dif = dr * dr + dg * dg + db * db;
1527 pixel = cc->palette[i].pixel;
1537 /* we failed to map onto a color */
1552 gdk_color_context_get_index_from_palette (GdkColorContext *cc,
1558 gint dif, dr, dg, db, j = -1;
1559 gint mindif = 0x7fffffff;
1560 gint err = 0, erg = 0, erb = 0;
1563 g_assert (cc != NULL);
1564 g_assert (red != NULL);
1565 g_assert (green != NULL);
1566 g_assert (blue != NULL);
1567 g_assert (failed != NULL);
1571 for (i = 0; i < cc->num_palette; i++)
1573 dr = *red - cc->palette[i].red;
1574 dg = *green - cc->palette[i].green;
1575 db = *blue - cc->palette[i].blue;
1577 dif = dr * dr + dg * dg + db * db;
1592 /* we failed to map onto a color */
1601 /* return error fractions */