Click here to Skip to main content
15,892,697 members
Articles / Desktop Programming / MFC

Fade Effect - Gradient Effect - Alphablending - Thumbnail Image - Copy HBITMAP

Rate me:
Please Sign up or sign in to vote.
2.71/5 (13 votes)
14 Mar 2008CPOL1 min read 49K   937   24   4
How easy to Play with color of bitmap
Image 1

Introduction

Image related task is always painful. I have seen so many articles on image processing. They have done very well, but still I think I need to contribute something. In my article, I have designed only one class named PlayColor where the reader can find the solution. Top right corner shows the preview of the whole canvas.

Background

I believe that every task in this world is a combination of many small tasks. So my thought process was to handle only one pixel at any time. If I can process one pixel, I think I can also process more pixels. Here you will see in gradient or fade effect or any processing, I just handle one pixel. Suppose we take gradient effect, the basic thing behind it is to only change one color to another color.

Using the Code

This method does almost everything:

C++
void fadeColor(const unsigned int aClrSrc,unsigned int& 
aClrDest,const int aPercent = 100); 
//---------------------------Transparent drawing--------------------- 
//This method draw a bitmap transparently. 
void drawBitmapTransparent( CDC* pDC,int aX,int aY,HBITMAP hBitmap,
    COLORREF aTransprent); Example: HBITMAP hBitmap;
//any valid HBITMAP 
//hBitmap = drawBitmapTransparent(pDC,0,0,hBitmap,0);
//IF you provide transparent color then it will be used 
//But if you don't then it will take pixel from 
if (aTransprent == 0) 
{ 
    aTransprent = memDC.GetPixel(1,1);
    //TRANSPARENT COLOR from HBITMAP... 
} 
//---------------------------Fading Effect--------------------------- 
HBITMAP fadeBitmap(HBITMAP aBitmap,const COLORREF aFadeto,
    const int aTransparency = 0); 
// Example: 
//NO EFFECT ON ORIGINAL BITMAP HBITMAP 
hBitmap = fadeBitmap( mBitmap,rectColor,mAlpha); 
//mBitmap ORIGINAL BITMAP 
//hBitmap CONVERTED BITMAP 
drawBitmap(pDC,0,0,hBitmap); 
//-------------------Gradient Effect--------------------------------- 
void hgradient(CDC* pDC,const unsigned int aClrSrc,
    const unsigned int aClrDest,const CRect aRect); 
//Example: 
//VERTICAL GRADIENT RED TO WHILT... 
vgradient(pDC,RGB(255,0,0),RGB(255,255,255),
    CRect(CPoint(0,160),CSize(50,160))); 
//------------------Resize Effect------------------------------------- 
HBITMAP getResizeBitmap( HBITMAP hBitmap ,const unsigned int aW,
    const unsigned int aH); 
//Example: 
//NO EFFECT ON ORIGINAL BITMAP HBITMAP hBitmap = getResizeBitmap( 
    mBitmap,100,100);
//------------------------------------------------- 
C++
--------------------------------Header File------------------------------------

//######################################################################
//# FILENAME: CPlayColor.h
//#
//# DESCRIPTION:    PERFORM Fade effect, Draw bitmap transparently,
//#                    Horizontal gradient, Vertical gradient, Copy HBITMAP,
//#                    Transparent HBITMAP ---bitmap from HBITMAP, Resize HBITMAP,
//#                    GET THE PREVIEW OF WHOLE DRAWING.
//# AUTHOR:        Mohammad Saiful Alam (Jewel)
//# POSITION:    Senior Software Engineer
//# E-MAIL:        saiful.alam@ bjitgroup.com
//# CREATE DATE: 2008/02/1
//#
//# Copyright (c) 2007 BJIT Ltd.
//######################################################################

#ifndef _CPlayColor_H_
#define _CPlayColor_H_

