File indexing completed on 2025-03-09 04:09:53

0001 /* Palette-manipulation functions functions for xcftools
0002  *
0003  * This file was written by Henning Makholm <henning@makholm.net>
0004  * It is hereby in the public domain.
0005  * 
0006  * In jurisdictions that do not recognise grants of copyright to the
0007  * public domain: I, the author and (presumably, in those jurisdictions)
0008  * copyright holder, hereby permit anyone to distribute and use this code,
0009  * in source code or binary form, with or without modifications. This
0010  * permission is world-wide and irrevocable.
0011  *
0012  * Of course, I will not be liable for any errors or shortcomings in the
0013  * code, since I give it away without asking any compenstations.
0014  *
0015  * If you use or distribute this code, I would appreciate receiving
0016  * credit for writing it, in whichever way you find proper and customary.
0017  */
0018 
0019 #include "palette.h"
0020 #include <assert.h>
0021 
0022 #define HASH_SIZE 1711
0023 /* If I remember correctly, this size hash will be able to handle
0024  * either of
0025  *  a) the Netscape cube with intensities 0x00, 0x33, 0x66, 0x99, 0xCC, xFF
0026  *  b) the EGA cube with intensities 0x00, 0x55, 0xAA, 0xFF
0027  *  c) the "CGA cube" with intensites 0x00, 0x80, 0xFF
0028  *  d) a full 256-step grayscale
0029  * without collisions. It will also have a minimal number of collisions
0030  * (4) on a full 16-to-a-side cube with intensities
0031  * 0x00, 0x11, 0x22, ..., 0xDD, 0xEE, 0xFF.
0032  */
0033 
0034 unsigned paletteSize ;
0035 rgba palette[MAX_PALETTE] ;
0036 static int masterhash[HASH_SIZE];
0037 static int bucketlinks[MAX_PALETTE];
0038     
0039 void
0040 init_palette_hash(void)
0041 {
0042   unsigned i ;
0043   for( i=0; i<HASH_SIZE; i++ )
0044     masterhash[i] = -1 ;
0045   for( i=0; i<MAX_PALETTE; i++ )
0046     bucketlinks[i] = -1 ;
0047   paletteSize = 0 ;
0048 }
0049 
0050 inline int
0051 lookup_or_intern(rgba color) {
0052   int *target = &masterhash[color % HASH_SIZE];
0053   while( *target >= 0 ) {
0054     if( palette[*target] == color )
0055       return *target ;
0056     target = &bucketlinks[*target] ;
0057   }
0058 #if 0
0059   fprintf(stderr,"Palette[%u] = %08x (%u --> %d)\n",paletteSize,color,
0060           color % HASH_SIZE, *target);
0061 #endif
0062   if( paletteSize >= MAX_PALETTE )
0063     return -1 ;
0064   *target = paletteSize ;
0065   palette[paletteSize] = color ;
0066   return paletteSize++ ;
0067 }
0068 
0069 static inline void
0070 unpalettify_row(rgba *row,unsigned ncols)
0071 {
0072   index_t *newrow = (index_t*) row ;
0073   unsigned i ;
0074   for( i=ncols; i--; ) {
0075     row[i] = palette[newrow[i]] ;
0076   }
0077 }
0078 
0079 int
0080 palettify_row(rgba *row,unsigned ncols)
0081 {
0082   index_t *newrow = (index_t*)row ;
0083   assert(sizeof(index_t) <= sizeof(rgba));
0084   unsigned i ;
0085   for( i=0; i<ncols; i++ ) {
0086     int j = lookup_or_intern(row[i]) ;
0087     if( j < 0 ) {
0088       unpalettify_row(row,i);
0089       return 0 ;
0090     }
0091     newrow[i] = j ;
0092   }
0093   return 1 ;
0094 }
0095     
0096 int
0097 palettify_rows (rgba *rows[],unsigned ncols,unsigned nlines)
0098 {
0099   unsigned i ;
0100   for( i=0; i<nlines; i++ ) {
0101     if( !palettify_row(rows[i],ncols) ) {
0102       while( i-- )
0103         unpalettify_row(rows[i],ncols);
0104       return 0 ;
0105     }
0106   }
0107   return 1 ;
0108 }
0109         
0110