# ARTEMIS adapter for open-computer-use@1.1.0 (MIT). # Never fall back to CopyFromScreen: an overlapping window is not test evidence. function Capture-WindowPngBase64($bounds, [IntPtr]$hwnd) { if ($hwnd -eq [IntPtr]::Zero) { return $null } if (-not (Test-CapturableFrame $bounds)) { return $null } $bitmap = $null $graphics = $null $stream = $null $hdc = [IntPtr]::Zero try { $frame = Get-CapturableWindowFrame $hwnd if ($null -eq $frame -or $frame.x -ne $bounds.x -or $frame.y -ne $bounds.y -or $frame.width -ne $bounds.width -or $frame.height -ne $bounds.height) { return $null } $bitmap = New-Object System.Drawing.Bitmap ([int][math]::Round($bounds.width)), ([int][math]::Round($bounds.height)) $graphics = [System.Drawing.Graphics]::FromImage($bitmap) $graphics.Clear([System.Drawing.Color]::Black) $hdc = $graphics.GetHdc() # PW_RENDERFULLCONTENT also asks modern applications to render their surface. # The upstream 30-second subprocess budget bounds an unresponsive WM_PRINT. $captured = [OCUWin32]::PrintWindow($hwnd, $hdc, 2) $graphics.ReleaseHdc($hdc) $hdc = [IntPtr]::Zero if (-not $captured) { return $null } $after = Get-CapturableWindowFrame $hwnd if ($null -eq $after -or $after.x -ne $frame.x -or $after.y -ne $frame.y -or $after.width -ne $frame.width -or $after.height -ne $frame.height) { return $null } # Some applications return success without rendering. Reject uniform frames; # a usable UI tree remains available even when a window cannot be captured. $first = $bitmap.GetPixel(0, 0).ToArgb() $hasContent = $false for ($row = 0; $row -lt 17 -and -not $hasContent; $row++) { for ($column = 0; $column -lt 17; $column++) { $x = [int][math]::Floor(($bitmap.Width - 1) * $column / 16) $y = [int][math]::Floor(($bitmap.Height - 1) * $row / 16) if ($bitmap.GetPixel($x, $y).ToArgb() -ne $first) { $hasContent = $true break } } } if (-not $hasContent) { return $null } $stream = New-Object System.IO.MemoryStream $bitmap.Save($stream, [System.Drawing.Imaging.ImageFormat]::Png) return [Convert]::ToBase64String($stream.ToArray()) } catch { return $null } finally { if ($hdc -ne [IntPtr]::Zero -and $null -ne $graphics) { $graphics.ReleaseHdc($hdc) } if ($null -ne $graphics) { $graphics.Dispose() } if ($null -ne $bitmap) { $bitmap.Dispose() } if ($null -ne $stream) { $stream.Dispose() } } }