class CPlayColor  
{
public:
    //TEST
    CRect mClientRect;
    CRect mDirtyRect;
    int mAlpha;
    CPoint mPoint;
    //TEST
    CPlayColor();
    virtual ~CPlayColor();
    void draw(CDC* pDC);
    //
    void fadeColor(const unsigned int aClrSrc,unsigned int& aClrDest,
        const int aPercent = 100);
    //
    void hgradient(CDC* pDC,const unsigned int aClrSrc,
        const unsigned int aClrDest,const CRect aRect);
    //
    void vgradient(CDC* pDC,const unsigned int aClrSrc,const unsigned int aClrDest,
        const CRect aRect);
    //
    void setGradientColor(const COLORREF aSrcClr,const COLORREF aDestClr);
    //
    HBITMAP fadeBitmap(
        HBITMAP aBitmap,const COLORREF aFadeto,const int aTransparency = 0);
    //
    HBITMAP getTransparentBitmap( CDC* pSrcDC,CPoint aImgCorner,HBITMAP aBitmap,
        COLORREF aTransprent);
    //
    HBITMAP getCloneBitmap( HBITMAP hBitmap );
    //
    HBITMAP getResizeBitmap( HBITMAP hBitmap ,
        const unsigned int aW,const unsigned int aH);
    //
    void drawBitmap(CDC* pDC,int aX, int aY,  HBITMAP hBitmap);
    //
    void drawBitmapTransparent( CDC* pDC,int aX,int aY,HBITMAP hBitmap,
        COLORREF aTransprent);
private:
    COLORREF mSrcColor[5];
    COLORREF mDestColor[5];
    //USED FOR TEST PURPOSE
    HBITMAP mBitmap;
    HBITMAP mBitmapCheck;
    HBITMAP mBitmapCheckTrans;    
    //NOT NEDDED...ONLY FOR TEST PURPOSE
};

#endif
------------------------------------------------------------------------------
C++
--------------------------------CPP File------------------------------------


//######################################################################
//# FILENAME: CPlayColor.cpp
//#
//# DESCRIPTION:    PERFORM Fade effect, Draw bitmap transparently,
//#                    Horizontal gradient, Vertical gradient, Copy HBITMAP,
//#                    Transparent HBITMAP ---bitmap from HBITMAP
//#                    GET THE PREVIEW OF WHOLE DRAWING.
//# AUTHOR:        Mohammad Saiful Alam (Jewel)
//# POSITION:    Senior Software Engineer
//# E-MAIL:        saiful.alam@ bjitgroup.com
//# CREATE DATE: 2008/02/1
//#
//# Copyright (c) 2007 BJIT Ltd.
//######################################################################

#include "stdafx.h"
#include "AlphaBlending.h"
#include "PlayColor.h"


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CPlayColor::CPlayColor()
{
    mSrcColor[0] = RGB(255,255,255);
    mDestColor[0] = RGB(0,0,255);

    mSrcColor[1] = RGB(255,255,255);
    mDestColor[1] = RGB(255,0,0);

    mSrcColor[2] = RGB(255,255,255);
    mDestColor[2] = RGB(0,255,0);

    mSrcColor[2] = RGB(255,255,255);
    mDestColor[3] = RGB(255,255,0);

    mBitmap = (HBITMAP)LoadImage(AfxGetInstanceHandle( ),
        MAKEINTRESOURCE(IDB_BITMAP_ME),IMAGE_BITMAP,0,0,LR_DEFAULTSIZE);
    mBitmapCheck = (HBITMAP)LoadImage(AfxGetInstanceHandle( ),
        MAKEINTRESOURCE(IDB_BITMAP_CHECK),IMAGE_BITMAP,0,0,LR_DEFAULTSIZE);
    mAlpha = 0;
    mClientRect = CRect(0,0,0,0);

    //mBitmapCheckTrans = getTransparentBitmap( &memDCDirty,
        CPoint(10,180),mBitmapCheck,0);
    mPoint = CPoint(10,180);
}

CPlayColor::~CPlayColor()
{

}
//
void CPlayColor::draw(CDC* pDC)
{
    COLORREF rectColor = RGB(0,124,125);//BACK COLOR
//    COLORREF rectColor = RGB(124,124,125);//BACK COLOR
    unsigned aFadeto = RGB(255,255,255);
    HBITMAP hBitmap;
    //ALL DRAWING PERFORM IN BITMAP SO THAT WE CAN USE THE BITMAP LATER..
    HBITMAP hBitmapDirty;
    CDC memDCDirty;         
    //DRAWAING STARTED...
    hBitmapDirty = getResizeBitmap( mBitmap,mClientRect.Width(),mClientRect.Height() );
    //LARGE BITMAP TO SUPPORT YOUR DRAWING AREA
    memDCDirty.CreateCompatibleDC( NULL );           
    HBITMAP hBmOldDirty = (HBITMAP)::SelectObject( memDCDirty.m_hDC, hBitmapDirty );    
    memDCDirty.FillSolidRect(CRect(CPoint(0,0),CSize(600,600)),rectColor);

    //DRAW A RECTANGLE WITH ALPHA COLOR
    hBitmap = fadeBitmap( mBitmap,rectColor,mAlpha);//NO EFFECT ON ORIGINAL BITMAP
    drawBitmap(&memDCDirty,0,0,hBitmap);
    
    hBitmap = getResizeBitmap( mBitmap,50,50 );
    drawBitmap(&memDCDirty,150,0,hBitmap);
    //
    vgradient(&memDCDirty,mSrcColor[0],mDestColor[0],CRect(CPoint(0,160),CSize(50,160)));
    hgradient(&memDCDirty,mDestColor[1],mSrcColor[0],
        CRect(CPoint(55,160),CSize(250,50)));
    hgradient(&memDCDirty,mSrcColor[0],mDestColor[2],
        CRect(CPoint(55,160+110),CSize(250,50)));
    vgradient(&memDCDirty,mDestColor[3],mSrcColor[0],
        CRect(CPoint(310,160),CSize(50,160)));
    
    drawBitmap(&memDCDirty,160,200,mBitmapCheck);

    //hBitmap = getTransparentBitmap( &memDCDirty,mPoint,mBitmapCheck,0);
    drawBitmapTransparent(&memDCDirty,mPoint.x,mPoint.y,mBitmapCheck,0);

    memDCDirty.SelectObject( hBmOldDirty );
    memDCDirty.DeleteDC();
    //DRAWAING FINISHED...
//    //DRAW WHOLE BITMAP INTO OUTPUT
    drawBitmap(pDC,0,0,hBitmapDirty);
//    //DRAW THUMBNAIL VIEW OF WHOLE DRAWING
    pDC->FillSolidRect(CRect(CPoint(259,9),CSize(102,102)),aFadeto);
    hBitmap = getResizeBitmap( hBitmapDirty,100,100);
    drawBitmap(pDC,260,10,hBitmap);//thumbnail image
}
//
void CPlayColor::setGradientColor(const COLORREF aSrcClr,const COLORREF aDestClr)
{

}

