00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063 #include "config.h"
00064
00065 #include <stdlib.h>
00066 #include <string.h>
00067
00068 #include "gdkcc.h"
00069 #include "gdkcolor.h"
00070 #include "gdkwin32.h"
00071
00072 #define MAX_IMAGE_COLORS 256
00073
00074 typedef struct _GdkColorContextPrivate GdkColorContextPrivate;
00075
00076 struct _GdkColorContextPrivate {
00077 GdkColorContext color_context;
00078 XStandardColormap std_cmap;
00079 };
00080
00081 static guint hash_color(gconstpointer key)
00082 {
00083 const GdkColor *color = key;
00084
00085 return (color->red * 33023 + color->green * 30013 +
00086 color->blue * 27011);
00087 }
00088
00089 static gint compare_colors(gconstpointer a, gconstpointer b)
00090 {
00091 const GdkColor *aa = a;
00092 const GdkColor *bb = b;
00093
00094 return ((aa->red == bb->red) && (aa->green == bb->green)
00095 && (aa->blue == bb->blue));
00096 }
00097
00098 static void
00099 free_hash_entry(gpointer key, gpointer value, gpointer user_data)
00100 {
00101 g_free(key);
00102 }
00103
00104 static int pixel_sort(const void *a, const void *b)
00105 {
00106 return ((GdkColor *) a)->pixel - ((GdkColor *) b)->pixel;
00107 }
00108
00109 static void
00110 my_x_query_colors(GdkColormap * colormap, GdkColor * colors, gint ncolors)
00111 {
00112 gint i;
00113
00114 for (i = 0; i < ncolors; i++) {
00115 PALETTEENTRY palentry;
00116
00117 GetPaletteEntries(GDK_COLORMAP_WIN32COLORMAP(colormap)->palette,
00118 colors[i].pixel, 1, &palentry);
00119 colors[i].red = (palentry.peRed * 65535) / 255;
00120 colors[i].green = (palentry.peGreen * 65535) / 255;
00121 colors[i].blue = (palentry.peBlue * 65535) / 255;
00122 }
00123 }
00124
00125 static void query_colors(GdkColorContext * cc)
00126 {
00127 gint i;
00128 GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
00129 cc->cmap = g_new(GdkColor, cc->num_colors);
00130
00131 for (i = 0; i < cc->num_colors; i++)
00132 cc->cmap[i].pixel =
00133 cc->clut ? cc->clut[i] : ccp->std_cmap.base_pixel + i;
00134
00135 my_x_query_colors(cc->colormap, cc->cmap, cc->num_colors);
00136
00137 qsort(cc->cmap, cc->num_colors, sizeof(GdkColor), pixel_sort);
00138 }
00139
00140 static void init_bw(GdkColorContext * cc)
00141 {
00142 GdkColor color;
00143
00144 g_warning
00145 ("init_bw: failed to allocate colors, falling back to black and white");
00146
00147 cc->mode = GDK_CC_MODE_BW;
00148
00149 color.red = color.green = color.blue = 0;
00150
00151 if (!gdk_color_alloc(cc->colormap, &color))
00152 cc->black_pixel = 0;
00153 else
00154 cc->black_pixel = color.pixel;
00155
00156 color.red = color.green = color.blue = 0xffff;
00157
00158 if (!gdk_color_alloc(cc->colormap, &color))
00159 cc->white_pixel = cc->black_pixel ? 0 : 1;
00160 else
00161 cc->white_pixel = color.pixel;
00162
00163 cc->num_colors = 2;
00164 }
00165
00166 static void init_gray(GdkColorContext * cc)
00167 {
00168 GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
00169 GdkColor *clrs, *cstart;
00170 gint i;
00171 gdouble dinc;
00172
00173 cc->num_colors = 256;
00174
00175 cc->clut = g_new(gulong, cc->num_colors);
00176 cstart = g_new(GdkColor, cc->num_colors);
00177
00178 retrygray:
00179
00180 dinc = 65535.0 / (cc->num_colors - 1);
00181
00182 clrs = cstart;
00183
00184 for (i = 0; i < cc->num_colors; i++) {
00185 clrs->red = clrs->green = clrs->blue = dinc * i;
00186
00187 if (!gdk_color_alloc(cc->colormap, clrs)) {
00188 gdk_colors_free(cc->colormap, cc->clut, i, 0);
00189
00190 cc->num_colors /= 2;
00191
00192 if (cc->num_colors > 1)
00193 goto retrygray;
00194 else {
00195 g_free(cc->clut);
00196 cc->clut = NULL;
00197 init_bw(cc);
00198 g_free(cstart);
00199 return;
00200 }
00201 }
00202
00203 cc->clut[i] = clrs++->pixel;
00204 }
00205
00206 g_free(cstart);
00207
00208
00209 ccp->std_cmap.colormap = GDK_COLORMAP_WIN32COLORMAP(cc->colormap);
00210 ccp->std_cmap.base_pixel = 0;
00211 ccp->std_cmap.red_max = cc->num_colors - 1;
00212 ccp->std_cmap.green_max = 0;
00213 ccp->std_cmap.blue_max = 0;
00214 ccp->std_cmap.red_mult = 1;
00215 ccp->std_cmap.green_mult = 0;
00216 ccp->std_cmap.blue_mult = 0;
00217
00218 cc->white_pixel = 255;
00219 cc->black_pixel = 0;
00220
00221 query_colors(cc);
00222
00223 cc->mode = GDK_CC_MODE_MY_GRAY;
00224 }
00225
00226 static void init_color(GdkColorContext * cc)
00227 {
00228 GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
00229 gint cubeval;
00230
00231 cubeval = 1;
00232 while ((cubeval * cubeval * cubeval) <
00233 GDK_VISUAL_XVISUAL(cc->visual)->map_entries)
00234 cubeval++;
00235 cubeval--;
00236
00237 cc->num_colors = cubeval * cubeval * cubeval;
00238
00239 ccp->std_cmap.red_max = cubeval - 1;
00240 ccp->std_cmap.green_max = cubeval - 1;
00241 ccp->std_cmap.blue_max = cubeval - 1;
00242 ccp->std_cmap.red_mult = cubeval * cubeval;
00243 ccp->std_cmap.green_mult = cubeval;
00244 ccp->std_cmap.blue_mult = 1;
00245 ccp->std_cmap.base_pixel = 0;
00246
00247 cc->white_pixel = 255;
00248 cc->black_pixel = 0;
00249
00250
00251
00252 cc->max_colors = cc->num_colors;
00253 cc->clut = g_new(gulong, cc->max_colors);
00254
00255 for (cubeval = 0; cubeval < cc->max_colors; cubeval++)
00256 cc->clut[cubeval] = cubeval;
00257
00258 query_colors(cc);
00259
00260 cc->mode = GDK_CC_MODE_STD_CMAP;
00261 }
00262
00263
00264 static void init_true_color(GdkColorContext * cc)
00265 {
00266 GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
00267 gulong rmask, gmask, bmask;
00268
00269 cc->mode = GDK_CC_MODE_TRUE;
00270
00271
00272
00273 rmask = cc->masks.red = cc->visual->red_mask;
00274
00275 cc->shifts.red = 0;
00276 cc->bits.red = 0;
00277
00278 while (!(rmask & 1)) {
00279 rmask >>= 1;
00280 cc->shifts.red++;
00281 }
00282
00283 while (rmask & 1) {
00284 rmask >>= 1;
00285 cc->bits.red++;
00286 }
00287
00288
00289
00290 gmask = cc->masks.green = cc->visual->green_mask;
00291
00292 cc->shifts.green = 0;
00293 cc->bits.green = 0;
00294
00295 while (!(gmask & 1)) {
00296 gmask >>= 1;
00297 cc->shifts.green++;
00298 }
00299
00300 while (gmask & 1) {
00301 gmask >>= 1;
00302 cc->bits.green++;
00303 }
00304
00305
00306
00307 bmask = cc->masks.blue = cc->visual->blue_mask;
00308
00309 cc->shifts.blue = 0;
00310 cc->bits.blue = 0;
00311
00312 while (!(bmask & 1)) {
00313 bmask >>= 1;
00314 cc->shifts.blue++;
00315 }
00316
00317 while (bmask & 1) {
00318 bmask >>= 1;
00319 cc->bits.blue++;
00320 }
00321
00322 cc->num_colors =
00323 (cc->visual->red_mask | cc->visual->green_mask | cc->visual->
00324 blue_mask) + 1;
00325
00326 cc->white_pixel = 0xffffff;
00327 cc->black_pixel = 0;
00328 }
00329
00330 static void init_palette(GdkColorContext * cc)
00331 {
00332
00333
00334 switch (cc->visual->type) {
00335 case GDK_VISUAL_STATIC_GRAY:
00336 case GDK_VISUAL_GRAYSCALE:
00337 if (GDK_VISUAL_XVISUAL(cc->visual)->map_entries == 2)
00338 cc->mode = GDK_CC_MODE_BW;
00339 else
00340 cc->mode = GDK_CC_MODE_MY_GRAY;
00341 break;
00342
00343 case GDK_VISUAL_TRUE_COLOR:
00344 cc->mode = GDK_CC_MODE_TRUE;
00345 break;
00346
00347 case GDK_VISUAL_STATIC_COLOR:
00348 case GDK_VISUAL_PSEUDO_COLOR:
00349 cc->mode = GDK_CC_MODE_STD_CMAP;
00350 break;
00351
00352 default:
00353 cc->mode = GDK_CC_MODE_UNDEFINED;
00354 break;
00355 }
00356
00357
00358
00359 if (cc->num_palette)
00360 g_free(cc->palette);
00361
00362 if (cc->fast_dither)
00363 g_free(cc->fast_dither);
00364
00365
00366
00367 if (cc->color_hash) {
00368 g_hash_table_foreach(cc->color_hash, free_hash_entry, NULL);
00369 g_hash_table_destroy(cc->color_hash);
00370 cc->color_hash = g_hash_table_new(hash_color, compare_colors);
00371 }
00372
00373 cc->palette = NULL;
00374 cc->num_palette = 0;
00375 cc->fast_dither = NULL;
00376 }
00377
00378 GdkColorContext *gdk_color_context_new(GdkVisual * visual,
00379 GdkColormap * colormap)
00380 {
00381 GdkColorContextPrivate *ccp;
00382 gint use_private_colormap = FALSE;
00383 GdkColorContext *cc;
00384 gint retry_count;
00385 GdkColormap *default_colormap;
00386
00387 g_assert(visual != NULL);
00388 g_assert(colormap != NULL);
00389
00390 ccp = g_new(GdkColorContextPrivate, 1);
00391 cc = (GdkColorContext *) ccp;
00392 cc->visual = visual;
00393 cc->colormap = colormap;
00394 cc->clut = NULL;
00395 cc->cmap = NULL;
00396 cc->mode = GDK_CC_MODE_UNDEFINED;
00397 cc->need_to_free_colormap = FALSE;
00398
00399 cc->color_hash = NULL;
00400 cc->palette = NULL;
00401 cc->num_palette = 0;
00402 cc->fast_dither = NULL;
00403
00404 default_colormap = gdk_colormap_get_system();
00405
00406 retry_count = 0;
00407
00408 while (retry_count < 2) {
00409
00410
00411
00412
00413
00414
00415 if (use_private_colormap || ((cc->visual != gdk_visual_get_system())
00416 &&(GDK_COLORMAP_WIN32COLORMAP(colormap)
00417 ==
00418 GDK_COLORMAP_WIN32COLORMAP
00419 (default_colormap)))) {
00420 g_warning("gdk_color_context_new: non-default visual detected, "
00421 "using private colormap");
00422
00423 cc->colormap = gdk_colormap_new(cc->visual, FALSE);
00424
00425 cc->need_to_free_colormap = (GDK_COLORMAP_WIN32COLORMAP(colormap)
00426 !=
00427 GDK_COLORMAP_WIN32COLORMAP
00428 (default_colormap));
00429 }
00430
00431 switch (visual->type) {
00432 case GDK_VISUAL_STATIC_GRAY:
00433 case GDK_VISUAL_GRAYSCALE:
00434 GDK_NOTE(COLOR_CONTEXT,
00435 g_message("gdk_color_context_new: visual class is %s\n",
00436 (visual->type == GDK_VISUAL_STATIC_GRAY) ?
00437 "GDK_VISUAL_STATIC_GRAY" :
00438 "GDK_VISUAL_GRAYSCALE"));
00439
00440 if (GDK_VISUAL_XVISUAL(cc->visual)->map_entries == 2)
00441 init_bw(cc);
00442 else
00443 init_gray(cc);
00444
00445 break;
00446
00447 case GDK_VISUAL_TRUE_COLOR:
00448 GDK_NOTE(COLOR_CONTEXT,
00449 g_message
00450 ("gdk_color_context_new: visual class is GDK_VISUAL_TRUE_COLOR\n"));
00451
00452 init_true_color(cc);
00453 break;
00454
00455 case GDK_VISUAL_STATIC_COLOR:
00456 case GDK_VISUAL_PSEUDO_COLOR:
00457 GDK_NOTE(COLOR_CONTEXT,
00458 g_message("gdk_color_context_new: visual class is %s\n",
00459 (visual->type == GDK_VISUAL_STATIC_COLOR) ?
00460 "GDK_VISUAL_STATIC_COLOR" :
00461 "GDK_VISUAL_PSEUDO_COLOR"));
00462
00463 init_color(cc);
00464 break;
00465
00466 default:
00467 g_assert_not_reached();
00468 }
00469
00470 if ((cc->mode == GDK_CC_MODE_BW) && (cc->visual->depth > 1)) {
00471 use_private_colormap = TRUE;
00472 retry_count++;
00473 } else
00474 break;
00475 }
00476
00477
00478
00479 cc->num_allocated = 0;
00480
00481 GDK_NOTE(COLOR_CONTEXT,
00482 g_message
00483 ("gdk_color_context_new: screen depth is %i, no. of colors is %i\n",
00484 cc->visual->depth, cc->num_colors));
00485
00486 return (GdkColorContext *) cc;
00487 }
00488
00489 GdkColorContext *gdk_color_context_new_mono(GdkVisual * visual,
00490 GdkColormap * colormap)
00491 {
00492 GdkColorContextPrivate *ccp;
00493 GdkColorContext *cc;
00494
00495 g_assert(visual != NULL);
00496 g_assert(colormap != NULL);
00497
00498 cc = g_new(GdkColorContext, 1);
00499 ccp = (GdkColorContextPrivate *) cc;
00500 cc->visual = visual;
00501 cc->colormap = colormap;
00502 cc->clut = NULL;
00503 cc->cmap = NULL;
00504 cc->mode = GDK_CC_MODE_UNDEFINED;
00505 cc->need_to_free_colormap = FALSE;
00506
00507 init_bw(cc);
00508
00509 return (GdkColorContext *) cc;
00510 }
00511
00512
00513
00514 void gdk_color_context_free(GdkColorContext * cc)
00515 {
00516 g_assert(cc != NULL);
00517
00518 if ((cc->visual->type == GDK_VISUAL_STATIC_COLOR)
00519 || (cc->visual->type == GDK_VISUAL_PSEUDO_COLOR)) {
00520 gdk_colors_free(cc->colormap, cc->clut, cc->num_allocated, 0);
00521 g_free(cc->clut);
00522 } else if (cc->clut != NULL) {
00523 gdk_colors_free(cc->colormap, cc->clut, cc->num_colors, 0);
00524 g_free(cc->clut);
00525 }
00526
00527 if (cc->cmap != NULL)
00528 g_free(cc->cmap);
00529
00530 if (cc->need_to_free_colormap)
00531 gdk_colormap_unref(cc->colormap);
00532
00533
00534
00535 init_palette(cc);
00536
00537 g_free(cc);
00538 }
00539
00540 gulong
00541 gdk_color_context_get_pixel(GdkColorContext * cc,
00542 gushort red,
00543 gushort green, gushort blue, gint * failed)
00544 {
00545 GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
00546 g_assert(cc != NULL);
00547 g_assert(failed != NULL);
00548
00549 *failed = FALSE;
00550
00551 switch (cc->mode) {
00552 case GDK_CC_MODE_BW:
00553 {
00554 gdouble value;
00555
00556 value = (red / 65535.0 * 0.30
00557 + green / 65535.0 * 0.59 + blue / 65535.0 * 0.11);
00558
00559 if (value > 0.5)
00560 return cc->white_pixel;
00561
00562 return cc->black_pixel;
00563 }
00564
00565 case GDK_CC_MODE_MY_GRAY:
00566 {
00567 gulong ired, igreen, iblue;
00568
00569 red = red * 0.30 + green * 0.59 + blue * 0.11;
00570 green = 0;
00571 blue = 0;
00572
00573 if ((ired =
00574 red * (ccp->std_cmap.red_max + 1) / 0xffff) >
00575 ccp->std_cmap.red_max)
00576 ired = ccp->std_cmap.red_max;
00577
00578 ired *= ccp->std_cmap.red_mult;
00579
00580 if ((igreen =
00581 green * (ccp->std_cmap.green_max + 1) / 0xffff) >
00582 ccp->std_cmap.green_max)
00583 igreen = ccp->std_cmap.green_max;
00584
00585 igreen *= ccp->std_cmap.green_mult;
00586
00587 if ((iblue =
00588 blue * (ccp->std_cmap.blue_max + 1) / 0xffff) >
00589 ccp->std_cmap.blue_max)
00590 iblue = ccp->std_cmap.blue_max;
00591
00592 iblue *= ccp->std_cmap.blue_mult;
00593
00594 if (cc->clut != NULL)
00595 return cc->clut[ccp->std_cmap.base_pixel + ired + igreen +
00596 iblue];
00597
00598 return ccp->std_cmap.base_pixel + ired + igreen + iblue;
00599 }
00600
00601 case GDK_CC_MODE_TRUE:
00602 {
00603 gulong ired, igreen, iblue;
00604
00605 if (cc->clut == NULL) {
00606 red >>= 16 - cc->bits.red;
00607 green >>= 16 - cc->bits.green;
00608 blue >>= 16 - cc->bits.blue;
00609
00610 ired = (red << cc->shifts.red) & cc->masks.red;
00611 igreen = (green << cc->shifts.green) & cc->masks.green;
00612 iblue = (blue << cc->shifts.blue) & cc->masks.blue;
00613
00614 return ired | igreen | iblue;
00615 }
00616
00617 ired = cc->clut[red * cc->max_entry / 65535] & cc->masks.red;
00618 igreen =
00619 cc->clut[green * cc->max_entry / 65535] & cc->masks.green;
00620 iblue = cc->clut[blue * cc->max_entry / 65535] & cc->masks.blue;
00621
00622 return ired | igreen | iblue;
00623 }
00624
00625 case GDK_CC_MODE_PALETTE:
00626 return gdk_color_context_get_pixel_from_palette(cc, &red, &green,
00627 &blue, failed);
00628
00629 case GDK_CC_MODE_STD_CMAP:
00630 default:
00631 {
00632 GdkColor color;
00633 GdkColor *result = NULL;
00634
00635 color.red = red;
00636 color.green = green;
00637 color.blue = blue;
00638
00639 if (cc->color_hash)
00640 result = g_hash_table_lookup(cc->color_hash, &color);
00641
00642 if (!result) {
00643 color.red = red;
00644 color.green = green;
00645 color.blue = blue;
00646 color.pixel = 0;
00647
00648 if (!gdk_color_alloc(cc->colormap, &color))
00649 *failed = TRUE;
00650 else {
00651 GdkColor *cnew;
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666 if (cc->num_allocated == cc->max_colors) {
00667 cc->max_colors *= 2;
00668
00669 GDK_NOTE(COLOR_CONTEXT,
00670 g_message("gdk_color_context_get_pixel: "
00671 "resizing CLUT to %i entries\n",
00672 cc->max_colors));
00673
00674 cc->clut = g_realloc(cc->clut,
00675 cc->max_colors * sizeof(gulong));
00676 }
00677
00678
00679
00680 cnew = g_new(GdkColor, 1);
00681 *cnew = color;
00682
00683 if (!cc->color_hash)
00684 cc->color_hash =
00685 g_hash_table_new(hash_color, compare_colors);
00686 g_hash_table_insert(cc->color_hash, cnew, cnew);
00687
00688 cc->clut[cc->num_allocated] = color.pixel;
00689 cc->num_allocated++;
00690 return color.pixel;
00691 }
00692 }
00693
00694 return result->pixel;
00695 }
00696 }
00697 }
00698
00699 void
00700 gdk_color_context_get_pixels(GdkColorContext * cc,
00701 gushort * reds,
00702 gushort * greens,
00703 gushort * blues,
00704 gint ncolors,
00705 gulong * colors, gint * nallocated)
00706 {
00707 gint i, k, idx;
00708 gint cmapsize, ncols = 0, nopen = 0, counter = 0;
00709 gint bad_alloc = FALSE;
00710 gint failed[MAX_IMAGE_COLORS], allocated[MAX_IMAGE_COLORS];
00711 GdkColor defs[MAX_IMAGE_COLORS], cmap[MAX_IMAGE_COLORS];
00712 #ifdef G_ENABLE_DEBUG
00713 gint exact_col = 0, subst_col = 0, close_col = 0, black_col = 0;
00714 #endif
00715 g_assert(cc != NULL);
00716 g_assert(reds != NULL);
00717 g_assert(greens != NULL);
00718 g_assert(blues != NULL);
00719 g_assert(colors != NULL);
00720 g_assert(nallocated != NULL);
00721
00722 memset(defs, 0, MAX_IMAGE_COLORS * sizeof(GdkColor));
00723 memset(failed, 0, MAX_IMAGE_COLORS * sizeof(gint));
00724 memset(allocated, 0, MAX_IMAGE_COLORS * sizeof(gint));
00725
00726
00727
00728 ncols = *nallocated;
00729
00730 *nallocated = 0;
00731
00732
00733
00734 for (i = 0; i < ncolors; i++) {
00735
00736
00737
00738
00739
00740 if (colors[i] == 0) {
00741 defs[i].red = reds[i];
00742 defs[i].green = greens[i];
00743 defs[i].blue = blues[i];
00744
00745 colors[i] =
00746 gdk_color_context_get_pixel(cc, reds[i], greens[i], blues[i],
00747 &bad_alloc);
00748
00749
00750
00751 if (!bad_alloc) {
00752 defs[i].pixel = colors[i];
00753 allocated[ncols++] = colors[i];
00754 } else
00755 failed[nopen++] = i;
00756 }
00757 }
00758
00759 *nallocated = ncols;
00760
00761
00762
00763 if ((ncols == ncolors) || (nopen == 0)) {
00764 GDK_NOTE(COLOR_CONTEXT,
00765 g_message
00766 ("gdk_color_context_get_pixels: got all %i colors; "
00767 "(%i colors allocated so far)\n", ncolors,
00768 cc->num_allocated));
00769
00770 return;
00771 }
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782 cmapsize = MIN(cc->num_colors, MAX_IMAGE_COLORS);
00783
00784
00785
00786 if (cmapsize < 0) {
00787 g_warning
00788 ("gdk_color_context_get_pixels: oops! no colors available, "
00789 "your images will look *really* ugly.");
00790
00791 return;
00792 }
00793 #ifdef G_ENABLE_DEBUG
00794 exact_col = ncols;
00795 #endif
00796
00797
00798
00799 for (i = 0; i < cmapsize; i++) {
00800 cmap[i].pixel = i;
00801 cmap[i].red = cmap[i].green = cmap[i].blue = 0;
00802 }
00803
00804
00805
00806 my_x_query_colors(cc->colormap, cmap, cmapsize);
00807
00808
00809
00810 counter = nopen;
00811 nopen = 0;
00812 idx = 0;
00813
00814 do {
00815 gint d, j, mdist, close, ri, gi, bi;
00816 gint rd, gd, bd;
00817
00818 i = failed[idx];
00819
00820 mdist = 0x1000000;
00821 close = -1;
00822
00823
00824
00825
00826
00827 ri = reds[i];
00828 gi = greens[i];
00829 bi = blues[i];
00830
00831
00832
00833
00834
00835 for (j = 0; (j < cmapsize) && (mdist != 0); j++) {
00836
00837
00838 rd = (ri - cmap[j].red) / 256;
00839 gd = (gi - cmap[j].green) / 256;
00840 bd = (bi - cmap[j].blue) / 256;
00841
00842 d = rd * rd + gd * gd + bd * bd;
00843
00844 if (d < mdist) {
00845 close = j;
00846 mdist = d;
00847 }
00848 }
00849
00850 if (close != -1) {
00851 rd = cmap[close].red;
00852 gd = cmap[close].green;
00853 bd = cmap[close].blue;
00854
00855
00856
00857 colors[i] =
00858 gdk_color_context_get_pixel(cc, rd, gd, bd, &bad_alloc);
00859
00860
00861
00862 if (!bad_alloc) {
00863 defs[i] = cmap[close];
00864 defs[i].pixel = colors[i];
00865 allocated[ncols++] = colors[i];
00866 #ifdef G_ENABLE_DEBUG
00867 close_col++;
00868 #endif
00869 } else
00870 failed[nopen++] = i;
00871 } else
00872 failed[nopen++] = i;
00873
00874 }
00875 while (++idx < counter);
00876
00877 *nallocated = ncols;
00878
00879
00880
00881
00882
00883 if ((ncols == ncolors) || (nopen == 0)) {
00884 GDK_NOTE(COLOR_CONTEXT,
00885 g_message
00886 ("gdk_color_context_get_pixels: got %i colors, %i exact and "
00887 "%i close (%i colors allocated so far)\n", ncolors,
00888 exact_col, close_col, cc->num_allocated));
00889
00890 return;
00891 }
00892
00893
00894
00895 idx = 0;
00896
00897 do {
00898 gint d, mdist, close, ri, gi, bi;
00899 gint j, rd, gd, bd;
00900
00901 i = failed[idx];
00902
00903 mdist = 0x1000000;
00904 close = -1;
00905
00906
00907
00908 ri = reds[i];
00909 gi = greens[i];
00910 bi = blues[i];
00911
00912
00913
00914 for (j = 0; (j < ncols) && (mdist != 0); j++) {
00915 k = allocated[j];
00916
00917
00918
00919 rd = (ri - defs[k].red) / 256;
00920 gd = (gi - defs[k].green) / 256;
00921 bd = (bi - defs[k].blue) / 256;
00922
00923 d = rd * rd + gd * gd + bd * bd;
00924
00925 if (d < mdist) {
00926 close = k;
00927 mdist = d;
00928 }
00929 }
00930
00931 if (close < 0) {
00932
00933
00934 defs[i].pixel = cc->black_pixel;
00935 defs[i].red = defs[i].green = defs[i].blue = 0;
00936 #ifdef G_ENABLE_DEBUG
00937 black_col++;
00938 #endif
00939 } else {
00940 defs[i] = defs[close];
00941 #ifdef G_ENABLE_DEBUG
00942 subst_col++;
00943 #endif
00944 }
00945
00946 colors[i] = defs[i].pixel;
00947 }
00948 while (++idx < nopen);
00949
00950 GDK_NOTE(COLOR_CONTEXT,
00951 g_message
00952 ("gdk_color_context_get_pixels: got %i colors, %i exact, %i close, "
00953 "%i substituted, %i to black (%i colors allocated so far)\n",
00954 ncolors, exact_col, close_col, subst_col, black_col,
00955 cc->num_allocated));
00956 }
00957
00958 void
00959 gdk_color_context_get_pixels_incremental(GdkColorContext * cc,
00960 gushort * reds,
00961 gushort * greens,
00962 gushort * blues,
00963 gint ncolors,
00964 gint * used,
00965 gulong * colors,
00966 gint * nallocated)
00967 {
00968 gint i, k, idx;
00969 gint cmapsize, ncols = 0, nopen = 0, counter = 0;
00970 gint bad_alloc = FALSE;
00971 gint failed[MAX_IMAGE_COLORS], allocated[MAX_IMAGE_COLORS];
00972 GdkColor defs[MAX_IMAGE_COLORS], cmap[MAX_IMAGE_COLORS];
00973 #ifdef G_ENABLE_DEBUG
00974 gint exact_col = 0, subst_col = 0, close_col = 0, black_col = 0;
00975 #endif
00976
00977 g_assert(cc != NULL);
00978 g_assert(reds != NULL);
00979 g_assert(greens != NULL);
00980 g_assert(blues != NULL);
00981 g_assert(used != NULL);
00982 g_assert(colors != NULL);
00983 g_assert(nallocated != NULL);
00984
00985 memset(defs, 0, MAX_IMAGE_COLORS * sizeof(GdkColor));
00986 memset(failed, 0, MAX_IMAGE_COLORS * sizeof(gint));
00987 memset(allocated, 0, MAX_IMAGE_COLORS * sizeof(gint));
00988
00989
00990
00991 ncols = *nallocated;
00992
00993 *nallocated = 0;
00994
00995
00996
00997 for (i = 0; i < ncolors; i++) {
00998
00999
01000
01001
01002
01003
01004
01005 if (used[i] != FALSE) {
01006 if (colors[i] == 0) {
01007 defs[i].red = reds[i];
01008 defs[i].green = greens[i];
01009 defs[i].blue = blues[i];
01010
01011 colors[i] =
01012 gdk_color_context_get_pixel(cc, reds[i], greens[i],
01013 blues[i], &bad_alloc);
01014
01015
01016
01017 if (!bad_alloc) {
01018 defs[i].pixel = colors[i];
01019 allocated[ncols++] = colors[i];
01020 } else
01021 failed[nopen++] = i;
01022 }
01023 #ifdef DEBUG
01024 else
01025 GDK_NOTE(COLOR_CONTEXT,
01026 g_message("gdk_color_context_get_pixels_incremental: "
01027 "pixel at slot %i already allocated, skipping\n",
01028 i));
01029 #endif
01030 }
01031 }
01032
01033 *nallocated = ncols;
01034
01035 if ((ncols == ncolors) || (nopen == 0)) {
01036 GDK_NOTE(COLOR_CONTEXT,
01037 g_message
01038 ("gdk_color_context_get_pixels_incremental: got all %i colors "
01039 "(%i colors allocated so far)\n", ncolors,
01040 cc->num_allocated));
01041
01042 return;
01043 }
01044
01045 cmapsize = MIN(cc->num_colors, MAX_IMAGE_COLORS);
01046
01047 if (cmapsize < 0) {
01048 g_warning("gdk_color_context_get_pixels_incremental: oops! "
01049 "No colors available images will look *really* ugly.");
01050 return;
01051 }
01052 #ifdef G_ENABLE_DEBUG
01053 exact_col = ncols;
01054 #endif
01055
01056
01057
01058 for (i = 0; i < cmapsize; i++) {
01059 cmap[i].pixel = i;
01060 cmap[i].red = cmap[i].green = cmap[i].blue = 0;
01061 }
01062
01063
01064
01065 my_x_query_colors(cc->colormap, cmap, cmapsize);
01066
01067
01068
01069 counter = nopen;
01070 nopen = 0;
01071 idx = 0;
01072
01073 do {
01074 gint d, j, mdist, close, ri, gi, bi;
01075 gint rd, gd, bd;
01076
01077 i = failed[idx];
01078
01079 mdist = 0x1000000;
01080 close = -1;
01081
01082
01083
01084 ri = reds[i];
01085 gi = greens[i];
01086 bi = blues[i];
01087
01088 for (j = 0; (j < cmapsize) && (mdist != 0); j++) {
01089
01090
01091 rd = (ri - cmap[j].red) / 256;
01092 gd = (gi - cmap[j].green) / 256;
01093 bd = (bi - cmap[j].blue) / 256;
01094
01095 d = rd * rd + gd * gd + bd * bd;
01096
01097 if (d < mdist) {
01098 close = j;
01099 mdist = d;
01100 }
01101 }
01102
01103 if (close != -1) {
01104 rd = cmap[close].red;
01105 gd = cmap[close].green;
01106 bd = cmap[close].blue;
01107
01108
01109
01110 colors[i] =
01111 gdk_color_context_get_pixel(cc, rd, gd, bd, &bad_alloc);
01112
01113
01114
01115 if (!bad_alloc) {
01116 defs[i] = cmap[close];
01117 defs[i].pixel = colors[i];
01118 allocated[ncols++] = colors[i];
01119 #ifdef G_ENABLE_DEBUG
01120 close_col++;
01121 #endif
01122 } else
01123 failed[nopen++] = i;
01124 } else
01125 failed[nopen++] = i;
01126
01127 }
01128 while (++idx < counter);
01129
01130 *nallocated = ncols;
01131
01132 if ((ncols == ncolors) || (nopen == 0)) {
01133 GDK_NOTE(COLOR_CONTEXT,
01134 g_message("gdk_color_context_get_pixels_incremental: "
01135 "got %i colors, %i exact and %i close "
01136 "(%i colors allocated so far)\n",
01137 ncolors, exact_col, close_col,
01138 cc->num_allocated));
01139
01140 return;
01141 }
01142
01143
01144
01145 idx = 0;
01146
01147 do {
01148 gint d, mdist, close, ri, gi, bi;
01149 gint j, rd, gd, bd;
01150
01151 i = failed[idx];
01152
01153 mdist = 0x1000000;
01154 close = -1;
01155
01156 ri = reds[i];
01157 gi = greens[i];
01158 bi = blues[i];
01159
01160
01161
01162 for (j = 0; (j < ncols) && (mdist != 0); j++) {
01163 k = allocated[j];
01164
01165
01166
01167
01168 rd = (ri - defs[k].red) / 256;
01169 gd = (gi - defs[k].green) / 256;
01170 bd = (bi - defs[k].blue) / 256;
01171
01172 d = rd * rd + gd * gd + bd * bd;
01173
01174 if (d < mdist) {
01175 close = k;
01176 mdist = d;
01177 }
01178 }
01179
01180 if (close < 0) {
01181
01182
01183 defs[i].pixel = cc->black_pixel;
01184 defs[i].red = defs[i].green = defs[i].blue = 0;
01185 #ifdef G_ENABLE_DEBUG
01186 black_col++;
01187 #endif
01188 } else {
01189 defs[i] = defs[close];
01190 #ifdef G_ENABLE_DEBUG
01191 subst_col++;
01192 #endif
01193 }
01194
01195 colors[i] = defs[i].pixel;
01196 }
01197 while (++idx < nopen);
01198
01199 GDK_NOTE(COLOR_CONTEXT,
01200 g_message("gdk_color_context_get_pixels_incremental: "
01201 "got %i colors, %i exact, %i close, %i substituted, %i to black "
01202 "(%i colors allocated so far)\n",
01203 ncolors, exact_col, close_col, subst_col, black_col,
01204 cc->num_allocated));
01205 }
01206
01207 gint gdk_color_context_query_color(GdkColorContext * cc, GdkColor * color)
01208 {
01209 return gdk_color_context_query_colors(cc, color, 1);
01210 }
01211
01212 gint
01213 gdk_color_context_query_colors(GdkColorContext * cc,
01214 GdkColor * colors, gint num_colors)
01215 {
01216 gint i;
01217 GdkColor *tc;
01218
01219 g_assert(cc != NULL);
01220 g_assert(colors != NULL);
01221
01222 switch (cc->mode) {
01223 case GDK_CC_MODE_BW:
01224 for (i = 0, tc = colors; i < num_colors; i++, tc++) {
01225 if (tc->pixel == cc->white_pixel)
01226 tc->red = tc->green = tc->blue = 65535;
01227 else
01228 tc->red = tc->green = tc->blue = 0;
01229 }
01230 break;
01231
01232 case GDK_CC_MODE_TRUE:
01233 if (cc->clut == NULL)
01234 for (i = 0, tc = colors; i < num_colors; i++, tc++) {
01235 #if 0
01236 tc->red =
01237 ((tc->pixel & cc->masks.red) >> cc->shifts.red) << (16 -
01238 cc->
01239 bits.
01240 red);
01241 tc->green =
01242 ((tc->pixel & cc->masks.green) >> cc->shifts.
01243 green) << (16 - cc->bits.green);
01244 tc->blue =
01245 ((tc->pixel & cc->masks.blue) >> cc->shifts.blue) << (16 -
01246 cc->
01247 bits.
01248 blue);
01249 #else
01250 tc->red = 65535. * (double)((tc->pixel & cc->masks.red)
01251 >> cc->shifts.red) / ((1 << cc->visual->red_prec) - 1);
01252 tc->green = 65535. * (double)((tc->pixel & cc->masks.green)
01253 >> cc->shifts.green) / ((1 << cc->visual->green_prec) - 1);
01254 tc->blue = 65535. * (double)((tc->pixel & cc->masks.blue)
01255 >> cc->shifts.blue) / ((1 << cc->visual->blue_prec) - 1);
01256 #endif
01257 } else {
01258 my_x_query_colors(cc->colormap, colors, num_colors);
01259 return 1;
01260 }
01261 break;
01262
01263 case GDK_CC_MODE_STD_CMAP:
01264 default:
01265 if (cc->cmap == NULL) {
01266 my_x_query_colors(cc->colormap, colors, num_colors);
01267 return 1;
01268 } else {
01269 gint first, last, half;
01270 gulong half_pixel;
01271
01272 for (i = 0, tc = colors; i < num_colors; i++) {
01273 first = 0;
01274 last = cc->num_colors - 1;
01275
01276 while (first <= last) {
01277 half = (first + last) / 2;
01278 half_pixel = cc->cmap[half].pixel;
01279
01280 if (tc->pixel == half_pixel) {
01281 tc->red = cc->cmap[half].red;
01282 tc->green = cc->cmap[half].green;
01283 tc->blue = cc->cmap[half].blue;
01284 first = last + 1;
01285 } else {
01286 if (tc->pixel > half_pixel)
01287 first = half + 1;
01288 else
01289 last = half - 1;
01290 }
01291 }
01292 }
01293 return 1;
01294 }
01295 break;
01296 }
01297 return 1;
01298 }
01299
01300 gint
01301 gdk_color_context_add_palette(GdkColorContext * cc,
01302 GdkColor * palette, gint num_palette)
01303 {
01304 gint i, j, erg;
01305 gushort r, g, b;
01306 gulong pixel[1];
01307
01308 g_assert(cc != NULL);
01309
01310
01311
01312 init_palette(cc);
01313
01314
01315
01316 if (num_palette == 0)
01317 return 0;
01318
01319
01320
01321 cc->palette = g_new0(GdkColor, num_palette);
01322
01323 j = 0;
01324
01325 for (i = 0; i < num_palette; i++) {
01326 erg = 0;
01327 pixel[0] = 0;
01328
01329
01330
01331 r = palette[i].red;
01332 g = palette[i].green;
01333 b = palette[i].blue;
01334
01335 gdk_color_context_get_pixels(cc, &r, &g, &b, 1, pixel, &erg);
01336
01337
01338
01339 if (erg) {
01340
01341
01342 cc->palette[j].red = r;
01343 cc->palette[j].green = g;
01344 cc->palette[j].blue = b;
01345 cc->palette[j].pixel = pixel[0];
01346
01347
01348
01349 j++;
01350 }
01351 }
01352
01353
01354
01355 if (j != num_palette)
01356 cc->palette = g_realloc(cc->palette, j * sizeof(GdkColor));
01357
01358
01359
01360 if (cc->color_hash) {
01361 g_hash_table_foreach(cc->color_hash, free_hash_entry, NULL);
01362 g_hash_table_destroy(cc->color_hash);
01363 cc->color_hash = NULL;
01364 }
01365
01366
01367
01368 cc->num_palette = j;
01369
01370
01371
01372 cc->mode = GDK_CC_MODE_PALETTE;
01373
01374
01375
01376 qsort(cc->palette, cc->num_palette, sizeof(GdkColor), pixel_sort);
01377
01378 cc->fast_dither = NULL;
01379
01380 return j;
01381 }
01382
01383 void gdk_color_context_init_dither(GdkColorContext * cc)
01384 {
01385 gint rr, gg, bb, err, erg, erb;
01386 gint success = FALSE;
01387
01388 g_assert(cc != NULL);
01389
01390
01391
01392 if (cc->fast_dither == NULL)
01393 cc->fast_dither = g_new(GdkColorContextDither, 1);
01394
01395
01396
01397
01398 for (rr = 0; rr < 32; rr++)
01399 for (gg = 0; gg < 32; gg++)
01400 for (bb = 0; bb < 32; bb++) {
01401 err = (rr << 3) | (rr >> 2);
01402 erg = (gg << 3) | (gg >> 2);
01403 erb = (bb << 3) | (bb >> 2);
01404
01405 cc->fast_dither->fast_rgb[rr][gg][bb] =
01406 gdk_color_context_get_index_from_palette(cc, &err, &erg,
01407 &erb, &success);
01408 cc->fast_dither->fast_err[rr][gg][bb] = err;
01409 cc->fast_dither->fast_erg[rr][gg][bb] = erg;
01410 cc->fast_dither->fast_erb[rr][gg][bb] = erb;
01411 }
01412 }
01413
01414 void gdk_color_context_free_dither(GdkColorContext * cc)
01415 {
01416 g_assert(cc != NULL);
01417
01418 if (cc->fast_dither)
01419 g_free(cc->fast_dither);
01420
01421 cc->fast_dither = NULL;
01422 }
01423
01424 gulong
01425 gdk_color_context_get_pixel_from_palette(GdkColorContext * cc,
01426 gushort * red,
01427 gushort * green,
01428 gushort * blue, gint * failed)
01429 {
01430 gulong pixel = 0;
01431 gint dif, dr, dg, db, j = -1;
01432 gint mindif = 0x7fffffff;
01433 gint err = 0, erg = 0, erb = 0;
01434 gint i;
01435
01436 g_assert(cc != NULL);
01437 g_assert(red != NULL);
01438 g_assert(green != NULL);
01439 g_assert(blue != NULL);
01440 g_assert(failed != NULL);
01441
01442 *failed = FALSE;
01443
01444 for (i = 0; i < cc->num_palette; i++) {
01445 dr = *red - cc->palette[i].red;
01446 dg = *green - cc->palette[i].green;
01447 db = *blue - cc->palette[i].blue;
01448
01449 dif = dr * dr + dg * dg + db * db;
01450
01451 if (dif < mindif) {
01452 mindif = dif;
01453 j = i;
01454 pixel = cc->palette[i].pixel;
01455 err = dr;
01456 erg = dg;
01457 erb = db;
01458
01459 if (mindif == 0)
01460 break;
01461 }
01462 }
01463
01464
01465
01466 if (j == -1)
01467 *failed = TRUE;
01468 else {
01469 *red = ABS(err);
01470 *green = ABS(erg);
01471 *blue = ABS(erb);
01472 }
01473
01474 return pixel;
01475 }
01476
01477 guchar
01478 gdk_color_context_get_index_from_palette(GdkColorContext * cc,
01479 gint * red,
01480 gint * green,
01481 gint * blue, gint * failed)
01482 {
01483 gint dif, dr, dg, db, j = -1;
01484 gint mindif = 0x7fffffff;
01485 gint err = 0, erg = 0, erb = 0;
01486 gint i;
01487
01488 g_assert(cc != NULL);
01489 g_assert(red != NULL);
01490 g_assert(green != NULL);
01491 g_assert(blue != NULL);
01492 g_assert(failed != NULL);
01493
01494 *failed = FALSE;
01495
01496 for (i = 0; i < cc->num_palette; i++) {
01497 dr = *red - cc->palette[i].red;
01498 dg = *green - cc->palette[i].green;
01499 db = *blue - cc->palette[i].blue;
01500
01501 dif = dr * dr + dg * dg + db * db;
01502
01503 if (dif < mindif) {
01504 mindif = dif;
01505 j = i;
01506 err = dr;
01507 erg = dg;
01508 erb = db;
01509
01510 if (mindif == 0)
01511 break;
01512 }
01513 }
01514
01515
01516
01517 if (j == -1) {
01518 *failed = TRUE;
01519 j = 0;
01520 } else {
01521
01522
01523 *red = err;
01524 *green = erg;
01525 *blue = erb;
01526 }
01527
01528 return j;
01529 }