Visual Basic 2005 Cookbook(c) Solutions for VB 2005 Programmers
Authors: Patrick T. Craig J.
Published year: 2006
Pages: 247-248/400
Buy this book on amazon.com >>

Recipe 10.17. Getting Display Dimensions

Problem

You want to determine the dimensions of the user 's screen at runtime, including both the entire screen and just the working area that doesn't include the task bar. Also, you want to determine the number of monitors on the user's system, the screen dimensions of each, and which screen is currently active.

Solution

Sample code folder: Chapter 10\ScreenInfo

Access this information from the Screen object, which includes an array of objects, one for each screen on the system.

Discussion

The following code extracts information from each Screen object returned by the Screen.AllScreens property, then formats the various data items returned for easy review:

Dim result As New System.Text.StringBuilder
	Dim scanScreen As Screen

	' ----- Include some summary data.
	result.Append("Number of screens: ")
	result.AppendLine(Screen.AllScreens.Length.ToString)
	result.AppendLine( )

	' ----- Process each installed screen.
	For Each scanScreen In Screen.AllScreens
	   result.AppendLine("Device Name: " & _
	      GetTerminatedString(scanScreen.DeviceName))

	   result.AppendLine("Bounds: " & _
	      scanScreen.Bounds.ToString)

	   result.AppendLine("Working Area: " & _
	      scanScreen.WorkingArea.ToString)

	   result.AppendLine("Is Primary: " & _
	      scanScreen.Primary.ToString)

	   result.AppendLine( )
	Next scanScreen

	MsgBox(result.ToString( ))

The device name returned by the scanScreen.DeviceName property may include an old C-style terminating null character (ASCII 0), so you must to add a custom function to extract just the part you need:

Private Function GetTerminatedString( _
	      ByVal sourceString As String) As String
	   ' ----- Return all text of a string up to the first
	   '       null character.
	   Dim index As Integer

	   index = sourceString.IndexOf(vbNullChar)
	   If (index > -1) Then
	      Return sourceString.Substring(0, index)
	   Else
	      Return sourceString
	End If
	    End Function

As shown in Figure 10-25, the system used for testing this code had only one monitor, with a screen resolution of 1680 x 1050 pixels and a working area of 1680 x 990 pixels (the working area is slightly smaller because the task bar was showing along the bottom edge of the screen).

Figure 10-25. The Screen.AllScreens array provides information about any monitors on your system



Recipe 10.18. Speeding Up Image Processing

Problem

You want to implement some image-processing algorithms, and you want the operations to be reasonably fast.

Solution

Sample code folder: Chapter 10\LockImage

Use the InteropServices.Marshal.LockBits() method to prevent the operating system from moving the bitmap data around in memory. This greatly speeds up the program's access to the pixel data. This recipe presents a LockImage class that wraps the LockBits() functionality for easy use.

Discussion

The LockImage class presented in this recipe and the remaining recipes in this chapter contains several image-processing methods . (The full LockImage class is listed in Recipe 10.21.) The goal is to provide enough examples to enable you to design your own image-processing functionality.

The processing function demonstrated in this recipe is Mirror() , a method of the LockImage class that flips an image left and right. To see how it works, create a form with a PictureBox on it that has its Dock property set to Fill and its SizeMode property set to StretchImage . Load a picture into its Image property, and add the following code to its Click event:

Private Sub PictureBox1_Click(ByVal sender As System.Object, _
	      ByVal e As System.EventArgs) Handles PictureBox1.Click
	   ' ----- Mirror-image the bitmap.
	   Dim mirrorIt As New LockImage
	   mirrorIt.Image = PictureBox1.Image
	   mirrorIt.Mirror( )
	   PictureBox1.Image = mirrorIt.Image
	End Sub

When you click on the picture, this procedure creates an instance of the LockImage class, copies the PictureBox 's image to it, calls the Mirror() method to process the image, and then copies the image back into the PictureBox . This is the pattern for using any of the processing methods of the LockImage class.

Now let's look at the portions of the LockImage class that relate to the mirroring processs.

First, you must import the requisite namespaces. InteropServices.Marshal is required for its LockBits() method. The class defines a few class-level variables :

Imports System.Drawing.Imaging
	Imports System.Runtime.InteropServices.Marshal

	Public Class LockImage
	   Private BaseImage As Bitmap
	   Private BaseImageWidth As Integer
	   Private BaseImageHeight As Integer
	   Private TotalPixels As Integer
	   Private ImageAddress As IntPtr
	   Private ImageContent As BitmapData
	   Private ImageBuffer( ) As Integer

