salut
En ce moment, je réalise un petit logiciel de 2D.
Pour celui-ci, j'utilise les surfaces comme calques (layers). J'ai donc besoin d'utilser l'alpha de ces surfaces, et de le gérer lors de l'enregistrement du calque en transparence (par exemple, en .png)
Un des "problèmes" de gamemaker est que les surface sont enregistrées sous forme d'image avec alpha prémultiplié.
Petite explication (si j'ai bien compris) sur l'alpha prémultiplié (corrigez-moi si je me trompe
).
Une image est composé de 2 informations :
- Un pixel composé de canaux RGB pour les couleurs : avec comme valeur 0 à 255.
- Elle peut avoir un canal Alpha Pour la transparence : avec des valeur en niveau de gris, de 0 à 255 (ou de 0 à1.0 pour un nombre à virgule).
Je crois que GameMaker utilise un nombre en 0 et 1.00 pour la valeur d'alpha équivalent au pixel couleur.
Image avec canal alpha (avec transparence)Maintenant, il y a plusieurs façons de créer une image avec un canal alpha :
- alpha "straight" : les canaux couleurs et alpha sont bien séparés (voir un peu plus bas pour plus de détail).
- alpha premultiplié : on multiplie les canaux des couleurs avec la valeur du pixel du canal alpha correspondant.
Explication en image :
Une image dans photoshop. chaque carré a une valeur de transparence (alpha) indiquée en % :
Le canal alpha équivalent à l'image ci-dessus :
Si on affiche cette image transparente (ou ce calque) sur un fond blanc, dans un mode "straight" (non -premultiplié), voici ce que l'on obtient :
Maintenant, voici la même image avec alpha prémulitiplié, affichée sur fond blanc :
Une petite comparaison pour bien comprendre la différence :
Au dessus :alpha non prémultiplié
en dessous : alpha prémultiplié
On voit bien que pour l'alpha prémultiplié, les valeurs de transparence ont été multipliées aux valeurs RGB, ce qui donne pour résultat que les pixels-couleurs sont plus sombres avec alpha prémultiplié (logique vulcaine
).
Bon, et alors me direz-vous ? Le problème est multiple :
- gamemaker : les surface sont enregistrées en tant qu' image avec un canal alpha. Si on utilise le code draw_set_clear(c_black,1), la premultiplication se fait avec le noir, si on choisit une autre couleur, elle se fait avec cette couleur-là. En somme :avec du noir on a des bords noirs, avec du blanc, on a des bords blancs, etc..
- les logiciels 2D classiques n'ouvrent pas facilement les images avec alpha prémultiplié.Ce que j'aimerai donc pouvoir faire :
- il s'agirait de "dé-pré multiplier" la surface (ou le sprite obtenu par un sprite_create_from_surface par exemple) afin de pouvoir enregistrer une image avec alpha straight.
Vous me suivez toujours ?
Au lieu d'obtenir comme résultat l'image du dessous (en sauvegardant ma surface), je voudrais obtenir l'image du dessus :
Autrement dit "dé-prémultiplier" ma surface ou l'image obtenue
. (boudiou, c'est compliqué :p)
Est-ce possible me direz-vous ? Je pense que oui, car j'ai vu sur ce sujet très intéressant que l'on peut créer un sprite prémultiplié à partir d'un sprite "straight" alpha :
http://gmc.yoyogames.com/index.php?showtopic=474273&st=0&p=3663622&hl=+surface%20+alpha&fromsearch=1&#entry3663622Moi, je veux faire l'inverse (prémul>straight), donc enlever aux canaux RGB le noir en fonction de la valeur du pixel du canal alpha équivalent.
Si la formule pour prémultiplier une couleur est donc (si j'ai bien tout compris), formule de Marteen Baert, issu de l'exemple qu'il a corrigé :
- Code:
-
return make_color_rgb
(
round(color_get_red(couleur)*alpha),
round(color_get_green(couleur)*alpha),
round(color_get_blue(couleur)*alpha)
);
Pour dé-prémultiplier, le code serait donc :
- Code:
-
return make_color_rgb
(
round(color_get_red(couleur)/alpha),
round(color_get_green(couleur)/alpha),
round(color_get_blue(couleur)/alpha)
);
Me gourre-je ?
Maintenant , les questionsComment appliquer ce genre de chose sur une image obtenue, à chaque pixel ?
Pour les couleurs, on a bien draw_getpixel(x,y);
Et pour récupérer l'alpha j'ai trouvé ça :
http://www.host-a.net/u/KooKoo/surface_getalpha.gmkAinsi que ça :
http://www.host-a.net/u/slayer64/surface_get_pixel%20revised.zipou encore ça (pour les explications) :
http://gmc.yoyogames.com/index.php?showtopic=478668&st=0&p=3551760&hl=+lalala%20+surface&fromsearch=1&#entry3551760Je suppose donc qu'avec ces exemples, je devrais y parvenir, même si le calcul est un peu long (après tout c'est juste pour sauvegarder, ça peut prendre quelques secondes, c'est pas très grave
.
Par contre, j'aurai besoin d'un peu d'aide pour la création d'un script permettant de faire ce remplacement sur disons une image de 640*480
.
Je n'ai pas trop d'idée pour l'étape de lecture et de conversion de l'image ou de la surface :
- lire chaque pixel, avec valeur RGB et alpha
- "dé-prémultiplier" chaque pixel de couleur (rgb=rgb/alpha ?) : enlever le % de noir (RGB) pixel en fonction du % d'alpha
- (?) rajouter la même valeur que la couleur (RGB) afin d'avoir une couleur pleine (et non mixée avec du blanc) ?
En gros, au lieu d'obtenir ça :
couleur + canal alpha= image final.png
J'aimerai obtenir obtenir ça(ou convertir l'image obtenue plus haut (uniquement la couleur, pour l'alpha, je preprendrai le même que l'image du haut) :
couleur + canal alpha= image final.png
Pour rester dans les images, je pense que ce qu'il faut faire c'est ça :
ceci n'est pas un png, c'est juste pour obtenir les canaux RGB de l'image PNG, ce qui correspondrait aux canaux RGB de l'image du dessus
)
Mais je ne sais pas comment je peux faire ça.
Il y a peut être moyen de faire quelque chose avec les blend_mode, mais je n'ai pas encore réussi.
Donc, si quelqu'un a une idée pour faire ça, cela m'intéresse énormément :
.
PS : désolé pour cette immense tartine, mais je voulais essayer d'être le plus clair possible pour que ce soit bien compréhensible (en espérant que ça le soit d'ailleurs
).