Fixed the same stupid bug about endless looping on palette reduction again.

git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@996 416bcca6-2ee7-4201-b75f-2eb2f807beb1
This commit is contained in:
Adrien Destugues 2009-08-17 19:48:20 +00:00
parent 025d27ff71
commit c957107d85
2 changed files with 120 additions and 86 deletions

BIN
gfx2.cfg

Binary file not shown.

72
op_c.c
View File

@ -16,6 +16,7 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Grafx2; if not, see <http://www.gnu.org/licenses/> along with Grafx2; if not, see <http://www.gnu.org/licenses/>
*/ */
#include <assert.h>
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -495,13 +496,14 @@ ENDCRUSH:
} }
} }
void Cluster_split(T_Cluster * c,T_Cluster * c1,T_Cluster * c2,int hue,T_Occurrence_table * to) void Cluster_split(T_Cluster * c, T_Cluster * c1, T_Cluster * c2, int hue,
T_Occurrence_table * to)
{ {
int limit; int limit;
int cumul; int cumul;
int r, g, b; int r, g, b;
limit=(c->occurences)/2; limit = c->occurences / 2;
cumul = 0; cumul = 0;
if (hue == 0) if (hue == 0)
{ {
@ -535,6 +537,7 @@ void Cluster_split(T_Cluster * c,T_Cluster * c1,T_Cluster * c2,int hue,T_Occurre
c1->vmin=c->vmin; c1->vmax=c->vmax; c1->vmin=c->vmin; c1->vmax=c->vmax;
c1->Bmin=c->Bmin; c1->Bmax=c->Bmax; c1->Bmin=c->Bmin; c1->Bmax=c->Bmax;
c1->bmin=c->bmin; c1->bmax=c->bmax; c1->bmin=c->bmin; c1->bmax=c->bmax;
c2->Rmin=r; c2->Rmax=c->Rmax; c2->Rmin=r; c2->Rmax=c->Rmax;
c2->rmin=r; c2->rmax=c->rmax; c2->rmin=r; c2->rmax=c->rmax;
c2->Gmin=c->Gmin; c2->Vmax=c->Vmax; c2->Gmin=c->Gmin; c2->Vmax=c->Vmax;
@ -575,6 +578,7 @@ void Cluster_split(T_Cluster * c,T_Cluster * c1,T_Cluster * c2,int hue,T_Occurre
c1->vmin=c->vmin; c1->vmax=g-1; c1->vmin=c->vmin; c1->vmax=g-1;
c1->Bmin=c->Bmin; c1->Bmax=c->Bmax; c1->Bmin=c->Bmin; c1->Bmax=c->Bmax;
c1->bmin=c->bmin; c1->bmax=c->bmax; c1->bmin=c->bmin; c1->bmax=c->bmax;
c2->Rmin=c->Rmin; c2->Rmax=c->Rmax; c2->Rmin=c->Rmin; c2->Rmax=c->Rmax;
c2->rmin=c->rmin; c2->rmax=c->rmax; c2->rmin=c->rmin; c2->rmax=c->rmax;
c2->Gmin=g; c2->Vmax=c->Vmax; c2->Gmin=g; c2->Vmax=c->Vmax;
@ -614,6 +618,7 @@ void Cluster_split(T_Cluster * c,T_Cluster * c1,T_Cluster * c2,int hue,T_Occurre
c1->vmin=c->vmin; c1->vmax=c->vmax; c1->vmin=c->vmin; c1->vmax=c->vmax;
c1->Bmin=c->Bmin; c1->Bmax=b-1; c1->Bmin=c->Bmin; c1->Bmax=b-1;
c1->bmin=c->bmin; c1->bmax=b-1; c1->bmin=c->bmin; c1->bmax=b-1;
c2->Rmin=c->Rmin; c2->Rmax=c->Rmax; c2->Rmin=c->Rmin; c2->Rmax=c->Rmax;
c2->rmin=c->rmin; c2->rmax=c->rmax; c2->rmin=c->rmin; c2->rmax=c->rmax;
c2->Gmin=c->Gmin; c2->Vmax=c->Vmax; c2->Gmin=c->Gmin; c2->Vmax=c->Vmax;
@ -657,6 +662,22 @@ void Cluster_compute_hue(T_Cluster * c,T_Occurrence_table * to)
//////////////////////////// Mthodes de gestion des ensembles de clusters // //////////////////////////// Mthodes de gestion des ensembles de clusters //
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// Debug helper : check if a cluster set has the right count value
/*
void CS_Check(T_Cluster_set* cs)
{
int i;
T_Cluster* c = cs->clusters;
for (i = cs->nb; i > 0; i--)
{
assert( c != NULL);
c = c->next;
}
assert(c == NULL);
}
*/
/// Setup the first cluster before we start the operations /// Setup the first cluster before we start the operations
void CS_Init(T_Cluster_set * cs, T_Occurrence_table * to) void CS_Init(T_Cluster_set * cs, T_Occurrence_table * to)
{ {
@ -682,7 +703,8 @@ T_Cluster_set * CS_New(int nbmax,T_Occurrence_table * to)
// On recopie les paramŠtres demands // On recopie les paramŠtres demands
n->nb_max = OT_count_colors(to); n->nb_max = OT_count_colors(to);
// On vient de compter le nombre de couleurs existantes, s'il est plus grand que 256 on limite à 256 // On vient de compter le nombre de couleurs existantes, s'il est plus grand
// que 256 on limite à 256
// (nombre de couleurs voulu au final) // (nombre de couleurs voulu au final)
if (n->nb_max > nbmax) if (n->nb_max > nbmax)
{ {
@ -698,7 +720,7 @@ T_Cluster_set * CS_New(int nbmax,T_Occurrence_table * to)
{ {
// Table impossible … allouer // Table impossible … allouer
free(n); free(n);
n=0; n = NULL;
} }
} }
@ -755,13 +777,11 @@ void CS_Set(T_Cluster_set * cs,T_Cluster * c)
T_Cluster* prev = NULL; T_Cluster* prev = NULL;
// Search the first cluster that is smaller than ours // Search the first cluster that is smaller than ours
if(current != NULL) // don't search if the list is empty while (current && current->occurences > c->occurences)
do
{ {
if (current->occurences < c->occurences)
break;
prev = current; prev = current;
} while((current = current -> next)); current = current->next;
}
// Now insert our cluster just before the one we found // Now insert our cluster just before the one we found
c -> next = current; c -> next = current;
@ -779,7 +799,8 @@ void CS_Set(T_Cluster_set * cs,T_Cluster * c)
// 1) On considère l'espace (R,G,B) comme 1 boîte // 1) On considère l'espace (R,G,B) comme 1 boîte
// 2) On cherche les extrêmes de la boîte en (R,G,B) // 2) On cherche les extrêmes de la boîte en (R,G,B)
// 3) On trie les pixels de l'image selon l'axe le plus long parmi (R,G,B) // 3) On trie les pixels de l'image selon l'axe le plus long parmi (R,G,B)
// 4) On coupe la boîte en deux au milieu, et on compacte pour que chaque bord corresponde bien à un pixel extreme // 4) On coupe la boîte en deux au milieu, et on compacte pour que chaque bord
// corresponde bien à un pixel extreme
// 5) On recommence à couper selon le plus grand axe toutes boîtes confondues // 5) On recommence à couper selon le plus grand axe toutes boîtes confondues
// 6) On s'arrête quand on a le nombre de couleurs voulu // 6) On s'arrête quand on a le nombre de couleurs voulu
void CS_Generate(T_Cluster_set * cs, T_Occurrence_table * to) void CS_Generate(T_Cluster_set * cs, T_Occurrence_table * to)
@ -797,7 +818,8 @@ void CS_Generate(T_Cluster_set * cs,T_Occurrence_table * to)
// On le coupe en deux // On le coupe en deux
Cluster_split(&current, &Nouveau1, &Nouveau2, current.plus_large, to); Cluster_split(&current, &Nouveau1, &Nouveau2, current.plus_large, to);
// On compacte ces deux nouveaux (il peut y avoir un espace entre l'endroit de la coupure et les premiers pixels du cluster) // On compacte ces deux nouveaux (il peut y avoir un espace entre l'endroit
// de la coupure et les premiers pixels du cluster)
Cluster_pack(&Nouveau1, to); Cluster_pack(&Nouveau1, to);
Cluster_pack(&Nouveau2, to); Cluster_pack(&Nouveau2, to);
@ -822,7 +844,7 @@ void CS_Sort_by_chrominance(T_Cluster_set * cs)
T_Cluster* place; T_Cluster* place;
T_Cluster* newlist = NULL; T_Cluster* newlist = NULL;
while((nc = cs->clusters)) while (cs->clusters)
{ {
// Remove the first cluster from the original list // Remove the first cluster from the original list
nc = cs->clusters; nc = cs->clusters;
@ -840,6 +862,7 @@ void CS_Sort_by_chrominance(T_Cluster_set * cs)
if (prev) prev->next = nc; if (prev) prev->next = nc;
else newlist = nc; else newlist = nc;
prev = NULL;
} }
// Put the new list bavk in place // Put the new list bavk in place
@ -873,7 +896,6 @@ void CS_Sort_by_luminance(T_Cluster_set * cs)
// reset prev pointer // reset prev pointer
prev = NULL; prev = NULL;
} }
// Put the new list back in place // Put the new list back in place
@ -1007,7 +1029,8 @@ void GS_Generate(T_Gradient_set * ds,T_Cluster_set * cs)
T_Conversion_table * Optimize_palette(T_Bitmap24B image,int size,T_Components * palette,int r,int g,int b) T_Conversion_table * Optimize_palette(T_Bitmap24B image, int size,
T_Components * palette, int r, int g, int b)
{ {
T_Occurrence_table * to; T_Occurrence_table * to;
T_Conversion_table * tc; T_Conversion_table * tc;
@ -1038,26 +1061,34 @@ T_Conversion_table * Optimize_palette(T_Bitmap24B image,int size,T_Components *
OT_delete(to); OT_delete(to);
return 0; return 0;
} }
//CS_Check(cs);
// C'est bon, on a pu tout allouer // C'est bon, on a pu tout allouer
// On génère les clusters (avec l'algo du median cut) // On génère les clusters (avec l'algo du median cut)
CS_Generate(cs, to); CS_Generate(cs, to);
//CS_Check(cs);
// On calcule la teinte de chaque pixel (Luminance et chrominance) // On calcule la teinte de chaque pixel (Luminance et chrominance)
CS_Compute_colors(cs, to); CS_Compute_colors(cs, to);
//CS_Check(cs);
ds = GS_New(cs); ds = GS_New(cs);
if (ds!=0) if (ds!= NULL)
{ {
GS_Generate(ds, cs); GS_Generate(ds, cs);
GS_Delete(ds); GS_Delete(ds);
} }
// Enfin on trie les clusters (donc les couleurs de la palette) dans un ordre sympa : par couleur, et par luminosité pour chaque couleur // Enfin on trie les clusters (donc les couleurs de la palette) dans un ordre
// sympa : par couleur, et par luminosité pour chaque couleur
CS_Sort_by_luminance(cs); CS_Sort_by_luminance(cs);
//CS_Check(cs);
CS_Sort_by_chrominance(cs); CS_Sort_by_chrominance(cs);
//CS_Check(cs);
// Enfin on génère la palette et la table de correspondance entre chaque couleur 24b et sa couleur palette associée. // Enfin on génère la palette et la table de correspondance entre chaque
// couleur 24b et sa couleur palette associée.
CS_Generate_color_table_and_palette(cs, tc, palette); CS_Generate_color_table_and_palette(cs, tc, palette);
//CS_Check(cs);
CS_Delete(cs); CS_Delete(cs);
OT_delete(to); OT_delete(to);
@ -1173,7 +1204,9 @@ void Convert_24b_bitmap_to_256_Floyd_Steinberg(T_Bitmap256 dest,T_Bitmap24B sour
} }
} }
void Convert_24b_bitmap_to_256_nearest_neighbor(T_Bitmap256 dest,T_Bitmap24B source,int width,int height,T_Components * palette,T_Conversion_table * tc) void Convert_24b_bitmap_to_256_nearest_neighbor(T_Bitmap256 dest,
T_Bitmap24B source, int width, int height, T_Components * palette,
T_Conversion_table * tc)
{ {
T_Bitmap24B current; T_Bitmap24B current;
T_Bitmap256 d; T_Bitmap256 d;
@ -1195,7 +1228,8 @@ void Convert_24b_bitmap_to_256_nearest_neighbor(T_Bitmap256 dest,T_Bitmap24B sou
red = current->R; red = current->R;
green = current->G; green = current->G;
blue = current->B; blue = current->B;
// Cherche la couleur correspondant dans la palette et la range dans l'image de destination // Cherche la couleur correspondant dans la palette et la range dans
// l'image de destination
*d = CT_get(tc, red, green, blue); *d = CT_get(tc, red, green, blue);
// On passe au pixel suivant : // On passe au pixel suivant :