From d3a107bb7cf228a4568bc0579ff4d7e437ea77aa Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Tue, 22 Nov 2011 21:38:03 +0000 Subject: [PATCH] Finished working on the new color lookup system. There is room for optimization and maybe bugfixing. The cluster table size is now: 511*15 = 7665bytes, this is 1094 times better than the color table. Please test and report your results ! git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@1874 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- src/Makefile | 2 +- src/Makefile.dep | 125 +++++++++++++++++++++------------------- src/colorred.c | 111 ++++++++++++++++++++--------------- src/colorred.h | 14 ++++- src/op_c.c | 146 ++++++++++------------------------------------- src/op_c.h | 42 +------------- 6 files changed, 178 insertions(+), 262 deletions(-) diff --git a/src/Makefile b/src/Makefile index 90932614..e9bed545 100644 --- a/src/Makefile +++ b/src/Makefile @@ -391,7 +391,7 @@ endif .PHONY : all debug release clean depend zip version force install uninstall # This is the list of the objects we want to build. Dependancies are built by "make depend" automatically. -OBJ = $(OBJDIR)/main.o $(OBJDIR)/init.o $(OBJDIR)/graph.o $(OBJDIR)/sdlscreen.o $(OBJDIR)/misc.o $(OBJDIR)/special.o $(OBJDIR)/buttons.o $(OBJDIR)/palette.o $(OBJDIR)/help.o $(OBJDIR)/operatio.o $(OBJDIR)/pages.o $(OBJDIR)/loadsave.o $(OBJDIR)/readline.o $(OBJDIR)/engine.o $(OBJDIR)/filesel.o $(OBJDIR)/op_c.o $(OBJDIR)/readini.o $(OBJDIR)/saveini.o $(OBJDIR)/shade.o $(OBJDIR)/keyboard.o $(OBJDIR)/io.o $(OBJDIR)/version.o $(OBJDIR)/text.o $(OBJDIR)/SFont.o $(OBJDIR)/setup.o $(OBJDIR)/pxsimple.o $(OBJDIR)/pxtall.o $(OBJDIR)/pxwide.o $(OBJDIR)/pxdouble.o $(OBJDIR)/pxtriple.o $(OBJDIR)/pxtall2.o $(OBJDIR)/pxwide2.o $(OBJDIR)/pxquad.o $(OBJDIR)/windows.o $(OBJDIR)/brush.o $(OBJDIR)/realpath.o $(OBJDIR)/mountlist.o $(OBJDIR)/input.o $(OBJDIR)/hotkeys.o $(OBJDIR)/transform.o $(OBJDIR)/pversion.o $(OBJDIR)/factory.o $(PLATFORMOBJ) $(OBJDIR)/fileformats.o $(OBJDIR)/miscfileformats.o $(OBJDIR)/libraw2crtc.o $(OBJDIR)/brush_ops.o $(OBJDIR)/buttons_effects.o $(OBJDIR)/layers.o $(OBJDIR)/oldies.o $(OBJDIR)/tiles.o +OBJ = $(OBJDIR)/main.o $(OBJDIR)/init.o $(OBJDIR)/graph.o $(OBJDIR)/sdlscreen.o $(OBJDIR)/misc.o $(OBJDIR)/special.o $(OBJDIR)/buttons.o $(OBJDIR)/palette.o $(OBJDIR)/help.o $(OBJDIR)/operatio.o $(OBJDIR)/pages.o $(OBJDIR)/loadsave.o $(OBJDIR)/readline.o $(OBJDIR)/engine.o $(OBJDIR)/filesel.o $(OBJDIR)/op_c.o $(OBJDIR)/readini.o $(OBJDIR)/saveini.o $(OBJDIR)/shade.o $(OBJDIR)/keyboard.o $(OBJDIR)/io.o $(OBJDIR)/version.o $(OBJDIR)/text.o $(OBJDIR)/SFont.o $(OBJDIR)/setup.o $(OBJDIR)/pxsimple.o $(OBJDIR)/pxtall.o $(OBJDIR)/pxwide.o $(OBJDIR)/pxdouble.o $(OBJDIR)/pxtriple.o $(OBJDIR)/pxtall2.o $(OBJDIR)/pxwide2.o $(OBJDIR)/pxquad.o $(OBJDIR)/windows.o $(OBJDIR)/brush.o $(OBJDIR)/realpath.o $(OBJDIR)/mountlist.o $(OBJDIR)/input.o $(OBJDIR)/hotkeys.o $(OBJDIR)/transform.o $(OBJDIR)/pversion.o $(OBJDIR)/factory.o $(PLATFORMOBJ) $(OBJDIR)/fileformats.o $(OBJDIR)/miscfileformats.o $(OBJDIR)/libraw2crtc.o $(OBJDIR)/brush_ops.o $(OBJDIR)/buttons_effects.o $(OBJDIR)/layers.o $(OBJDIR)/oldies.o $(OBJDIR)/tiles.o $(OBJDIR)/colorred.o SKIN_FILES = ../share/grafx2/skins/skin_classic.png ../share/grafx2/skins/skin_modern.png ../share/grafx2/skins/skin_DPaint.png ../share/grafx2/skins/font_Classic.png ../share/grafx2/skins/font_Fun.png ../share/grafx2/skins/font_Fairlight.png ../share/grafx2/skins/font_Melon.png ../share/grafx2/skins/font_DPaint.png ../share/grafx2/skins/skin_scenish.png ../share/grafx2/skins/font_Seen.png ../share/grafx2/skins/skin_Aurora.png diff --git a/src/Makefile.dep b/src/Makefile.dep index 5a8bbedc..77768330 100644 --- a/src/Makefile.dep +++ b/src/Makefile.dep @@ -1,33 +1,34 @@ -$(OBJDIR)/SFont.o: SFont.c SFont.h -$(OBJDIR)/brush.o: brush.c global.h struct.h const.h graph.h misc.h errors.h \ - windows.h sdlscreen.h brush.h $(OBJDIR)/brush_ops.o: brush_ops.c brush.h struct.h const.h buttons.h engine.h \ global.h graph.h misc.h operatio.h pages.h sdlscreen.h windows.h +$(OBJDIR)/brush.o: brush.c global.h struct.h const.h graph.h misc.h errors.h \ + windows.h sdlscreen.h brush.h tiles.h +$(OBJDIR)/buttons_effects.o: buttons_effects.c brush.h struct.h const.h \ + buttons.h engine.h global.h graph.h help.h input.h misc.h pages.h \ + readline.h sdlscreen.h windows.h tiles.h $(OBJDIR)/buttons.o: buttons.c const.h struct.h global.h misc.h graph.h engine.h \ readline.h filesel.h loadsave.h init.h buttons.h operatio.h pages.h \ palette.h errors.h readini.h saveini.h shade.h io.h help.h text.h \ - sdlscreen.h windows.h brush.h input.h special.h setup.h -$(OBJDIR)/buttons_effects.o: buttons_effects.c buttons.h struct.h const.h engine.h \ - global.h graph.h help.h input.h misc.h readline.h sdlscreen.h windows.h \ - brush.h + sdlscreen.h windows.h brush.h input.h special.h tiles.h setup.h +$(OBJDIR)/colorred.o: colorred.c $(OBJDIR)/engine.o: engine.c const.h struct.h global.h graph.h misc.h special.h \ buttons.h operatio.h shade.h errors.h sdlscreen.h windows.h brush.h \ input.h engine.h pages.h layers.h factory.h loadsave.h io.h -$(OBJDIR)/factory.o: factory.c brush.h struct.h const.h buttons.h engine.h errors.h \ - filesel.h loadsave.h global.h graph.h io.h misc.h pages.h readline.h \ - sdlscreen.h windows.h palette.h input.h help.h realpath.h +$(OBJDIR)/factory.o: factory.c brush.h struct.h const.h buttons.h engine.h \ + errors.h filesel.h loadsave.h global.h graph.h io.h misc.h pages.h \ + readline.h sdlscreen.h windows.h palette.h input.h help.h realpath.h \ + setup.h $(OBJDIR)/fileformats.o: fileformats.c errors.h global.h struct.h const.h \ loadsave.h misc.h io.h windows.h pages.h $(OBJDIR)/filesel.o: filesel.c const.h struct.h global.h misc.h errors.h io.h \ - windows.h sdlscreen.h loadsave.h mountlist.h engine.h readline.h input.h \ - help.h filesel.h + windows.h sdlscreen.h loadsave.h mountlist.h engine.h readline.h \ + input.h help.h filesel.h $(OBJDIR)/graph.o: graph.c global.h struct.h const.h engine.h buttons.h pages.h \ errors.h sdlscreen.h graph.h misc.h pxsimple.h pxtall.h pxwide.h \ pxdouble.h pxtriple.h pxwide2.h pxtall2.h pxquad.h windows.h input.h \ - brush.h -$(OBJDIR)/help.o: help.c const.h struct.h global.h misc.h engine.h helpfile.h \ - help.h sdlscreen.h text.h keyboard.h windows.h input.h hotkeys.h \ - errors.h pages.h + brush.h tiles.h +$(OBJDIR)/help.o: help.c haiku.h struct.h const.h global.h misc.h engine.h \ + helpfile.h help.h sdlscreen.h text.h keyboard.h windows.h input.h \ + hotkeys.h errors.h pages.h $(OBJDIR)/hotkeys.o: hotkeys.c struct.h const.h global.h hotkeys.h $(OBJDIR)/init.o: init.c buttons.h struct.h const.h errors.h global.h graph.h \ init.h io.h factory.h help.h hotkeys.h keyboard.h loadsave.h misc.h \ @@ -37,70 +38,76 @@ $(OBJDIR)/input.o: input.c global.h struct.h const.h keyboard.h sdlscreen.h \ windows.h errors.h misc.h buttons.h input.h loadsave.h $(OBJDIR)/io.o: io.c struct.h const.h io.h realpath.h $(OBJDIR)/keyboard.o: keyboard.c global.h struct.h const.h keyboard.h -$(OBJDIR)/layers.o: layers.c const.h struct.h global.h windows.h engine.h pages.h \ - sdlscreen.h input.h help.h misc.h +$(OBJDIR)/layers.o: layers.c const.h struct.h global.h windows.h engine.h \ + pages.h sdlscreen.h input.h help.h misc.h readline.h $(OBJDIR)/libraw2crtc.o: libraw2crtc.c const.h global.h struct.h loadsave.h -$(OBJDIR)/loadsave.o: loadsave.c buttons.h struct.h const.h errors.h global.h io.h \ - loadsave.h misc.h graph.h op_c.h pages.h palette.h sdlscreen.h windows.h \ - engine.h brush.h setup.h -$(OBJDIR)/main.o: main.c const.h struct.h global.h graph.h misc.h init.h buttons.h \ - engine.h pages.h loadsave.h sdlscreen.h errors.h readini.h saveini.h \ - io.h text.h setup.h windows.h brush.h palette.h realpath.h input.h \ - help.h -$(OBJDIR)/misc.o: misc.c struct.h const.h sdlscreen.h global.h errors.h buttons.h \ - engine.h misc.h keyboard.h windows.h palette.h input.h graph.h pages.h -$(OBJDIR)/miscfileformats.o: miscfileformats.c engine.h struct.h const.h errors.h \ - global.h io.h libraw2crtc.h loadsave.h misc.h sdlscreen.h windows.h -$(OBJDIR)/mountlist.o: mountlist.c -$(OBJDIR)/op_c.o: op_c.c op_c.h struct.h const.h errors.h global.h engine.h \ - windows.h -$(OBJDIR)/operatio.o: operatio.c const.h struct.h global.h misc.h engine.h graph.h \ - operatio.h buttons.h pages.h errors.h sdlscreen.h brush.h windows.h \ - input.h +$(OBJDIR)/loadsave.o: loadsave.c buttons.h struct.h const.h errors.h global.h \ + io.h loadsave.h misc.h graph.h op_c.h pages.h palette.h sdlscreen.h \ + windows.h engine.h brush.h setup.h +$(OBJDIR)/main.o: main.c const.h struct.h global.h graph.h misc.h init.h \ + buttons.h engine.h pages.h loadsave.h sdlscreen.h errors.h readini.h \ + saveini.h io.h text.h setup.h windows.h brush.h palette.h realpath.h \ + input.h help.h +$(OBJDIR)/misc.o: misc.c struct.h const.h sdlscreen.h global.h errors.h \ + buttons.h engine.h misc.h keyboard.h windows.h palette.h input.h \ + graph.h pages.h +$(OBJDIR)/miscfileformats.o: miscfileformats.c engine.h struct.h const.h \ + errors.h global.h io.h libraw2crtc.h \ + /boot/develop/abi/x86/gcc2/tools/gcc-2.95.3-haiku-100818/lib/gcc-lib/i586-pc-haiku/2.95.3-haiku-100818/include/limits.h \ + loadsave.h misc.h sdlscreen.h windows.h oldies.h +$(OBJDIR)/mountlist.o: mountlist.c mountlist.h +$(OBJDIR)/oldies.o: oldies.c struct.h const.h global.h errors.h misc.h palette.h +$(OBJDIR)/op_c.o: op_c.c op_c.h struct.h const.h errors.h global.h \ + /boot/develop/abi/x86/gcc2/tools/gcc-2.95.3-haiku-100818/lib/gcc-lib/i586-pc-haiku/2.95.3-haiku-100818/include/limits.h \ + engine.h windows.h +$(OBJDIR)/operatio.o: operatio.c const.h struct.h global.h misc.h engine.h \ + graph.h operatio.h buttons.h pages.h errors.h sdlscreen.h brush.h \ + windows.h input.h $(OBJDIR)/pages.o: pages.c global.h struct.h const.h pages.h errors.h loadsave.h \ misc.h windows.h -$(OBJDIR)/palette.o: palette.c const.h struct.h global.h misc.h engine.h readline.h \ - buttons.h pages.h help.h sdlscreen.h errors.h op_c.h windows.h input.h \ - palette.h shade.h -$(OBJDIR)/palette_test.o: palette_test.c const.h struct.h global.h misc.h engine.h \ +$(OBJDIR)/palette.o: palette.c const.h struct.h global.h misc.h engine.h \ readline.h buttons.h pages.h help.h sdlscreen.h errors.h op_c.h \ windows.h input.h palette.h shade.h $(OBJDIR)/pversion.o: pversion.c $(OBJDIR)/pxdouble.o: pxdouble.c global.h struct.h const.h sdlscreen.h misc.h \ graph.h pxdouble.h pxwide.h -$(OBJDIR)/pxquad.o: pxquad.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ - pxquad.h +$(OBJDIR)/pxquad.o: pxquad.c global.h struct.h const.h sdlscreen.h misc.h \ + graph.h pxquad.h $(OBJDIR)/pxsimple.o: pxsimple.c global.h struct.h const.h sdlscreen.h misc.h \ graph.h pxsimple.h -$(OBJDIR)/pxtall.o: pxtall.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ - pxtall.h pxsimple.h -$(OBJDIR)/pxtall2.o: pxtall2.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ - pxtall2.h +$(OBJDIR)/pxtall.o: pxtall.c global.h struct.h const.h sdlscreen.h misc.h \ + graph.h pxtall.h pxsimple.h +$(OBJDIR)/pxtall2.o: pxtall2.c global.h struct.h const.h sdlscreen.h misc.h \ + graph.h pxtall2.h $(OBJDIR)/pxtriple.o: pxtriple.c global.h struct.h const.h sdlscreen.h misc.h \ graph.h pxtriple.h -$(OBJDIR)/pxwide.o: pxwide.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ - pxwide.h -$(OBJDIR)/pxwide2.o: pxwide2.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ - pxwide2.h -$(OBJDIR)/readini.o: readini.c const.h errors.h global.h struct.h misc.h readini.h \ - setup.h realpath.h io.h +$(OBJDIR)/pxwide.o: pxwide.c global.h struct.h const.h sdlscreen.h misc.h \ + graph.h pxwide.h +$(OBJDIR)/pxwide2.o: pxwide2.c global.h struct.h const.h sdlscreen.h misc.h \ + graph.h pxwide2.h +$(OBJDIR)/readini.o: readini.c const.h errors.h global.h struct.h misc.h \ + readini.h setup.h realpath.h io.h $(OBJDIR)/readline.o: readline.c const.h struct.h global.h misc.h errors.h \ sdlscreen.h readline.h windows.h input.h engine.h $(OBJDIR)/realpath.o: realpath.c $(OBJDIR)/saveini.o: saveini.c const.h global.h struct.h readini.h io.h errors.h \ misc.h saveini.h setup.h -$(OBJDIR)/sdlscreen.o: sdlscreen.c global.h struct.h const.h sdlscreen.h errors.h \ - misc.h +$(OBJDIR)/sdlscreen.o: sdlscreen.c global.h struct.h const.h sdlscreen.h \ + errors.h misc.h $(OBJDIR)/setup.o: setup.c struct.h const.h io.h setup.h +$(OBJDIR)/SFont.o: SFont.c SFont.h $(OBJDIR)/shade.o: shade.c global.h struct.h const.h graph.h engine.h errors.h \ misc.h readline.h help.h sdlscreen.h windows.h input.h shade.h -$(OBJDIR)/special.o: special.c const.h struct.h global.h graph.h engine.h windows.h \ - special.h pages.h misc.h buttons.h +$(OBJDIR)/special.o: special.c const.h struct.h global.h graph.h engine.h \ + windows.h special.h pages.h misc.h buttons.h $(OBJDIR)/text.o: text.c SFont.h struct.h const.h global.h sdlscreen.h io.h \ errors.h windows.h misc.h setup.h -$(OBJDIR)/tiles.o: tiles.c -$(OBJDIR)/transform.o: transform.c global.h struct.h const.h transform.h engine.h \ - sdlscreen.h windows.h input.h help.h misc.h readline.h buttons.h pages.h +$(OBJDIR)/tiles.o: tiles.c struct.h const.h global.h graph.h sdlscreen.h \ + engine.h windows.h input.h misc.h tiles.h +$(OBJDIR)/transform.o: transform.c global.h struct.h const.h transform.h \ + engine.h sdlscreen.h windows.h input.h help.h misc.h readline.h \ + buttons.h pages.h tiles.h $(OBJDIR)/version.o: version.c $(OBJDIR)/windows.o: windows.c windows.h struct.h const.h engine.h errors.h \ - global.h graph.h input.h misc.h op_c.h readline.h sdlscreen.h palette.h + global.h graph.h input.h misc.h op_c.h readline.h sdlscreen.h \ + palette.h diff --git a/src/colorred.c b/src/colorred.c index 154d8ce9..4eaacc44 100644 --- a/src/colorred.c +++ b/src/colorred.c @@ -23,6 +23,7 @@ */ #include +#include #include "colorred.h" @@ -35,11 +36,19 @@ but : CT_Node* CT_new() {return NULL;} -void CT_set(CT_Node* colorTree, byte Rmin, byte Gmin, byte Bmin, +// debug helper +void CT_Print(CT_Node* node) +{ + printf("R %d %d\tG %d %d\tB %d %d\ti %d\n", + node->Rmin, node->Rmax, node->Gmin, node->Gmax, + node->Bmin, node->Bmax, node->index); +} + +void CT_set(CT_Node** colorTree, byte Rmin, byte Gmin, byte Bmin, byte Rmax, byte Gmax, byte Bmax, byte index) { int i; - CT_Node* parent = colorTree; + CT_Node* parent; // Create and setup node CT_Node* node = malloc(sizeof(CT_Node)); @@ -51,65 +60,77 @@ void CT_set(CT_Node* colorTree, byte Rmin, byte Gmin, byte Bmin, node->Bmax = Bmax; node->index = index; - for(i = 0; i < 7; i++) + printf("Add node:"); + CT_Print(node); + + for(i = 0; i < 2; i++) node->children[i] = NULL; // Now insert it in tree - + parent = *colorTree; if (parent == NULL) { // This is our first node. - colorTree = node; + *colorTree = node; } else for(;;) { // Find where to insert ourselves - // (clusters are non-intersecting, so there is no need to check for that) - int where = 0; - if (parent->Rmin < node->Rmin) - where += 4; - if (parent->Gmin < node->Gmin) - where += 2; - if (parent->Bmin < node->Bmin) - where += 1; - - // TODO - we always insert downwards, maybe we should try to keep - // the tree balanced... - - if (parent->children[where] == NULL) + + // pre-condition: the parent we're looking at is a superset of the node we're inserting + // it may have 0, 1, or 2 child + + // 0 child: insert as child 0 + // 1 child: either we're included in the child, and recurse, or we''re not, and insert at child 1 + // 2 child: one of them has to be a superset of the node. + + if (parent->children[0] == NULL) { - // insert! - parent->children[where] = node; + parent->children[0] = node; break; } else { - // recurse - parent = parent->children[where]; + CT_Node* child0 = parent->children[0]; + if (child0->Rmin <= node->Rmin + && child0->Gmin <= node->Gmin + && child0->Bmin <= node->Bmin + && child0->Rmax >= node->Rmax + && child0->Gmax >= node->Gmax + && child0->Bmax >= node->Bmax + ) { + parent = child0; + } else if(parent->children[1] == NULL) + { + parent->children[1] = node; + break; + } else { + parent = parent->children[1]; + } } } } byte CT_get(CT_Node* node, byte r, byte g, byte b) { - int wheremin = 0; - int wheremax = 0; + // pre condition: node contains (rgb) + // find the leaf that also contains (rgb) - if (node->Rmin < r) - wheremin += 4; - if (node->Gmin < g) - wheremin += 2; - if (node->Bmin < b) - wheremin += 1; - - if (node->Rmax < r) - wheremin += 4; - if (node->Gmax < g) - wheremin += 2; - if (node->Bmax < b) - wheremin += 1; - - if (wheremin == 7 && wheremax == 0) - { - // Found it! - return node->index; - } else { - return CT_get(node->children[wheremin], r, g, b); + for(;;) { + if(node->children[0] == NULL) + return node->index; + else { + // Left or right ? + CT_Node* child0 = node->children[0]; + if (child0->Rmin <= r + && child0->Gmin <= g + && child0->Bmin <= b + && child0->Rmax >= r + && child0->Gmax >= g + && child0->Bmax >= b + ) { + // left + node = child0; + } else { + // right + node = node->children[1]; + } + } } } @@ -118,7 +139,7 @@ void CT_delete(CT_Node* tree) int i; if (tree == NULL) return; - for (i = 0; i < 8; i++) + for (i = 0; i < 2; i++) { CT_delete(tree->children[i]); } diff --git a/src/colorred.h b/src/colorred.h index 6f4d4001..62d1ea12 100644 --- a/src/colorred.h +++ b/src/colorred.h @@ -46,18 +46,26 @@ typedef struct CT_Node_s byte Gmax; byte Bmax; + // possible optimization: a cluster has either two childs or a color index. + // if the first child is NULL, then the other can be used to store the index + // when the tree is being built, a node may have child0 set and not child1, but not the reverse) + + // possible optimization: there can't be more than 511 clusters in the tree + // for a 256 color picture, so use int16 as pointers and store everything in a table : + // * makes them smaller + // * helps with cache locality + // palette index (valid iff any child is NULL) byte index; // child nodes - struct CT_Node_s* children[8]; - //rgb rgB rGb rGB Rgb RgB RGb RGB + struct CT_Node_s* children[2]; } CT_Node; CT_Node* CT_new(); void CT_delete(CT_Node* t); byte CT_get(CT_Node* t,byte r,byte g,byte b); -void CT_set(CT_Node* colorTree, byte Rmin, byte Gmin, byte Bmin, +void CT_set(CT_Node** colorTree, byte Rmin, byte Gmin, byte Bmin, byte Rmax, byte Gmax, byte Bmax, byte index); #endif diff --git a/src/op_c.c b/src/op_c.c index 004446e2..add43eb5 100644 --- a/src/op_c.c +++ b/src/op_c.c @@ -30,6 +30,7 @@ #include "op_c.h" #include "errors.h" +#include "colorred.h" int Convert_24b_bitmap_to_256_fast(T_Bitmap256 dest,T_Bitmap24B source,int width,int height,T_Components * palette); @@ -178,95 +179,6 @@ long Perceptual_lightness(T_Components *color) 19*color->B*19*color->B; } -// Conversion table handlers -// The conversion table is built after a run of the median cut algorithm and is -// used to find the best color index for a given (RGB) color. GIMP avoids -// creating the whole table and only create parts of it when they are actually -// needed. This may or may not be faster - -/// Creates a new conversion table -/// params: bumber of bits for R, G, B (precision) -T_Conversion_table * CT_new(int nbb_r,int nbb_g,int nbb_b) -{ - T_Conversion_table * n; - int size; - - n=(T_Conversion_table *)malloc(sizeof(T_Conversion_table)); - if (n!=NULL) - { - // Copy the passed parameters - n->nbb_r=nbb_r; - n->nbb_g=nbb_g; - n->nbb_b=nbb_b; - - // Calculate the others - - // Value ranges (max value actually) - n->rng_r=(1<rng_g=(1<rng_b=(1<dec_r=nbb_g+nbb_b; - n->dec_g=nbb_b; - n->dec_b=0; - - // Reductions (how many bits are lost) - n->red_r=8-nbb_r; - n->red_g=8-nbb_g; - n->red_b=8-nbb_b; - - // Allocate the table - size=(n->rng_r)*(n->rng_g)*(n->rng_b); - n->table=(byte *)calloc(size, 1); - if (n->table == NULL) - { - // Not enough memory - free(n); - n=NULL; - } - } - - return n; -} - - -/// Delete a conversion table and release its memory -void CT_delete(T_Conversion_table * t) -{ - free(t->table); - free(t); - t = NULL; -} - - -/// Get the best palette index for an (R, G, B) color -byte CT_get(T_Conversion_table * t,int r,int g,int b) -{ - int index; - - // Reduce the number of bits to the table precision - r=(r>>t->red_r); - g=(g>>t->red_g); - b=(b>>t->red_b); - - // Find the nearest color - index=(r<dec_r) | (g<dec_g) | (b<dec_b); - - return t->table[index]; -} - - -/// Set an entry of the table, index (RGB), value i -void CT_set(T_Conversion_table * t,int r,int g,int b,byte i) -{ - int index; - - index=(r<dec_r) | (g<dec_g) | (b<dec_b); - t->table[index]=i; -} - - // Handlers for the occurences tables // This table is used to count the occurence of an (RGB) pixel value in the // source 24bit image. These count are then used by the median cut algorithm to @@ -883,7 +795,8 @@ void CS_Set(T_Cluster_set * cs,T_Cluster * c) // 4) We pack the 2 resulting boxes again to leave no empty space between the box border and the first pixel // 5) We take the box with the biggest number of pixels inside and we split it again // 6) Iterate until there are 256 boxes. Associate each of them to its middle color -void CS_Generate(T_Cluster_set * cs, T_Occurrence_table * to) +// At the same time, put the split clusters in the color tree for later palette lookup +void CS_Generate(T_Cluster_set * cs, T_Occurrence_table * to, CT_Node** colorTree) { T_Cluster current; T_Cluster Nouveau1; @@ -894,6 +807,10 @@ void CS_Generate(T_Cluster_set * cs, T_Occurrence_table * to) { // Get the biggest one CS_Get(cs,¤t); + + // We're going to split, so add the cluster to the colortree + CT_set(colorTree,current.Rmin, current.Gmin, current.Bmin, + current.Rmax, current.Vmax, current.Bmax, 0); // Split it Cluster_split(¤t, &Nouveau1, &Nouveau2, current.plus_large, to); @@ -994,10 +911,9 @@ void CS_Sort_by_luminance(T_Cluster_set * cs) /// Generates the palette from the clusters, then the conversion table to map (RGB) to a palette index -void CS_Generate_color_table_and_palette(T_Cluster_set * cs,T_Conversion_table * tc,T_Components * palette) +void CS_Generate_color_table_and_palette(T_Cluster_set * cs,CT_Node** tc,T_Components * palette) { int index; - int r,g,b; T_Cluster* current = cs->clusters; for (index=0;indexnb;index++) @@ -1006,10 +922,8 @@ void CS_Generate_color_table_and_palette(T_Cluster_set * cs,T_Conversion_table * palette[index].G=current->g; palette[index].B=current->b; - for (r=current->Rmin; r<=current->Rmax; r++) - for (g=current->Gmin;g<=current->Vmax;g++) - for (b=current->Bmin;b<=current->Bmax;b++) - CT_set(tc,r,g,b,index); + CT_set(tc,current->Rmin, current->Gmin, current->Bmin, + current->Rmax, current->Vmax, current->Bmax, index); current = current->next; } } @@ -1120,11 +1034,11 @@ void GS_Generate(T_Gradient_set * ds,T_Cluster_set * cs) /// Compute best palette for given picture. -T_Conversion_table * Optimize_palette(T_Bitmap24B image, int size, +CT_Node* Optimize_palette(T_Bitmap24B image, int size, T_Components * palette, int r, int g, int b) -{ +{ T_Occurrence_table * to; - T_Conversion_table * tc; + CT_Node* tc; T_Cluster_set * cs; T_Gradient_set * ds; @@ -1135,13 +1049,14 @@ T_Conversion_table * Optimize_palette(T_Bitmap24B image, int size, if (to == NULL) return 0; - tc = CT_new(r, g, b); + tc = CT_new(); + /* if (tc == NULL) { - OT_delete(to); - return 0; + OT_delete(to); + return NULL; } - +*/ // Count pixels for each color OT_count_occurrences(to, image, size); @@ -1156,7 +1071,7 @@ T_Conversion_table * Optimize_palette(T_Bitmap24B image, int size, // Ok, everything was allocated // Generate the cluster set with median cut algorithm - CS_Generate(cs, to); + CS_Generate(cs, to, &tc); //CS_Check(cs); // Compute the color data for each cluster (palette entry + HL) @@ -1174,11 +1089,11 @@ T_Conversion_table * Optimize_palette(T_Bitmap24B image, int size, //CS_Check(cs); CS_Sort_by_chrominance(cs); //CS_Check(cs); - + // And finally generate the conversion table to map RGB > pal. index - CS_Generate_color_table_and_palette(cs, tc, palette); + CS_Generate_color_table_and_palette(cs, &tc, palette); //CS_Check(cs); - + CS_Delete(cs); OT_delete(to); return tc; @@ -1204,7 +1119,7 @@ int Modified_value(int value,int modif) /// Convert a 24b image to 256 colors (with a given palette and conversion table) /// This destroys the 24b picture ! /// Uses floyd steinberg dithering. -void Convert_24b_bitmap_to_256_Floyd_Steinberg(T_Bitmap256 dest,T_Bitmap24B source,int width,int height,T_Components * palette,T_Conversion_table * tc) +void Convert_24b_bitmap_to_256_Floyd_Steinberg(T_Bitmap256 dest,T_Bitmap24B source,int width,int height,T_Components * palette,CT_Node* tc) { T_Bitmap24B current; T_Bitmap24B c_plus1; @@ -1300,7 +1215,7 @@ void Convert_24b_bitmap_to_256_Floyd_Steinberg(T_Bitmap256 dest,T_Bitmap24B sour /// Converts from 24b to 256c without dithering, using given conversion table void Convert_24b_bitmap_to_256_nearest_neighbor(T_Bitmap256 dest, T_Bitmap24B source, int width, int height, __attribute__((unused)) T_Components * palette, - T_Conversion_table * tc) + CT_Node* tc) { T_Bitmap24B current; T_Bitmap256 d; @@ -1359,19 +1274,20 @@ int Convert_24b_bitmap_to_256(T_Bitmap256 dest,T_Bitmap24B source,int width,int return Convert_24b_bitmap_to_256_fast(dest, source, width, height, palette); #else - T_Conversion_table * table; // table de conversion + CT_Node* table; // table de conversion int ip; // index de précision pour la conversion // On essaye d'obtenir une table de conversion qui loge en mémoire, avec la // meilleure précision possible for (ip=0;ip<(10*3);ip+=3) { - table=Optimize_palette(source,width*height,palette,precision_24b[ip+0], - precision_24b[ip+1],precision_24b[ip+2]); - if (table!=0) - break; + table = Optimize_palette(source,width*height,palette, + precision_24b[ip], precision_24b[ip+1], precision_24b[ip+2]); + if (table != NULL) + break; } - if (table!=0) + + if (table!=NULL) { //Convert_24b_bitmap_to_256_Floyd_Steinberg(dest,source,width,height,palette,table); Convert_24b_bitmap_to_256_nearest_neighbor(dest,source,width,height,palette,table); diff --git a/src/op_c.h b/src/op_c.h index 76b544a2..161e77c5 100644 --- a/src/op_c.h +++ b/src/op_c.h @@ -30,6 +30,7 @@ #define _OP_C_H_ #include "struct.h" +#include "colorred.h" //////////////////////////////////////////////// Définition des types de base @@ -37,32 +38,6 @@ typedef T_Components * T_Bitmap24B; typedef byte * T_Bitmap256; - -//////////////////////////////////////// Définition d'une table de conversion - -typedef struct -{ - int nbb_r; // Nb de bits de précision sur les rouges - int nbb_g; // Nb de bits de précision sur les verts - int nbb_b; // Nb de bits de précision sur les bleu - - int rng_r; // Nb de valeurs sur les rouges (= 1<