The Image property stores or retrieves the bitmap image to be locked and processed :

Public Property Image( ) As Bitmap
	   ' ----- User access to the relevant image.
	   Get
	      Return BaseImage
	   End Get
	   Set(ByVal Value As Bitmap)
	      Dim canvas As Graphics
	      BaseImage = New Bitmap(Value.Width, _
	         Value.Height, Value.PixelFormat)
	      canvas = Graphics.FromImage(BaseImage)
	      canvas.DrawImage(Value, 0, 0, _
	         Value.Width, Value.Height)
	      canvas.Dispose( )
	   End Set
	End Property

The LockTheImage() method provides the important core functionality of this class; with it, you can lock down the bits of the bitmap and present the pixel data in an integer array for efficient processing. All pixel processing in the methods you create, such as the Mirror() method presented later, will process in place the integer pixel data stored in ImageBuffer() .

Each 32-bit integer in ImageBuffer() represents a single pixel. The most significant byte is alpha, the opacity value. The next most significant byte is for red, then green, and the least significant byte is for blue. Each of these four values ranges from to 255 . Two other variables of importance for your image-processing methods are BaseImageWidth and BaseImageHeight . The ImageBuffer() array is one-dimensional, so these two values are required to determine the rectangular layout of the pixels:

Private Sub LockTheImage( )
	   ' ----- Lock the image in memory. How much room
	   '       do we need?
	   BaseImageWidth = BaseImage.Width
	   BaseImageHeight = BaseImage.Height
	   TotalPixels = BaseImageWidth * BaseImageHeight

	   ' ----- Create a stable (locked) area in memory. It
	   '       will store 32-bit color images.
	   ReDim ImageBuffer(TotalPixels - 1)
	   ImageContent = BaseImage.LockBits( _
	      New Rectangle(0, 0, BaseImageWidth, _
	      BaseImageHeight), ImageLockMode.ReadWrite, _
	      PixelFormat.Format32bppRgb)
	   ImageAddress = ImageContent.Scan0

	   ' ----- Associate the buffer and the locked memory.
	   Copy(ImageAddress, ImageBuffer, 0, TotalPixels)
	End Sub

The Mirror() method works by locating the first and last pixels of each row of the image, then swapping the pixels at those locations. The next and previous pixels in the row are swapped next, and this continues until all pixels in the row have been swapped. Here is the code for the Mirror() method:

Public Sub Mirror( )
	   ' ----- Make a left-to-right mirror image.
	   Dim pixelIndex1 As Integer
	   Dim pixelIndex2 As Integer
	   Dim holdPixel As Integer
	   Dim down As Integer

	   ' ----- Lock the image for speed.
	   LockTheImage( )

	   ' ----- Process each row of the image.
	   For down = 0 To BaseImageHeight - 1
	      ' ----- Process each column,  
up to halfway across.
	      pixelIndex1 = down * BaseImageWidth
	      pixelIndex2 = pixelIndex1 + BaseImageWidth - 1
	      Do While pixelIndex1 < pixelIndex2
	         ' ----- Swap two pixels.
	         holdPixel = ImageBuffer(pixelIndex1)
	         ImageBuffer(pixelIndex1) = _
	            ImageBuffer(pixelIndex2)
	         ImageBuffer(pixelIndex2) = holdPixel
	         pixelIndex1 += 1
	         pixelIndex2 -= 1
	      Loop
	   Next down

	   ' ----- Finished. Unlock the image.
	   UnlockTheImage( )
	End Sub

The UnlockTheImage( ) method restores the processed pixel data in ImageBuffer( ) to the bitmap, ready to be retrieved by the code that uses the class:

Private Sub UnlockTheImage( )
	   ' ----- Unlock the memory area.
	   Copy(ImageBuffer, 0, ImageAddress, TotalPixels)
	   Image.UnlockBits(ImageContent)
	   ImageContent = Nothing
	   ReDim ImageBuffer(0)
	End Sub

Figure 10-26 shows a sample picture just before being flipped ; Figure 10-27 shows the picture immediately afterwards.

Figure 10-26. An image about to be flipped horizontally

See Also

Recipe 10.21 includes the full source code for the LockImage class.

Figure 10-27. The same image after the Mirror( ) method has worked its magic


Visual Basic 2005 Cookbook(c) Solutions for VB 2005 Programmers
Authors: Patrick T. Craig J.
Published year: 2006
Pages: 247-248/400
Buy this book on amazon.com >>

Similar books on Amazon