旋转 PictureBox 控件






4.39/5 (14投票s)
一个 PictureBox 控件,允许您旋转图像。
引言
您有多少次想在 PictureBox
控件中旋转图像?我知道我曾多次想这样做。
此控件使旋转图像变得简单。在代码中引用它很容易 - 命名空间是 System.Windows.Forms
,因此您可以轻松地将其声明为 RImage
。
属性/方法
此控件继承了所有内容,因此 PictureBox
拥有的任何属性/方法,此控件都将拥有 - 但是,有几个属性将为您提供内置于控件中的其他选项。
公共属性 ShowThrough() As Boolean
公共属性 Direction() As DirectionEnum
公共属性 Rotation() As Integer
公共属性 TransparentColor() As Color
ShowThrough
将决定图像未使用的空间是否透明并显示其下方的控件。这是通过区域实现的。
Direction
如您所见,它被声明为 DirectionEnum
。这个枚举是为该控件创建的。它告诉控件旋转图像的方向:Clockwise
(顺时针)或 Counter_Clockwise
(逆时针)。
Rotation
是图像的旋转角度。单位是度。范围是 0 到 359;但是,输入超出范围的数字会将其缩放到范围内的相应角度。
TransparentColor
允许您为图像设置透明颜色。演示项目包含一个带有青绿色背景的图像。如果将 TransparentColor
属性设置为青绿色,则图像中的该颜色将变为透明。不幸的是,它不会透过显示下方的控件,只会显示父级的背景颜色。
添加控件
右键单击工具箱的空白区域,然后选择“添加/删除项”。在对话框屏幕的“.NET Framework 组件”选项卡上,选择“浏览”并导航到 DLL 文件。完成此操作后,单击“确定”。
您现在已将控件添加到工具箱。
使用控件
使用该控件很简单。它的工作方式几乎与 PictureBox
控件完全相同。将一个添加到您的窗体,并为其指定一张图片。一旦有了图片,ShowThrough
就会开始工作(如果没有图片,OnPaint
会在设置透明区域之前退出)如果它被设置了。
现在,只需在“属性”窗口的下拉框中设置您的 Direction
,然后输入 Rotation
的角度。
如果您想为图像设置透明颜色 - 您可以使用“属性”窗口中的 TransparentColor
来实现。
工作原理
所有旋转都在 OnPaint
事件中处理。我首先获取图像的当前角点。
Dim bm_in As New Bitmap(MyBase.Image)
Dim wid As Single = bm_in.Width
Dim hgt As Single = bm_in.Height
Dim corners As Point() = { _
New Point(0, 0), _
New Point(wid, 0), _
New Point(0, hgt), _
New Point(wid, hgt)}
接下来,我获取图像的中心 - 我们要围绕其旋转的点 - 并从中减去每个角点。
Dim cx As Single = wid / 2
Dim cy As Single = hgt / 2
Dim i As Long
For i = 0 To 3
corners(i).X -= cx
corners(i).Y -= cy
Next
现在我们需要获取 theta 的正弦和 theta 的余弦 - 这意味着我们需要 theta。
Dim theta As Single = CSng((_degree) * _direction) * PI / 180
Dim sin_theta As Single = Sin(theta)
Dim cos_theta As Single = Cos(theta)
这里是关键所在,我们需要将旋转公式应用于所有角点。
Dim X As Single
Dim Y As Single
For i = 0 To 3
X = corners(i).X
Y = corners(i).Y
corners(i).X = (X * cos_theta) - (Y * sin_theta)
corners(i).Y = (Y * cos_theta) + (X * sin_theta)
Next
好了,我们得到了旋转后的角点,让我们来修复找到旋转点时产生的偏移量,为此我们需要最小的 x 和 y 值。
Dim xmin As Single = corners(0).X
Dim ymin As Single = corners(0).Y
For i = 1 To 3
If xmin > corners(i).X Then xmin = corners(i).X
If ymin > corners(i).Y Then ymin = corners(i).Y
Next
For i = 0 To 3
corners(i).X -= xmin
corners(i).Y -= ymin
Next
现在我们可以实际输出旋转后的图像了,但首先我使用一个函数创建一个基于这些角点的区域。
Dim bm_out As New Bitmap(CInt(-2 * xmin), CInt(-2 * ymin))
Dim bgr As Graphics = Graphics.FromImage(bm_out)
Dim rg As Region = CreateTransRegion(corners)
Dim tp As Point = corners(3)
ReDim Preserve corners(2)
bgr.DrawImage(bm_in, corners)
现在我们在输出缓冲区中得到了旋转后的图像,以及一个区域,允许对不会绘制图像的控件部分进行透明处理。现在来实现 SizeMode
。对于 StretchImage
,我们需要旋转图像的宽度和高度 - 这很容易,因为它存储在 corners
数组的索引 3 处 - 对于拉伸或居中,我们需要一个新的区域。
Dim gr_out As Graphics = pe.Graphics
gr_out.FillRectangle(New SolidBrush(Me.BackColor), 0, 0, Me.Width, Me.Height)
bm_in.MakeTransparent(_transColor)
If _sizemode = PictureBoxSizeMode.StretchImage Then
Dim maxW As Integer = tp.X
Dim maxH As Integer = tp.Y
For t As Integer = 0 To 2
If maxW < corners(t).X Then maxW = corners(t).X
If maxH < corners(t).Y Then maxH = corners(t).Y
Next
'get hscale
Dim hscale As Double = Me.Width / maxW
'get vscale
Dim vscale As Double = Me.Height / maxH
'convert points
corners(0) = New Point(corners(0).X * hscale, corners(0).Y * vscale)
corners(1) = New Point(corners(1).X * hscale, corners(1).Y * vscale)
corners(2) = New Point(corners(2).X * hscale, corners(2).Y * vscale)
gr_out.DrawImage(bm_out, 0, 0, Me.Width, Me.Height)
Dim np(3) As Point
np(0) = corners(0)
np(1) = corners(1)
np(2) = corners(2)
np(3) = New Point(tp.X * hscale, tp.Y * vscale)
rg = CreateTransRegion(np)
对于居中图像,我们不需要那么多。
ElseIf _sizemode = PictureBoxSizeMode.CenterImage Then
Dim wadd As Integer = CInt((Me.Width / 2) - (bm_out.Width / 2))
Dim hadd As Integer = CInt((Me.Height / 2) - (bm_out.Height / 2))
corners(0) = New Point(corners(0).X + wadd, corners(0).Y + hadd)
corners(1) = New Point(corners(1).X + wadd, corners(1).Y + hadd)
corners(2) = New Point(corners(2).X + wadd, corners(2).Y + hadd)
gr_out.DrawImage(bm_in, corners)
Dim np(3) As Point
np(0) = corners(0)
np(1) = corners(1)
np(2) = corners(2)
np(3) = New Point(tp.X + wadd, tp.Y + hadd)
rg = CreateTransRegion(np)
任何其他大小模式都会输出到 0,0,所以我们不需要特别处理,除了 AutoSize
- 它只是将控件的大小更改为与图像匹配。
Else
gr_out.DrawImage(bm_in, corners)
End If
If _sizemode = PictureBoxSizeMode.AutoSize Then
MyBase.Width = bm_out.Width
MyBase.Height = bm_out.Height
End If
我们处理的最后一件事是区域(用于透明度),但如果属性 ShowThrough
被更改为 False
,那么我们需要确保删除任何现有区域。
Me.Region = Nothing
If _showThrough Then
Me.Region = rg
End If
就是这样!当然可以修改它以围绕中心以外的点进行旋转(尽管我还没有尝试过)。