Si ce que tu appelles colour banding veut dire garder les contours pixellisés d'origine, alors il faut éviter les algos de diffusion tel que Floyd-Steinberg.
Dans Grafx2, quand le programme convertissait des images 24bits il y avait du FS dithering, mais comme le programme n'a plus besoin d'etre un viewer, on l'a supprimé.
Le choix de palette et le mappage RGB -> couleur indexée sont faits par Median Cut. J'en suis pas super content car en plus d'utiliser une table de mappage de 12Mo et de mettre plusieurs secondes sur ma machine (qui a 10 ans c'est vrai) à la calculer, l'approximation est vraiment axée sur l'espace RGB et les distances dans cet espace, ce qui est pas le plus agréable à l'oeil.
Pour choisir la meilleure couleur parmi un choix limité, DawnBringer m'a recemment fourni une formule de "color distance" avec laquelle la luminosité apparente a plus de poids que la teinte :
// Brillance des deux couleurs
bri = sqrt((0.26*r)² + (0.55*g)² + (0.19*b)²)
bri2 = sqrt((0.26*r2)² + (0.55*g2)² + (0.19*b2)²)
// Color distance "brute"
diff_c = sqrt((0.26*(r2-r))² + (0.55*(g2-g))² + (0.19*b2-b))²)
// différence de brillance
diff_b = abs(target_bri-bri);
// Color distance finale: pondérée par la différence de brillance
diff=0.25*(diff_b-diff_c)+diff_c;
Un ratio de 0.25 à 0.5 lui a semblé bien pour pas mal d'images "demoscene".
Enfin bon, un algo de color distance c'est bien quand on a déja une palette cible, mais je vois pas du tout comment calculer cette palette cible en minimisant la différence "perceptuelle" de l'image finale...