Dessiner une image transparente (win32)

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

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.