//IF U CAN TRANSLATE ONE COLOR U CAN TRANSLATE WHOLE IMAGE...
void CPlayColor::fadeColor(const unsigned int aClrSrc,
    unsigned int& aClrDest,const int aPercent)
{
    register int rr,gg,bb,dr,dg,db,r1,g1,b1,r2,g2,b2;
    register int f1,f2,f3;
    
    r1 = (aClrSrc)&0xff;
    g1 = ((aClrSrc)>>8)&0xff;
    b1 = ((aClrSrc)>>16)&0xff;


    r2 = (aClrDest)&0xff;
    g2 = ((aClrDest)>>8)&0xff;
    b2 = ((aClrDest)>>16)&0xff;

    rr = r1 - r2;
    gg = g1 - g2;
    bb = b1 - b2;
    //aPercent = 100 means fully converted to aClrSrc;
    f1 = (rr*aPercent)/100;
    f2 = (gg*aPercent)/100;
    f3 = (bb*aPercent)/100;

    dr = r1 - f1;
    dg = g1 - f2;
    db = b1 - f3;    
    aClrDest = RGB(dr,dg,db);
}
//
void CPlayColor::hgradient(CDC* pDC,
    const unsigned int aClrSrc,const unsigned int aClrDest,const CRect aRect)
{
    register int rw,factor,l,t;
    CRect rg;
    unsigned dc = aClrDest;
    rw = aRect.Width();     
    //
    l = aRect.left;
    t = aRect.top;
    for (int i = 1;i<=rw; i++)
    {
        factor = (i*100)/rw;
        fadeColor(aClrSrc,dc,factor);        
        pDC->FillSolidRect(l,t,1,aRect.Height(),dc);        
        dc = aClrDest;
        l+=1;    
    }
}
//
void CPlayColor::vgradient(CDC* pDC,
    const unsigned int aClrSrc,const unsigned int aClrDest,const CRect aRect)
{
    register int rh,factor,l,t;
    CRect rg;
    unsigned dc = aClrDest;
    rh = aRect.Height();
    //
    l = aRect.left;
    t = aRect.top;
    for (int i = 1;i<=rh; i++)
    {
        factor = (i*100)/rh;
        fadeColor(aClrSrc,dc,factor);        
        pDC->FillSolidRect(l,t,aRect.Width(),1,dc);        
        dc = aClrDest;
        t+=1;    
    }
}
//
HBITMAP CPlayColor::fadeBitmap(HBITMAP aBitmap,
    const COLORREF aFadeto,const int aTransparency )
{
    HBITMAP hbitmap;
    CBitmap bmpSrc;
    BITMAP bmp;
    if(!bmpSrc.Attach(aBitmap))
        return NULL;
    if(!bmpSrc.GetBitmap(&bmp))
        return NULL;
    CDC memDC;
    memDC.CreateCompatibleDC( NULL );           
    hbitmap = getCloneBitmap( aBitmap);
    HBITMAP hBmOld = (HBITMAP)::SelectObject( memDC.m_hDC, hbitmap );    
    memDC.SetBkColor(RGB(0,0,0));                // 1 -> black
    memDC.SetTextColor(RGB(255,255,255));        // 0 -> white    
    COLORREF cs;
    unsigned dc1 = aFadeto;

    for (int x = 0; x<bmp.bmheight; hbitmap=""getCloneBitmap("" cs=""memDC.GetPixel(y,x);"" dc1=""aFadeto;"" hbmold=""(HBITMAP)::SelectObject("" y=""0;"" /> black
    memDC.SetTextColor(RGB(255,255,255));        // 0 -> white    
    COLORREF cs;
    COLORREF dc1 = aTransprent;
    if (aTransprent == 0)
    {
        aTransprent = memDC.GetPixel(1,1);//GET LET TOP PIXEL AS TRANSPARENT    
    }
    for (int x = 0; x<bmp.bmheight; cs=""pSrcDC-"" y=""0;"" />GetPixel(y+aImgCorner.x,x+aImgCorner.y);
            dc1 = memDC.GetPixel(y,x);
            if (dc1 == aTransprent)//if this color is same then need to be transparent..
            {
                dc1 = cs;
            }
            memDC.SetPixel(y,x,dc1);
        }
    }    
    memDC.SelectObject(hBmOld);
    memDC.DeleteDC();
    bmpSrc.Detach();    

    return hbitmap;    
}
//CLONE A BITMAP TO ANOTHER...
HBITMAP CPlayColor::getCloneBitmap( HBITMAP hBitmap)
{
    // Create a memory DC compatible with the display
    CDC sourceDC, destDC;
    sourceDC.CreateCompatibleDC( NULL );
    destDC.CreateCompatibleDC( NULL );

    // Get logical coordinates
    BITMAP bm;
    ::GetObject( hBitmap, sizeof( bm ), &bm );

    // Create a bitmap to hold the result
    HBITMAP hbmResult = ::CreateCompatibleBitmap(CClientDC(NULL),
        bm.bmWidth, bm.bmHeight);

    // Select bitmaps into the DCs
    HBITMAP hbmOldSource = (HBITMAP)::SelectObject( sourceDC.m_hDC, hBitmap );
    HBITMAP hbmOldDest = (HBITMAP)::SelectObject( destDC.m_hDC, hbmResult );
    destDC.BitBlt( 0, 0, bm.bmWidth, bm.bmHeight, &sourceDC,0,0, SRCCOPY );
    // Reselect the old bitmaps
    ::SelectObject( sourceDC.m_hDC, hbmOldSource );
    ::SelectObject( destDC.m_hDC, hbmOldDest );

    return hbmResult;
}
//
HBITMAP CPlayColor::getResizeBitmap( HBITMAP hBitmap ,
    const unsigned int aW,const unsigned int aH)
{
    // Create a memory DC compatible with the display
    CDC sourceDC, destDC;
    sourceDC.CreateCompatibleDC( NULL );
    destDC.CreateCompatibleDC( NULL );
    // Get logical coordinates
    BITMAP bm;
    ::GetObject( hBitmap, sizeof( bm ), &bm );
    // Create a bitmap to hold the result
    HBITMAP hbmResult = ::CreateCompatibleBitmap(CClientDC(NULL),aW,aH);
    // Select bitmaps into the DCs
    HBITMAP hbmOldSource = (HBITMAP)::SelectObject( sourceDC.m_hDC, hBitmap );
    HBITMAP hbmOldDest = (HBITMAP)::SelectObject( destDC.m_hDC, hbmResult );
    
    destDC.SetStretchBltMode( HALFTONE);//for better output
    destDC.StretchBlt(0,0,aW,aH,&sourceDC,0,0,bm.bmWidth, bm.bmHeight,SRCCOPY);
    // Reselect the old bitmaps
    ::SelectObject( sourceDC.m_hDC, hbmOldSource );
    ::SelectObject( destDC.m_hDC, hbmOldDest );
    return hbmResult;
}
//
void CPlayColor::drawBitmap(CDC* pDC,int aX, int aY,  HBITMAP hBitmap)
{
    BITMAP bm;
    CDC memDC;
    memDC.CreateCompatibleDC(NULL);
    ::GetObject( hBitmap, sizeof( bm ), &bm );
    HBITMAP hbmOld = (HBITMAP)memDC.SelectObject(hBitmap);
    pDC->BitBlt( aX,aY,bm.bmWidth,bm.bmHeight,&memDC,0,0,SRCCOPY);
    memDC.SelectObject( hbmOld );
    memDC.DeleteDC();
}
//
void CPlayColor::drawBitmapTransparent( CDC* pDC,int aX,int aY,
    HBITMAP hBitmap,COLORREF aTransprent)
{
    CBitmap bmpSrc;
    BITMAP bmp;
    if(!bmpSrc.Attach(hBitmap))
        return;
    if(!bmpSrc.GetBitmap(&bmp))
        return;
    CDC memDC;
    memDC.CreateCompatibleDC( NULL );           
    HBITMAP hBmOld = (HBITMAP)::SelectObject( memDC.m_hDC, hBitmap );    
    COLORREF dc1 = aTransprent;
    if (aTransprent == 0)
    {
        aTransprent = memDC.GetPixel(1,1);//GET LET TOP PIXEL AS TRANSPARENT    
    }
    for (int x = 0; x<bmp.bmheight; dc1=""memDC.GetPixel(y,x);"" y=""0;"" !=""aTransprent)//if"" />SetPixel( y+aX,x+aY,dc1 );
            }                        
        }
    }    
    memDC.SelectObject(hBmOld);
    memDC.DeleteDC();
    bmpSrc.Detach();    
}        

Points of Interest

Before solving the problem, I was thinking about how I could write my own algorithm for gradient effect. Suddenly I thought, why not begin with only one pixel. So, think small from big. Zany?

History

  • 14th March, 2008: Initial post

Rotation of image will be in the next version of my article.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Bangladesh Bangladesh
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralVerify the code for Page Turn Effect Pin
saiful_vonair9-Jun-10 4:15
saiful_vonair9-Jun-10 4:15 
PageVal getPageDesc(float aPageWidth, float aPageHeight, float aHotSpotDistance)
{
double angle = 0;
double radians = 0;
double movingY = 0;
double movingX = 0;

PageVal pageval = new PageVal();
pageval.pageSymetric = new PageVal();
// This is the angle formed at the bottom of the rectangle just under the line of symmetry
angle = 45d + ((45d * aHotSpotDistance) / aPageWidth);
radians = angle * (Math.PI / 180); // convert to radians for the math function
if (isPathTrapezoid == false)
{
// Still a triangle
movingY = (aHotSpotDistance) * (Math.Tan(radians));
if (movingY > aPageHeight)
{
isPathTrapezoid = true;
}
}

if (isPathTrapezoid == true)
{
movingX = aPageHeight / Math.Tan(radians);
movingY = aPageHeight;
}
else
{
// Still a triangle
movingY = (aHotSpotDistance) * (Math.Tan(radians));
}
pageval.angle = angle;
pageval.point1 = new PointF(aPageWidth*2, aPageHeight);
pageval.point2 = new PointF(aPageWidth * 2 - aHotSpotDistance, aPageHeight);
pageval.point3 = new PointF(aPageWidth * 2, aPageHeight-(float)movingY);
pageval.point4 = new PointF((float)(aPageWidth*2 - ( aHotSpotDistance - movingX)), 0);
//
pageval.pageSymetric.angle = angle + (180 - (2* angle));
pageval.pageSymetric.point1 = pageval.point2;//new PointF(0, aPageHeight);
pageval.pageSymetric.point2 = new PointF(pageval.point2.X - aHotSpotDistance, pageval.point2.Y);//new PointF(aHotSpotDistance, aPageHeight);
//
if (!isPathTrapezoid)
{
pageval.pageSymetric.point3 = pageval.point3;//new PointF(0, aPageHeight-(float)movingY);
pageval.pageSymetric.point4 = pageval.point4; //new PointF(aHotSpotDistance - (float)movingX, 0);
pageval.pageSymetric.point2 = rotatePoint(pageval.point2, pageval.pageSymetric.point2, -pageval.pageSymetric.angle);
}
else
{
pageval.pageSymetric.point3 = pageval.point4;//new PointF(0, aPageHeight-(float)movingY);
double diff = aPageWidth*2 - pageval.point4.X;
pageval.pageSymetric.point4 = new PointF(pageval.point4.X - (float)diff, pageval.point4.Y); //new PointF(aHotSpotDistance - (float)movingX, 0);
}
pageval.pathTrapezoid = isPathTrapezoid;
return pageval;
}
GeneralONE pixel at a time? REALLY?? How insane!! Pin
NickVellios6-Jun-08 22:41
NickVellios6-Jun-08 22:41 
GeneralRe: ONE pixel at a time? REALLY?? How insane!! Pin
xliqz5-Apr-09 3:19
xliqz5-Apr-09 3:19 
GeneralRe: ONE pixel at a time? REALLY?? How insane!! Pin
xox_c0bra_xox8-May-10 19:10
xox_c0bra_xox8-May-10 19:10 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.