Click here to Skip to main content
Click here to Skip to main content
Go to top

FoxTools Screen Shooter

, 14 Feb 2013
Rate this:
Please Sign up or sign in to vote.
Capture screen, edit, and send images to the Internet.

The window of screen capture

Contents

Introduction

I like the Snipping Tool tool in Windows 7 but it does not allow pixelized image fragments. And... I made it.

The program (FoxTools Screen Shooter) interface is similar to a Snipping Tool, but my program has several special features.

Features:

  • Capturing the screen in one of three modes: free-form, rectangle, full screen.
  • Drawing tools: pen, marker, pixelation, eraser.
  • Send images to FoxTools.ru or ZzWeb.ru.
  • Saving images in graphic formats: PNG, JPG (JPEG), and GIF.
  • Multilingual interface (Russian, English).

This is a complete software. You can use it, it's free. The program is open source and you can modify the code for yourself.

In this article, I will explain how to use the source code. And also I will give answers to some questions that were raised during the creation of a program.

Using the code

I used the development environment Visual Studio 2010. To open the project, use the file FoxTools.Shooter.vbproj.

Opening the Forms on the Design mode you may get an error:

Design mode error

It's normal. You need to build (compile) a project.

When you build (compile) a project you may get an error: FileTracker : error FTK1011: C:\some path\FileTracker FoxTools.Shooter.

FileTracker : error FTK1011

It's not normal, but it's not my fault. Smile | :) Check that the path to a project does not contain spaces.

A program consists of three main forms: Main - the screen capture tool; ScreenContainer - the screen container; Result - the image editor.

For Main form I created a custom ToolStripSplitButton - FoxToolStripSplitButton and a ToolStripMenuItem - FoxToolStripMenuItem.

In the FoxToolStripSplitButton control I created custom Paint method, because necessary to draw a pushed button style.

Protected Overrides Sub OnPaint(e As System.Windows.Forms.PaintEventArgs)
  MyBase.OnPaint(e)
  'draw the pushed button style
  If Me.Pushed Then
    Dim g As Graphics = e.Graphics
    ControlPaint.DrawBorder3D(g, Me.ButtonBounds)
    ControlPaint.DrawBorder3D(g, Me.DropDownButtonBounds)
  End If
End Sub

And also I created Info property for storing help information.

The FoxToolStripMenuItem control contains one extra property - Mode. This property will set the mode screen capture: Full, Window (todo), Rectangle, and Custom.

The ScreenContainer form has a simple code. But note, to debug mode please set False for TopMost property.

Public Sub New(mf As Main, mode As Enums.ScreenMode)
  InitializeComponent()
  '...
  'ATTENTION: comment this line to debug!
  'Me.TopMost = True : _mf.TopMost = True '<<< SET COMMENT HERE
  '...
End Sub

Result form has drawing tools. Now it's: Pen, Marker, Pixelate, and Eraser.

I created custom ToolStripButton - it's FoxToolStripButton, which has one extra property - ShapeType. ShapeType is tool type of drawing.

You can see the variable _shapes in a Result form code. This is collection of shapes. Shape can be added to the collection when a user clicks on the button tool, excluding eraser. All tool buttons has one click handler, is btnShapeType_Click. The variable _shapeType contains information about type of selected shape.

The drawing tools may have config forms. I crated base class for config forms - ConfigShapeForm. Pen tool is ConfigPen, Pixelate tool is ConfigPixelate. Configuration from can be displayed before start drawing (Pen), or after (Pixelate). The variable _shapeConfig contains link to configuration form for current shape.

Drawing starts after clicking the left mouse button on a PictureBox, you can see it in the MouseDown event handler. To add a shape to collection using the AddShape method. For Pixelate type of shape, the item is added to the top of the list. For other types of shapes, a item is added to the bottom of a list.

Shapes is drawing in the DrawShapes method to the Graphics object. The finished image can be generated by GetImage method, or  GetImageBuffer for byte array.

Sending images to Internet created via API.FoxTools.ru. This is my independent project and currently it's only for russian language, sorry. But you can do sending data to your server, without my API. It's easy. You can use my helper class from FoxTools.Lib.dll.

Private Sub CustomSend() 'you can do event handler here
  'need to use a separate thread, otherwise the form freezes
  Dim t As New Thread(AddressOf CustomSend_Start) 'create thread
  t.IsBackground = True 
  t.Start() 'start sending
End Sub

