Dessiner une image transparente (win32)

Soyez le premier à donner votre avis sur cette source.

Vue 16 549 fois - Téléchargée 1 472 fois

Description

Ce code montre comment dessiner une image avec de la transparence, mais de manière non uniforme (les régions de l'image sont plus ou moins transparentes). Ceci est fait grâce à l'API UpdateLayeredWindow. Le code n'est pas spécialement compliqué ni long, mais j'ai quand même cherché une bonne journée avant de réussir a avoir ce résultat.
L'image est a l'origine stockée dans une image png (format qui gère la transparence). J'utilise les librairies libpng et CxImage pour supporter ce format.

Source / Exemple :


#define _CRT_SECURE_NO_DEPRECATE
#define _WIN32_WINNT 0x0501
#define _WIN32_IE 0x0501
#include <windows.h>

#include "ximage.h"
#include "ximapng.h"

HWND g_hWnd;
char g_szAppName[] = "Transparence";
int alpha = 255;

void SetImage(LPCTSTR fileName, int alpha)
{
  CxImage img;
  img.Load(fileName, CXIMAGE_FORMAT_PNG);
  RECT rcWnd;
  GetWindowRect(g_hWnd, &rcWnd);
  POINT ptWindowScreenPosition = {rcWnd.left, rcWnd.top}, ptSrc = {0, 0};
  SIZE size = {img.GetWidth(), img.GetHeight()};

  HDC dcScreen = GetDC(0);

  // Création d'un dc mémoire de la taille de l'image, et dans lequel on dessine l'image
  HDC hmemdc = CreateCompatibleDC(dcScreen);
  HBITMAP hbmp = CreateCompatibleBitmap(dcScreen, size.cx, size.cy);
  HGDIOBJ oldbmp = SelectObject(hmemdc, hbmp);
  img.Draw(hmemdc);

  BITMAP bmp;
  GetObject(hbmp, sizeof bmp, &bmp);

  BITMAPINFO bi;
  memset(&bi, 0, sizeof bi);
  bi.bmiHeader.biSize = sizeof bi.bmiHeader;
  bi.bmiHeader.biWidth = bmp.bmWidth;
  bi.bmiHeader.biHeight = bmp.bmHeight;
  bi.bmiHeader.biBitCount= bmp.bmBitsPixel;
  bi.bmiHeader.biPlanes = bmp.bmPlanes;
  bi.bmiHeader.biCompression = BI_RGB;

  int nbbytes = bmp.bmBitsPixel * bmp.bmWidth * bmp.bmHeight / 8;
  LPBYTE lpBits = new BYTE[nbbytes];
  // Récupération des bits de l'image
  GetDIBits(hmemdc, hbmp, 0, bmp.bmHeight, lpBits, &bi, DIB_RGB_COLORS);
  // C'est ca que j'ai eu du mal à trouver:
  // ici on gère la transparence des pixels un par un
  LPBYTE pAlpha = img.AlphaGetPointer();
  for(int i = 0; i < nbbytes; i += 4) lpBits[i + 3] = *pAlpha++;

  SetDIBits(hmemdc, hbmp, 0, bmp.bmHeight, lpBits, &bi, DIB_RGB_COLORS);
  delete[] lpBits;
  

  BLENDFUNCTION bf = {AC_SRC_OVER, 0, alpha, AC_SRC_ALPHA};
  UpdateLayeredWindow(g_hWnd, dcScreen, &ptWindowScreenPosition, &size, hmemdc, &ptSrc, 0, &bf, ULW_ALPHA);

  SelectObject(hmemdc, oldbmp);
  DeleteObject(hbmp);
  DeleteDC(hmemdc);
  ReleaseDC(0, dcScreen);
}

LRESULT CALLBACK AppWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  switch(uMsg)
  {
  case WM_KEYDOWN:
    switch(wParam)
    {
    case VK_ESCAPE:
    case VK_RETURN:
      DestroyWindow(hWnd);
      break;
    case VK_UP:
      if(alpha > 0) alpha--;
      SetImage("image.png", alpha);
      break;
    case VK_DOWN:
      if(alpha != 255) alpha++;
      SetImage("image.png", alpha);
      break;
    }
    break;
  case WM_NCHITTEST:
    return HTCAPTION;
  case WM_DESTROY:
    PostQuitMessage(0);
    return 0;
  }
  return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

#ifdef _DEBUG
int main()
#else
int APIENTRY WinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
#endif
{
  MSG msg;
  HINSTANCE g_hInst = GetModuleHandle(0);
  WNDCLASSEX wcex;

  memset(&wcex, 0, sizeof wcex);
  wcex.cbSize         = sizeof wcex;
  wcex.lpfnWndProc    = AppWndProc;
  wcex.style          = CS_HREDRAW | CS_VREDRAW;
  wcex.hInstance      = g_hInst;
  wcex.lpszClassName  = g_szAppName;
  wcex.hbrBackground  = GetSysColorBrush(COLOR_WINDOW);
  wcex.hCursor        = LoadCursor(0, IDC_ARROW);
  RegisterClassEx(&wcex);

  g_hWnd = CreateWindowEx(WS_EX_LAYERED, g_szAppName, g_szAppName, WS_OVERLAPPED | WS_SYSMENU,
    0, 0, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, g_hInst, 0);

  SetImage("image.png", alpha);
  ShowWindow(g_hWnd, SW_SHOW);

  while(GetMessage(&msg, NULL, 0, 0))
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  return (int)msg.wParam;
}

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

Messages postés
475
Date d'inscription
vendredi 27 juin 2003
Statut
Membre
Dernière intervention
20 septembre 2010

Salut, je viens d'essayer ta source, elle semble fonctionner mais après quelques secondes (variable) l'image disparait pour laisser place à une fenetre standard. Quelqu'un aurait une idée ?
(pour info je suis sous windows 7)
Messages postés
24
Date d'inscription
jeudi 19 juin 2003
Statut
Membre
Dernière intervention
15 décembre 2008

Merci, merci, merci ! Super code qui marche du premier coup sans le moindre changement à faire. Depuis une semaine, j'ai cherché partout un exemple pour dessiner une PNG par dessus l'écran et il n'y a que le tien qui fonctionne. Et sans MFC en plus - chapeau !
Messages postés
3246
Date d'inscription
lundi 25 avril 2005
Statut
Modérateur
Dernière intervention
27 octobre 2012
32
Le but, est-ce bien d'avoir le texte de l'image totalement opaque et le reste de l'image transparente ?

Je pense que la partie qui t'as posé un problème, là où tu récupères les pixels un par un est inutile.. j'obtiens le même résultat sans manipuler les pixels. C'est peut être la méthode Draw de librairie CxImage qui te joue des tours. Tu devrais essayer avec Bitmap::GetHBITMAP de GDI+.
Messages postés
1
Date d'inscription
mercredi 16 août 2006
Statut
Membre
Dernière intervention
14 septembre 2006

Désolé de poster un commentaire 3 mois après la parution de cette source.

Bravo à Vecchio56 qui a réalisé un chouette travail :p

Pour mon information, croyez-vous possible l'utilisation de la fonction UpdateLayeredWindow sur un fichier vidéo ou le canal alpha serait défini ?
Messages postés
868
Date d'inscription
dimanche 26 décembre 2004
Statut
Membre
Dernière intervention
26 février 2008
1
lol. Quelle idiot ! J'avais complètement oublié. :-p
Afficher les 9 commentaires

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.