将CDib封装类写好后,在文档管理中添加了图像旋转的函数HGLOBAL CDibImage::RotateDIB(LPSTR lpDIB)
{
LONG lWidth;             //源图像的宽度
LONG lHeight;            //源图像的高度
LONG lNewWidth;          //旋转后的图像的宽度
LONG lNewHeight;         //旋转后图像的高度
LONG lLineBytes;        //图像每行的字节数
LONG lNewLineBytes;         //旋转后图像的宽度(lNewWidth',必须是4的倍数)
LPSTR lpDIBBits;         //指向源图像的指针
LPSTR lpSrc;             //指向源像素的指针
HDIB  hDIB;              //旋转后新DIB句柄
LPSTR lpDst;             //指向旋转图像对应像素的指针
LPSTR lpNewDIB;          //指向旋转图像的指针
LPSTR lpNewDIBBits;
LPBITMAPINFOHEADER lpbmi;    //指向BITMAPINFO结构的指针
LPBITMAPCOREHEADER lpbmc;    //指向BITMAPCOREINFO结构的指针
LONG i,j,i0,j0;
float fSina=1.0;
float fCosa=0.0;             //旋转角度的正弦和余弦
//原图4个角的坐标(以图像中心为坐标原点) float fSrcX1,fSrcY1,fSrcX2,fSrcY2,fSrcX3,fSrcY3,fSrcX4,fSrcY4; //旋转之后的4个角的坐标(以图像中心为原点) float fDstX1,fDstY1,fDstX2,fDstY2,fDstX3,fDstY3,fDstX4,fDstY4;
float f1,f2; lpDIBBits=FindDIBBits(lpDIB);     //找到源DIB图像像素起始位置
lWidth=DIBWidth(lpDIB);
lLineBytes=WIDTHBYTES(lWidth*8);   //计算图像每行的字节数
lHeight=DIBHeight(lpDIB);          //获取图像的高度 //计算原图的4个角的坐标
fSrcX1=(float)(-(lWidth-1)/2);
fSrcY1=(float)((lHeight-1)/2);
fSrcX2=(float)((lWidth-1)/2);
fSrcY2=(float)((lHeight-1)/2);
fSrcX3=(float)(-(lWidth-1)/2);
fSrcY3=(float)(-(lHeight-1)/2);
fSrcX4=(float)((lWidth-1)/2);
fSrcY4=(float)(-(lHeight-1)/2); //计算新图的4个角的坐标,(以图像中心为坐标原点)
fDstX1=fCosa*fSrcX1+fSina*fSrcY1;
fDstY1=-fSina*fSrcX1+fCosa*fSrcY1;
fDstX2=fCosa*fSrcX2+fSina*fSrcY2;
fDstY2=-fSina*fSrcX2+fCosa*fSrcY2;
fDstX3=fCosa*fSrcX3+fSina*fSrcY3;
fDstY3=-fSina*fSrcX3+fCosa*fSrcY3;
fDstX4=fCosa*fSrcX4+fSina*fSrcY4;
fDstY4=-fSina*fSrcX4+fCosa*fSrcY4; //计算旋转后的图像实际宽度 lNewWidth=(LONG)(max(fabs(fDstX4-fDstX1),fabs(fDstX3-fDstX2))+0.5);
//计算新图像每行的字节数
lNewLineBytes=WIDTHBYTES(lNewWidth*8); //计算旋转后的图像高度
lNewHeight=(LONG)(max(fabs(fDstY4-fDstY1),fabs(fDstY3-fDstY2))+0.5); //两个常数,这样不用以后每次都计算了
f1=(float)(-0.5*(lNewWidth-1)*fCosa-0.5*(lNewHeight-1)*fSina+0.5*(lWidth-1));
f2=(float)(0.5*(lNewWidth-1)*fSina-0.5*(lNewHeight-1)*fCosa+0.5*(lHeight-1)); //分配内存,以保存新DIB
hDIB=(HDIB)::GlobalAlloc(GHND,lNewLineBytes*lNewHeight+*(LPDWORD)lpDIB+PaletteSize(lpDIB));
if(hDIB==NULL)
{
return NULL;
} lpNewDIB=(char*)::GlobalLock((HGLOBAL)hDIB); //复制DIB信息头和调色板
memcpy(lpNewDIB,lpDIB,*(LPDWORD)lpDIB+PaletteSize(lpDIB)); //找到新DIB像素起始位置
lpNewDIBBits=FindDIBBits(lpNewDIB);
lpbmi=(LPBITMAPINFOHEADER)lpNewDIB;
lpbmc=(LPBITMAPCOREHEADER)lpNewDIB; //更新DIB中图像的高度和宽度
if(IS_WIN30_DIB(lpNewDIB))
{
//对于Windows3.0DIB
lpbmi->biWidth=lNewWidth;
lpbmi->biHeight=lNewHeight;
} else
{
//对于其他格式的DIB
lpbmc->bcWidth=(unsigned short)lNewWidth;
lpbmc->bcHeight=(unsigned short)lNewHeight;
} for(i=0;i<lNewHeight;i++)                  //针对图像每行进行操作
{
for(j=0;j<lNewWidth;j++)                  //针对图像每列进行操作

{
//指向新DIB第i行,第j个像素的指针
//注意此处宽度和高度是新DIB的宽度和高度
lpDst=(char*)lpNewDIBBits+lNewLineBytes*(lNewHeight-1-i)+j;
//该像素在源DIB中的坐标
i0=(LONG)(-((float)j)*fSina+((float)i)*fCosa+f2+0.5);
j0=(LONG)(((float)j)*fCosa+((float)i)*fSina+f1+0.5);
//判断是否在原图范围内
if((j0>=0)&&(j0<lWidth)&&(i0>=0)&&(i0<lHeight))
{
//指向源DIB第i0行,第j0个像素的指针
lpSrc=(char*)lpDIBBits+lLineBytes*(lHeight-1-i0)+j0; //复制像素
*lpDst=*lpSrc;
}
else
{
//对于原图中没有的像素,直接赋值为255
*((unsigned char*)lpDst)=255;
}
}
}
return hDIB;
}
然后再DIBDisplayView.cpp中添加按钮的消息响应函数:void CDIBImageView::OnEditRorate()
{
// TODO: 在此添加命令处理程序代码
//图像旋转
  CDIBImageDoc *pDoc=GetDocument();
  LPSTR lpDIB;                  //指向DIB的指针
  lpDIB=(LPSTR)::GlobalLock((HGLOBAL)pDoc->GetHDIB());
 
  HDIB hNewDIB=NULL;
  BeginWaitCursor();
  hNewDIB=(HDIB)pDoc->GetDibImage()->RotateDIB(lpDIB);
  if(hNewDIB!=NULL)
  {
  pDoc->ReplaceHDIB(hNewDIB);     //替换DIB,同时释放DIB对象
  pDoc->InitDIBData();     //更新DIB大小和调色板
  pDoc->SetModifiedFlag(1);    //设置脏标记
  SetScrollSizes(MM_TEXT,pDoc->GetDocSize());     //重新设置滚动视图大小
  pDoc->UpdateAllViews(NULL);             //更新视图
  }
  else
  {
  MessageBox("分配内存失败!","系统提示",MB_ICONINFORMATION|MB_OK);
  }
  ::GlobalUnlock((HGLOBAL)pDoc->GetHDIB());
  EndWaitCursor();
}
但是,图像显示出来之后,单击图像旋转按钮:首先显示出错对话框:DIBDisplay.exe 中的 0x00405ce2 处未处理的异常: 0xC0000005: 读取位置 0x00000000 时发生访问冲突
同时错误指向DWORD  CDibImage::DIBWidth(LPSTR lpDIB)
{
LPBITMAPINFOHEADER lpbmi;     //指向BITMAPINFO结构的指针
LPBITMAPCOREHEADER lpbmc;     //指向BITMAPCOREINFO结构的指针
lpbmi=(LPBITMAPINFOHEADER)lpDIB;
lpbmc=(LPBITMAPCOREHEADER)lpDIB;
//返回DIB中的图像的宽度
if(IS_WIN30_DIB(lpDIB))
{
return lpbmi->biWidth;                //对于Windows3.0DIB,返回lpbmi->biWidth
}
else
{
return (DWORD) lpbmc->bcWidth;       //对于其他格式的DIB,返回lpbmc->bcWidth
}
}
中的IS_WIN30_DIB(lpDIB),搞了很长时间了,没弄出来!恳请各位的帮助!谢谢!!

解决方案 »

  1.   

    内存违规访问错误.
    检查一下你传入的lpDIB指针是否正确指向图象数据
      

  2.   

    同意这个看法!建议楼主仔细看看IS_WIN30_DIB的传入参数!!
      

  3.   

    楼上的高手们,我一步一步调试调试发现,lpDIB是正确的指向我打开的图像!可是,一运行,程序就有出错了!!请问原因!!
      

  4.   

    lpbmi=(LPBITMAPINFOHEADER)lpNewDIB; 
    一个是DIB对象的指针,一个是LPBITMAPINFOHEADER
    为什么可以这么多呢
      

  5.   

    时间太长了,忘了,可能是自己犯得低级失误。
    我把我定义的给你吧!
    #define IS_WIN30_DIB(lpbi)  ((*(LPDWORD)(lpbi))==sizeof(BITMAPINFOHEADER))