LCOV - code coverage report
Current view: top level - gdraw - gimageclut.c (source / functions) Hit Total Coverage
Test: FontForge coverage report 2017-08-04 01:21:11+02:00 (commit d35f7e4107a9e1db65cce47c468fcc914cecb8fd) Lines: 0 669 0.0 %
Date: 2017-08-04 Functions: 0 29 0.0 %

          Line data    Source code
       1             : /* Copyright (C) 2000-2012 by George Williams */
       2             : /*
       3             :  * Redistribution and use in source and binary forms, with or without
       4             :  * modification, are permitted provided that the following conditions are met:
       5             : 
       6             :  * Redistributions of source code must retain the above copyright notice, this
       7             :  * list of conditions and the following disclaimer.
       8             : 
       9             :  * Redistributions in binary form must reproduce the above copyright notice,
      10             :  * this list of conditions and the following disclaimer in the documentation
      11             :  * and/or other materials provided with the distribution.
      12             : 
      13             :  * The name of the author may not be used to endorse or promote products
      14             :  * derived from this software without specific prior written permission.
      15             : 
      16             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
      17             :  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
      18             :  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
      19             :  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      20             :  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
      21             :  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
      22             :  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
      23             :  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      24             :  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
      25             :  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      26             :  */
      27             : #include "gdrawP.h"
      28             : #include "colorP.h"
      29             : #include "charset.h"
      30             : #include "ustring.h"
      31             : #include "gutils.h"
      32             : 
      33             : #if defined(__MINGW32__)
      34             : #  include "../gutils/divisors.c"
      35             : #endif
      36             : 
      37             : struct clutinf {
      38             :     Color col;
      39             :     int32 cnt;
      40             :     struct clutinf *next;
      41             : };
      42             : 
      43             : struct clutcube {
      44             :     int32 cnt;
      45             :     struct clutinf *ours;
      46             : };
      47             : 
      48             : struct clutcnt {
      49             :     int sofar;
      50             :     struct clutinf clut[256];
      51             :     struct clutinf transinf;
      52             :     struct clutcube cube[16][16][16];
      53             :     int32 dither[6*6*6];
      54             :     int size, div;
      55             : };
      56             : 
      57             : struct clut_range {
      58             :     unsigned short red_min;
      59             :     unsigned short green_min;
      60             :     unsigned short blue_min;
      61             :     int shift;
      62             : };
      63             : 
      64             : struct colcnt {
      65             :     Color col;
      66             :     int32 cnt;
      67             : };
      68             : 
      69           0 : static void RevColListFree(struct revcol *rc) {
      70             :     struct revcol *next;
      71             : 
      72           0 :     while ( rc!=NULL ) {
      73           0 :         next = rc->next;
      74           0 :         free(rc);
      75           0 :         rc = next;
      76             :     }
      77           0 : }
      78             : 
      79           0 : static int cccomp(const void *_c1, const void *_c2) {
      80           0 :     register const struct colcnt *c1 = _c1, *c2 = _c2;
      81             : 
      82           0 : return( c2->cnt-c1->cnt );
      83             : }
      84             : 
      85           0 : static int colcomp(const void *_c1, const void *_c2) {
      86           0 :     register const Color *c1 = _c1, *c2 = _c2;
      87             : 
      88           0 : return( *c1-*c2 );
      89             : }
      90             : 
      91           0 : static int cicomp(const void *_c1, const void *_c2) {
      92           0 :     register const struct clutinf *c1 = _c1, *c2 = _c2;
      93             : 
      94           0 : return( c1->col-c2->col );
      95             : }
      96             : 
      97           0 : static int cicntcomp(const void *_c1, const void *_c2) {
      98           0 :     register const struct clutinf *c1 = _c1, *c2 = _c2;
      99             : 
     100           0 : return( c2->cnt-c1->cnt );
     101             : }
     102             : 
     103             : /* we have cnt different colors, the colors and their histogram is given in */
     104             : /*  clutinf. We want to fit that into clutmax colors */
     105             : /* first thing is to create a dithering cube which will fit in clutmax */
     106             : /*  (if clutmax<8 then we are probably screwed, so just return 8) */
     107             : /* Ok figure out what bits of the cube we need (the subcubes we have colors in*/
     108             : /*  and some of those adjacent (assuming the color doesn't match exactly the */
     109             : /*  subcube's mid-point we'll need to dither and for that we need the adjacent))*/
     110             : /* Then we'll probably have some left over. Well, let's just add as many of the*/
     111             : /*  most used colors as we can */
     112           0 : static GClut *gimage_reduceclut(GClut *clut,int clutmax,struct clutinf *clutinf,
     113             :         int cnt, struct clutinf *transinf) {
     114             :     int i,j;
     115             :     int size, div, s2, s3;
     116             :     int r,g,b,dindex;
     117             :     int32 dither[6*6*6];
     118             : 
     119           0 :     if ( transinf->cnt )
     120           0 :         --clutmax;
     121           0 :     for ( size=6; size>0; --size )
     122           0 :         if ( size*size*size<=clutmax )
     123           0 :     break;
     124           0 :     if ( size<2 ) size=2;
     125           0 :     div = (255/(size-1));
     126             : 
     127           0 :     for ( i=0; i<cnt; ++i ) {
     128           0 :         Color val = clutinf[i].col;
     129           0 :         r=COLOR_RED(val), g=COLOR_GREEN(val), b=COLOR_BLUE(val);
     130           0 :         dindex = ((r/div)*size+(g/div))*size+(b/div);
     131           0 :         dither[dindex] += clutinf[i].cnt;
     132             :     }
     133             : 
     134           0 :     s2 = size*size;
     135           0 :     for ( r=0; r<size-1; ++r ) for ( g=0; g<size-1; ++g ) for ( b=0; b<size-1; ++b ) {
     136           0 :         if ( dither[r*s2+g*size+b] > 0 ) {
     137           0 :             if ( dither[r*s2+g*size+b+1] == 0 ) dither[r*s2+g*size+b+1] = -1;
     138           0 :             if ( dither[r*s2+(g+1)*size+b] == 0 ) dither[r*s2+(g+1)*size+b] = -1;
     139           0 :             if ( dither[(r+1)*s2+g*size+b] == 0 ) dither[(r+1)*s2+g*size+b] = -1;
     140           0 :             if ( dither[r*s2+(g+1)*size+b+1] == 0 ) dither[r*s2+(g+1)*size+b+1] = -1;
     141           0 :             if ( dither[(r+1)*s2+(g+1)*size+b] == 0 ) dither[(r+1)*s2+(g+1)*size+b] = -1;
     142           0 :             if ( dither[(r+1)*s2+g*size+b+1] == 0 ) dither[(r+1)*s2+g*size+b+1] = -1;
     143           0 :             if ( dither[(r+1)*s2+(g+1)*size+b+1] == 0 ) dither[(r+1)*s2+(g+1)*size+b+1] = -1;
     144             :         }
     145             :     }
     146           0 :     s3 = s2*size;
     147           0 :     for ( i=j=0; i<s3; ++i ) if ( dither[i]!= 0 ) {
     148           0 :         r = (i/(s2))*div;       if ( r>250 ) r=255;
     149           0 :         g = (i/size)%size*div;  if ( g>250 ) g=255;
     150           0 :         b = (i%(size))*div;     if ( b>250 ) b=255;
     151           0 :         clut->clut[j++] = COLOR_CREATE(r,g,b);
     152             :     }
     153             : 
     154           0 :     if ( j<clutmax ) {
     155           0 :         qsort(clutinf,sizeof(clutinf[0]),cnt,cicntcomp);
     156           0 :         i = 0;
     157           0 :         while ( j<clutmax && i<cnt ) {
     158           0 :             r = COLOR_RED(clutinf[i].col); g = COLOR_GREEN(clutinf[i].col);
     159           0 :             b = COLOR_BLUE(clutinf[i].col);
     160           0 :             if ( (r!=255 || (r<250 && r%div==0)) &&
     161           0 :                     (g!=255 || (g<250 && g%div==0)) && 
     162           0 :                     (b!=255 || (b<250 && b%div==0)) )
     163           0 :                 clut->clut[j++] = clutinf[i].col;
     164           0 :             ++i;
     165             :         }
     166             :     }
     167           0 :     if ( transinf->cnt!=0 )
     168           0 :         clut->clut[j++] = transinf->col;
     169           0 :     clut->clut_len = j;
     170           0 : return( clut );
     171             : }
     172             : 
     173           0 : static void gimage_count32(GImage *image, struct clutcnt *clutcnt,int clutmax) {
     174             :     int i, j, len, size, div;
     175             :     uint32 *ipt, *istart, *iend;
     176             :     struct _GImage *base, **bases;
     177           0 :     int orig_trans = clutcnt->transinf.cnt;
     178             : 
     179           0 :     if ( image->list_len ) {
     180           0 :         len = image->list_len;
     181           0 :         bases = image->u.images;
     182             :     } else {
     183           0 :         bases = &image->u.image;
     184           0 :         len = 1;
     185             :     }
     186           0 :     for ( size=6; size>0; --size )
     187           0 :         if ( size*size*size<=clutmax )
     188           0 :     break;
     189           0 :     if ( size<2 ) size=2;
     190           0 :     clutcnt->size = size;
     191           0 :     clutcnt->div = div = (255/(size-1));
     192             : 
     193           0 :     for ( j=0; j<len; ++j ) {
     194           0 :         base = bases[j];
     195           0 :         ipt = (uint32 *) (base->data);
     196           0 :         for ( i=0; i<base->height; ++i ) {
     197           0 :             istart = ipt;
     198           0 :             for ( iend = ipt + base->width; ipt<iend; ++ipt ) {
     199           0 :                 register int32 val = *ipt;
     200           0 :                 register int r=COLOR_RED(val), g=COLOR_GREEN(val), b=COLOR_BLUE(val);
     201           0 :                 int dindex = (r/div)*size*size+(g/div)*size+(b/div);
     202           0 :                 register struct clutcube *cc = &clutcnt->cube[r>>4][g>>4][b>>4];
     203             :                 register struct clutinf *test;
     204           0 :                 if ( val==base->trans )
     205           0 :                     ++clutcnt->transinf.cnt;
     206             :                 else {
     207           0 :                     ++ cc->cnt;
     208           0 :                     ++clutcnt->dither[dindex];
     209           0 :                     if ( clutcnt->sofar<=256 ) {
     210           0 :                         for ( test = cc->ours; test!=NULL; test=test->next )
     211           0 :                             if ( test->col==val )
     212           0 :                         break;
     213           0 :                         if ( test==NULL ) {
     214           0 :                             if ( clutcnt->sofar<256 ) {
     215           0 :                                 test = &clutcnt->clut[clutcnt->sofar];
     216           0 :                                 test->next = cc->ours;
     217           0 :                                 test->col = val;
     218           0 :                                 cc->ours = test;
     219             :                             }
     220           0 :                             ++clutcnt->sofar;
     221             :                         } else
     222           0 :                             ++ test->cnt;
     223             :                     }
     224             :                 }
     225             :             }
     226           0 :             ipt = (uint32 *) (((uint8 *) istart) + base->bytes_per_line);
     227             :         }
     228           0 :         if ( clutcnt->transinf.cnt!=orig_trans )
     229           0 :             clutcnt->transinf.col = base->trans;
     230             :     }
     231           0 : }
     232             : 
     233           0 : static GClut *gimage_pickclut32(GClut *clut,int clutmax, struct clutcnt *clutcnt) {
     234           0 :     struct clutcube *cube = &clutcnt->cube[0][0][0];
     235             :     struct colcnt cc[4096];
     236             :     int i,j,r,g,b,incr,size,s2,s3, wantstrans;
     237             : 
     238           0 :     size = clutcnt->size; s2 = size*size; s3 = size*s2;
     239           0 :     incr = clutcnt->div;
     240           0 :     j = 0;
     241             :     /* if we have a color in a cube cell then we want to make sure that the */
     242             :     /*  edges of that cell are available to us so we can dither */
     243           0 :     for ( r=0; r<size-1; ++r ) for ( g=0; g<size-1; ++g ) for ( b=0; b<size-1; ++b ) {
     244           0 :         if ( clutcnt->dither[r*s2+g*size+b] > 0 ) {
     245           0 :             if ( clutcnt->dither[r*s2+g*size+b+1] == 0 ) clutcnt->dither[r*s2+g*size+b+1] = -1;
     246           0 :             if ( clutcnt->dither[r*s2+(g+1)*size+b] == 0 ) clutcnt->dither[r*s2+(g+1)*size+b] = -1;
     247           0 :             if ( clutcnt->dither[(r+1)*s2+g*size+b] == 0 ) clutcnt->dither[(r+1)*s2+g*size+b] = -1;
     248           0 :             if ( clutcnt->dither[r*s2+(g+1)*size+b+1] == 0 ) clutcnt->dither[r*s2+(g+1)*size+b+1] = -1;
     249           0 :             if ( clutcnt->dither[(r+1)*s2+(g+1)*size+b] == 0 ) clutcnt->dither[(r+1)*s2+(g+1)*size+b] = -1;
     250           0 :             if ( clutcnt->dither[(r+1)*s2+g*size+b+1] == 0 ) clutcnt->dither[(r+1)*s2+g*size+b+1] = -1;
     251           0 :             if ( clutcnt->dither[(r+1)*s2+(g+1)*size+b+1] == 0 ) clutcnt->dither[(r+1)*s2+(g+1)*size+b+1] = -1;
     252             :         }
     253             :     }
     254           0 :     for ( i=0; i<s3; ++i ) if ( clutcnt->dither[i]!= 0 ) {
     255           0 :         r = (i/(s2))*incr;      if ( r>250 ) r=255;
     256           0 :         g = (i/size)%size*incr; if ( g>250 ) g=255;
     257           0 :         b = (i%(size))*incr;    if ( b>250 ) b=255;
     258           0 :         clut->clut[j++] = COLOR_CREATE(r,g,b);
     259             :     }
     260           0 :     wantstrans = (clutcnt->transinf.cnt!=0);
     261             : 
     262           0 :     for ( i=0; i<16*16*16; ++i ) {
     263           0 :         if ( cube[i].ours!=NULL && cube[i].ours->cnt>(3*cube[i].cnt)/4 )
     264           0 :             cc[i].col = cube[i].ours->col;
     265             :         else
     266           0 :             cc[i].col = COLOR_CREATE( ((i>>8)<<4) + 8,(((i>>4)&0xf)<<4) + 8, ((i&0xf)<<4)+8 );
     267           0 :         cc[i].cnt = cube[i].cnt;
     268             :     }
     269           0 :     qsort(cc,4096,sizeof(cc[0]),cccomp);
     270           0 :     for ( i=0; j<clutmax-wantstrans; ++j,++i ) {
     271           0 :         if ( cc[i].cnt==0 )
     272           0 :     break;
     273           0 :         clut->clut[j] = cc[i].col;
     274             :     }
     275           0 :     qsort(clut->clut,j,sizeof(Color),colcomp);
     276             : 
     277           0 :     if ( wantstrans ) {
     278           0 :         clut->trans_index = j;
     279           0 :         clut->clut[j++] = clutcnt->transinf.col/*COLOR_CREATE(clutcnt->transinf.red,clutcnt->transinf.green,clutcnt->transinf.blue)!!!!*/;
     280             :     }
     281           0 :     clut->clut_len = j;
     282           0 : return( clut );
     283             : }
     284             : 
     285           0 : static GClut *gimage_findclut32(GImage *image,GClut *clut,int clutmax) {
     286             :     struct clutcnt clutcnt;
     287             :     int i;
     288             : 
     289           0 :     memset(&clutcnt,'\0',sizeof(clutcnt));
     290           0 :     gimage_count32(image, &clutcnt,clutmax);
     291           0 :     if ( clutcnt.sofar+(clutcnt.transinf.cnt!=0) <=clutmax ) {
     292           0 :         for ( i=0; i<clutcnt.sofar; ++i )
     293           0 :             clut->clut[i] = clutcnt.clut[i].col;
     294           0 :         if ( clutcnt.transinf.cnt!=0 ) {
     295           0 :             clut->trans_index = i;
     296           0 :             clut->clut[i++] = clutcnt.transinf.col;
     297             :         }
     298           0 :         clut->clut_len = i;
     299           0 : return( clut );
     300             :     }
     301             : 
     302           0 :     if ( clutcnt.sofar<=256 )
     303           0 : return( gimage_reduceclut(clut,clutmax,clutcnt.clut,clutcnt.sofar,&clutcnt.transinf));
     304             : 
     305           0 : return( gimage_pickclut32(clut,clutmax,&clutcnt));
     306             : }
     307             : 
     308           0 : static int gimage_count8(GImage *image, struct clutinf *clutinf, int pos, struct clutinf *transinf) {
     309             :     int i, j, k, len;
     310             :     uint8 *ipt, *istart, *iend;
     311             :     struct _GImage *base, **bases;
     312             :     GClut *clut;
     313             :     int clutmax;
     314             : 
     315           0 :     if ( image->list_len ) {
     316           0 :         len = image->list_len;
     317           0 :         bases = image->u.images;
     318             :     } else {
     319           0 :         bases = &image->u.image;
     320           0 :         len = 1;
     321             :     }
     322             : 
     323           0 :     for ( k=0; k<len; ++k ) {
     324           0 :         base = bases[k];
     325           0 :         ipt = (uint8 *) (base->data);
     326           0 :         clutmax = base->clut->clut_len;
     327           0 :         for ( i=0; i<base->height; ++i ) {
     328           0 :             istart = ipt;
     329           0 :             for ( iend = ipt + base->width; ipt<iend; ++ipt ) {
     330           0 :                 register int val = *ipt;
     331           0 :                 if ( val<clutmax )
     332           0 :                     ++clutinf[val+pos].cnt;
     333             :             }
     334           0 :             ipt = istart + base->bytes_per_line;
     335             :         }
     336             :     
     337           0 :         clut = base->clut;
     338           0 :         if ( base->trans!=COLOR_UNKNOWN ) {
     339           0 :             if ( transinf->cnt==0 )
     340           0 :                 transinf->col = clut->clut[base->trans];
     341           0 :             transinf->cnt += clutinf[base->trans+pos].cnt;
     342           0 :             clutinf[base->trans+pos].cnt = 0;
     343             :         }
     344           0 :         for ( i=0; i<clutmax; ++i ) {
     345           0 :             clutinf[i+pos].col = clut->clut[i];
     346             :         }
     347           0 :         pos += clutmax;
     348             :     }
     349             : 
     350           0 :     if ( len>1 ) {
     351             :         /* remove duplicates (if any), by sorting first so dups are adjacent */
     352           0 :         qsort(clutinf,sizeof(clutinf[0]),pos,cicomp);
     353           0 :         for ( i=j=0; i<pos; ++i ) {
     354           0 :             if ( clutinf[i].cnt==0 )
     355           0 :         continue;
     356           0 :             if ( i!=j )
     357           0 :                 clutinf[j++] = clutinf[i];
     358             :             else
     359           0 :                 j++;
     360           0 :             for ( k=i+1; k<pos; ++k ) {
     361           0 :                 if ( clutinf[i].col != clutinf[k].col )
     362           0 :             break;
     363           0 :                 clutinf[i].cnt += clutinf[k].cnt;
     364           0 :                 clutinf[k].cnt = 0;
     365             :             }
     366           0 :             i = k-1;
     367             :         }
     368           0 :         pos = j;
     369             :     }
     370             : 
     371           0 : return( pos );
     372             : }
     373             : 
     374           0 : static int TickGreyClut(GClut *clut, char *grey_clut) {
     375             :     int i, r,b,g;
     376             : 
     377           0 :     if ( clut==NULL ) {
     378           0 :         grey_clut[0] = true;
     379           0 :         grey_clut[255] = true;
     380           0 : return( true );
     381             :     }
     382           0 :     for ( i=0; i<clut->clut_len; ++i ) {
     383           0 :         r = COLOR_RED(clut->clut[i]);
     384           0 :         g = COLOR_GREEN(clut->clut[i]);
     385           0 :         b = COLOR_BLUE(clut->clut[i]);
     386           0 :         if ( r!=g || g!=b ) {
     387           0 :             clut->is_grey = false;
     388           0 : return( false );
     389             :         }
     390           0 :         grey_clut[r] = true;
     391             :     }
     392           0 :     clut->is_grey = true;
     393           0 : return( true );
     394             : }
     395             : 
     396           0 : static int is_grey(GImage *image, char *grey_clut) {
     397           0 :     struct _GImage *base = image->list_len==0?image->u.image:image->u.images[0];
     398             :     int i;
     399             : 
     400           0 :     for ( i=0; i<256; ++i ) grey_clut[i] = 0;
     401           0 :     if ( base->image_type == it_true )
     402           0 : return( false );
     403           0 :     if ( image->list_len==0 ) {
     404           0 :         if ( TickGreyClut(base->clut,grey_clut) && base->trans==COLOR_UNKNOWN )
     405           0 : return( base->clut->clut_len );
     406             : 
     407           0 : return( 0 );
     408             :     } else {
     409             :         int m;
     410           0 :         struct _GImage **im = image->u.images, **end = im+image->list_len;
     411           0 :         while ( im<end ) {
     412           0 :             if ( !TickGreyClut(im[0]->clut,grey_clut) || im[0]->trans != COLOR_UNKNOWN )
     413           0 : return( 0 );
     414             :         }
     415           0 :         m = 0;
     416           0 :         for ( i=0; i<256; ++i )
     417           0 :             if ( grey_clut[i])
     418           0 :                 ++m;
     419           0 : return( m );
     420             :     }
     421             : }
     422             : 
     423           0 : static GClut *PickGreyClut(GClut *clut,int clutmax,char *grey_clut,int tot) {
     424             :     int i,j;
     425             : 
     426           0 :     clut->trans_index = COLOR_UNKNOWN;
     427           0 :     if ( clutmax==256 ) {
     428           0 :         for ( i=0; i<256; ++i )
     429           0 :             clut->clut[i] = COLOR_CREATE(i,i,i);
     430           0 :         clut->clut_len = 256;
     431           0 :     } else if ( tot<=clutmax ) {
     432           0 :         for ( i=j=0; i<256; ++i )
     433           0 :             if ( grey_clut[i] )
     434           0 :                 clut->clut[j++] = COLOR_CREATE(i,i,i);
     435           0 :         clut->clut_len = j;
     436             :     } else {
     437             :         int min_val, max_val;
     438             :         int incr;
     439             : 
     440           0 :         for ( i=0; i<256 && !grey_clut[i]; ++i );
     441           0 :         min_val = i;
     442           0 :         for ( i=255; i>=0 && !grey_clut[i]; --i );
     443           0 :         max_val = i+1;
     444           0 :         incr = (max_val-min_val)/(clutmax-1);
     445           0 :         for ( i=0; i<clutmax; ++i )
     446           0 :             clut->clut[i] = COLOR_CREATE(min_val+i*incr,min_val+i*incr,min_val+i*incr);
     447           0 :         clut->clut[i-1] = COLOR_CREATE(max_val,max_val,max_val);
     448           0 :         clut->clut_len = clutmax;
     449             :     }
     450           0 :     clut->is_grey = true;
     451           0 : return( clut );
     452             : }
     453             : 
     454           0 : GClut *GImageFindCLUT(GImage *image,GClut *clut,int clutmax) {
     455             :     int i,cnt;
     456             :     struct clutinf *clutinf, transinf;
     457             :     struct _GImage **list;
     458           0 :     struct _GImage *base = image->list_len==0?image->u.image:image->u.images[0];
     459             :     char grey_clut[256];
     460             : 
     461           0 :     if ( clut==NULL )
     462           0 :         clut = malloc(sizeof(GClut));
     463           0 :     if ( clutmax<2 || clut==NULL )
     464           0 : return( 0 );
     465             : 
     466           0 :     clut->clut_len = 0; clut->is_grey = false;
     467           0 :     if ( clutmax>256 ) clutmax = 256;
     468             : 
     469           0 :     if ( base->image_type==it_true )
     470           0 : return( gimage_findclut32(image,clut,clutmax));
     471             : 
     472           0 :     if ( image->list_len==0 ) {
     473           0 :         if ( base->clut==NULL ) {    /* Black & White */
     474           0 :             clut->clut[0] = COLOR_CREATE(0,0,0);
     475           0 :             clut->clut[1] = COLOR_CREATE(255,255,255);
     476           0 :             clut->clut_len = 2;
     477           0 :             clut->trans_index = 0;
     478           0 : return( clut );
     479           0 :         } else if ( base->clut->clut_len<=clutmax ) {
     480           0 :             memcpy(clut->clut,base->clut->clut,base->clut->clut_len*sizeof(Color));
     481           0 :             clut->clut_len = base->clut->clut_len;
     482           0 :             clut->trans_index = base->trans;
     483           0 : return( clut );
     484             :         }
     485             :     }
     486             : 
     487           0 :     if ( (cnt = is_grey(image,grey_clut)) )
     488           0 : return( PickGreyClut(clut,clutmax,grey_clut,cnt));
     489             : 
     490           0 :     if ( image->list_len ) {
     491           0 :         cnt = 0;
     492           0 :         for ( i=0, list = image->u.images; i<image->list_len; ++i, ++list)
     493           0 :             cnt += (*list)->clut->clut_len;
     494             :     } else
     495           0 :         cnt = image->u.image->clut->clut_len;
     496             : 
     497           0 :     memset(&transinf,'\0',sizeof(transinf));
     498           0 :     clutinf = calloc(cnt,sizeof(struct clutinf));
     499             :     
     500           0 :     cnt = gimage_count8(image, clutinf, 0, &transinf);
     501           0 :     if ( cnt+(transinf.cnt!=0)<clutmax ) {
     502           0 :         clut->clut_len = cnt+(transinf.cnt!=0);
     503           0 :         clut->trans_index = cnt;
     504           0 :         for ( i=0; i<cnt; ++i )
     505           0 :             clut->clut[i] = clutinf[i].col;
     506           0 :         clut->clut[i] = transinf.col;
     507           0 :         free(clutinf);
     508           0 : return(clut);
     509             :     }
     510             : 
     511           0 :     gimage_reduceclut(clut,clutmax,clutinf,cnt,&transinf);
     512           0 :     free(clutinf);
     513           0 :     return clut;
     514             : }
     515             : 
     516             : static const GCol white = { 0xff, 0xff, 0xff, 1 }, black = { 0, 0, 0, 0 };
     517             : 
     518           0 : const GCol *_GImage_GetIndexedPixel(Color col,RevCMap *rev) {
     519             :     int val, t, best, r, g, b;
     520             :     struct revitem *this;
     521             :     struct revcol *test, *bestcol;
     522             : 
     523           0 :     if ( rev==NULL ) {          /* Mono */
     524           0 :         if ( COLOR2WHITE(col) )
     525           0 : return( &white );
     526             :         else
     527           0 : return( &black );
     528             :     }
     529           0 :     if ( rev->is_grey ) {
     530           0 :         val = COLOR2GREY(col);
     531           0 : return( &rev->greys[val]);
     532             :     }
     533             : 
     534             :   reverse_clut:
     535           0 :     r = COLOR_RED(col); g = COLOR_GREEN(col); b = COLOR_BLUE(col);
     536           0 :     if ( rev->div_mul==1 ) {
     537           0 :         val = r>>rev->div_shift;
     538           0 :         val = (val<<rev->side_shift)+(g>>rev->div_shift);
     539           0 :         val = (val<<rev->side_shift)+(b>>rev->div_shift);
     540             :     } else {
     541           0 :         val = ((r+rev->div_add)*rev->div_mul)>>rev->div_shift;
     542           0 :         t = ((g+rev->div_add)*rev->div_mul)>>rev->div_shift;
     543           0 :         val = (val*rev->side_cnt)+t;
     544           0 :         t = ((b+rev->div_add)*rev->div_mul)>>rev->div_shift;
     545           0 :         val = (val*rev->side_cnt)+t;
     546             :     }
     547           0 :     this = &rev->cube[val];
     548           0 :     if ( this->sub!=NULL ) {
     549           0 :         col &= rev->mask;
     550           0 :         rev = this->sub;
     551           0 :   goto reverse_clut;
     552             :     }
     553             : 
     554           0 :     test = this->cols[0];
     555           0 :     if ( test->next==NULL )
     556           0 : return( (GCol *) test );
     557             : 
     558           0 :     if (( best = (r-test->red))<0 ) best = -best;
     559           0 :     if (( t = (g-test->green))<0 ) t = -t; best += t;
     560           0 :     if (( t = (b-test->blue))<0 ) t = -t; best += t;
     561           0 :     bestcol = test;
     562           0 :     for ( test=test->next; test!=NULL; test = test->next ) {
     563           0 :         if (( val = (r-test->red))<0 ) val = -val;
     564           0 :         if (( t = (g-test->green))<0 ) t = -t; val += t;
     565           0 :         if (( t = (b-test->blue))<0 ) t = -t; val += t;
     566           0 :         if ( val<best ) {
     567           0 :             val = best;
     568           0 :             bestcol = test;
     569             :         }
     570             :     }
     571           0 : return( (GCol *) bestcol );
     572             : }
     573             : 
     574             : 
     575           0 : const GCol *_GImage_GetIndexedPixelPrecise(Color col,RevCMap *rev) {
     576             :     int val, t, best, r, g, b;
     577             :     struct revitem *this;
     578             :     struct revcol *test, *bestcol;
     579             : 
     580           0 :     if ( rev==NULL ) {          /* Mono */
     581           0 :         if ( COLOR2WHITE(col) )
     582           0 : return( &white );
     583             :         else
     584           0 : return( &black );
     585             :     }
     586           0 :     if ( rev->is_grey ) {
     587           0 :         val = COLOR2GREY(col);
     588           0 : return( &rev->greys[val]);
     589             :     }
     590             : 
     591             :   reverse_clut:
     592           0 :     r = COLOR_RED(col); g = COLOR_GREEN(col); b = COLOR_BLUE(col);
     593           0 :     if ( rev->div_mul==1 ) {
     594           0 :         r>>=rev->div_shift;
     595           0 :         g>>=rev->div_shift;
     596           0 :         b>>=rev->div_shift;
     597           0 :         val = (((r<<rev->side_shift) + g)<<rev->side_shift)+ b;
     598             :     } else {
     599           0 :         r = ((r+rev->div_add)*rev->div_mul)>>rev->div_shift;
     600           0 :         g = ((g+rev->div_add)*rev->div_mul)>>rev->div_shift;
     601           0 :         b = ((b+rev->div_add)*rev->div_mul)>>rev->div_shift;
     602           0 :         val = ((r*rev->side_cnt)+g)*rev->side_cnt + b;
     603             :     }
     604           0 :     this = &rev->cube[val];
     605           0 :     if ( this->sub!=NULL ) {
     606           0 :         col &= rev->mask;
     607           0 :         rev = this->sub;
     608           0 :   goto reverse_clut;
     609             :     }
     610             : 
     611           0 :     test = this->cols[0];
     612           0 :     if ( test->next==NULL && this->cols[1]==NULL )
     613           0 : return( (GCol *) test );
     614             : 
     615           0 :     if (( best = (r-test->red))<0 ) best = -best;
     616           0 :     if (( t = (g-test->green))<0 ) t = -t; best += t;
     617           0 :     if (( t = (b-test->blue))<0 ) t = -t; best += t;
     618           0 :     bestcol = test;
     619           0 :     for ( test=test->next; test!=NULL; test = test->next ) {
     620           0 :         if (( val = (r-test->red))<0 ) val = -val;
     621           0 :         if (( t = (g-test->green))<0 ) t = -t; val += t;
     622           0 :         if (( t = (b-test->blue))<0 ) t = -t; val += t;
     623           0 :         if ( val<best ) {
     624           0 :             val = best;
     625           0 :             bestcol = test;
     626             :         }
     627             :     }
     628             : 
     629           0 :     for ( test=this->cols[1]; test!=NULL; test = test->next ) {
     630           0 :         if (( val = (r-test->red))<0 ) val = -val;
     631           0 :         if (( t = (g-test->green))<0 ) t = -t; val += t;
     632           0 :         if (( t = (b-test->blue))<0 ) t = -t; val += t;
     633           0 :         if ( val<best ) {
     634           0 :             val = best;
     635           0 :             bestcol = test;
     636             :         }
     637             :     }
     638           0 : return( (GCol *) bestcol );
     639             : }
     640             : 
     641           0 : static int rccnt( struct revcol *cols) {
     642           0 :     int cnt = 0;
     643           0 :     while ( cols!=NULL ) {
     644           0 :         ++cnt;
     645           0 :         cols = cols->next;
     646             :     }
     647           0 : return( cnt );
     648             : }
     649             : 
     650           0 : static struct revcol *add_adjacent(struct revcol *test, struct revcol *old, Color col, int dmax) {
     651           0 :     int r=COLOR_RED(col), g=COLOR_GREEN(col), b=COLOR_BLUE(col);
     652             :     int off, t, bestoff;
     653           0 :     struct revcol *best=NULL;
     654             : 
     655           0 :     if ( test==NULL || test->dist>dmax )
     656           0 : return( old );
     657           0 :     bestoff = 3*255;
     658           0 :     for ( test=test; test!=NULL; test = test->next ) {
     659           0 :         if ( (off = (r-test->red))<0 ) off = -off;
     660           0 :         if ( (t = (g-test->green))<0 ) t = -t; off +=t;
     661           0 :         if ( (b = (g-test->blue))<0 ) t = -t; off +=t;
     662           0 :         if ( off<bestoff ) {
     663           0 :             bestoff = off;
     664           0 :             best = test;
     665             :         }
     666             :     }
     667           0 :     if ( old!=NULL ) {
     668           0 :         if ( (off = (r-old->red))<0 ) off = -off;
     669           0 :         if ( (t = (g-old->green))<0 ) t = -t; off +=t;
     670           0 :         if ( (b = (g-old->blue))<0 ) t = -t; off +=t;
     671           0 :         if ( off<bestoff ) {
     672           0 :             bestoff = off;
     673           0 :             best = old;
     674             :         }
     675             :     }
     676           0 :     if ( best!=old ) {
     677           0 :         if ( old==NULL ) old = calloc(1,sizeof(struct revcol));
     678           0 :         *old = *best;
     679           0 :         old->next = NULL;
     680           0 :         ++old->dist;
     681             :     }
     682           0 : return( old );
     683             : }
     684             : 
     685           0 : static struct revcol *addrevcol(struct revcol *copy,struct revcol *old, int dist) {
     686           0 :     struct revcol *rc = malloc(sizeof(struct revcol));
     687             : 
     688           0 :     *rc = *copy;
     689           0 :     rc->next = old;
     690           0 :     rc->dist = dist;
     691           0 : return( rc );
     692             : }
     693             : 
     694           0 : static RevCMap *_GClutReverse(int side_cnt,int range,struct revcol *basecol,
     695             :         struct revcol *cols,struct revcol *outercols) {
     696             :     RevCMap *rev;
     697             :     int i, s2, s3, side_size;
     698             :     struct revcol *test;
     699             :     int changed, dmax, anynulls;
     700             : 
     701           0 :     rev = calloc(1,sizeof(RevCMap));
     702             : 
     703           0 :     rev->side_cnt = side_cnt;
     704           0 :     rev->range = range;
     705           0 :     if ( side_cnt<0 ) {
     706             :         /* special cases ... */
     707           0 :         side_cnt = -side_cnt;
     708           0 :         rev->side_cnt = side_cnt;
     709           0 :         if ( side_cnt==6 ) {            /* Used for the inefficient standard 6 by cube */
     710           0 :             rev->div_mul = div_tables[0x33][0];
     711           0 :             rev->div_shift = div_tables[0x33][1];
     712           0 :             rev->div_add = 0x19;
     713             :         }
     714           0 :         side_size = 0x33;
     715           0 :     } else if ( div_tables[side_cnt][0]==1 ) {
     716           0 :         rev->side_shift = div_tables[side_cnt][1];
     717           0 :         rev->div_shift = div_tables[range][1]-rev->side_shift;
     718           0 :         rev->div_mul = 1;
     719           0 :         rev->mask = ( 0x010101 * ((-1<rev->div_shift)&0xff) );
     720           0 :         side_size = 1<<(rev->div_shift);
     721             :     } else {
     722           0 :         side_size = (range+side_cnt-1)/side_cnt;
     723           0 :         rev->div_mul = div_tables[side_cnt][0];
     724           0 :         rev->div_shift = div_tables[side_cnt][1];
     725             :     }
     726             : 
     727           0 :     rev->cube = calloc(side_cnt*side_cnt*side_cnt,sizeof(struct revitem));
     728           0 :     for ( test = cols; test!=NULL; test = test->next ) {
     729             :         int pos, dist;
     730             :         int r,g,b;
     731           0 :         int rbase = (test->red-basecol->red)/side_size, gbase = (test->green-basecol->green)/side_size, bbase = (test->blue-basecol->blue)/side_size;
     732           0 :         for ( r = (test->red-basecol->red-side_size/2)/side_size;
     733           0 :                 r<=(test->red-basecol->red+side_size/2)/side_size; ++r ) {
     734           0 :             if ( r<0 || r==side_cnt )
     735           0 :         continue;
     736           0 :             for ( g = (test->green-basecol->green-side_size/2)/side_size;
     737           0 :                     g<=(test->green-basecol->green+side_size/2)/side_size; ++g ) {
     738           0 :                 if ( g<0 || g==side_cnt )
     739           0 :             continue;
     740           0 :                 for ( b = (test->blue-basecol->blue-side_size/2)/side_size;
     741           0 :                         b<=(test->blue-basecol->blue+side_size/2)/side_size; ++b ) {
     742           0 :                     if ( b<0 || b==side_cnt )
     743           0 :                 continue;
     744           0 :                     pos = (r*side_cnt + g)*side_cnt + b;
     745           0 :                     dist = r!=rbase || g!=gbase || b!=bbase;
     746           0 :                     rev->cube[pos].cols[dist] = addrevcol(test,rev->cube[pos].cols[dist],
     747             :                             dist );
     748             :                 }
     749             :             }
     750             :         }
     751             :     }
     752             : 
     753             :     /* Ok. We just put every color into the sub-cube that it belongs in */
     754             :     /*  but that's not good enough. Say we are looking for a color that */
     755             :     /*  is on the edge of a sub-cube, then the best match for it may be */
     756             :     /*  in one of the adjacent sub-cubes, rather than within it's own */
     757             :     /* So we also ran through the list of colors, casting our net a */
     758             :     /*  little wider. Essentially for every sub-cube we found all the colors */
     759             :     /*  within a subcube centered on the color */
     760             : 
     761             :     /* Some sub-cubes will probably have no information in them. Fill them */
     762             :     /*  in by looking at near-by cubes */
     763           0 :     s2 = side_cnt*side_cnt; s3 = s2*side_cnt;
     764           0 :     for ( i=0; i<s3; ++i ) {
     765           0 :         if ( rev->cube[i].cols[0]==NULL && rev->cube[i].cols[1]!=NULL ) {
     766           0 :             rev->cube[i].cols[0] = rev->cube[i].cols[1];
     767           0 :             rev->cube[i].cols[1] = NULL;
     768             :         }
     769             :     }
     770           0 :     changed = true; anynulls = false; dmax = 0;
     771           0 :     while ( changed || (anynulls && dmax<256) ) {
     772           0 :         changed = false; anynulls = false;
     773           0 :         for ( i=0; i<s3; ++i ) {
     774           0 :             if ( rev->cube[i].cols[0]==NULL ) {
     775           0 :                 int r = i/s2, g = (i/side_cnt)%side_cnt, b = i%side_cnt;
     776           0 :                 int col = ((r*side_cnt+(side_cnt>>1))<<16) |
     777           0 :                           ((g*side_cnt+(side_cnt>>1))<<8) |
     778           0 :                           ((b*side_cnt+(side_cnt>>1))) ;
     779           0 :                 if ( r>0 ) rev->cube[i].cols[0] = add_adjacent(rev->cube[i-s2].cols[0],NULL,col,dmax);
     780           0 :                 if ( r+1<side_cnt ) rev->cube[i].cols[0] = add_adjacent(rev->cube[i+s2].cols[0],rev->cube[i].cols[0],col,dmax);
     781           0 :                 if ( g>0 ) rev->cube[i].cols[0] = add_adjacent(rev->cube[i-side_cnt].cols[0],rev->cube[i].cols[0],col,dmax);
     782           0 :                 if ( g+1<side_cnt ) rev->cube[i].cols[0] = add_adjacent(rev->cube[i+side_cnt].cols[0],rev->cube[i].cols[0],col,dmax);
     783           0 :                 if ( b>0 ) rev->cube[i].cols[0] = add_adjacent(rev->cube[i-1].cols[0],rev->cube[i].cols[0],col,dmax);
     784           0 :                 if ( b+1<side_cnt ) rev->cube[i].cols[0] = add_adjacent(rev->cube[i+1].cols[0],rev->cube[i].cols[0],col,dmax);
     785           0 :                 if ( rev->cube[i].cols[0]!=NULL ) changed = true;
     786           0 :                 else anynulls = true;
     787             :             }
     788             :         }
     789           0 :         ++dmax;
     790             :     }
     791             : 
     792           0 :     if ( anynulls ) {
     793           0 :         fprintf(stderr, "I'm sorry I cannot use this visual, please reconfigure your display\n" );
     794           0 :         exit(1);
     795             :     }
     796             : 
     797           0 :     if ( rev->side_shift!=0 ) {
     798           0 :         range >>= rev->side_shift;
     799           0 :         if ( range>8 ) for ( i=0; i<s3; ++i ) if ( rev->cube[i].cols[0]->dist==0 ) {
     800           0 :             int ql = rccnt(rev->cube[i].cols[0]);
     801           0 :             int nr= -1;
     802             :             struct revcol nbase;
     803           0 :             if ( ql>128 )
     804           0 :                 nr = 16;
     805           0 :             else if ( ql>32 )
     806           0 :                 nr = 8;
     807           0 :             else if ( ql>=8 )
     808           0 :                 nr = 4;
     809           0 :             if ( nr!=-1 ) {
     810           0 :                 nbase.red = basecol->red+(i/s2)*range;
     811           0 :                 nbase.green = basecol->green+(i/side_cnt)%side_cnt*range;
     812           0 :                 nbase.blue = basecol->blue+(i%side_cnt)*range;
     813           0 :                 while ( nr>range ) nr >>= 1;
     814           0 :                 if ( nr!=1 )
     815           0 :                     rev->cube[i].sub = _GClutReverse(nr,range,&nbase,
     816           0 :                             rev->cube[i].cols[0],rev->cube[i].cols[1]);
     817             :             }
     818             :         }
     819             :     }
     820           0 : return( rev );
     821             : }
     822             : 
     823           0 : RevCMap *GClutReverse(GClut *clut,int side_cnt) {
     824           0 :     struct revcol *base = NULL;
     825             :     int i;
     826             :     RevCMap *ret;
     827             :     struct revcol basecol;
     828             : 
     829           0 :     if ( GImageGreyClut(clut) ) {
     830             :         GCol *greys; int changed;
     831           0 :         ret = calloc(1,sizeof(RevCMap));
     832           0 :         ret->is_grey = 1;
     833           0 :         greys = ret->greys = malloc(256*sizeof(GCol));
     834           0 :         for ( i=0; i<256; ++i ) greys[i].pixel = 0x1000;
     835           0 :         for ( i=0; i<clut->clut_len; ++i ) {
     836           0 :             int g = clut->clut[i]&0xff;
     837           0 :             greys[g].red = greys[g].green = greys[g].blue = g;
     838           0 :             greys[g].pixel = i;
     839             :         }
     840           0 :         changed = true;
     841           0 :         while ( changed ) {
     842           0 :             changed = false;
     843           0 :             for ( i=0; i<256; ++i ) {
     844           0 :                 if ( greys[i].pixel!=0x1000 ) {
     845           0 :                     if ( i!=0 && greys[i-1].pixel == 0x1000 ) {
     846           0 :                         greys[i-1] = greys[i]; changed = true; }
     847           0 :                     if ( i!=255 && greys[i+1].pixel == 0x1000 ) {
     848           0 :                         greys[i+1] = greys[i]; changed = true; }
     849             :                 }
     850             :             }
     851             :         }
     852           0 : return( ret );
     853             :     }
     854             : 
     855           0 :     for ( i=0; i<clut->clut_len; ++i ) {
     856           0 :         struct revcol *rc = malloc(sizeof(struct revcol));
     857           0 :         rc->red = COLOR_RED(clut->clut[i]);
     858           0 :         rc->green = COLOR_GREEN(clut->clut[i]);
     859           0 :         rc->blue = COLOR_BLUE(clut->clut[i]);
     860           0 :         rc->index = i;
     861           0 :         rc->dist = 0;
     862           0 :         rc->next = base;
     863           0 :         base = rc;
     864             :     }
     865           0 :     memset(&basecol,'\0',sizeof(basecol));
     866           0 :     ret = _GClutReverse(side_cnt,256,&basecol,base,base);
     867           0 :     while ( base!=NULL ) {
     868           0 :         struct revcol *rc = base->next;
     869           0 :         free(base);
     870           0 :         base = rc;
     871             :     }
     872           0 : return( ret );
     873             : }
     874             : 
     875           0 : void GClut_RevCMapFree(RevCMap *rev) {
     876             :     int i;
     877             : 
     878           0 :     for ( i=0; i<rev->side_cnt*rev->side_cnt*rev->side_cnt; ++i ) {
     879           0 :         if ( rev->cube[i].sub!=NULL )
     880           0 :             GClut_RevCMapFree(rev->cube[i].sub);
     881           0 :         RevColListFree(rev->cube[i].cols[0]);
     882           0 :         RevColListFree(rev->cube[i].cols[1]);
     883             :     }
     884           0 :     free(rev->cube);
     885           0 :     free(rev);
     886           0 : }
     887             : 
     888           0 : int GImageSameClut(GClut *clut,GClut *nclut) {
     889             :     static GClut dummy = { 2, true, COLOR_UNKNOWN, GCLUT_CLUT_EMPTY };
     890             :     int i;
     891             :     
     892           0 :     dummy.clut[0] = COLOR_CREATE(0, 0, 0);
     893           0 :     dummy.clut[1] = COLOR_CREATE(0xff, 0xff, 0xff);
     894             : 
     895           0 :     if ( clut==nclut )
     896           0 : return( true );
     897           0 :     if ( clut==NULL )
     898           0 :         clut = &dummy;
     899           0 :     if ( nclut==NULL )
     900           0 :         nclut = &dummy;
     901           0 :     if ( clut->clut_len!=nclut->clut_len )
     902           0 : return( false );
     903           0 :     for ( i = 0; i<clut->clut_len; ++i )
     904           0 :         if ( clut->clut[i]!=nclut->clut[i] )
     905           0 : return( false );
     906             : 
     907           0 : return( true );
     908             : }
     909             : 
     910           0 : int GImageGreyClut(GClut *clut) {
     911             :     int i, r,b,g;
     912             : 
     913           0 :     if ( clut==NULL )
     914           0 : return( true );
     915           0 :     for ( i=0; i<clut->clut_len; ++i ) {
     916           0 :         r = COLOR_RED(clut->clut[i]);
     917           0 :         g = COLOR_GREEN(clut->clut[i]);
     918           0 :         b = COLOR_BLUE(clut->clut[i]);
     919           0 :         if ( r!=g || g!=b ) {
     920           0 :             clut->is_grey = false;
     921           0 : return( false );
     922             :         }
     923             :     }
     924           0 :     clut->is_grey = true;
     925           0 : return( true );
     926             : }
     927             : 
     928             : static struct { char *name; long value; } predefn[] = {
     929             :     { "red", 0xff0000 },
     930             :     { "green", 0x008000 },
     931             :     { "blue", 0x0000ff },
     932             :     { "cyan", 0x00ffff },
     933             :     { "magenta", 0xff00ff },
     934             :     { "yellow", 0xffff00 },
     935             :     { "black", 0x000000 },
     936             :     { "gray", 0x808080 },
     937             :     { "grey", 0x808080 },
     938             :     { "white", 0xffffff },
     939             :     { "maroon", 0x800000 },
     940             :     { "olive", 0x808000 },
     941             :     { "navy", 0x000080 },
     942             :     { "purple", 0x800080 },
     943             :     { "lime", 0x00ff00 },
     944             :     { "aqua", 0x00ffff },
     945             :     { "teal", 0x008080 },
     946             :     { "fuchsia", 0xff0080 },
     947             :     { "silver", 0xcccccc },
     948             :     { NULL, 0 }
     949             : };
     950             : 
     951           0 : Color _GImage_ColourFName(char *name) {
     952             :     int i;
     953             :     int r,g,b,a;
     954             :     double dr,dg,db,da;
     955             :     struct hslrgb hs;
     956             :     Color col;
     957             : 
     958           0 :     for ( i=0; predefn[i].name!=NULL; ++i )
     959           0 :         if ( strmatch(name,predefn[i].name)==0 )
     960           0 : return( predefn[i].value );
     961             : 
     962           0 :     if ( sscanf(name,"%d %d %d", &r, &g, &b )==3 ||
     963           0 :             sscanf(name,"%x %x %x", (unsigned *) &r, (unsigned *) &g, (unsigned *) &b )==3 ||
     964           0 :             (strlen(name)==7 && sscanf(name,"#%2x%2x%2x", (unsigned *) &r, (unsigned *) &g, (unsigned *) &b )==3) ) {
     965           0 :         if ( r>255 ) r=255; else if ( r<0 ) r=0;
     966           0 :         if ( g>255 ) g=255; else if ( g<0 ) g=0;
     967           0 :         if ( b>255 ) b=255; else if ( b<0 ) b=0;
     968           0 : return( ((long) r<<16) | (g<<8) | b );
     969           0 :     } else if ( (strlen(name)==9 && sscanf(name,"#%2x%2x%2x%2x",
     970             :             (unsigned *) &a, (unsigned *) &r, (unsigned *) &g, (unsigned *) &b )==4) ) {
     971           0 :         if ( a>255 ) a=255; else if ( a<0 ) a=0;
     972           0 :         if ( r>255 ) r=255; else if ( r<0 ) r=0;
     973           0 :         if ( g>255 ) g=255; else if ( g<0 ) g=0;
     974           0 :         if ( b>255 ) b=255; else if ( b<0 ) b=0;
     975           0 :         col = ((long) a<<24) | ((long) r<<16) | (g<<8) | b;
     976           0 :         if ( (col&0xfffffff0)==0xfffffff0 )
     977           0 :             col &= 0xffffff;        /* I use these colors internally for things like "Undefined" */
     978             :                             /* but since I also treat colors with 0 alpha channel as fully */
     979             :                             /* opaque, I can just represent this that way */
     980           0 : return( col );
     981           0 :     } else if ( sscanf(name,"rgb(%lg,%lg,%lg)", &dr, &dg, &db)==3 ) {
     982           0 :         if ( dr>1.0 ) dr=1.0; else if ( dr<0 ) dr= 0;
     983           0 :         if ( dg>1.0 ) dg=1.0; else if ( dg<0 ) dg= 0;
     984           0 :         if ( db>1.0 ) db=1.0; else if ( db<0 ) db= 0;
     985           0 :         r = dr*255 +.5;
     986           0 :         g = dg*255 +.5;
     987           0 :         b = db*255 +.5;
     988           0 : return( ((long) r<<16) | (g<<8) | b );
     989           0 :     } else if ( sscanf(name,"argb(%lg,%lg,%lg,%lg)", &da, &dr, &dg, &db)==4 ) {
     990           0 :         if ( da>1.0 ) da=1.0; else if ( da<0 ) da= 0;
     991           0 :         if ( dr>1.0 ) dr=1.0; else if ( dr<0 ) dr= 0;
     992           0 :         if ( dg>1.0 ) dg=1.0; else if ( dg<0 ) dg= 0;
     993           0 :         if ( db>1.0 ) db=1.0; else if ( db<0 ) db= 0;
     994           0 :         a = da*255 +.5;
     995           0 :         r = dr*255 +.5;
     996           0 :         g = dg*255 +.5;
     997           0 :         b = db*255 +.5;
     998           0 :         col = ((long) a<<24) | ((long) r<<16) | (g<<8) | b;
     999           0 :         if ( (col&0xfffffff0)==0xfffffff0 )
    1000           0 :             col &= 0xffffff;        /* I use these colors internally for things like "Undefined" */
    1001             :                             /* but since I also treat colors with 0 alpha channel as fully */
    1002             :                             /* opaque, I can just represent this that way */
    1003           0 : return( col );
    1004           0 :     } else if ( sscanf(name,"hsv(%lg,%lg,%lg)", &hs.h, &hs.s, &hs.v)==3 ) {
    1005             :         /* Hue is an angle in degrees. HS?2RGB does appropriate clipping */
    1006           0 :         if ( hs.s>1.0 ) hs.s=1.0; else if ( hs.s<0 ) hs.s= 0;
    1007           0 :         if ( hs.v>1.0 ) hs.v=1.0; else if ( hs.v<0 ) hs.v= 0;
    1008           0 :         gHSV2RGB(&hs);
    1009           0 :         r = hs.r*255 +.5;
    1010           0 :         g = hs.g*255 +.5;
    1011           0 :         b = hs.b*255 +.5;
    1012           0 : return( ((long) r<<16) | (g<<8) | b );
    1013           0 :     } else if ( sscanf(name,"hsl(%lg,%lg,%lg)", &hs.h, &hs.s, &hs.l)==3 ) {
    1014             :         /* Hue is an angle in degrees. HS?2RGB does appropriate clipping */
    1015           0 :         if ( hs.s>1.0 ) hs.s=1.0; else if ( hs.s<0 ) hs.s= 0;
    1016           0 :         if ( hs.l>1.0 ) hs.l=1.0; else if ( hs.l<0 ) hs.l= 0;
    1017           0 :         gHSL2RGB(&hs);
    1018           0 :         r = hs.r*255 +.5;
    1019           0 :         g = hs.g*255 +.5;
    1020           0 :         b = hs.b*255 +.5;
    1021           0 : return( ((long) r<<16) | (g<<8) | b );
    1022           0 :     } else if ( (strlen(name)==4 && sscanf(name,"#%1x%1x%1x", (unsigned *) &r, (unsigned *) &g, (unsigned *) &b )==3) ) {
    1023           0 :         if ( r>15 ) r=15; else if ( r<0 ) r=0;
    1024           0 :         if ( g>15 ) g=15; else if ( g<0 ) g=0;
    1025           0 :         if ( b>15 ) b=15; else if ( b<0 ) b=0;
    1026           0 : return( ((long) (r*0x110000)) | (g*0x1100) | (b*0x11) );
    1027           0 :     } else if ( (strlen(name)==17 && sscanf(name,"#%4x%4x%4x", (unsigned *) &r, (unsigned *) &g, (unsigned *) &b )==3) ) {
    1028           0 :         r>>=8; g>>=8; b>>=8;
    1029           0 :         if ( r>255 ) r=255; else if ( r<0 ) r=0;
    1030           0 :         if ( g>255 ) g=255; else if ( g<0 ) g=0;
    1031           0 :         if ( b>255 ) b=255; else if ( b<0 ) b=0;
    1032           0 : return( ((long) r<<16) | (g<<8) | b );
    1033           0 :     } else if ( sscanf(name,"rgb(%lg%%,%lg%%,%lg%%)", &dr, &dg, &db)==3 ) {
    1034           0 :         if ( dr>100 ) dr=100; else if ( dr<0 ) dr= 0;
    1035           0 :         if ( dg>100 ) dg=100; else if ( dg<0 ) dg= 0;
    1036           0 :         if ( db>100 ) db=100; else if ( db<0 ) db= 0;
    1037           0 :         r = (dr*255+50)/100 +.5;
    1038           0 :         g = (dg*255+50)/100 +.5;
    1039           0 :         b = (db*255+50)/100 +.5;
    1040           0 : return( ((long) r<<16) | (g<<8) | b );
    1041             :     }
    1042           0 : return( -1 );
    1043             : }
    1044             : 
    1045           0 : Color GImageColourFName(unichar_t *name) {
    1046           0 : return( _GImage_ColourFName(u_to_c(name)) );
    1047             : }
    1048             : 
    1049           0 : char *GImageNameFColour(Color col) {
    1050             :     int i;
    1051             : 
    1052           0 :     col &=0xffffff;
    1053           0 :     for ( i=0; predefn[i].name!=NULL; ++i )
    1054           0 :         if ( col == predefn[i].value )
    1055           0 : return( predefn[i].name );
    1056             : 
    1057           0 : return(NULL);
    1058             : }
    1059             : 
    1060           0 : Color GDrawColorBrighten(Color col, int by) {
    1061             :     int r, g, b;
    1062           0 :     if (( r = COLOR_RED(col)+by )>255 ) r=255;
    1063           0 :     if (( g=COLOR_GREEN(col)+by )>255 ) g=255;
    1064           0 :     if (( b=COLOR_BLUE(col)+by )>255 ) b=255;
    1065           0 : return( COLOR_CREATE(r,g,b));
    1066             : }
    1067             : 
    1068           0 : Color GDrawColorDarken(Color col, int by) {
    1069             :     int r, g, b;
    1070           0 :     if (( r = COLOR_RED(col)-by )<0 ) r=0;
    1071           0 :     if (( g=COLOR_GREEN(col)-by )<0 ) g=0;
    1072           0 :     if (( b=COLOR_BLUE(col)-by )<0 ) b=0;
    1073           0 : return( COLOR_CREATE(r,g,b));
    1074             : }

Generated by: LCOV version 1.10