Пример #1
0
 def _get_icon_image(self, id_: int) -> "BuildImage":
     icon = icon_path / f"{id_}.png"
     if icon.exists():
         return BuildImage(int(50 * self.ratio),
                           int(50 * self.ratio),
                           background=icon)
     return BuildImage(
         int(50 * self.ratio),
         int(50 * self.ratio),
         background=f"{icon_path}/box.png",
     )
Пример #2
0
async def download_map_init(semaphore: Semaphore, flag: bool = False):
    global CENTER_POINT, MAP_RATIO
    map_path.mkdir(exist_ok=True, parents=True)
    _map = map_path / "map.png"
    if _map.exists() and os.path.getsize(_map) > 1024 * 1024 * 30:
        _map.unlink()
    try:
        async with aiohttp.ClientSession() as session:
            async with session.get(MAP_URL) as resp:
                if resp.status == 200:
                    data = await resp.json()
                    if data["message"] == "OK":
                        data = json.loads(data["data"]["info"]["detail"])
                        CENTER_POINT = (data["origin"][0], data["origin"][1])
                        if not _map.exists():
                            data = data["slices"]
                            idx = 0
                            for _map_data in data[0]:
                                map_url = _map_data['url']
                                await download_image(
                                    map_url,
                                    f"{map_path}/{idx}.png",
                                    semaphore,
                                    force_flag=flag,
                                )
                                BuildImage(0,
                                           0,
                                           background=f"{map_path}/{idx}.png",
                                           ratio=MAP_RATIO).save()
                                idx += 1
                            _w, h = BuildImage(
                                0, 0, background=f"{map_path}/0.png").size
                            w = _w * len(os.listdir(map_path))
                            map_file = BuildImage(w, h, _w, h, ratio=MAP_RATIO)
                            for i in range(idx):
                                map_file.paste(
                                    BuildImage(
                                        0, 0,
                                        background=f"{map_path}/{i}.png"))
                            map_file.save(f"{map_path}/map.png")
                    else:
                        logger.warning(f'获取原神地图失败 msg: {data["message"]}')
                else:
                    logger.warning(f"获取原神地图失败 code:{resp.status}")
    except TimeoutError:
        logger.warning("下载原神地图数据超时....")
    except Exception as e:
        logger.error(f"下载原神地图数据超时 {type(e)}:{e}")
Пример #3
0
def get_background_height(weapons_imgs: List[str]) -> int:
    height = 0
    for weapons in weapons_imgs:
        height += BuildImage(0, 0, background=weapons).size[1]
    last_weapon = BuildImage(0, 0, background=weapons_imgs[-1])
    w, h = last_weapon.size
    last_weapon.crop((0, 0, w, h - 10))
    last_weapon.save(weapons_imgs[-1])

    return height
def centered_text(img: BuildImage, text: str, add_h: int):
    top_h = img.h - add_h + (img.h / 100)
    bottom_h = img.h - (img.h / 100)
    text_sp = text.split("<|>")
    w, h = img.getsize(text_sp[0])
    if len(text_sp) == 1:
        w = int((img.w - w) / 2)
        h = int(top_h + (bottom_h - top_h - h) / 2)
        img.text((w, h), text_sp[0], (255, 255, 255))
    else:
        br_h = int(top_h + (bottom_h - top_h) / 2)
        w = int((img.w - w) / 2)
        h = int(top_h + (br_h - top_h - h) / 2)
        img.text((w, h), text_sp[0], (255, 255, 255))
        w, h = img.getsize(text_sp[1])
        w = int((img.w - w) / 2)
        h = int(br_h + (bottom_h - br_h - h) / 2)
        img.text((w, h), text_sp[1], (255, 255, 255))
