Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

获取屏幕设备大小函数更新 #9

Open
FoxonFires opened this issue Dec 1, 2024 · 0 comments
Open

获取屏幕设备大小函数更新 #9

FoxonFires opened this issue Dec 1, 2024 · 0 comments

Comments

@FoxonFires
Copy link

FoxonFires commented Dec 1, 2024

可在多屏下不同排列方式所计算出的最大屏幕大小范围。比如1|2排列或者2|1排列,以及1/2 1\2,没有对齐在一条线上的情况。
另外也修复了多屏时,坐标空间默认按顺序横向排列的问题。现在可以绘制任意方式排列的多屏了(但其实我只有两块屏幕没有测试过上限)
已解决但还不会提交……先po在这里了…

测试环境Win7,19201080分辨率屏幕2,python 3.6

utils\get_screen_size.py

此模块仅用于获取屏幕设备大小

在App中 size=(self.winfo_screenwidth(), self.winfo_screenheight())
这样的方法获取到的屏幕尺寸大小有问题。win11,机械革命电脑,分辨率超过1080p,屏幕缩放倍数150%
"""
from PIL import ImageGrab
from functools import lru_cache

from service.types import Size
from screeninfo import get_monitors


@lru_cache(1)
def get_main_screen_size() -> Size:
    """
    获取主屏幕的大小
    """
    # return ImageGrab.grab().size
    return get_mutil_screen_size()


# 以后如果涉及多屏幕显示器
# 获取其中任意一个等方法
# 还可以继续在这里添加函数

def get_mutil_screen_size() -> Size:
    total_width = 0
    total_height = 0
    monitors = get_monitors()
    # for index, monitor in enumerate(monitors):
    #     screen_width = monitor.width
    #     screen_height = monitor.height

    #     total_width += screen_width
    #     max_height = max(max_height, screen_height)
    (min_x, min_y, max_x, max_y) = calculate_bounding_box(monitors)
    total_width = max_x - min_x
    total_height = max_y - min_y

    return total_width, total_height


from screeninfo.common import Monitor
import typing
# 计算多块屏幕拼接后的上下左右边界坐标,可以根据每块屏幕的坐标和大小进行计算。
# written by GPT-4o
def calculate_bounding_box(monitors: typing.List[Monitor]):
    # 初始化边界坐标
    min_x = float('inf')
    min_y = float('inf')
    max_x = float('-inf')
    max_y = float('-inf')

    for index, monitor in enumerate(monitors):
        current_min_x = monitor.x
        current_min_y = monitor.y
        current_max_x = monitor.x + monitor.width
        current_max_y = monitor.y + monitor.height

        # 更新全局边界
        min_x = min(min_x, current_min_x)
        min_y = min(min_y, current_min_y)
        max_x = max(max_x, current_max_x)
        max_y = max(max_y, current_max_y)

    return (min_x, min_y, max_x, max_y)

除此之外还对绘图进行了坐标修正,在image_cache.py中增加了两个局部变量

center_x = 0
center_y = 0

对以下函数做了更新:
service\image_cache.py

def _refresh(self):
        """
        将内部的绘制图片重置为一个纯黑色图片
        :return:
        """
        # self._cache = Image.new(
        #     "RGBA",
        #     self._size,
        #     (0, 0, 0, 255),
        # )
        screen_images = []
        screen_info = []
        total_width = 0
        total_height = 0
        # max_height = 0
        monitors = get_monitors()
        # if len(monitors) != 2:
        #     raise ValueError("当前代码仅针对两个屏幕的情况进行颜色区分,实际检测到的屏幕数量不是2个。")

        (min_x, min_y, max_x, max_y) = calculate_bounding_box(monitors)
        total_width = max_x - min_x
        total_height = max_y - min_y

        for index, monitor in enumerate(monitors):
            screen_width = monitor.width
            screen_height = monitor.height

            # total_width += screen_width
            # max_height = max(max_height, screen_height)

            # 创建一个与屏幕分辨率相同的空白图像,模式为RGB,背景填充为黑色
            image = Image.new('RGBA', (screen_width, screen_height), (0, 0, 0))

            # 创建一个ImageDraw对象,用于在图像上绘制边框
            draw = ImageDraw.Draw(image)

            # 白色边框的宽度(可根据需要调整)
            border_width = 1

            # 绘制白色边框,坐标计算是根据边框宽度和图像尺寸来确定四个边的位置
            draw.rectangle([(0, 0), (screen_width - 2, screen_height - 2)],
                           outline=(64, 64, 64), width=border_width)

            screen_images.append(image)

            if monitor.is_primary:      # 记录主屏幕坐标
                global center_x, center_y
                center_x = monitor.x - min_x
                center_y = monitor.y - min_y


            print(f"monitor{index} size ({monitor.width}, {monitor.height}), Location ({monitor.x}, {monitor.y}), is primary:({monitor.is_primary})")

        

        # 创建一个新的空白图像,用于组合所有屏幕图像,大小为总宽度和最大高度,背景也填充为黑色
        combined_image = Image.new('RGBA', (total_width, total_height), (0, 0, 0))
        x_offset = 0
        y_offset = 0
        # for screen_image in screen_images:
        for i in range(0, len(screen_images)):
            screen_image = screen_images[i]

            # combined_image.paste(screen_image, (x_offset, 0))
            # x_offset += screen_image.width

            x_offset = monitors[i].x - min_x
            y_offset = monitors[i].y - min_y
            combined_image.paste(screen_image, (x_offset, y_offset))

        self._cache = combined_image
        #print(f"screen full size ({total_width}, {total_height}), center({center_x}, {center_y}), ")

    def line(self, start: Position, end: Position, color=Colors.Move, width=2):
        """
        Draw a line
        Parameters:
        - start: tuple of the line's start
        - end: tuple of the line's end
        """
        offset = [center_x, center_y]
        start = tuple(a + b for a, b in zip(start, offset))
        end = tuple(a + b for a, b in zip(end, offset))

        start = start
        self._draw_transp_line(xy=[start, end], fill=color, width=width)

    def ellipse(self, x, y, color: Color, radius=10):
        """
        Draw a point at `(x, y)`
        :param x:
        :param y:
        :param color: 注意:有四个值,最后一个值的不透明度最大值是255,不是float的0~1
        :param radius:
        :return: None
        """
        x = x + center_x
        y = y + center_y
        self._draw_transparent_ellipse(
            [(x - radius, y - radius), (x + radius, y + radius)],
            fill=color,
        )

已知问题:在程序运行时更改屏幕分辨率,进行绘图时会因为原有屏幕缓存大小与现有不符而崩溃。可重启程序解决。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant