[.Net] Récupérer, Modifier et Travailler avec les pixels et les bitmap
Pour un de mes projets (dont je parlerai plus longuement dans quelques mois), j’ai eu besoin de faire des captures d’écran via une application Dotnet.
Une fois la capture réalisée, j’ai voulu lire et modifier les valeurs RGB de certains pixels.
Certains traitements tels que la mise à jour de nombreux pixels sont coûteux en ressource, c’est pourquoi j’ai fait une petite classe nommée SpeedBitmap. Cette classe permet ainsi d’optimiser certains traitements.
Voici les fonctionnalités de ma classe SpeedBitmap:
- réaliser une capture d’écran
- lire le code RGB d’un pixel
- modifier le code RGB d’un pixel
- bloquer et débloquer un bitmap afin d’optimiser les temps de traitement
Les fonctions de bloquage et débloquage du bitmap sont relativement pratiques si vous avez à effectuer de nombreux traitements sur le bitmap.
Voici ma classe pratique pour travailler avec des screenshots:
Private Class SpeedBitmap
#Region "Properties"
Private pixelBytes() As Byte
Private bmpData As BitmapData
Private Depth As PixelFormat = PixelFormat.Format24bppRgb
Private Width As Integer
#End Region
#Region "Mappage des fonctions Win32"
<DllImport("gdi32.dll", EntryPoint:="DeleteDC")>
Public Shared Function DeleteDC(ByVal hdc As IntPtr) As IntPtr
End Function
<DllImport("gdi32.dll", EntryPoint:="DeleteObject")>
Public Shared Function DeleteObject(ByVal hObject As IntPtr) As IntPtr
End Function
<DllImport("gdi32.dll", EntryPoint:="BitBlt")>
Public Shared Function BitBlt(ByVal hdcDest As IntPtr, ByVal nXDest As Integer, ByVal nYDest As Integer, ByVal nWidth As Integer, _
ByVal nHeight As Integer, ByVal hdcSrc As IntPtr, ByVal nXSrc As Integer, ByVal nYSrc As Integer, ByVal dwRop As Integer) As Boolean
End Function
<DllImport("gdi32.dll", EntryPoint:="CreateCompatibleBitmap")>
Public Shared Function CreateCompatibleBitmap(ByVal hdc As IntPtr, ByVal nWidth As Integer, ByVal nHeight As Integer) As IntPtr
End Function
<DllImport("gdi32.dll", EntryPoint:="CreateCompatibleDC")>
Public Shared Function CreateCompatibleDC(ByVal hdc As IntPtr) As IntPtr
End Function
<DllImport("gdi32.dll", EntryPoint:="SelectObject")>
Public Shared Function SelectObject(ByVal hdc As IntPtr, ByVal hgdiobjBmp As IntPtr) As IntPtr
End Function
<DllImport("user32.dll", EntryPoint:="GetDesktopWindow")>
Public Shared Function GetDesktopWindow() As IntPtr
End Function
<DllImport("user32.dll", EntryPoint:="GetDC")>
Public Shared Function GetDC(ByVal hWnd As IntPtr) As IntPtr
End Function
<DllImport("user32.dll", EntryPoint:="GetSystemMetrics")>
Public Shared Function GetSystemMetrics(ByVal nIndex As Integer) As Integer
End Function
<DllImport("user32.dll", EntryPoint:="ReleaseDC")>
Public Shared Function ReleaseDC(ByVal hWnd As IntPtr, ByVal hDC As IntPtr) As IntPtr
End Function
#End Region
'Fonction qui lock le bitmap
Public Sub LockBitmap(ByVal bm As Bitmap)
' Lock the bitmap data.
Width = bm.Width
Dim bounds As Rectangle = New Rectangle(0, 0, bm.Width, bm.Height)
bmpData = bm.LockBits(bounds, ImageLockMode.ReadWrite, Depth)
' Allocate room for the data.
Dim total_size As Integer = bmpData.Stride * bmpData.Height
ReDim pixelBytes(total_size)
' Copy the data into the g_PixBytes array.
Marshal.Copy(bmpData.Scan0, pixelBytes, 0, total_size)
End Sub
'Fonction qui unlock le bitmap
Public Sub UnlockBitmap(ByVal bm As Bitmap)
' Copy the data back into the bitmap.
Dim total_size As Integer = bmpData.Stride * bmpData.Height
Marshal.Copy(pixelBytes, 0, bmpData.Scan0, total_size)
' Unlock the bitmap.
bm.UnlockBits(bmpData)
' Release resources.
pixelBytes = Nothing
bmpData = Nothing
End Sub
'Fonction qui recupere la couleur d'un pixel
Public Function GetPixel(ByVal x As Integer, ByVal y As Integer) As Color
Dim clr As Color = Color.Empty
'Get color components count
Dim cCount As Integer = 24 \ 8
'Get start index of the specified pixel
Dim i As Integer = ((y * Width) + x) * cCount
If (i > pixelBytes.Length - cCount) Then
Throw New IndexOutOfRangeException()
End If
Dim b As Byte = pixelBytes(i)
Dim g As Byte = pixelBytes(i + 1)
Dim r As Byte = pixelBytes(i + 2)
clr = Color.FromArgb(r, g, b)
Return clr
End Function
'Fonction qui met à jour la couleur pour un pixel
Public Sub SetPixel(ByVal x As Integer, ByVal y As Integer, ByVal clr As Color)
'Get color components count
Dim cCount As Integer = Depth \ 8
'Get start index of the specified pixel
Dim i As Integer = ((y * Width) + x) * cCount
pixelBytes(i) = clr.B
pixelBytes(i + 1) = clr.G
pixelBytes(i + 2) = clr.R
End Sub
'Fonction qui prend un screenshot de votre écran
Public Function Capture() As Bitmap
Dim screenX, screenY As Integer
Dim hBmp As IntPtr
Dim hdcScreen As IntPtr = GetDC(GetDesktopWindow())
Dim hdcCompatible As IntPtr = CreateCompatibleDC(hdcScreen)
screenX = GetSystemMetrics(0)
screenY = GetSystemMetrics(1)
hBmp = CreateCompatibleBitmap(hdcScreen, screenX, screenY)
If (hBmp <> IntPtr.Zero) Then
Dim hOldBmp As IntPtr = SelectObject(hdcCompatible, hBmp)
BitBlt(hdcCompatible, 0, 0, screenX, screenY, hdcScreen, 0, 0, 13369376)
SelectObject(hdcCompatible, hOldBmp)
DeleteDC(hdcCompatible)
ReleaseDC(GetDesktopWindow(), hdcScreen)
Dim bmp As Bitmap = System.Drawing.Image.FromHbitmap(hBmp)
DeleteObject(hBmp)
GC.Collect()
Return bmp
End If
Return Nothing
End Function
End Class