Sample code folder: Chapter 10\LockImage This recipe contains the full code for the LockImage class described in Recipes 10.18, 10.19 through 10.20: 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 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 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 Private Sub UnlockTheImage( ) ' ----- Unlock the memory area. Copy(ImageBuffer, 0, ImageAddress, TotalPixels) Image.UnlockBits(ImageContent) ImageContent = Nothing ReDim ImageBuffer(0) End Sub Public Sub MakeGray( ) ' ----- Make a grayscale version of the image. Dim pixelIndex As Integer Dim onePixel As Integer Dim alphaPart As Integer Dim redPart As Integer Dim greenPart As Integer Dim bluePart As Integer Dim maxColor As Integer Dim minColor As Integer Dim down As Integer Dim across As Integer ' ----- Lock the image for speed. LockTheImage( ) ' ----- Process each pixel in the grid. For down = 0 To BaseImageHeight - 1 For across = 0 To BaseImageWidth - 1 ' ----- Locate the pixel's color. pixelIndex = down * BaseImageWidth + across onePixel = ImageBuffer(pixelIndex) ' ----- Extract the color values. alphaPart = (onePixel >> 24) And &HFF redPart = (onePixel >> 16) And &HFF greenPart = (onePixel >> 8) And &HFF bluePart = onePixel And &HFF ' ----- Get the general color intensity. maxColor = Math.Max(redPart, Math.Max(greenPart, _ bluePart)) minColor = Math.Min(redPart, Math.Min(greenPart, _ bluePart)) onePixel = (maxColor + minColor) \ 2 ' ----- Use a common intensity for all colors. bluePart = onePixel greenPart = onePixel redPart = onePixel ' ----- Set the pixel to the new color. Retain ' the original alpha channel. ImageBuffer(pixelIndex) = (alphaPart << 24) + _ (redPart << 16) + (greenPart << 8) + bluePart Next across Next down ' ----- Finished. Unlock the image. UnlockTheImage( ) End Sub 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 Public Sub EdgeDetect( ) ' ----- Enhance the edges within the image. Dim onePixel As Integer Dim redPart As Integer Dim greenPart As Integer Dim bluePart As Integer Dim maxColor As Integer Dim minColor As Integer Dim down As Integer Dim across As Integer Dim pixArray(,) As Integer Dim target(,) As Integer Dim sumX As Integer Dim sumY As Integer Dim useSum As Integer Dim squareX As Integer Dim squareY As Integer ' ----- Define the Sobel Edge Detector gradient ' matrices. Dim edgeX(,) = {{-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1}} Dim edgeY(,) = {{1, 2, 1}, {0, 0, 0}, {-1, -2, -1}} ' ----- Lock the image for speed. LockTheImage( ) ' ----- Convert the 1D pixel array to 2D for ease ' of processing. ReDim pixArray(BaseImageHeight - 1, BaseImageWidth - 1) For down = 0 To BaseImageHeight - 1 For across = 0 To BaseImageWidth - 1 ' ----- Convert each pixel to a grayscale value. onePixel = ImageBuffer(down * BaseImageWidth + _ across) redPart = (onePixel >> 16) And &HFF greenPart = (onePixel >> 8) And &HFF bluePart = onePixel And &HFF maxColor = Math.Max(redPart, Math.Max(greenPart, _ bluePart)) minColor = Math.Min(redPart, Math.Min(greenPart, _ bluePart)) pixArray(down, across) = (maxColor + minColor) \ 2 Next across Next down ' ----- Results will be placed in a second pixel array. ReDim target(BaseImageHeight - 1, BaseImageWidth - 1) ' ----- Process for edge detection. For down = 0 To BaseImageHeight - 1 For across = 0 To BaseImageWidth - 1 ' ----- Calculate the edge factor. sumX = 0 sumY = 0 If (down = 0) Or _ (down = (BaseImageHeight - 1)) Then ' ----- Ignore true edges. useSum = 0 ElseIf (across = 0) Or _ (across = (BaseImageWidth - 1)) Then ' ---- Ignore true edges. useSum = 0 Else ' ----- Summarize a small square around ' the point. For squareX = -1 To 1 For squareY = -1 To 1 sumX += pixArray(down + squareY, _ across + squareX) * _ edgeX(squareX + 1, squareY + 1) sumY += pixArray(down + squareY, _ across + squareX) * _ edgeY(squareX + 1, squareY + 1) Next squareY Next squareX ' ----- Force the value into the 0 to 255 range. useSum = Math.Abs(sumX) + Math.Abs(sumY) If (useSum < 0) Then useSum = 0 If (useSum > 255) Then useSum = 255 useSum = 255 - useSum ' ----- Save it as a grayscale value in ' the pixel. target(down, across) = useSum + _ (useSum << 8) + (useSum << 16) End If Next across Next down ' ----- Move results back into the locked pixels array. For down = 0 To BaseImageHeight - 1 For across = 0 To BaseImageWidth - 1 ImageBuffer(down * BaseImageWidth + across) = _ target(down, across) Next across Next down ' ----- Finished. Unlock the image. UnlockTheImage( ) End Sub End Class |