将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),搞了很长时间了,没弄出来!恳请各位的帮助!谢谢!!
{
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),搞了很长时间了,没弄出来!恳请各位的帮助!谢谢!!
检查一下你传入的lpDIB指针是否正确指向图象数据
一个是DIB对象的指针,一个是LPBITMAPINFOHEADER
为什么可以这么多呢
我把我定义的给你吧!
#define IS_WIN30_DIB(lpbi) ((*(LPDWORD)(lpbi))==sizeof(BITMAPINFOHEADER))