Создание α-перехода в точечном рисунке


Пример кода ниже делит окно на три горизонтальных области. Затем там рисует альфа-переход точечного рисунка  в каждой из этих областей окна как ниже указано:

void DrawAlphaBlend (HWND hWnd, HDC hdcwnd)
{
    HDC hdc;               // дескриптор DC, нужно создать 
    BLENDFUNCTION bf;      // структура для alpha-перехода
    HBITMAP hbitmap;       // дескриптор точечного рисунка
    BITMAPINFO bmi;        // заголовок точечного рисунка
    VOID *pvBits;          // указатель на DIB секцию
    ULONG   ulWindowWidth, ulWindowHeight;   // окно ширина/высота
    ULONG   ulBitmapWidth, ulBitmapHeight;   // рисунок ширина/высота
    RECT    rt;            // используется для получения габаритов окна
    UINT32   x,y;          // пошаговые переменные
    UCHAR ubAlpha;         // для создания градиентов прозрачности
    UCHAR ubRed;        
    UCHAR ubGreen;
    UCHAR ubBlue;
    float fAlphaFactor;    // чтобы делать умножение в обратном порядке
            
    // получим габариты окна
    GetClientRect(hWnd, &rt);
    
    // вычислим ширину/высоту окна
    ulWindowWidth = rt.right - rt.left;  
    ulWindowHeight = rt.bottom - rt.top;  

    // убедимся, что мы имеем по меньшей мере какой-то размер окна
    if ((!ulWindowWidth) || (!ulWindowHeight))
        return;

    // поделим окно внутри на 3 горизонтальных области
    ulWindowHeight = ulWindowHeight / 3;

    // создадим DC для нашего рисунка - источниковый DC для AlphaBlend 
    hdc = CreateCompatibleDC(hdcwnd);
    
    // обнулим область памяти для информации о точечном рисунке
    ZeroMemory(&bmi, sizeof(BITMAPINFO));

    // установим информацию о рисунке 
    // зададим ширину и высоту рисунка 60% от ширины и высоты
    // каждой области из этих трех горизонтальных областей. Позже,
    // переход произойдет в центре каждой из этих трех областей.
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth = ulBitmapWidth = ulWindowWidth - 
                                            (ulWindowWidth/5)*2;
    bmi.bmiHeader.biHeight = ulBitmapHeight = ulWindowHeight -
                                            (ulWindowHeight/5)*2;
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 32;     // четыре 8-битовых компонента
    bmi.bmiHeader.biCompression = BI_RGB;
    bmi.bmiHeader.biSizeImage = ulBitmapWidth * ulBitmapHeight * 4;

    // создадим свою DIB секцию и выберем рисунок в DC
    hbitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pvBits,
                               NULL, 0x0);
    SelectObject(hdc, hbitmap);

    // В верхней области окна, α = 50%, но нет исходного α
    // формат цвета для каждого пикселя равен 0xaarrggbb 
    // установим все пиксели в синий, а исходный α в 0 
    for (y = 0; y < ulBitmapHeight; y++)
        for (x = 0; x < ulBitmapWidth; x++)
            ((UINT32 *)pvBits)[x + y * ulBitmapWidth] = 0x000000ff; 

    bf.BlendOp = AC_SRC_OVER;
    bf.BlendFlags = 0;
    bf.SourceConstantAlpha = 0x7f;  // поовина 0xff = 50% прозрачности
    bf.AlphaFormat = 0;             // игнорируем исходный α-канал

    if (!AlphaBlend(hdcwnd, ulWindowWidth/5, ulWindowHeight/5, 
                    ulBitmapWidth, ulBitmapHeight, 
                    hdc, 0, 0, ulBitmapWidth, ulBitmapHeight, bf))
        return;                     // α-переход завершился ошибкой
    
    // в средней области окна, α = 100% (отключено), исходный α равен 
    // 0 в середине рисунка и непрозрачный в остальной части рисунка 
    for (y = 0; y < ulBitmapHeight; y++)
        for (x = 0; x < ulBitmapWidth; x++)
            if ((x > (int)(ulBitmapWidth/5)) && 
                (x < (ulBitmapWidth-ulBitmapWidth/5)) &&
                (y > (int)(ulBitmapHeight/5)) && 
                (y < (ulBitmapHeight-ulBitmapHeight/5)))
                //в середине рисунка: исходный α = 0 (прозрачный).
                // Это означает умножение каждого компонента на 0x00.
                // Поэтому, после AlphaBlend, мы имеем  a, 0x00 * r, 
                // 0x00 * g и 0x00 * b (что равно 0x00000000)
                // пока установим все пиксели в красный цвет
                ((UINT32 *)pvBits)[x + y * ulBitmapWidth] = 0x00ff0000;
            else
                // в остатке рисунка исходный α = 0xff (непрозрачный) 
                // и установим все пиксели в синий цвет 
                ((UINT32 *)pvBits)[x + y * ulBitmapWidth] = 0xff0000ff;
            endif;
    
    bf.BlendOp = AC_SRC_OVER;
    bf.BlendFlags = 0;
    bf.AlphaFormat = AC_SRC_ALPHA;  // используем исходный α 
    bf.SourceConstantAlpha = 0xff;  // непрозрачный (α отключена)
   
    if (!AlphaBlend(hdcwnd, ulWindowWidth/5, 
                    ulWindowHeight/5+ulWindowHeight, ulBitmapWidth, 
                    ulBitmapHeight, hdc, 0, 0, ulBitmapWidth, 
                    ulBitmapHeight, bf))
        return;

    // нижняя область окна использует α = 75%, исходный α изменяется
    // Создадим градиент действия, используя исходный α, а затем 
    // изменим его даже несколько больше чем α
    ubRed = 0x00;
    ubGreen = 0x00;
    ubBlue = 0xff;
    
    for (y = 0; y < ulBitmapHeight; y++)
        for (x = 0; x < ulBitmapWidth; x++)
        {
            // обычный градиент исходит от значения пикселя α до 
            // значения пикселя x 
            ubAlpha = (UCHAR)((float)x / (float)ulBitmapWidth * 255);
            // вычисляем коэффициент на который умножаем каждый 
            // компонент
            fAlphaFactor = (float)ubAlpha / (float)0xff; 
            // умножаем каждый пиксель fAlphaFactor, таким образом 
            // каждый компонент меньше или равен значению α.
            ((UINT32 *)pvBits)[x + y * ulBitmapWidth] 
                = (ubAlpha << 24) |                       //0xaa000000
                 ((UCHAR)(ubRed * fAlphaFactor) << 16) |  //0x00rr0000
                 ((UCHAR)(ubGreen * fAlphaFactor) << 8) | //0x0000gg00
                 ((UCHAR)(ubBlue   * fAlphaFactor));      //0x000000bb
        }

    bf.BlendOp = AC_SRC_OVER;
    bf.BlendFlags = 0;
    bf.AlphaFormat = AC_SRC_ALPHA;   // используем исходный α 
    bf.SourceConstantAlpha = 0xbf;   // используем α с 
                                     // 75% непрозрачности

    AlphaBlend(hdcwnd, ulWindowWidth/5, 
               ulWindowHeight/5+2*ulWindowHeight, ulBitmapWidth, 
               ulBitmapHeight, hdc, 0, 0, ulBitmapWidth, 
               ulBitmapHeight, bf);

    // сделаем очистку
    DeleteObject(hbitmap);
    DeleteDC(hdc);
    
}


Назад в оглавление темы
На главную страницу темы

Hosted by uCoz