Пример #5
0
    def __init__(
        self,
        resource_name: str,
        center_point: Tuple[int, int],
        deviation: Tuple[int, int] = (25, 51),
        padding: int = 100,
        planning_route: bool = False,
        ratio: float = 1,
    ):
        """
        参数:
            :param resource_name: 资源名称
            :param center_point: 中心点
            :param deviation: 坐标误差
            :param padding: 截图外边距
            :param planning_route: 是否规划最佳线路
            :param ratio: 压缩比率
        """
        self.map = BuildImage(0, 0, background=map_path)
        self.resource_name = resource_name
        self.center_x = center_point[0]
        self.center_y = center_point[1]
        self.deviation = deviation
        self.padding = int(padding * ratio)
        self.planning_route = planning_route
        self.ratio = ratio

        self.deviation = (
            int(self.deviation[0] * ratio),
            int(self.deviation[1] * ratio),
        )

        data = json.load(open(resource_label_file, "r", encoding="utf8"))
        # 资源 id
        self.resource_id = [
            data[x]["id"] for x in data
            if x != "CENTER_POINT" and data[x]["name"] == resource_name
        ][0]
        # 传送锚点 id
        self.teleport_anchor_id = [
            data[x]["id"] for x in data
            if x != "CENTER_POINT" and data[x]["name"] == "传送锚点"
        ][0]
        # 神像 id
        self.teleport_god_id = [
            data[x]["id"] for x in data
            if x != "CENTER_POINT" and data[x]["name"] == "七天神像"
        ][0]
        # 资源坐标
        data = json.load(open(resource_point_file, "r", encoding="utf8"))
        self.resource_point = [
            Resources(
                int((self.center_x + data[x]["x_pos"]) * ratio),
                int((self.center_y + data[x]["y_pos"]) * ratio),
            ) for x in data
            if x != "CENTER_POINT" and data[x]["label_id"] == self.resource_id
        ]
        # 传送锚点坐标
        self.teleport_anchor_point = [
            Resources(
                int((self.center_x + data[x]["x_pos"]) * ratio),
                int((self.center_y + data[x]["y_pos"]) * ratio),
            ) for x in data if x != "CENTER_POINT"
            and data[x]["label_id"] == self.teleport_anchor_id
        ]
        # 神像坐标
        self.teleport_god_point = [
            Resources(
                int((self.center_x + data[x]["x_pos"]) * ratio),
                int((self.center_y + data[x]["y_pos"]) * ratio),
            ) for x in data if x != "CENTER_POINT"
            and data[x]["label_id"] == self.teleport_god_id
        ]
