source: trunk/Snippets/CropImage/ImageCropBox.vb @ 111

Last change on this file since 111 was 111, checked in by roman, 12 years ago
File size: 13.7 KB
Line 
1Imports System.Diagnostics
2Imports System.Drawing
3Imports System.Drawing.Imaging
4Imports System.Drawing.Drawing2D
5
6Public Class ImageCropBox
7    Private Const Spacing As Integer = 2
8    Private Const SpotSize As Integer = 7
9    Private _Image As Bitmap
10    Private _FadeImage As Bitmap
11    Private _MinimalSelectionSize As Size
12    Private _SelectionRectangle As Rectangle
13    Private ClientImageOrigin As Point
14    Private ClientImageExtent As Size
15    Private ClientSelectionRectangle As Rectangle
16    Private BoundaryPenA As Pen
17    Private BoundaryPenB As Pen
18    Private SpotBrush As Brush
19    Private SpotPen As Pen
20    Private DragSpotIndex As Integer ' 0..3 Corner Resize, 4 Body Move
21    Private MouseDownSelection As Rectangle
22    Private MouseDownPosition As Point
23
24    Public Event SelectionRectangleChanged As EventHandler
25    Public Event SelectionDoubleClick As EventHandler
26
27    Public Sub New()
28        ' This call is required by the designer.
29        InitializeComponent()
30        ' Add any initialization after the InitializeComponent() call.
31        _MinimalSelectionSize = New Size(0, 0)
32    End Sub
33
34    Public Property Image As Bitmap
35        Get
36            Image = _Image
37        End Get
38        Set(value As Bitmap)
39            _Image = value
40            If _Image IsNot Nothing Then
41                _SelectionRectangle = New Rectangle(value.Width * 1 / 16, value.Height * 1 / 16, value.Width * 14 / 16, value.Height * 14 / 16)
42                '_SelectionRectangle = New Rectangle(0, 0, value.Width, value.Height)
43                _FadeImage = _Image.Clone
44                Dim FadeImageGraphics As Graphics = Graphics.FromImage(_FadeImage)
45                Dim FadeBrush As HatchBrush = New HatchBrush(HatchStyle.Percent25, Color.FromArgb(0, Color.Black), Color.FromArgb(255, Color.Black))
46                FadeImageGraphics.FillRectangle(FadeBrush, 0, 0, _FadeImage.Width, _FadeImage.Height)
47                FadeImageGraphics.Save()
48            Else
49                _FadeImage = Nothing
50            End If
51            Update()
52        End Set
53    End Property
54    Public Property MinimalSelectionSize As Size
55        Get
56            MinimalSelectionSize = _MinimalSelectionSize
57        End Get
58        Set(value As Size)
59            Debug.Assert(value.Width >= 0 And value.Height >= 0)
60            _MinimalSelectionSize = value
61            ' TODO: Update SelectionRectangle
62        End Set
63    End Property
64    Public Property SelectionRectangle As Rectangle
65        Get
66            SelectionRectangle = _SelectionRectangle
67        End Get
68        Set(value As Rectangle)
69            Dim SelectionRectangleChanged As Boolean = _SelectionRectangle <> value
70            ' TODO: Validate against MinimalSelectionSize
71            _SelectionRectangle = value
72            RaiseEvent SelectionRectangleChanged(Me, New System.EventArgs())
73            If SelectionRectangleChanged Then Invalidate()
74        End Set
75    End Property
76
77    Private Sub ImageCropBox_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
78        BoundaryPenA = New Pen(Brushes.White)
79        BoundaryPenA.Width = 1
80        BoundaryPenA.DashPattern = New Single() {8.0F, 4.0F}
81        BoundaryPenB = New Pen(Brushes.Black)
82        BoundaryPenB.Width = 1
83        BoundaryPenB.DashPattern = New Single() {4.0F, 8.0F}
84        BoundaryPenB.DashOffset = 4
85        SpotBrush = Brushes.Black
86        SpotPen = New Pen(Brushes.White)
87        SpotPen.Width = 1
88        ResizeRedraw = True
89    End Sub
90    Private Sub DrawSpot(Graphics As Graphics, Position As Point)
91        Graphics.FillRectangle(SpotBrush, Position.X - CInt(SpotSize / 2) - 1, Position.Y - CInt(SpotSize / 2) - 1, SpotSize + 2, SpotSize + 2)
92        Graphics.DrawRectangle(SpotPen, Position.X - CInt(SpotSize / 2), Position.Y - CInt(SpotSize / 2), SpotSize, SpotSize)
93    End Sub
94    Private Sub DrawSpot(Graphics As Graphics, PositionX As Integer, PositionY As Integer)
95        DrawSpot(Graphics, New Point(PositionX, PositionY))
96    End Sub
97    Private Sub ImageCropBox_Paint(sender As System.Object, e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
98        If Image Is Nothing Then Exit Sub
99        Dim Extent = Me.Size
100        Extent.Width -= Spacing + SpotSize + Spacing
101        Extent.Height -= Spacing + SpotSize + Spacing
102        If Extent.Width <= 0 Or Extent.Height <= 0 Then Exit Sub
103        Debug.Assert(Image.Width > 0 AndAlso Image.Height > 0)
104        Dim Ratio As Double = Math.Max(Image.Width / Extent.Width, Image.Height / Extent.Height)
105        If Ratio > 1 And Ratio < 1.1 Then Ratio = 1.0 ' Snap to 100%
106        ClientImageExtent.Width = Math.Round(Image.Width / Ratio)
107        ClientImageExtent.Height = Math.Round(Image.Height / Ratio)
108        ClientImageOrigin.X = Spacing + SpotSize / 2 + (Extent.Width - ClientImageExtent.Width) / 2
109        ClientImageOrigin.Y = Spacing + SpotSize / 2 + (Extent.Height - ClientImageExtent.Height) / 2
110        e.Graphics.DrawImage(_FadeImage, ClientImageOrigin.X, ClientImageOrigin.Y, ClientImageExtent.Width, ClientImageExtent.Height)
111        ClientSelectionRectangle.X = Math.Round(_SelectionRectangle.Left / Ratio)
112        ClientSelectionRectangle.Y = Math.Round(_SelectionRectangle.Top / Ratio)
113        ClientSelectionRectangle.Width = Math.Round(_SelectionRectangle.Right / Ratio) - ClientSelectionRectangle.X
114        ClientSelectionRectangle.Height = Math.Round(_SelectionRectangle.Bottom / Ratio) - ClientSelectionRectangle.Y
115        ClientSelectionRectangle.Offset(ClientImageOrigin)
116        e.Graphics.SetClip(ClientSelectionRectangle)
117        e.Graphics.DrawImage(_Image, ClientImageOrigin.X, ClientImageOrigin.Y, ClientImageExtent.Width, ClientImageExtent.Height)
118        e.Graphics.ResetClip()
119        e.Graphics.DrawRectangle(BoundaryPenA, ClientSelectionRectangle)
120        e.Graphics.DrawRectangle(BoundaryPenB, ClientSelectionRectangle)
121        DrawSpot(e.Graphics, ClientSelectionRectangle.Left, ClientSelectionRectangle.Top)
122        DrawSpot(e.Graphics, ClientSelectionRectangle.Right, ClientSelectionRectangle.Top)
123        DrawSpot(e.Graphics, ClientSelectionRectangle.Left, ClientSelectionRectangle.Bottom)
124        DrawSpot(e.Graphics, ClientSelectionRectangle.Right, ClientSelectionRectangle.Bottom)
125    End Sub
126    Private Function SourcePointFromPoint(Position As Point) As Point
127        Dim SourcePosition As Point
128        SourcePosition.X = Math.Round((Position.X - ClientImageOrigin.X) * Image.Width / ClientImageExtent.Width)
129        SourcePosition.Y = Math.Round((Position.Y - ClientImageOrigin.Y) * Image.Height / ClientImageExtent.Height)
130        SourcePointFromPoint = SourcePosition
131    End Function
132    Private Function PointFromSourcePoint(SourcePosition As Point) As Point
133        Dim Position As Point
134        Position.X = ClientImageOrigin.X + Math.Round(SourcePosition.X * ClientImageExtent.Width / Image.Width)
135        Position.Y = ClientImageOrigin.Y + Math.Round(SourcePosition.Y * ClientImageExtent.Height / Image.Height)
136        PointFromSourcePoint = Position
137    End Function
138    Private Function IsSpotPosition(SpotPosition As Point, Position As Point) As Boolean
139        Dim SpotPositionEx = New Rectangle(SpotPosition.X - SpotSize / 2, SpotPosition.Y - SpotSize / 2, SpotSize, SpotSize)
140        IsSpotPosition = SpotPositionEx.Contains(Position)
141    End Function
142    Private Function IsSpotPosition(SpotPositionX As Integer, SpotPositionY As Integer, PositionX As Integer, PositionY As Integer) As Boolean
143        IsSpotPosition = IsSpotPosition(New Point(SpotPositionX, SpotPositionY), New Point(PositionX, PositionY))
144    End Function
145    Private Sub ApplyPointConstraint(ByRef Position As Point, P1 As Point, P2 As Point)
146        If Position.X > P2.X Then Position.X = P2.X
147        If Position.Y > P2.Y Then Position.Y = P2.Y
148        If Position.X < P1.X Then Position.X = P1.X
149        If Position.Y < P1.Y Then Position.Y = P1.Y
150    End Sub
151    Private Sub ImageCropBox_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
152        Dim Position As Point = e.Location, SourcePosition As Point
153        If Capture Then
154            Dim P1 As Point, P2 As Point
155            Select Case DragSpotIndex
156                Case 0 ' Left Top
157                    P1 = ClientImageOrigin
158                    P2 = PointFromSourcePoint(New Point(SelectionRectangle.Right - MinimalSelectionSize.Width, SelectionRectangle.Bottom - MinimalSelectionSize.Height))
159                    ApplyPointConstraint(Position, P1, P2)
160                    SourcePosition = SourcePointFromPoint(Position)
161                    SelectionRectangle = Rectangle.FromLTRB(SourcePosition.X, SourcePosition.Y, SelectionRectangle.Right, SelectionRectangle.Bottom)
162                Case 1 ' Right Top
163                    P1 = New Point(ClientImageOrigin.X + ClientImageExtent.Width, ClientImageOrigin.Y)
164                    P2 = PointFromSourcePoint(New Point(SelectionRectangle.Left + MinimalSelectionSize.Width, SelectionRectangle.Bottom - MinimalSelectionSize.Height))
165                    ApplyPointConstraint(Position, New Point(P2.X, P1.Y), New Point(P1.X, P2.Y))
166                    SourcePosition = SourcePointFromPoint(Position)
167                    SelectionRectangle = Rectangle.FromLTRB(SelectionRectangle.Left, SourcePosition.Y, SourcePosition.X, SelectionRectangle.Bottom)
168                Case 2 ' Left Bottom
169                    P1 = New Point(ClientImageOrigin.X, ClientImageOrigin.Y + ClientImageExtent.Height)
170                    P2 = PointFromSourcePoint(New Point(SelectionRectangle.Right - MinimalSelectionSize.Width, SelectionRectangle.Top + MinimalSelectionSize.Height))
171                    ApplyPointConstraint(Position, New Point(P1.X, P2.Y), New Point(P2.X, P1.Y))
172                    SourcePosition = SourcePointFromPoint(Position)
173                    SelectionRectangle = Rectangle.FromLTRB(SourcePosition.X, SelectionRectangle.Top, SelectionRectangle.Right, SourcePosition.Y)
174                Case 3 ' Right Bottom
175                    P1 = PointFromSourcePoint(New Point(SelectionRectangle.Left + MinimalSelectionSize.Width, SelectionRectangle.Top + MinimalSelectionSize.Height))
176                    P2 = ClientImageOrigin + ClientImageExtent
177                    ApplyPointConstraint(Position, P1, P2)
178                    SourcePosition = SourcePointFromPoint(Position)
179                    SelectionRectangle = Rectangle.FromLTRB(SelectionRectangle.Left, SelectionRectangle.Top, SourcePosition.X, SourcePosition.Y)
180                Case 4 ' Move
181                    Dim Move As Size = SourcePointFromPoint(e.Location) - SourcePointFromPoint(MouseDownPosition)
182                    Dim PreSelection As Rectangle = MouseDownSelection
183                    PreSelection.Offset(Move)
184                    PreSelection.Offset(Math.Max(0, -PreSelection.Left), Math.Max(0, -PreSelection.Top))
185                    PreSelection.Offset(-Math.Max(0, PreSelection.Right - Image.Width), -Math.Max(0, PreSelection.Bottom - Image.Height))
186                    SelectionRectangle = PreSelection
187            End Select
188            Exit Sub
189        Else
190            If IsSpotPosition(ClientSelectionRectangle.Left, ClientSelectionRectangle.Top, e.X, e.Y) Then
191                Cursor = Cursors.SizeNWSE
192                Exit Sub
193            End If
194            If IsSpotPosition(ClientSelectionRectangle.Right, ClientSelectionRectangle.Top, e.X, e.Y) Then
195                Cursor = Cursors.SizeNESW
196                Exit Sub
197            End If
198            If IsSpotPosition(ClientSelectionRectangle.Left, ClientSelectionRectangle.Bottom, e.X, e.Y) Then
199                Cursor = Cursors.SizeNESW
200                Exit Sub
201            End If
202            If IsSpotPosition(ClientSelectionRectangle.Right, ClientSelectionRectangle.Bottom, e.X, e.Y) Then
203                Cursor = Cursors.SizeNWSE
204                Exit Sub
205            End If
206            If ClientSelectionRectangle.Contains(e.Location) Then
207                Cursor = Cursors.SizeAll
208                Exit Sub
209            End If
210        End If
211        Cursor = Cursors.Default
212    End Sub
213    Private Sub ImageCropBox_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
214        DragSpotIndex = -1
215        MouseDownSelection = SelectionRectangle
216        MouseDownPosition = e.Location
217        If IsSpotPosition(ClientSelectionRectangle.Left, ClientSelectionRectangle.Top, e.X, e.Y) Then
218            DragSpotIndex = 0
219            Capture = True
220            Exit Sub
221        End If
222        If IsSpotPosition(ClientSelectionRectangle.Right, ClientSelectionRectangle.Top, e.X, e.Y) Then
223            DragSpotIndex = 1
224            Capture = True
225            Exit Sub
226        End If
227        If IsSpotPosition(ClientSelectionRectangle.Left, ClientSelectionRectangle.Bottom, e.X, e.Y) Then
228            DragSpotIndex = 2
229            Capture = True
230            Exit Sub
231        End If
232        If IsSpotPosition(ClientSelectionRectangle.Right, ClientSelectionRectangle.Bottom, e.X, e.Y) Then
233            DragSpotIndex = 3
234            Capture = True
235            Exit Sub
236        End If
237        If ClientSelectionRectangle.Contains(e.Location) Then
238            DragSpotIndex = 4
239            Capture = True
240            Exit Sub
241        End If
242    End Sub
243    Private Sub ImageCropBox_MouseUp(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseUp
244        Capture = False
245    End Sub
246    Private Sub ImageCropBox_MouseDoubleClick(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDoubleClick
247        If ClientSelectionRectangle.Contains(e.Location) Then
248            RaiseEvent SelectionDoubleClick(Me, New System.EventArgs)
249            Exit Sub
250        End If
251    End Sub
252End Class
Note: See TracBrowser for help on using the repository browser.