screenshot.go 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. // ============================================================================
  2. // screenshot.go — 屏幕截图
  3. //
  4. // 截取全部或指定显示器,多屏拼接为一张图,返回 PNG base64 data URI。
  5. // ============================================================================
  6. package main
  7. import (
  8. "bytes"
  9. "encoding/base64"
  10. "fmt"
  11. "image"
  12. "image/png"
  13. "github.com/kbinani/screenshot"
  14. )
  15. // captureScreen 截取整个主屏幕(或指定显示器),返回 PNG 的 base64 数据 URI。
  16. // displayIndex 为显示器索引,-1 表示全部屏幕拼接;越界自动回退主屏。
  17. func captureScreen(displayIndex int) (string, error) {
  18. n := screenshot.NumActiveDisplays()
  19. if n <= 0 {
  20. return "", fmt.Errorf("未检测到可用显示器")
  21. }
  22. bounds := image.Rect(0, 0, 0, 0)
  23. if displayIndex >= 0 && displayIndex < n {
  24. bounds = screenshot.GetDisplayBounds(displayIndex)
  25. } else {
  26. // 全部屏幕拼接:合并所有显示器的边界
  27. for i := 0; i < n; i++ {
  28. b := screenshot.GetDisplayBounds(i)
  29. if b.Min.X < bounds.Min.X {
  30. bounds.Min.X = b.Min.X
  31. }
  32. if b.Min.Y < bounds.Min.Y {
  33. bounds.Min.Y = b.Min.Y
  34. }
  35. if b.Max.X > bounds.Max.X {
  36. bounds.Max.X = b.Max.X
  37. }
  38. if b.Max.Y > bounds.Max.Y {
  39. bounds.Max.Y = b.Max.Y
  40. }
  41. }
  42. }
  43. if bounds.Dx() <= 0 || bounds.Dy() <= 0 {
  44. return "", fmt.Errorf("显示器尺寸无效")
  45. }
  46. img, err := screenshot.CaptureRect(bounds)
  47. if err != nil {
  48. return "", fmt.Errorf("截屏失败: %w", err)
  49. }
  50. var buf bytes.Buffer
  51. if err := png.Encode(&buf, img); err != nil {
  52. return "", fmt.Errorf("编码 PNG 失败: %w", err)
  53. }
  54. return "data:image/png;base64," + base64.StdEncoding.EncodeToString(buf.Bytes()), nil
  55. }