Пример #6
0
class Map:
    """
    原神资源生成类
    """
    def __init__(
        self,
        resource_name: str,
        center_point: Tuple[int, int],
        deviation: Tuple[int, int] = (25, 51),
        padding: int = 100,
        planning_route: bool = False,
        ratio: float = 1,
    ):
        """
        参数:
            :param resource_name: 资源名称
            :param center_point: 中心点
            :param deviation: 坐标误差
            :param padding: 截图外边距
            :param planning_route: 是否规划最佳线路
            :param ratio: 压缩比率
        """
        self.map = BuildImage(0, 0, background=map_path)
        self.resource_name = resource_name
        self.center_x = center_point[0]
        self.center_y = center_point[1]
        self.deviation = deviation
        self.padding = int(padding * ratio)
        self.planning_route = planning_route
        self.ratio = ratio

        self.deviation = (
            int(self.deviation[0] * ratio),
            int(self.deviation[1] * ratio),
        )

        data = json.load(open(resource_label_file, "r", encoding="utf8"))
        # 资源 id
        self.resource_id = [
            data[x]["id"] for x in data
            if x != "CENTER_POINT" and data[x]["name"] == resource_name
        ][0]
        # 传送锚点 id
        self.teleport_anchor_id = [
            data[x]["id"] for x in data
            if x != "CENTER_POINT" and data[x]["name"] == "传送锚点"
        ][0]
        # 神像 id
        self.teleport_god_id = [
            data[x]["id"] for x in data
            if x != "CENTER_POINT" and data[x]["name"] == "七天神像"
        ][0]
        # 资源坐标
        data = json.load(open(resource_point_file, "r", encoding="utf8"))
        self.resource_point = [
            Resources(
                int((self.center_x + data[x]["x_pos"]) * ratio),
                int((self.center_y + data[x]["y_pos"]) * ratio),
            ) for x in data
            if x != "CENTER_POINT" and data[x]["label_id"] == self.resource_id
        ]
        # 传送锚点坐标
        self.teleport_anchor_point = [
            Resources(
                int((self.center_x + data[x]["x_pos"]) * ratio),
                int((self.center_y + data[x]["y_pos"]) * ratio),
            ) for x in data if x != "CENTER_POINT"
            and data[x]["label_id"] == self.teleport_anchor_id
        ]
        # 神像坐标
        self.teleport_god_point = [
            Resources(
                int((self.center_x + data[x]["x_pos"]) * ratio),
                int((self.center_y + data[x]["y_pos"]) * ratio),
            ) for x in data if x != "CENTER_POINT"
            and data[x]["label_id"] == self.teleport_god_id
        ]

    # 将地图上生成资源图标
    def generate_resource_icon_in_map(self) -> int:
        x_list = [x.x for x in self.resource_point]
        y_list = [x.y for x in self.resource_point]
        min_width = min(x_list) - self.padding
        max_width = max(x_list) + self.padding
        min_height = min(y_list) - self.padding
        max_height = max(y_list) + self.padding
        self._generate_transfer_icon(
            (min_width, min_height, max_width, max_height))
        for res in self.resource_point:
            icon = self._get_icon_image(self.resource_id)
            self.map.paste(
                icon, (res.x - self.deviation[0], res.y - self.deviation[1]),
                True)
        if self.planning_route:
            self._generate_best_route()
        self.map.crop((min_width, min_height, max_width, max_height))
        rand = random.randint(1, 10000)
        if not (IMAGE_PATH / "genshin" / "temp").exists():
            os.mkdir(str(IMAGE_PATH / "genshin" / "temp"))
        self.map.save(IMAGE_PATH / "genshin" / "temp" /
                      f"genshin_map_{rand}.png")
        return rand

    # 资源数量
    def get_resource_count(self) -> int:
        return len(self.resource_point)

    # 生成传送锚点和神像
    def _generate_transfer_icon(self, box: Tuple[int, int, int, int]):
        min_width, min_height, max_width, max_height = box
        for resources in [self.teleport_anchor_point, self.teleport_god_point]:
            id_ = (self.teleport_anchor_id if resources
                   == self.teleport_anchor_point else self.teleport_god_id)
            for res in resources:
                if min_width < res.x < max_width and min_height < res.y < max_height:
                    icon = self._get_icon_image(id_)
                    self.map.paste(
                        icon,
                        (res.x - self.deviation[0], res.y - self.deviation[1]),
                        True,
                    )

    # 生成最优路线(说是最优其实就是直线最短)
    def _generate_best_route(self):
        line_points = []
        teleport_list = self.teleport_anchor_point + self.teleport_god_point
        for teleport in teleport_list:
            current_res, res_min_distance = teleport.get_resource_distance(
                self.resource_point)
            current_teleport, teleport_min_distance = current_res.get_resource_distance(
                teleport_list)
            if current_teleport == teleport:
                self.map.line((current_teleport.x, current_teleport.y,
                               current_res.x, current_res.y), (255, 0, 0),
                              width=1)
        is_used_res_points = []
        for res in self.resource_point:
            if res in is_used_res_points:
                continue
            current_teleport, teleport_min_distance = res.get_resource_distance(
                teleport_list)
            current_res, res_min_distance = res.get_resource_distance(
                self.resource_point)
            if teleport_min_distance < res_min_distance:
                self.map.line(
                    (current_teleport.x, current_teleport.y, res.x, res.y),
                    (255, 0, 0),
                    width=1)
            else:
                is_used_res_points.append(current_res)
                self.map.line((current_res.x, current_res.y, res.x, res.y),
                              (255, 0, 0),
                              width=1)
                res_cp = self.resource_point[:]
                res_cp.remove(current_res)
                # for _ in res_cp:
                current_teleport_, teleport_min_distance = res.get_resource_distance(
                    teleport_list)
                current_res, res_min_distance = res.get_resource_distance(
                    res_cp)
                if teleport_min_distance < res_min_distance:
                    self.map.line(
                        (current_teleport.x, current_teleport.y, res.x, res.y),
                        (255, 0, 0),
                        width=1)
                else:
                    self.map.line((current_res.x, current_res.y, res.x, res.y),
                                  (255, 0, 0),
                                  width=1)
                    is_used_res_points.append(current_res)
            is_used_res_points.append(res)

        # resources_route = []
        # # 先连上最近的资源路径
        # for res in self.resource_point:
        #     # 拿到最近的资源
        #     current_res, _ = res.get_resource_distance(
        #         self.resource_point
        #         + self.teleport_anchor_point
        #         + self.teleport_god_point
        #     )
        #     self.map.line(
        #         (current_res.x, current_res.y, res.x, res.y), (255, 0, 0), width=1
        #     )
        # resources_route.append((current_res, res))
        # teleport_list = self.teleport_anchor_point + self.teleport_god_point
        # for res1, res2 in resources_route:
        #     point_list = [x for x in resources_route if res1 in x or res2 in x]
        #     if not list(set(point_list).intersection(set(teleport_list))):
        #         if res1 not in teleport_list and res2 not in teleport_list:
        #             # while True:
        #             #     tmp = [x for x in point_list]
        #             #     break
        #             teleport1, distance1 = res1.get_resource_distance(teleport_list)
        #             teleport2, distance2 = res2.get_resource_distance(teleport_list)
        #             if distance1 > distance2:
        #                 self.map.line(
        #                     (teleport1.x, teleport1.y, res1.x, res1.y),
        #                     (255, 0, 0),
        #                     width=1,
        #                 )
        #             else:
        #                 self.map.line(
        #                     (teleport2.x, teleport2.y, res2.x, res2.y),
        #                     (255, 0, 0),
        #                     width=1,
        #                 )

        # self.map.line(xy, (255, 0, 0), width=3)

    # 获取资源图标
    def _get_icon_image(self, id_: int) -> "BuildImage":
        icon = icon_path / f"{id_}.png"
        if icon.exists():
            return BuildImage(int(50 * self.ratio),
                              int(50 * self.ratio),
                              background=icon)
        return BuildImage(
            int(50 * self.ratio),
            int(50 * self.ratio),
            background=f"{icon_path}/box.png",
        )
Пример #7
0
def gen_icon(icon: str):
    A = BuildImage(0, 0, background=f"{icon_path}/box.png")
    B = BuildImage(0, 0, background=f"{icon_path}/box_alpha.png")
    icon_ = icon_path / f"{icon}"
    icon_img = BuildImage(115, 115, background=icon_)
    icon_img.circle()
    B.paste(icon_img, (17, 10), True)
    B.paste(A, alpha=True)
    B.save(icon)
    logger.info(f"生成图片成功 file:{str(icon)}")
 async def handle(app: Ariadne, message: MessageChain, group: Group,
                  member: Member, content: RegexResult,
                  image: ElementResult):
     msg = content.result.asDisplay()
     img = await image.result.get_bytes()
     msg = await get_translate(msg)
     w2b = BuildImage(0, 0, background=BytesIO(img))
     w2b.convert("L")
     msg_sp = msg.split("<|>")
     w, h = w2b.size
     add_h, font_size = init_h_font_size(h)
     bg = BuildImage(w, h + add_h, color="black", font_size=font_size)
     bg.paste(w2b)
     chinese_msg = formalization_msg(msg)
     if not bg.check_font_size(chinese_msg):
         if len(msg_sp) == 1:
             centered_text(bg, chinese_msg, add_h)
         else:
             centered_text(bg, chinese_msg + "<|>" + msg_sp[1], add_h)
     elif not bg.check_font_size(msg_sp[0]):
         centered_text(bg, msg, add_h)
     else:
         ratio = (bg.getsize(msg_sp[0])[0] + 20) / bg.w
         add_h = add_h * ratio
         bg.resize(ratio)
         centered_text(bg, msg, add_h)
     return MessageItem(
         MessageChain.create([Image(data_bytes=bg.pic2bytes())]),
         QuoteSource())
