capture-qmai-window.py 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import win32gui
  2. import win32ui
  3. import win32con
  4. from ctypes import windll
  5. from PIL import Image
  6. import time
  7. import sys
  8. TARGET_TITLES = ['青幕AI写作', 'qingmuai', 'qmai', 'com.qingmuai', 'AI 小说创作工作台', 'AI Novel Production Engine', 'Novel Production Engine']
  9. def find_main_window():
  10. candidates = []
  11. def callback(hwnd, extra):
  12. if not win32gui.IsWindowVisible(hwnd):
  13. return
  14. title = win32gui.GetWindowText(hwnd)
  15. cls = win32gui.GetClassName(hwnd)
  16. for t in TARGET_TITLES:
  17. if t.lower() in title.lower() or t.lower() in cls.lower():
  18. rect = win32gui.GetWindowRect(hwnd)
  19. width = rect[2] - rect[0]
  20. height = rect[3] - rect[1]
  21. if width > 200 and height > 200:
  22. candidates.append((hwnd, title, cls, width * height))
  23. break
  24. win32gui.EnumWindows(callback, None)
  25. if not candidates:
  26. return None
  27. # 选择面积最大的窗口
  28. candidates.sort(key=lambda x: x[3], reverse=True)
  29. return candidates[0][0]
  30. def capture_window(hwnd, save_path):
  31. win32gui.ShowWindow(hwnd, win32con.SW_RESTORE)
  32. win32gui.SetForegroundWindow(hwnd)
  33. time.sleep(1.5)
  34. rect = win32gui.GetWindowRect(hwnd)
  35. x, y, x2, y2 = rect
  36. width = x2 - x
  37. height = y2 - y
  38. print(f'Window rect: {rect}, size: {width}x{height}')
  39. if width <= 0 or height <= 0:
  40. print('Invalid window size')
  41. return False
  42. hwndDC = win32gui.GetWindowDC(hwnd)
  43. mfcDC = win32ui.CreateDCFromHandle(hwndDC)
  44. saveDC = mfcDC.CreateCompatibleDC()
  45. saveBitMap = win32ui.CreateBitmap()
  46. saveBitMap.CreateCompatibleBitmap(mfcDC, width, height)
  47. saveDC.SelectObject(saveBitMap)
  48. result = windll.user32.PrintWindow(hwnd, saveDC.GetSafeHdc(), 2)
  49. print('PrintWindow result:', result)
  50. bmpinfo = saveBitMap.GetInfo()
  51. bmpstr = saveBitMap.GetBitmapBits(True)
  52. im = Image.frombuffer(
  53. 'RGB',
  54. (bmpinfo['bmWidth'], bmpinfo['bmHeight']),
  55. bmpstr, 'raw', 'BGRX', 0, 1)
  56. im.save(save_path)
  57. print(f'Saved screenshot to {save_path}')
  58. win32gui.DeleteObject(saveBitMap.GetHandle())
  59. saveDC.DeleteDC()
  60. mfcDC.DeleteDC()
  61. win32gui.ReleaseDC(hwnd, hwndDC)
  62. return True
  63. def main():
  64. hwnd = None
  65. for i in range(30):
  66. hwnd = find_main_window()
  67. print(f'Try {i+1}: hwnd={hwnd}')
  68. if hwnd:
  69. break
  70. time.sleep(1.0)
  71. if hwnd is None:
  72. print('Could not find QMAI main window')
  73. sys.exit(1)
  74. save_path = sys.argv[1] if len(sys.argv) > 1 else r'c:\QMAI_C\QMAI-main\qmai-runtime-screenshot.png'
  75. ok = capture_window(hwnd, save_path)
  76. if not ok:
  77. sys.exit(1)
  78. if __name__ == '__main__':
  79. main()