Hello, I was wondering if there is a way to select areas of an image in VB .NET 2008, kind of like how you can select areas of your desktop in Windows Systems(kind of like ).

I've searched and searched for ways to do this, but I can't figure out how to draw something like that along with your mouse. I've thought of just having the user put a form over the wanted object, but I don't think that's a very good idea, and it seemed rather amateurish after I finished making it, so I just deleted it. Thank you for any tips you may have. The only code I'd have to offer is my former idea, I don't think it's necessary, but I'll post it if I have to.

Dani AI

Generated

Two compact, practical patterns are included: a WinForms rubber-band selection that can show a translucent fill and a "marching ants" outline (useful for ), plus a helper to map that selection into image pixels and crop. After that, a small VB.NET routine shows how to POST the cropped image as multipart/form-data (for ). These avoid hacks like laying another form over the image and handle common PictureBox SizeMode cases.

Use the PictureBox MouseDown/Move/Up to build the selection rectangle, draw it in the PictureBox.Paint event, and animate the dashed outline with a Timer by changing the Pen.DashOffset. Call PictureBox.Invalidate() on mouse move and timer ticks so the UI updates.

' Declarations
Private selecting As Boolean = False
Private startPt As Point
Private selRect As Rectangle
Private antsOffset As Single = 0

Private Sub PictureBox1_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs) Handles PictureBox1.MouseDown
    If e.Button = MouseButtons.Left Then
        selecting = True
        startPt = e.Location
        selRect = New Rectangle(e.X, e.Y, 0, 0)
        PictureBox1.Invalidate()
    End If
End Sub

Private Sub PictureBox1_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs) Handles PictureBox1.MouseMove
    If selecting Then
        selRect = New Rectangle(Math.Min(startPt.X, e.X), Math.Min(startPt.Y, e.Y), Math.Abs(e.X - startPt.X), Math.Abs(e.Y - startPt.Y))
        PictureBox1.Invalidate()
    End If
End Sub

Private Sub PictureBox1_MouseUp(ByVal sender As Object, ByVal e As MouseEventArgs) Handles PictureBox1.MouseUp
    If e.Button = MouseButtons.Left Then
        selecting = False
        PictureBox1.Invalidate()
        ' selRect contains selection in PictureBox client coords
    End If
End Sub

Private Sub tmrAnts_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles tmrAnts.Tick
    antsOffset += 1
    If antsOffset > 6 Then antsOffset = 0
    PictureBox1.Invalidate()
End Sub

Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As PaintEventArgs) Handles PictureBox1.Paint
    If selRect.Width > 0 AndAlso selRect.Height > 0 Then
        Using p As New Pen(Color.White)
            p.DashStyle = Drawing2D.DashStyle.Dash
            p.DashPattern = New Single() {4, 2}
            p.DashOffset = antsOffset
            e.Graphics.DrawRectangle(p, selRect)
        End Using
        Using b As New SolidBrush(Color.FromArgb(64, Color.LightBlue))
            e.Graphics.FillRectangle(b, selRect)
        End Using
    End If
End Sub

When the PictureBox uses StretchImage, Zoom, CenterImage, etc., convert the client selection to image pixels before cropping. The helper below handles common SizeMode cases and performs the pixel crop.

Private Function GetImageRectFromSelection(pb As PictureBox, sel As Rectangle) As Rectangle
    If pb.Image Is Nothing Then Return Rectangle.Empty
    Dim imgW = pb.Image.Width, imgH = pb.Image.Height
    Dim pbW = pb.ClientSize.Width, pbH = pb.ClientSize.Height

    Select Case pb.SizeMode
        Case PictureBoxSizeMode.Normal, PictureBoxSizeMode.AutoSize
            Return Rectangle.Intersect(sel, New Rectangle(0, 0, imgW, imgH))
        Case PictureBoxSizeMode.StretchImage
            Dim xr = imgW / CSng(pbW), yr = imgH / CSng(pbH)
            Dim r = New Rectangle(CInt(sel.X * xr), CInt(sel.Y * yr), CInt(sel.Width * xr), CInt(sel.Height * yr))
            Return Rectangle.Intersect(r, New Rectangle(0, 0, imgW, imgH))
        Case PictureBoxSizeMode.Zoom
            Dim ratio = Math.Min(pbW / CSng(imgW), pbH / CSng(imgH))
            Dim dispW = CInt(imgW * ratio), dispH = CInt(imgH * ratio)
            Dim offX = (pbW - dispW) \ 2, offY = (pbH - dispH) \ 2
            Dim x = CInt((sel.X - offX) / ratio), y = CInt((sel.Y - offY) / ratio)
            Dim w = CInt(sel.Width / ratio), h = CInt(sel.Height / ratio)
            Return Rectangle.Intersect(New Rectangle(x, y, w, h), New Rectangle(0, 0, imgW, imgH))
        Case PictureBoxSizeMode.CenterImage
            Dim offX = (pbW - imgW) \ 2, offY = (pbH - imgH) \ 2
            Return Rectangle.Intersect(New Rectangle(sel.X - offX, sel.Y - offY, sel.Width, sel.Height), New Rectangle(0, 0, imgW, imgH))
        Case Else
            Return Rectangle.Empty
    End Select
End Function

Private Function CropImage(orig As Image, rect As Rectangle) As Bitmap
    If orig Is Nothing OrElse rect.Width <= 0 OrElse rect.Height <= 0 Then Return Nothing
    Dim bmp As New Bitmap(rect.Width, rect.Height)
    Using g = Graphics.FromImage(bmp)
        g.DrawImage(orig, New Rectangle(0, 0, rect.Width, rect.Height), rect, GraphicsUnit.Pixel)
    End Using
    Return bmp
End Function

To upload the cropped bitmap as multipart/form-data, build the multipart body with a boundary, write the part headers, the image bytes, and the closing boundary. The snippet below sends a single file part; additional form fields are similar (each gets its own boundary + headers + value).

Public Function UploadImageMultipart(url As String, img As Image, formField As String, fileName As String, Optional mimeType As String = "image/jpeg") As String
    Dim ms As New IO.MemoryStream()
    img.Save(ms, Imaging.ImageFormat.Jpeg)
    Dim fileData() As Byte = ms.ToArray()
    ms.Dispose()

    Dim boundary = "----Boundary" & DateTime.Now.Ticks.ToString("x")
    Dim bBytes() As Byte = Text.Encoding.ASCII.GetBytes("--" & boundary & vbCrLf)
    Dim trailer() As Byte = Text.Encoding.ASCII.GetBytes("--" & boundary & "--" & vbCrLf)
    Dim header = String.Format("Content-Disposition: form-data; name=""{0}""; filename=""{1}""" & vbCrLf & "Content-Type: {2}" & vbCrLf & vbCrLf, formField, fileName, mimeType)
    Dim hBytes() As Byte = Text.Encoding.UTF8.GetBytes(header)
    Dim nl() As Byte = Text.Encoding.ASCII.GetBytes(vbCrLf)

    Dim req = CType(Net.WebRequest.Create(url), Net.HttpWebRequest)
    req.Method = "POST"
    req.ContentType = "multipart/form-data; boundary=" & boundary
    req.KeepAlive = False
    req.ContentLength = bBytes.Length + hBytes.Length + fileData.Length + nl.Length + trailer.Length

    Using rs = req.GetRequestStream()
        rs.Write(bBytes, 0, bBytes.Length)
        rs.Write(hBytes, 0, hBytes.Length)
        rs.Write(fileData, 0, fileData.Length)
        rs.Write(nl, 0, nl.Length)
        rs.Write(trailer, 0, trailer.Length)
    End Using

    Using resp = CType(req.GetResponse(), Net.HttpWebResponse)
        Using sr As New IO.StreamReader(resp.GetResponseStream())
            Return sr.ReadToEnd()
        End Using
    End Using
End Function

Notes and cautions: match the server's expected form field name, set the correct MIME type, and avoid loading very large files entirely in memory for production use (stream in chunks). WebClient.UploadFile can be used as a simpler alternative if saving a temp file is acceptable. Dispose GDI objects and streams to prevent leaks, and marshal cross-thread UI updates with Invoke when using background uploads.

Alright, I solved this problem already, but now I'm trying to figure out how to upload via multipart/form-data POST. I need to have the cropped out image uploaded to a web server that uses multipart. I can't figure out the correct procedure, and I've done it in Python before. Any help for this new problem would be great, thanks.

Alright, I solved this problem already...

I also need something similar that you have because I have a user selecting a portion of the image, that i loaded, that I need to analyze and it works great now but I would like to include the indicator of the selection to make it look more professional and let the user see exactly what he is selecting. Something like the "running ants" would also work.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.