牵着老婆满街逛

严以律己,宽以待人. 三思而后行.
GMail/GTalk: yanglinbo#google.com;
MSN/Email: tx7do#yahoo.com.cn;
QQ: 3 0 3 3 9 6 9 2 0 .

基于Directshow框架使用Windows渲染器VMR叠加水印

转载自:http://blog.sina.com.cn/s/blog_6281e5750100xdnj.html

对于windows系统,EVR/VMR9/VMR渲染器均提供了叠加静态图片的接口:
SetAlphaBitmap();
 
此接口支持静态图片的资源使用方式,一种是HDC,一种是SURFACE;
使用发现,如果静态图片不规则,是有Alpha通道的不同取值形成,
则通过HDC叠加的会有黑边存在;
 
对于EVR/VMR9可采用SURFACE,使用D3D创建,完美水印效果相对容易实现,略过;
对于VMR渲染器,SURFACE需要基于DirectDraw创建离屏表面;
 
离屏表面创建后,静态图片数据使用决定着是否能完美呈现水印效果;
一种是通过离屏表面获取HDC,操作HDC,把静态图片附加给离屏表面,
一种是通过直接操作离屏表面的内存数据地址;
 
经过几天的摸索,实现了比较完美的水印效果,代码如下:
LPDIRECTDRAW7 lpDDraw7;
 
  
if(FAILED(DirectDrawCreateEx(NULL, (LPVOID *)&lpDDraw7, IID_IDirectDraw7, NULL)))
  
{
   
return ;
  }

 
if (FAILED(lpDDraw7->SetCooperativeLevel(m_hShowWin, DDSCL_NORMAL)))
 
{
  
return ;
 }

 
 DDSURFACEDESC2 ddsd;
 ZeroMemory(
&ddsd, sizeof(ddsd));
   ddsd.dwSize 
= sizeof(ddsd);
   ddsd.dwFlags 
= DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
   ddsd.ddsCaps.dwCaps 
= DDSCAPS_OFFSCREENPLAIN;
   ddsd.dwWidth 
= xs;
 ddsd.dwHeight 
= ys;
  ddsd.ddpfPixelFormat.dwSize 
=sizeof(DDPIXELFORMAT);
  ddsd.ddpfPixelFormat.dwFlags 
=DDPF_RGB | DDPF_ALPHAPIXELS;
  ddsd.ddpfPixelFormat.dwRGBBitCount 
=32;
   ddsd.ddpfPixelFormat.dwRBitMask
=0x00ff0000;
   ddsd.ddpfPixelFormat.dwGBitMask
=0x0000ff00;
   ddsd.ddpfPixelFormat.dwBBitMask
=0x000000ff;
 ddsd.ddpfPixelFormat.dwRGBAlphaBitMask
=0xff000000;
  
if(FAILED(lpDDraw7->CreateSurface(&ddsd, lpSource, NULL)))
 
{
  
return ;
 }

 
 
lpSurface
->Restore();
  CImage img;
  HRESULT result;
  result 
= img.Load(_bstr_t(path));
  
if(!SUCCEEDED(result))
   
return ;
  LPBYTE lpBits 
= (LPBYTE)img.GetBits();
  
int nPitch = img.GetPitch();
  
int imgWidth = img.GetWidth();
  
int bpp = img.GetBPP();
  
if(bpp != 24 && bpp != 32)
   
return ;
 
  DDSURFACEDESC2 dds;
  ZeroMemory(
&dds,0,sizeof(dds));
  dds.dwSize   
=   sizeof(dds);
  
if(DD_OK != lpSurface->Lock(NULL, &dds, DDLOCK_WAIT, NULL))
   
return;
 
  LPBYTE dest 
= (LPBYTE)dds.lpSurface;
  
forint yPos = 0; yPos < img.GetHeight(); yPos++)
  
{
   LPBYTE lpBytes 
= lpBits + ( yPos * nPitch );
   
int width = img.GetWidth( ) * (bpp / 8);
 
   
forint xPos = 0; xPos < width; )
   
{
    
if(bpp == 24)
    
{
 
     
*dest++ = lpBytes[xPos ];
     
*dest++ = lpBytes[xPos + 1];
     
*dest++ = lpBytes[xPos + 2];
     
*dest++ = 0xff;
 
     xPos 
+= 3 ;
    }

    
else if(bpp == 32)
    
{
     
*dest++ = lpBytes[xPos];
     xPos 
++;
    }

   }

 
   dest 
+= dds.lPitch - width;
  }

  lpSurface
->Unlock(NULL);
静态图片的数据赋给离屏表面,上面代码采用的是操作内存的方式,如果采用
lpSurface->GetDc(&hdc)的方式,然后通过BitBlt方式绘制的话,alpha通道会丢失,达不到水印的完美呈现

posted on 2012-09-17 11:06 杨粼波 阅读(1315) 评论(0)  编辑 收藏 引用 所属分类: C++Windows


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理