Пример #9
0
async def i_have_a_friend(app: Ariadne, message: MessageChain, group: Group,
                          member: Member, content: RegexResult,
                          target: ElementResult, dark: RegexResult):
    if content.matched and content.result.asDisplay().strip():
        content = content.result.asDisplay()
        if target.matched:
            target = target.result.target
            member = await app.getMember(group, target)
            if not member:
                await app.sendGroupMessage(group,
                                           MessageChain("获取成员信息失败!"),
                                           quote=message.getFirst(Source))
                return
        else:
            target = member
        if avatar := await get_avatar(target, 160):
            avatar = BuildImage(200, 100, background=BytesIO(avatar))
        else:
            avatar = BuildImage(200, 100, color=(0, 0, 0))
        avatar.circle_new()
        text = BuildImage(300,
                          30,
                          font_size=30,
                          color="white" if not dark.matched else "black")
        text.text((0, 0), member.name, (0, 0, 0) if not dark.matched else
                  (141, 141, 146))
        A = BuildImage(700,
                       150,
                       font_size=25,
                       color="white" if not dark.matched else "black")
        A.paste(avatar, (30, 25), True)
        A.paste(text, (150, 38))
        A.text((150, 85), content.strip(),
               (125, 125, 125) if not dark.matched else (255, 255, 255))
        await app.sendGroupMessage(group,
                                   MessageChain(
                                       [Image(data_bytes=A.pic2bytes())]),
                                   quote=message.getFirst(Source))
Пример #10
0
async def update_image():
    # try:
    if not os.path.exists(str(IMAGE_PATH)):
        os.makedirs(str(IMAGE_PATH))
    for file in os.listdir(str(IMAGE_PATH)):
        os.remove(str(IMAGE_PATH / file))
    browser = await get_browser()
    if not browser:
        raise ValueError("获取browser失败!")
    url = "https://genshin.pub/daily"
    page = await browser.new_page()
    await page.goto(url, wait_until="networkidle", timeout=100000)
    await page.set_viewport_size({"width": 2560, "height": 1080})
    await page.evaluate("""
        document.getElementsByClassName('GSTitleBar_gs_titlebar__2IJqy')[0].remove();
        e = document.getElementsByClassName('GSContainer_gs_container__2FbUz')[0];
        e.setAttribute("style", "height:880px");
    """)
    await page.click("button")
    div = await page.query_selector(".GSContainer_content_box__1sIXz")
    for i, card in enumerate(
            await
            page.query_selector_all(".GSTraitCotainer_trait_section__1f3bc")):
        index = 0
        type_ = "char" if not i else "weapons"
        for x in await card.query_selector_all("xpath=child::*"):
            await x.screenshot(
                path=f"{IMAGE_PATH}/{type_}_{index}.png",
                timeout=100000,
            )
            # 下滑两次
            for _ in range(3):
                await div.press("PageDown")
            index += 1
        # 结束后上滑至顶
        for _ in range(index * 3):
            await div.press("PageUp")
    file_list = os.listdir(str(IMAGE_PATH))
    char_imgs = [
        f"{IMAGE_PATH}/{x}" for x in file_list if x.startswith("char")
    ]
    weapons_imgs = [
        f"{IMAGE_PATH}/{x}" for x in file_list if x.startswith("weapons")
    ]
    char_imgs.sort()
    weapons_imgs.sort()
    height = await asyncio.get_event_loop().run_in_executor(
        None, get_background_height, weapons_imgs)
    background_img = BuildImage(1200, height + 100, color="#f6f2ee")
    current_width = 50
    for imgs in [char_imgs, weapons_imgs]:
        current_height = 20
        for img in imgs:
            x = BuildImage(0, 0, background=img)
            background_img.paste(x, (current_width, current_height))
            current_height += x.size[1]
        current_width += 600
    file_name = str((datetime.now() - timedelta(hours=4)).date())
    background_img.save(f"{IMAGE_PATH}/{file_name}.png")
    await page.close()
    return True