Confirmado es en dependencia del tipo de juego..
Tú mismo lo has dicho. El problema está en como trabaja/renderiza ese juego en específico,
Battlefield 3 (y el resto de juegos que sean similares en ese sentido).
Lo he descargado para probarlo y lo primero que me he dado cuenta es que el juego no puede trabajar a una resolución nativa de 1920x1080px, sino que trabaja en una resolución bastante menor, y entonces cuando juegas en modo fullscreen el juego reescala hasta una resolución mayor. Esto es importante, y es lo que causa que no se pueda obtener una imagen real y al tamaño esperado, por que para reescalar la pantalla se vuelve negra o se queda una imagen estática de la ventana del juego antes de ponerlo en fullscreen. Si el juego trabajase a una resolución nativa igual que la de la pantalla, entonces la imagen al menos se tomaria a pantalla completa.
He probado varios capturadores de pantalla profesionales para intentar confirmar que realmente se trata del juego y no de mi algoritmo. Estos han sido los resultados:
Primero de nada, si estando dentro del juego pulsamos la tecla "Imprimir pantalla" para dejar que Windows tome la captura, este es el resultado:
( Una imagen a 1920x1080. La parte blanca imagino que es la superfie de renderizado que el juego no puede rellenar, al no trabajar a esa resolución. )
Esta imagen fue tomada con
WinSnap, una captura de pantalla con retardo de 10 segundos, estando dentro del juego. Exactamente el mismo resultado que una captura de Windows:
Esta es una imagen tomada con
ElektroKit, el resultado fue exactamente el mismo:
El código utilizado fue este:
Imports System.Drawing.Imaging
Imports Elektro.Application.Types
Imports Elektro.Core.IO.Enums
Imports Elektro.Imaging.Tools
Public NotInheritable Class Form1 : Inherits Form
' Fullscreen capture.
Friend WithEvents HotkeyScreenshotType1 As New Hotkey(HotkeyModifiers.None, Keys.D1)
' BF3 window capture.
Friend WithEvents HotkeyScreenshotType2 As New Hotkey(HotkeyModifiers.None, Keys.D2)
Private Sub HotkeyScreenshotType1_Press(ByVal sender As Object, ByVal e As HotkeyPressEventArgs) _
Handles HotkeyScreenshotType1.Press
Static imgIndex As Integer = 0
Dim path As String = String.Format(".\Fullscreen_{0:00}.png", Interlocked.Increment(imgIndex))
Using screenshot As Image = ImageUtil.TakeScreenshotFromDesktop(includeMouse:=False)
screenshot.Save(path, ImageFormat.Png)
End Using
' Process.Start(path)
End Sub
Private Sub HotkeyScreenshotType2_Press(ByVal sender As Object, ByVal e As HotkeyPressEventArgs) _
Handles HotkeyScreenshotType2.Press
Static imgIndex As Integer = 0
Dim name As String = "bf3"
Dim proc As Process = Process.GetProcessesByName(name).Single()
Dim hwnd As IntPtr = proc.MainWindowHandle
Dim path As String = String.Format(".\{0}_{1:00}.png", name, Interlocked.Increment(imgIndex))
Using screenshot As Image = ImageUtil.TakeScreenshotFromObject(hwnd, includeMouse:=False)
screenshot.Save(path, ImageFormat.Png)
End Using
' Process.Start(path)
End Sub
End Class
No creo que pueda haber una solución "directa" a este tipo de problema. Sabiendo que la resolución nativa de ese juego es 1280x720px, lo único que se me ocurre que puedes hacer es recortar la imagen para eliminar la superficie o canvas blanco, y redimensionar la imagen cortada.
El siguiente código producirá esta imagen a 1920x1080p o la resolución que sea tu pantalla...:
Imports System.Drawing.Imaging
Imports Elektro.Application.Types
Imports Elektro.Core.IO.Enums
Imports Elektro.Imaging.Extensions.Image
Imports Elektro.Imaging.Tools
Public NotInheritable Class Form1 : Inherits Form
Friend WithEvents HotkeyScreenshot As New Hotkey(HotkeyModifiers.None, Keys.D0)
Private Sub HotkeyScreenshot_Press(ByVal sender As Object, ByVal e As HotkeyPressEventArgs) _
Handles HotkeyScreenshot.Press
Static imgIndex As Integer = 0
Dim procName As String = "bf3"
Dim proc As Process = Process.GetProcessesByName(procName).Single()
Dim hwnd As IntPtr = proc.MainWindowHandle
Dim gameRes As New Size(1280, 720)
Dim scr As Screen = Screen.PrimaryScreen
Dim path As String = String.Format(".\{0}_{1:00}.png", procName, Interlocked.Increment(imgIndex))
If (scr.Bounds.Width > gameRes.Width) AndAlso (scr.Bounds.Height > gameRes.Height) Then
Using screenshot As Image = ImageUtil.TakeScreenshotFromRegion(scr.Bounds, includeMouse:=True),
cutted As Image = screenshot.Cut(gameRes.Width, gameRes.Height, 0, 0),
resized As Image = cutted.Resize(scr.Bounds.Size)
resized.Save(path, ImageFormat.Png)
End Using
Else
Using screenshot As Image = ImageUtil.TakeScreenshotFromRegion(scr.Bounds, includeMouse:=True)
screenshot.Save(path, ImageFormat.Png)
End Using
End If
' Process.Start(path)
End Sub
End Class
Pero ese código de nada sirve ya que aun faltaría solucionar otro problema que no he sido capaz de lograr, ni Windows, ni el resto de capturadores profesionales: actualizar la imagen del juego.
Cuando quieras tomar una captura del juego, primero debes minimizar el juego y maximizarlo de nuevo para que se guarde una imagen (estática) del juego en ese preciso momento y la captura tome esa imagen, de lo contrario siempre tomará la misma imagen (si nunca restauraste la ventana del juego entonces no habrá imagen, será una imagen negra o blanca). Al parecer no es posible capturar una imagen real, sino la última imagen del juego cuando lo restauras de esta forma, no se si me explico, pero así es como funciona.
Saludos!