Private Sub CustomSend_Start()
  Using w As New FoxTools.Lib.Net.Web()
    'for proxy
    'w.UseProxy = True
    'w.ProxyIp = "127.0.0.1"
    'w.ProxyPort = 8888
    'w.ProxyCredential = New System.Net.NetworkCredential("username", "password")
    '// --
    w.Method = FoxTools.Lib.Net.Enums.HttpMethod.POST
    w.Url = "http://example.com/upload.php" 'your page
    w.ContentType = "multipart/form-data" 'don't change it
    w.Queries.AddFile("myfile", "test.png", GetImageBuffer(), "image/png") 'add image file
    Dim result As String = w.ExecuteString() 'execute request/sending file
    ShowResultOfSending(result)'show result form (search the method in the Result.vb file)
  End Using
End Sub

Posted file, you can get on a server:

' ASP (.NET)
Request.Files("myfile")
// PHP
$_FILES["myfile"]

You can use FoxTools.Lib.dll for other projects, I don't forbid it. But you do not have permissions for disassemble the library. As for API, you can use it, if you will understand how it works. I created opening API key special for CodeProject members: ID = 13, Access key = e91268b7-1162-4044-9236-7191c8c3b5d2. FoxTools Screen Shooter using other limited Access key, you can see it in the Settings window.

API Key

For this Access key set permissions only on the Screen and the ZzWeb API methods. But the API has many more methods and CodeProject Key has permissions for all this methods. For example, a request for information about the IP address:

Dim myApi As New FoxTools.Lib.Api(13, "e91268b7-1162-4044-9236-7191c8c3b5d2") 
'proxy settings
'myApi.UseProxy = True
'myApi.ProxyAddress = "127.0.0.1"
'myApi.ProxyPort = 8888
'myApi.ProxyCredential = New System.Net.NetworkCredential("username", "password")
'// --
Dim ip As FoxTools.Lib.Objects.Ip = myApi.Ip("171.204.20.75")
Console.WriteLine("Is proxy server: {0}", ip.IsProxy)
If ip.Country IsNot Nothing Then
  Console.WriteLine("Country: {0} ({1})", ip.Country.NameEn, ip.Country.ISO3166A2)
  If ip.City IsNot Nothing Then
    Console.WriteLine("City: {0}", ip.City.NameEn)
    Console.WriteLine("Location: {0} - {1}", ip.City.Latitude, ip.City.Longitude)
  End If
End If

You can see all methods on the http://api.foxtools.ru. But that's another theme.

TODO

This is TODO List for next versions:

  1. Marker is wrong. In the current implementation, the marker color is overlaid, but must mix. I have not idea, how to do it.
  2. Capture windows. I have not idea, how to do it. I tried using Windows API, but without result. I can not get a list of visible windows on the display.
  3. Image resize.
  4. Image print.
  5. Send by Email.
  6. Undo the last changes (Ctrl + Z).
  7. Remove TopMost (ScreenContainer)... What do you think about this?
  8. Add drawing tools.
  9. Your ideas...

Questions and Answers

Screen Capture

Capture screen is very simple. You can get screen via of the same name class.

' get primary screen
Dim s As Screen = Screen.PrimaryScreen
' create bitmap
Dim bmp As New Bitmap(s.Bounds.Width, s.Bounds.Height, PixelFormat.Format32bppArgb)
' create graphics from bitmap
Dim g As Graphics = Graphics.FromImage(bmp)
' copy screen to bitmap
g.CopyFromScreen(s.Bounds.X, s.Bounds.Y, 0, 0, s.Bounds.Size, CopyPixelOperation.SourceCopy)

I used only the primary screen - PrimaryScreen, but a computer can have multiple screens. You can get each screens from AllScreens property.

For Each s As Screen In Screen.AllScreens
  ' create bitmap
  Dim bmp As New Bitmap(s.Bounds.Width, s.Bounds.Height, PixelFormat.Format32bppArgb)
  ' create graphics from bitmap
  Dim g As Graphics = Graphics.FromImage(bmp)
  ' copy screen to bitmap
  g.CopyFromScreen(s.Bounds.X, s.Bounds.Y, 0, 0, s.Bounds.Size, CopyPixelOperation.SourceCopy)
  ' save image
  bmp.Save(String.Format("{0}.png", System.Text.RegularExpressions.Regex.Replace(_
      s.DeviceName, "[^\w\d]+", "")), System.Drawing.Imaging.ImageFormat.Png)
  ' System.Text.RegularExpressions.Regex.Replace(s.DeviceName, "[^\w\d]+", "") - replace bad chars
Next

Rectangle area selection

