📄 clr.c
字号:
/** * clr.c - color management * * Copyright (c) 1998 * Transvirtual Technologies, Inc. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file. */#include "toolkit.h"#include <limits.h>#include <math.h>#define CLR_DIST 8.0/******************************************************************************** * auxiliary functions */static inline intxclrEquals ( XColor* pc, int r, int g, int b ){ return ((pc->red == r) && (pc->green == g) && (pc->blue == b));}/* * this is a rather crude color difference - a HSV difference might be * more ergonomical, but also much more expensive */static inline doublecolorDiff ( int r1, int g1, int b1, int r2, int g2, int b2 ){ int dr,dg, db; dr = r1 - r2; dr *= dr; dg = g1 - g2; dg *= dg; db = b1 - b2; db *= db; return sqrt( dr + dg + db);}/******************************************************************************** * 256 PseudoColor visual * * This is a real source of trouble, since we just can mitigate a serious lack * of resources. There are just 256 different colors available, and if this has to * be mapped to a equally distributed RGB model (used by Java), a 3/3/2 visual is * usually used, which is computed by a right shift of the Java color values (x>>5, * x>>6). This is wrong, twice. * First, it would give us just two gray values (not counting black and white), * because we just have 4 different blues. We therefore have to use a more fine * grained color cube to map Java rgbs to pixel values. A (virtual) 3/3/3 visual will * do the job. But this requires that we have a strategy for filling up cube cells * which don't have a direct system colormap equivalence (done by computing the * "nearest" initialized cell). Of course, this higher "color resolution" is just a * fake (we still have only 256 colors), and therefore we also need a mechanism to * ask for some "exact" color matches. If we have writable color cells, we first * satisfy them (if not already in the system colormap), if there still are colors * left, we allocate the worst RGB cube-to-colormap mismatches. * Second, we can't just truncate a Java RGB to get our color cube indices. This * might be tolerable with TrueColor visuals, but here we have just 8 distinct * values [0, 36.4, ..., 255], i.e. each cube point/cell represents a rather large * interval (36x36x36), and we have to round requests to the nearest cube cell index * But all this effort can easily be rendered almost useless by a bad system * colormap (i.e. if we don't have enough "different" colors, or if there are * no writable color cells at all). This is usually caused by rather careless * window managers, and the only way to get rid of this is to direct the window * manager to use one of the standard colormaps (if feasible) * An alternative strategy could be to defer color allocation until Color objects * with not-yet allocated cells are created. But since Java uses Color arithmetic * frequently (brighter(), darker(), HSV conversion etc.), this might lead to very * uneven results. *//* this is a linear [0..255] / 8 rgb mapping (255/7 = 36.4) */unsigned char rgb8 [] = { 0, 36, 73, 109, 146, 182, 219, 255 };/* * Note that this implementation of nearestColor works "geometrically", i.e. * it just computes the best match for equal (index) distance color cells, not the * absolute best value (regardless of cell distance). We therefore shouldn't use * its result to set cells in m->pix while other empty cells are still waiting to * be served. */static unsigned charnearestColor ( Rgb2Pseudo* m, int pi, int pj, int pk, int dist ){ int i, j, k, i0, i1, j0, j1, k0, k1; int pix, idx = -1; double drgb, d = 1e6; if ( (i0 = pi-dist) < 0 ) i0 = 0; if ( (i1 = pi+dist) > 7 ) i1 = 7; if ( (j0 = pj-dist) < 0 ) j0 = 0; if ( (j1 = pj+dist) > 7 ) j1 = 7; if ( (k0 = pk-dist) < 0 ) k0 = 0; if ( (k1 = pk+dist) > 7 ) k1 = 7; for ( i=i0; i <= i1; i++ ) { for ( j=j0; j <= j1; j++ ) { for ( k=k0; k <= k1; k++ ) { if ( (pix = m->pix[i][j][k]) ) { drgb = colorDiff( m->rgb[pix].r, m->rgb[pix].g, m->rgb[pix].b, rgb8[pi], rgb8[pj], rgb8[pk]); if ( drgb < d ){ d = drgb; idx = pix; } } } } } if ( idx >= 0 ) return idx; else { if ( (i0 == 0) && (i1 == 7) ) /* should never happen, backup */ return 0; else return nearestColor( m, pi, pj, pk, dist+1); }}typedef struct _Mismatch { unsigned char d; unsigned char i, j, k;} Mismatch;static voidfillUpColorCube ( Rgb2Pseudo* map, Colormap cm, int nAvail, unsigned long *pixels, unsigned char (*mp) [8][8][8] ){ int i, j, k, pix, l; int nMis = 0, maxMis = nAvail; int r, g, b; Mismatch *mm = alloca( maxMis* sizeof( Mismatch)); unsigned char d; XColor xclr; memset( *mp, 0, 8*8*8); /* * Find the nearest values for not yet initialized cells. Note that we * cannot set these values directly in map->pix because it would cause * interference with other unset cells (the way nearestColor works), and * pixel values should just be computed from direct match cells */ for ( i=0; i<8; i++ ){ for ( j=0; j<8; j++ ) { for ( k=0; k<8; k++ ){ if ( (map->pix[i][j][k] == 0) && (i | j | k) ){ pix = nearestColor( map, i, j, k, 1); (*mp)[i][j][k] = pix; /* * If we still have available color cells, build a sorted list of the * worst mismatches (but skip dark values) */ if ( (nAvail > 0) && (i|j|k) > 2) { if ( (d = (unsigned char) colorDiff( rgb8[i], rgb8[j], rgb8[k], map->rgb[pix].r, map->rgb[pix].g, map->rgb[pix].b)) > 50 ){ for ( l=0; l<nMis && mm[l].d > d ; l++ ); if ( l < nMis ) memmove( mm + l+1, mm+l, (nMis - l)*sizeof( Mismatch)); mm[l].d = d; mm[l].i = i; mm[l].j = j; mm[l].k = k; if ( nMis < maxMis ) nMis++; } } } } } } /* if there is a mismatch list, resolve it */ for ( l=0; l< nMis-1; l++ ) { r = rgb8[ mm[l].i ]; g = rgb8[ mm[l].j ]; b = rgb8[ mm[l].k ]; xclr.pixel = pixels[l]; xclr.flags = DoRed | DoGreen | DoBlue; xclr.red = r << 8; xclr.green = g << 8; xclr.blue = b << 8; XStoreColor( X->dsp, cm, &xclr); map->pix [mm[l].i] [mm[l].j] [mm[l].k] = xclr.pixel; map->rgb[xclr.pixel].r = r; map->rgb[xclr.pixel].g = g; map->rgb[xclr.pixel].b = b; /* mark this cell as satisifed */ (*mp) [mm[l].i] [mm[l].j] [mm[l].k] = 0; } /* store all still uninitialized cube cells from our temp cube of nearest values */ for ( i=0; i<8; i++ ){ for ( j=0; j<8; j++ ) { for ( k=0; k<8; k++ ){ if ( (pix = (*mp) [i][j][k]) ) map->pix[i][j][k] = pix; } } }}#define MAX_REQUESTS 16static voidinitColormap ( JNIEnv* env, Toolkit* tk, Colormap cm, Rgb2Pseudo* map ){ jclass clazz; jfieldID fid; jintArray rgbRequests = 0; jboolean isCopy; jint *jrgbs = 0; int nReq = 0; unsigned long pixels[MAX_REQUESTS]; jint req[MAX_REQUESTS]; unsigned long planeMasks[1]; int n, i, j, k, l, m, pix; Visual *v = DefaultVisualOfScreen( DefaultScreenOfDisplay( tk->dsp)); XColor xclr; int r, g, b; char blackSeen = 0; unsigned char (*mp)[8][8][8] = alloca( 8*8*8 * sizeof( char)); memset( *mp, 0, 8*8*8); /* get the java.awt.DefaultsRGB.RgbRequests field */ if ( (clazz = (*env)->FindClass( env, "java/awt/Defaults")) ){ if ( (fid = (*env)->GetStaticFieldID( env, clazz, "RgbRequests", "[I")) ){ if ( (rgbRequests = (*env)->GetStaticObjectField( env, clazz, fid)) ){ jrgbs = (*env)->GetIntArrayElements( env, rgbRequests, &isCopy); nReq = (*env)->GetArrayLength( env, rgbRequests); if ( nReq > MAX_REQUESTS ) nReq = MAX_REQUESTS; memcpy( req, jrgbs, nReq * sizeof( jint)); (*env)->ReleaseIntArrayElements( env, rgbRequests, jrgbs, JNI_ABORT); } } } /* * Determine how many RW cells there are available. Don't try to grab * too many cells, since this might disturb other apps and could end up * in even worse results */ for ( n= 10; n; n-- ) { if ( XAllocColorCells( tk->dsp, cm, False, planeMasks, 0, pixels, n) ) break; } xclr.red = 0; xclr.green = 0; xclr.blue = 0; xclr.flags = DoRed | DoGreen | DoBlue; /* mark all of our cells (so that we don't rely on their current values) */ for ( i=0; i<n; i++ ){ xclr.pixel = pixels[i]; XStoreColor( tk->dsp, cm, &xclr); } /* check which of our rgb requests are already in the colormap */ for ( l=0; l<v->map_entries; l++ ) { xclr.pixel = l; XQueryColor( tk->dsp, cm, &xclr); r = xclr.red >> 8; g = xclr.green >> 8; b = xclr.blue >> 8; i = JI8(r); j = JI8(g); k = JI8(b); if ( r | g | b ) { for ( m=0; m<nReq; m++ ) { if ( req[m] && colorDiff( JRED(req[m]), JGREEN(req[m]), JBLUE(req[m]), r, g, b) < CLR_DIST ) { req[m] = 0; /* mark color request as satisfied */ (*mp)[i][j][k] = 1; /* mark cube cell (i,j,k) as requested */ break; } } } /* * we start to populate the color cube as we go (XQueryColor might be expensive), * but we don't overwrite an already set cell with a worse match (if we don't * have a standard system colormap, there is a good chance that several * colormap cells will map to the same indices of our 3/3/3 color cube). We also * shouldn't overwrite requested colors with better cube-cell matches (hence the * 'mp' check) */ if ( !(i|j|k) && blackSeen++ ) /* don't overwrite real black with avail cell */ continue; if ( ((*mp)[i][j][k] < 2) && (!(pix = map->pix [i][j][k]) || (colorDiff( r, g, b, rgb8[i], rgb8[j], rgb8[k]) < colorDiff( map->rgb[pix].r, map->rgb[pix].g, map->rgb[pix].b, rgb8[i], rgb8[j], rgb8[k]))) ) { if ( (*mp)[i][j][k] ) /* prevent cube cell from being overwritten, again */ (*mp)[i][j][k] ++; map->pix [i][j][k] = l; map->rgb[l].r = r; map->rgb[l].g = g; map->rgb[l].b = b; } } /* set cells of not-yet satisfied rgb requests */ for ( i=0, j=0; (i<nReq) && (i<n); i++ ) { if ( req[i] ){ r = JRED( req[i]); g = JGREEN( req[i]); b = JBLUE( req[i]); xclr.pixel = pixels[j++]; xclr.red = r << 8; xclr.green = g << 8; xclr.blue = b << 8; XStoreColor( X->dsp, cm, &xclr); map->pix [JI8(r)] [JI8(g)] [JI8(b)] = xclr.pixel; map->rgb[xclr.pixel].r = r; map->rgb[xclr.pixel].g = g; map->rgb[xclr.pixel].b = b; } } /* * initalize rest of cube cells by computing their nearest rgb value, optionally * allocating new cells for the worst mismatches (if there still are colors avail) */ fillUpColorCube( map, cm, (n - j), pixels+j, mp );}static Rgb2Pseudo*initRgb2Pseudo ( JNIEnv* env, jclass clazz UNUSED, Toolkit* tk ){ Colormap dcm; int i, j, k; XColor xclr; Rgb2Pseudo *map; dcm = DefaultColormapOfScreen( DefaultScreenOfDisplay( tk->dsp)); map = (Rgb2Pseudo*) AWT_MALLOC( sizeof(Rgb2Pseudo)); xclr.flags = DoRed | DoGreen | DoBlue; for ( i=0; i<8; i++ ){ for ( j=0; j<8; j++ ) { for ( k=0; k<8; k++ ) map->pix[i][j][k] = 0; } } initColormap( env, tk, dcm, map); tk->colorMode = CM_PSEUDO_256; return map;}/******************************************************************************** * TrueColor (RGB) visual */static Rgb2True*initRgb2True (JNIEnv* env UNUSED, jclass clazz UNUSED, Toolkit* tk ){ Visual *v = DefaultVisualOfScreen( DefaultScreenOfDisplay( tk->dsp)); unsigned int m;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -