9
votes

Comment générer un masque de bits monochrome pour un bitmap 32 bits

Sous Win32, il s'agit d'une technique commune de générer un bitmask monochrome à partir d'un bitmap pour une utilisation en transparence en procédant comme suit:

HBITMAP CreateTransparencyMask(HDC hdc, HBITMAP hSource, COLORREF crTransparency);


1 commentaires

GDI est coincé à 24 bpp. TransparentBlt () est un peu inhabituel, il est documenté pour prendre en charge 32BPP. Il est temps de passer à GDI + peut-être.


4 Réponses :


4
votes

Vous ne pouvez pas le faire s'il y a un canal alpha. Colricref utilise les 8 bits les plus top 8 à un certain nombre d'usages, notamment en précisant que les 3 octets inférieurs sont un indice de table de couleur dans la palette actuelle ou un triplet RGB. En tant que tel, vous ne pouvez rien spécifier sauf 0x00 dans l'octein supérieur de CLRTRANSPARENCE.

Si vous avez un bitmap alpha, alors à GDI qui reste "ignorant" du canal alpha, il n'y a pas de solution sain d'alpha de comparer un BKColor 24 bits avec des pixels 32 bits dans le bitmap.

Je m'attendrais à ce que GDI traite le canal alpha dans des bitmaps 32BPP comme "réservé", et comparer uniquement les pixels avec succès où le canal réservé est égal à zéro. C'est-à-dire que votre couleur de masque doit être entièrement transparente de toute façon avoir une chance de réussir. (Et si vous avez fait un bitmap légitime Premulgitiplied, cela implique que les valeurs RVV seront également zéro, plutôt contraignantes de votre choix de couleurs de masque: p)


4 commentaires

Dans ce cas particulier, le problème est que je commence par un bitmap couleur 4 bits. Ensuite, afin de l'afficher de manière agréable lorsque vous êtes désactivé, j'aimerais faire un rendu d'échelle de gris, puis l'utiliser comme la face de bouton (à l'aide de la technique de transparence masquée comme avant). Mais le code que j'utilise pour produire l'échelle de gris est basé sur GDI +, que je soupçonne crée une image couleur 32 bits plutôt qu'une image couleur 24 bits.


@MORDACACHAI: Compte tenu de ce que vous venez de décrire, pouvez-vous créer le masque de l'image d'origine 4 bits et l'utiliser avec le GDI-créé?


J'aime l'idée à mes besoins. Mais je serais toujours intéressé par un générique "Comment créer un masque de bits monochrome pour n'importe quel Source Hitalmap".


Je pense que la seule façon de le faire pour Tout HBITMAP est d'écrire votre propre. Beaucoup de ces techniques de cartographie de couleur dans le GDI uni sont spécifiques aux images à base de palette et ne sont pas applicables aux images non-Palette.



0
votes

Une autre méthode serait de numériser les pixels vous-même et de générer et de générer et de générer des bitmap monochrome en fonction de la couleur source (ou de la source alpha contre un seuil).

Notez que si vous utilisez GDI +, alors, en fonction de l'opération, les pixels ont peut-être été antialiasés, ce qui n'en étant donné qu'aucun d'entre eux n'est une correspondance exacte pour votre couleur "transparente". < / p>


1 commentaires

J'ai sauvegardé l'image GDI + Échelle Grey générée sous forme de PNG de profondeur de 32 bits, puis échantillonnée les pixels de la peinture. Ils vont bien. Cependant, j'ai fait vérifier le HBITMAP résultant que GDI + produit (via bitmap :: gethbitmap ()) et c'est toujours une profondeur de 32 bits, malgré l'instance bitmap sous-jacente étant PixelFormat24BPPRGB).



3
votes

peut faire :)
Comme indiqué par 'Chris Becke' ci-dessus, GDI ne peut comparer que si le canal alpha réservé est zéro.
Le HBITMAP est venu de bitmap :: gethbitmap () Retourne un HBITMAP avec Alpha Channel tout défini sur 0xff.
Doit être 0x00 pour la comparaison de SetbkColor () au travail.
Par conséquent, la Soln: boucle à travers chaque pixel et définissez le composant alpha à zéro.

Bitmap img(L"X.bmp");
HBITMAP hBM;
img.GetHBITMAP(Color::White, &hBM);
BITMAP bm;
GetObject(g_hbmBall, sizeof(BITMAP), &bm);
for(UINT i = 0, n = -1; i &lt bm.bmHeight; i++)
    for(UINT j = 0; j &lt bm.bmWidth; j++)
    {
        n += 4; // Once per Pixel of 4 Bytes
        ((LPBYTE)bm.bmBits)[n] = 0;
    }
// Now SetBkColor and BitBlt will work as expected


1 commentaires

Merci pour l'idée. J'ai fini par décider de ne pas utiliser cette technique. Cette branche de codage est donc actuellement défuntée. Je peux y retourner à l'avenir et j'essaierai à nouveau cette idée. ;)



2
votes

La méthode qui a fonctionné pour moi était de convertir le bitmap de 32 bits à 24 bits en premier. xxx

sur ma machine qui s'exécute plus rapidement que la double boucle de la réponse de Ujjwal.


1 commentaires

Juste pour rendre cette méthode plus claire, a. 3) SelectObject sélectionne le bitmap créé avec crédibsection dans un nouveau CC créé dans 1) b. Pour créer le masque, vous devez vous assurer d'appeler SetBkColor sur le nouveau courant continu 24 bits créé dans 1), j'ai accidentellement eu Setbkcolor appelé le 32bit DC, et il a fallu un certain temps pour dépanner.