To implement the selection of a image area, you need to handle mouse events.

Imports System.Drawing.Imaging

Public Class Form1

  Private _bmp As Bitmap
  Private _start As Point?
  Private _end As Point?

  Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    'to avoid flicker
    Me.DoubleBuffered = True
    ' get primary screen
    Dim s As Screen = Screen.PrimaryScreen
    ' create bitmap
    _bmp = New Bitmap(s.Bounds.Width, s.Bounds.Height, PixelFormat.Format32bppArgb)
    ' create graphics from bitmap
    Dim g As Graphics = Graphics.FromImage(_bmp)
    ' copy screen to bitmap
    g.CopyFromScreen(s.Bounds.X, s.Bounds.Y, 0, 0, s.Bounds.Size, CopyPixelOperation.SourceCopy)
  End Sub

  Private Sub Form1_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
    'start selection
    _start = e.Location
    _end = e.Location
    Me.Refresh()
  End Sub

  Private Sub Form1_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
    'selecting
    If _start.HasValue Then
      _end = e.Location
      Me.Refresh()
    End If
  End Sub

  Private Sub Form1_MouseUp(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseUp
    'end selection
    _start = Nothing
    _end = Nothing
    Me.Refresh()
  End Sub

  Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
    Dim g As Graphics = e.Graphics
    'draw image
    g.DrawImage(_bmp, 0, 0)

    'create region
    Dim r As New Region(New Rectangle(0, 0, _bmp.Width, _bmp.Height))

    'highlight the selected area
    If _start.HasValue AndAlso _end.HasValue Then
      Dim p As New Pen(Brushes.Red) 'create pen
      Dim rec As Rectangle = Rectangle.Empty
      Dim x, y, w, h As Integer
      If _end.Value.X - _start.Value.X < 0 Then
        x = _end.Value.X
        w = _start.Value.X - _end.Value.X
      Else
        x = _start.Value.X
        w = _end.Value.X - _start.Value.X
      End If
      If _end.Value.Y - _start.Value.Y < 0 Then
        y = _end.Value.Y
        h = _start.Value.Y - _end.Value.Y
      Else
        y = _start.Value.Y
        h = _end.Value.Y - _start.Value.Y
      End If
      rec = New Rectangle(x, y, w, h)

      If Not rec = Rectangle.Empty Then
        g.DrawRectangle(p, rec) 'rectangle
      End If
    End If
  End Sub

End Class

It is code for Windows Forms application.

Overlay

Overlay - is filling a translucent color image. You can make an overlay using the FillRegion method.

'draw overlay
Dim b As SolidBrush = New SolidBrush(Color.FromArgb(100, Color.White)) 'create brush
g.FillRegion(b, r)

This code should be at end of the Form1_Paint method.

Overlay with hole

To make a hole in the overlay, you must use the Exclude method of Region instance.

If Not rec = Rectangle.Empty Then
  r.Exclude(rec) 'hole
  g.DrawRectangle(p, rec) 'rectangle
End If

Overlay with hole

You can download project file here.

Free-form area selection

Rectangle area selection is simple, but the free-form area selection easier!

Imports System.Drawing.Imaging

Public Class Form1

  Private _bmp As Bitmap
  Private _points As List(Of Point)

  Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    'to avoid flicker
    Me.DoubleBuffered = True
    ' get primary screen
    Dim s As Screen = Screen.PrimaryScreen
    ' create bitmap
    _bmp = New Bitmap(s.Bounds.Width, s.Bounds.Height, PixelFormat.Format32bppArgb)
    ' create graphics from bitmap
    Dim g As Graphics = Graphics.FromImage(_bmp)
    ' copy screen to bitmap
    g.CopyFromScreen(s.Bounds.X, s.Bounds.Y, 0, 0, s.Bounds.Size, CopyPixelOperation.SourceCopy)
  End Sub

  Private Sub Form1_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
    'start selection
    _points = New List(Of Point)
    _points.Add(e.Location)
    Me.Refresh()
  End Sub

  Private Sub Form1_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
    'selecting
    If _points IsNot Nothing Then
      _points.Add(e.Location)
      Me.Refresh()
    End If
  End Sub

  Private Sub Form1_MouseUp(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseUp
    'end selection
    _points = Nothing
    Me.Refresh()
  End Sub

  Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
    Dim g As Graphics = e.Graphics
    'draw image
    g.DrawImage(_bmp, 0, 0)

    'create region
    Dim r As New Region(New Rectangle(0, 0, _bmp.Width, _bmp.Height))

    'highlight the selected area
    If _points IsNot Nothing AndAlso _points.Count > 1 Then
      Dim p As New Pen(Brushes.Red)
      Dim gp As New System.Drawing.Drawing2D.GraphicsPath()
      gp.AddCurve(_points.ToArray())
      'r.Exclude(gp)
      g.DrawPath(p, gp)
    End If

    'draw overlay
    Dim b As SolidBrush = New SolidBrush(Color.FromArgb(100, Color.White)) 'create brush
    g.FillRegion(b, r) 'overlay
  End Sub

End Class

Free-form area selection

You can download project file here.

Pixelization

Pixelization it is a lowering an image resolution for hiding individual fragments or full an image.

To solve this problem, I calculated average color of a pixel and drawn big pixel via FillRectangle method.

Imports System.Drawing.Imaging

Public Class Form1

  Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    Dim tab As New TabControl()
    tab.Dock = DockStyle.Fill
    tab.TabPages.Add("Original")

    Dim pic As New PictureBox() With {.Left = 0, .Top = 0, .Width = 250, .Height = 135}
    'pic.Image = Image.FromFile("logo250x135.gif")
    'download image from server
    pic.Image = Image.FromStream(New System.IO.MemoryStream( _
                                 New System.Net.WebClient().DownloadData(_
                                 "http://s.codeproject.com/App_Themes/Std/Img/logo250x135.gif") _
                                 ))
    tab.TabPages(tab.TabPages.Count - 1).Controls.Add(pic)

    For i As Integer = 1 To 8
      tab.TabPages.Add(String.Format("Pixelate {0}px", i * 4))
      Dim pic2 As New PictureBox() With {.Left = 0, .Top = 0, .Width = 250, .Height = 135}
      pic2.Image = Pixelization(pic.Image, i * 4)
      tab.TabPages(tab.TabPages.Count - 1).Controls.Add(pic2)
    Next

    Me.Controls.Add(tab)
  End Sub

  Private Function Pixelization(img As Bitmap, size As Integer) As Bitmap
    'create result image
    Dim result As New Bitmap(img.Width, img.Height)

    Try
      Dim g2 As Graphics = Graphics.FromImage(result)

      Dim pixWidth As Integer = size
      Dim pixHeight As Integer = size

      If pixWidth > size Then
        pixWidth = img.Width
      End If
      If pixHeight > size Then
        pixHeight = img.Height
      End If

      For x As Integer = 0 To img.Width Step pixWidth

        For y As Integer = 0 To img.Height Step pixHeight

          'get red, green and blue colors
          Dim ir As Integer? = Nothing, ig As Integer? = Nothing, ib As Integer? = Nothing 'set null
          For x2 As Integer = x To x + pixWidth - 1

            If x2 >= img.Width Then Exit For

            For y2 As Integer = y To y + pixHeight - 1

              If y2 >= img.Height Then Exit For

              Dim clr As Color = img.GetPixel(x2, y2)

              If Not ir.HasValue Then
                ir = 0 : ig = 0 : ib = 0
              End If

              ir += clr.R
              ig += clr.G
              ib += clr.B

            Next
          Next
          '//--

          'has color
          If ir.HasValue Then
            'calculate average color of a square
            ir \= pixWidth * pixHeight
            ig \= pixWidth * pixHeight
            ib \= pixWidth * pixHeight

            'big pixel
            g2.FillRectangle(New SolidBrush(Color.FromArgb(255, ir, ig, ib)), x, y, pixWidth, pixHeight)
          End If

        Next
      Next


    Catch ex As Exception
    End Try

    Return result
  End Function

End Class

Pixelization result

You can download project file here.

Epilog

I hope that my program will be useful to you, and I hope the article will help answer some of your questions.

Thanks all for reading this article.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)

Share

About the Author

Alеksey Nemiro
Web Developer Kbyte.Ru
Russian Federation Russian Federation
Web Developer. Writer. Author of the Kbyte.Ru.
I like ASP .NET WebForms/MVC, C#, Visual Basic .NET, T-SQL, JavaScript, HTML, CSS, PHP.
Follow on   Twitter

Comments and Discussions

 
QuestionSorry but why did you use FoxTools?? Pinmember i007-Mar-13 19:30 
AnswerRe: Sorry but why did you use FoxTools?? PinmemberAlеksey Nemiro7-Mar-13 19:46 
GeneralMy vote of 5 PinmemberAlhoot200414-Feb-13 13:02 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140916.1 | Last Updated 14 Feb 2013
Article Copyright 2013 by Alеksey Nemiro
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid