summaryrefslogtreecommitdiffstats
path: root/palette.c
diff options
context:
space:
mode:
Diffstat (limited to 'palette.c')
-rw-r--r--palette.c110
1 files changed, 110 insertions, 0 deletions
diff --git a/palette.c b/palette.c
new file mode 100644
index 0000000..20947cd
--- /dev/null
+++ b/palette.c
@@ -0,0 +1,110 @@
+/* Palette-manipulation functions functions for xcftools
+ *
+ * Copyright (C) 2006 Henning Makholm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "palette.h"
+#include <assert.h>
+
+#define HASH_SIZE 1711
+/* If I remember correctly, this size hash will be able to handle
+ * either of
+ * a) the Netscape cube with intensities 0x00, 0x33, 0x66, 0x99, 0xCC, xFF
+ * b) the EGA cube with intensities 0x00, 0x55, 0xAA, 0xFF
+ * c) the "CGA cube" with intensites 0x00, 0x80, 0xFF
+ * d) a full 256-step grayscale
+ * without collisions. It will also have a minimal number of collisions
+ * (4) on a full 16-to-a-side cube with intensities
+ * 0x00, 0x11, 0x22, ..., 0xDD, 0xEE, 0xFF.
+ */
+
+rgba palette[MAX_PALETTE] ;
+unsigned paletteSize ;
+static int masterhash[HASH_SIZE];
+static int bucketlinks[MAX_PALETTE];
+
+void
+init_palette_hash(void)
+{
+ unsigned i ;
+ for( i=0; i<HASH_SIZE; i++ )
+ masterhash[i] = -1 ;
+ for( i=0; i<MAX_PALETTE; i++ )
+ bucketlinks[i] = -1 ;
+ paletteSize = 0 ;
+}
+
+inline int
+lookup_or_intern(rgba color) {
+ int *target = &masterhash[color % HASH_SIZE];
+ while( *target >= 0 ) {
+ if( palette[*target] == color )
+ return *target ;
+ target = &bucketlinks[*target] ;
+ }
+#if 0
+ fprintf(stderr,"Palette[%u] = %08x (%u --> %d)\n",paletteSize,color,
+ color % HASH_SIZE, *target);
+#endif
+ if( paletteSize >= MAX_PALETTE )
+ return -1 ;
+ *target = paletteSize ;
+ palette[paletteSize] = color ;
+ return paletteSize++ ;
+}
+
+static inline void
+unpalettify_row(rgba *row,unsigned ncols)
+{
+ index_t *newrow = (index_t*) row ;
+ unsigned i ;
+ for( i=ncols; i--; ) {
+ row[i] = palette[newrow[i]] ;
+ }
+}
+
+int
+palettify_row(rgba *row,unsigned ncols)
+{
+ index_t *newrow = (index_t*)row ;
+ assert(sizeof(index_t) <= sizeof(rgba));
+ unsigned i ;
+ for( i=0; i<ncols; i++ ) {
+ int j = lookup_or_intern(row[i]) ;
+ if( j < 0 ) {
+ unpalettify_row(row,i);
+ return 0 ;
+ }
+ newrow[i] = j ;
+ }
+ return 1 ;
+}
+
+int
+palettify_rows (rgba *rows[],unsigned ncols,unsigned nlines)
+{
+ unsigned i ;
+ for( i=0; i<nlines; i++ ) {
+ if( !palettify_row(rows[i],ncols) ) {
+ while( i-- )
+ unpalettify_row(rows[i],ncols);
+ return 0 ;
+ }
+ }
+ return 1 ;
+}
+
+