1、目录用 vc 怎么画旋转(非线性)椭圆 1VC 旋转图片 .2VC+ TransparentBlt 函数实现 .5vc 图像旋转 7用 vc 怎么画旋转(非线性)椭圆 介绍 窗口中的矩形,带圆角的矩形和椭圆只能由 GDI 在轴向上绘制。假如有人希望在 Windows NT 下绘制旋转或歪斜的图形,他可以使用世界坐标系变换。很不幸的是在 Windows 95/98 下,是没有世界坐标系变换的。作为一个跨平台的解决方案,就需要自己做更多的工作。矩形能由四边形模拟,这样它就能旋转和歪斜了。然而,椭圆又该怎么办呢?基本上有三个选择。 两种选择 使用一个定制的函数来画椭圆。 椭圆的数学模型相对简单,而且
2、还有用于在标准文本中旋转椭圆的修改过的 Bresenham 方程。然而,这种方法必须自己执行光栅操作,这样在绘制宽线时就变得复杂了。这种努力只有在向一个脱离屏幕的表面(比如 DirectDraw)或位图上绘制视才是值得的 用连接的线段来绘制椭圆。 实际的线条可以通过 LineTo(.)或 Polyline(.)图形设备接口调用。你可以自己完成椭圆的近似,或者使用 GDI 的FlattenPath(.) 函数。 使用贝塞尔曲线来近似绘制椭圆。 这里就举例说明这种方法。 用贝塞尔曲线绘制椭圆 使用四条贝塞尔曲线,每条代表原轴向椭圆的 90 度,这样就能获得一个相当近似的椭圆,最大误差只有 0.02
3、7%。这个最大误差相当于长径 3700 的椭圆的误差小于一个像素,这已经超出我们所要求的准确度了。 优点 简单。 只需要有四个 GDI 调用。贝塞尔曲线控制点的计算代价是很小的。 快速 你可以利用现在新的显卡对曲线绘制的硬件支持。在我的系统上,这和调用 GDI 函数 Ellipse(.)绘制椭圆的速度比,如果不是更快,至少也是一样快。 变化 因为贝塞尔曲线在旋转、缩放和平移时是不变的,在对椭圆做同样的变化时就只需要传送控制点。更巧的是,因为在一个三次贝塞尔曲线上的每个点都是控制点的重心组合,在仿射映射中曲线上控制点之间的关系是不变的。 设备无关性 假如想自己把椭圆转化为线段或光栅,那么每次表面
4、的分辨率和设备描述表改变时(例如向一个打印机设备描述表绘制时),就必须重新光栅化。而使用贝塞尔曲线时就不需要这样做。还有一个好处就是椭圆能通过图元文件输出到绘画程序,例如CORELDRAW,在其中可以没有失真的缩放图形。 过程 首先以一个轴向椭圆的外接边界矩形开始(使用一个普通的 GDI 调用)。13 个定义 4 条组成椭圆的贝塞尔曲线的控制点(以下标为 0-12)可使用一个经验常量计算得出。下列代码为 Y 轴正方向向下的的映射模式产生控制点(例如 MM_TEXT)。在 Y 轴正方向向上时,只要如注释中所示,把偏移量设为负值就行了。 / Create points to simulate el
5、lipse using beziers /使用贝塞尔曲线创建点,模拟椭圆 void EllipseToBezier(CRect CSize offset(int)(r.Width() * EToBConst), (int)(r.Height() * EToBConst); / Use the following line instead for mapping systems where +ve Y is upwards / 在 Y 轴正方向向上时,使用下面一行 / CSize offset(int)(r.Width() * EToBConst), -(int)(r.Height() * ET
6、oBConst); CPoint centre(r.left + r.right) / 2, (r.top + r.bottom) / 2); cCtlPt0.x = /-/ cCtlPt1.x = / / cCtlPt11.x = / 2_3_4 / cCtlPt12.x = r.left; / 1 5 / cCtlPt5.x = / | | / cCtlPt6.x = / | | / cCtlPt7.x = r.right; / 0,12 6 / cCtlPt2.x = / | | / cCtlPt10.x = centre.x - offset.cx; / | | / cCtlPt4.x
7、 = / 11 7 / cCtlPt8.x = centre.x + offset.cx; / 10_9_8 / cCtlPt3.x = / / cCtlPt9.x = centre.x; /-* cCtlPt2.y = cCtlPt3.y = cCtlPt4.y = r.top; cCtlPt8.y = cCtlPt9.y = cCtlPt10.y = r.bottom; cCtlPt7.y = cCtlPt11.y = centre.y + offset.cy; cCtlPt1.y = cCtlPt5.y = centre.y - offset.cy; cCtlPt0.y = cCtlPt
8、12.y = cCtlPt6.y = centre.y; 使用与下面近似的代码可完成椭圆的旋转 / LDPoint is an equivalent type to CPoint but with floating point precision / LDPoint 是一个和 CPoint 相当的类型,不过它还具有浮点精度。 void Rotate(double radians, const CPoint double cosAng = cos(radians); LDPoint constTerm( c.x - c.x * cosAng - c.y * sinAng, c.y + c.x *
9、 sinAng - c.y * cosAng); for (int i = Cnt-1; i=0; -i) vCtlPti = (LDPoint( vCtlPti.x * cosAng + vCtlPti.y * sinAng, -vCtlPti.x * sinAng + vCtlPti.y * cosAng) + constTerm).GetCPoint(); / Create Ellipse / 创建椭圆 CRect rect; GetClientRect( CPoint ellipsePts13; EllipseToBezier(ellipseR, ellipsePts); / Rota
10、te / 旋转 Rotate(m_Radians, midPoint, ellipsePts, 13); 填充椭圆 当然,无论是不是旋转,四条贝塞尔曲线只完成了椭圆的轮廓。幸运的是,Win32 路径功能可用于填充椭圆。你只在需要调用PolyBezier(.)来封闭路径。完成的路径是一笔画出的,而且能被让人满意的填充。假如有人觉得还不够,比如更特殊的填充,比如斜线、用户位图或不规则碎片等。这些能由 SelectClipPath(.)来把剪贴区域设置到路径上来而获得。 dc.BeginPath(); dc.PolyBezier(ellipsePts); dc.EndPath(); dc.Strok
11、ePath; / or FillPath(); / or StrokeAndFillPath(); / or PathToRegion(dc.m_hDC); / /或者 FillPath(); /或者 StrokeAndFillPath(); /或者 PathToRegion(dc.m_hDC); 在 Win95/8 下宽的虚线或点椭圆轮廓。Win95/8 只支持实体宽线。然而,虚线或点椭圆轮廓能容易的由一系列贝塞尔曲线段模拟。 VC 旋转图片 2009-07-03 13:58:22| 分类: VC | 标签: |字号大中小 订阅 第一步,你必须知道位图即 BMP 格式的文件的结构. 位图(b
12、mp)文件由以下几个部分组成:1.BITMAPFILEHEADER,它的定义如下 :typedef struct tagBITMAPFILEHEADER WORD bfType; /必须为BMDWORD bfSize; /文件大小WORD bfReserved1; /必须为 0WORD bfReserved2; /必须为 0DWORD bfOffBits; /从 ITMAPFILEHEADER 到存放 bmp 数据的偏移量 BITMAPFILEHEADER, *PBITMAPFILEHEADER; 2.BITMAPINFOHEADER,它的定义如下:typedef struct tagBITM
13、APINFOHEADERDWORD biSize; /此结构的大小,可用 sizeof(BITMAPINFOHEAER)得到LONG biWidth; /位图宽度, 以象素为单位LONG biHeight; /位图高度 ,以象素为单位WORD biPlanes; /必须为 1WORD biBitCount;/位图象素位数, 可为 0,1,4,8,24,32 DWORD biCompression; DWORD biSizeImage; /(仅用于压缩)LONG biXPelsPerMeter; /一米横向象素数LONG biYPelsPerMeter; /一米纵向象素数DWORD biClrU
14、sed;/ (非零用语短颜色表)DWORD biClrImportant; BITMAPINFOHEADER, *PBITMAPINFOHEADER; 由于以上信息可以直接从 MSDN 上查到,所以只做简单介绍, 你可以自己查看 NSDN 帮助,上面有很详细的介绍.3.DIB 位图像.这里放的是真正的位图数据.知道了位图的存放格式,下面我们就可以很容易的把它读如内存.第二步, 读入 bmp 图像LPCTSTR lpszFileName4=“untitled.bmp“; /文件路径CFile file; /用于读取 BMP 文件BITMAPFILEHEADER bfhHeader;/bmp 文件
15、头BITMAPINFOHEADER bmiHeader; /bmp 格式头 LPBITMAPINFO lpBitmapInfo; /bmp 格式具体信息int bmpWidth=0; /图片宽度int bmpHeight = 0; /图片高度 if(!file.Open(lpszFileName,CFile:modeRead)return ; /打开文件file.Read(/读取文件头if(bfhHeader.bfType!=(WORD) (M(x1x2?x2:x1)?(x1x2?x2:x1):x3;minWidth = minWidth0?0:minWidth;minHeight = y3(
16、y1y2?y2:y1)?(y1y2?y2:y1):y3;minHeight = minHeight0?0:minHeight;maxWidth = x3(x1x2?x1:x2)?x3:(x1x2?x1:x2);maxWidth = maxWidth0?maxWidth:0;maxHeight = y3(y1y2?y1:y2)?y3:(y1y2?y1:y2);maxHeight = maxHeight0?maxHeight:0;DstWidth = maxWidth - minWidth;DstHeight = maxHeight - minHeight;dcDst = CreateCompat
17、ibleDC(dcSrc);newBitmap = CreateCompatibleBitmap(dcSrc,(int)DstWidth,(int)DstHeight);SelectObject(dcDst,newBitmap);for( int I = 0 ;I= 0) minWidth = minWidth0?0:minWidth;minHeight = y3(y1y2?y2:y1)?(y1y2?y2:y1):y3;minHeight = minHeight0?0:minHeight;maxWidth = x3(x1x2?x1:x2)?x3:(x1x2?x1:x2);maxWidth =
18、maxWidth0?maxWidth:0;maxHeight = y3(y1y2?y1:y2)?y3:(y1y2?y1:y2);maxHeight = maxHeight0?maxHeight:0;DstWidth = maxWidth - minWidth;DstHeight = maxHeight - minHeight;dcDst = CreateCompatibleDC(dcSrc);newBitmap = CreateCompatibleBitmap(dcSrc,(int)DstWidth,(int)DstHeight);SelectObject(dcDst,newBitmap);r
19、Rect.left = 0;rRect.top = 0;rRect.right = DstWidth;rRect.bottom = DstHeight;FillRect(dcDst,for( i=0 ;i= 0) lpbmi-biHeight = lNewHeight;else/ 对于其它格式的 DIBlpbmc-bcWidth = (unsigned short) lNewWidth;lpbmc-bcHeight = (unsigned short) lNewHeight;/ 针对图像每行进行操作for(i = 0; i = 0) / Bits per pixel int nColors =
20、 lpBmInfo-bmiHeader.biClrUsed ? lpBmInfo-bmiHeader.biClrUsed : 1 bmiHeader.biWidth; int nHeight = lpBmInfo-bmiHeader.biHeight; int nRowBytes = (nWidth * bpp) + 31) / Make sure height is positive and biCompression is BI_RGB or BI_BITFIELDS DWORD compression = lpBmInfo-bmiHeader.biCompression; if( nHe
21、ight bmiHeader.biWidth = w; lpBmInfoResult-bmiHeader.biHeight = h; lpBmInfoResult-bmiHeader.biSizeImage = len; LPBYTE lpDIBBitsResult = FindDIBBits(LPBYTE)lpBmInfoResult); / Get the back color value (index) ZeroMemory( lpDIBBitsResult, len ); DWORD dwBackColor; switch(bpp) case 1: /Monochrome if( cl
22、rBack = RGB(255,255,255) ) memset( lpDIBBitsResult, 0xff, len ); break; case 4: case 8: /Search the color table int i; for(i = 0; i bmiColorsi.rgbBlue = GetBValue(clrBack) else / Bitmap is RGB565 dwBackColor = (GetRValue(clrBack)3) 2) 3) ; break; case 24: case 32: dwBackColor = (DWORD)GetRValue(clrB
23、ack) bmiHeader.biBitCount; / Bits per pixelint nColors = lpBmInfo-bmiHeader.biClrUsed ? lpBmInfo-bmiHeader.biClrUsed : 1 bmiHeader.biWidth;int nHeight = lpBmInfo-bmiHeader.biHeight;int nRowBytes = (nWidth * bpp) + 31) / Make sure height is positive and biCompression is BI_RGB or BI_BITFIELDSDWORD co
24、mpression = lpBmInfo-bmiHeader.biCompression;if( nHeight bmiHeader.biWidth = w;lpBmInfoResult-bmiHeader.biHeight = h;lpBmInfoResult-bmiHeader.biSizeImage = len;LPBYTE lpDIBBitsResult = FindDIBBits(LPBYTE)lpBmInfoResult);/ Get the back color value (index)ZeroMemory( lpDIBBitsResult, len );DWORD dwBac
25、kColor;switch(bpp)case 1: /Monochromeif( clrBack = RGB(255,255,255) )memset( lpDIBBitsResult, 0xff, len );break;case 4:case 8: /Search the color tableint i;for(i = 0; i bmiColorsi.rgbBlue = GetBValue(clrBack)else/ Bitmap is RGB565dwBackColor = (GetRValue(clrBack)3) 2) 3) ;break;case 24:case 32:dwBackColor = (DWORD)GetRValue(clrBack) 16) | (DWORD)GetGValue(clrBack) 8) |(DWORD)GetBValue(clrBack);break;实例:使用: