|
| 1 | +import logging |
| 2 | +from typing import Dict, Optional, Set, Tuple |
| 3 | + |
| 4 | +from PIL import Image |
| 5 | +from PIL.Image import Image as ImageType |
| 6 | + |
| 7 | +from custom_components.xiaomi_cloud_map_extractor.common.image_handler import ImageHandler |
| 8 | +from custom_components.xiaomi_cloud_map_extractor.const import * |
| 9 | +from custom_components.xiaomi_cloud_map_extractor.types import Colors, ImageConfig |
| 10 | +from custom_components.xiaomi_cloud_map_extractor.ijai.parsing_buffer import ParsingBuffer |
| 11 | + |
| 12 | +_LOGGER = logging.getLogger(__name__) |
| 13 | + |
| 14 | + |
| 15 | +class ImageHandlerIjai(ImageHandler): |
| 16 | + MAP_OUTSIDE = 0x00 |
| 17 | + MAP_WALL = 0xff |
| 18 | + MAP_SCAN = 0x01 |
| 19 | + MAP_NEW_DISCOVERED_AREA = 0x02 |
| 20 | + MAP_ROOM_MIN = 10 |
| 21 | + MAP_ROOM_MAX = 59 |
| 22 | + MAP_SELECTED_ROOM_MIN = 60 |
| 23 | + MAP_SELECTED_ROOM_MAX = 109 |
| 24 | + @staticmethod |
| 25 | + def parse(buf: ParsingBuffer, width: int, height: int, colors: Colors, image_config: ImageConfig, |
| 26 | + draw_cleaned_area: bool) \ |
| 27 | + -> Tuple[ImageType, Dict[int, Tuple[int, int, int, int]], Set[int], Optional[ImageType]]: |
| 28 | + palette = {\ |
| 29 | + ImageHandlerIjai.MAP_OUTSIDE: ImageHandler.__get_color__(COLOR_MAP_OUTSIDE, colors),\ |
| 30 | + ImageHandlerIjai.MAP_WALL: ImageHandler.__get_color__(COLOR_MAP_WALL_V2, colors),\ |
| 31 | + ImageHandlerIjai.MAP_SCAN: ImageHandler.__get_color__(COLOR_SCAN, colors),\ |
| 32 | + ImageHandlerIjai.MAP_NEW_DISCOVERED_AREA: ImageHandler.__get_color__(COLOR_NEW_DISCOVERED_AREA, colors)} |
| 33 | + rooms = {} |
| 34 | + cleaned_areas = set() |
| 35 | + scale = image_config[CONF_SCALE] |
| 36 | + trim_left = int(image_config[CONF_TRIM][CONF_LEFT] * width / 100) |
| 37 | + trim_right = int(image_config[CONF_TRIM][CONF_RIGHT] * width / 100) |
| 38 | + trim_top = int(image_config[CONF_TRIM][CONF_TOP] * height / 100) |
| 39 | + trim_bottom = int(image_config[CONF_TRIM][CONF_BOTTOM] * height / 100) |
| 40 | + trimmed_height = height - trim_top - trim_bottom |
| 41 | + trimmed_width = width - trim_left - trim_right |
| 42 | + if trimmed_width == 0 or trimmed_height == 0: |
| 43 | + return ImageHandler.create_empty_map_image(colors), rooms, cleaned_areas, None |
| 44 | + image = Image.new('RGBA', (trimmed_width, trimmed_height)) |
| 45 | + pixels = image.load() |
| 46 | + cleaned_areas_layer = None |
| 47 | + cleaned_areas_pixels = None |
| 48 | + if draw_cleaned_area: |
| 49 | + cleaned_areas_layer = Image.new('RGBA', (trimmed_width, trimmed_height)) |
| 50 | + cleaned_areas_pixels = cleaned_areas_layer.load() |
| 51 | + _LOGGER.debug(f"trim_bottom = {trim_bottom}, trim_top = {trim_top}, trim_left = {trim_left}, trim_right = {trim_right}") |
| 52 | + buf.skip('trim_bottom', trim_bottom * width) |
| 53 | + unknown_pixels = set() |
| 54 | + _LOGGER.debug(f"buffer: [{buf._offs:#x}] = {buf.peek_uint32("some_int32")}") |
| 55 | + for img_y in range(trimmed_height): |
| 56 | + buf.skip('trim_left', trim_left) |
| 57 | + for img_x in range(trimmed_width): |
| 58 | + pixel_type = buf.get_uint8('pixel') |
| 59 | + x = img_x |
| 60 | + y = trimmed_height - 1 - img_y |
| 61 | + if pixel_type in palette.keys(): |
| 62 | + pixels[x, y] = palette[pixel_type] |
| 63 | + elif ImageHandlerIjai.MAP_ROOM_MIN <= pixel_type <= ImageHandlerIjai.MAP_SELECTED_ROOM_MAX: |
| 64 | + room_x = img_x + trim_left |
| 65 | + room_y = img_y + trim_bottom |
| 66 | + if pixel_type < ImageHandlerIjai.MAP_SELECTED_ROOM_MIN: |
| 67 | + room_number = pixel_type |
| 68 | + else: |
| 69 | + room_number = pixel_type - ImageHandlerIjai.MAP_SELECTED_ROOM_MIN + ImageHandlerIjai.MAP_ROOM_MIN |
| 70 | + cleaned_areas.add(room_number) |
| 71 | + if draw_cleaned_area: |
| 72 | + cleaned_areas_pixels[x, y] = ImageHandler.__get_color__(COLOR_CLEANED_AREA, colors) |
| 73 | + if room_number not in rooms: |
| 74 | + rooms[room_number] = (room_x, room_y, room_x, room_y) |
| 75 | + else: |
| 76 | + rooms[room_number] = (min(rooms[room_number][0], room_x), |
| 77 | + min(rooms[room_number][1], room_y), |
| 78 | + max(rooms[room_number][2], room_x), |
| 79 | + max(rooms[room_number][3], room_y)) |
| 80 | + default = ImageHandler.ROOM_COLORS[room_number % len(ImageHandler.ROOM_COLORS)] |
| 81 | + pixels[x, y] = ImageHandler.__get_color__(f"{COLOR_ROOM_PREFIX}{room_number}", colors, default) |
| 82 | + else: |
| 83 | + pixels[x, y] = ImageHandler.__get_color__(COLOR_UNKNOWN, colors) |
| 84 | + unknown_pixels.add(pixel_type) |
| 85 | + _LOGGER.debug(f"unknown pixel [{x},{y}] = {pixel_type}") |
| 86 | + buf.skip('trim_right', trim_right) |
| 87 | + buf.skip('trim_top', trim_top * width) |
| 88 | + if image_config["scale"] != 1 and trimmed_width != 0 and trimmed_height != 0: |
| 89 | + image = image.resize((int(trimmed_width * scale), int(trimmed_height * scale)), resample=Image.NEAREST) |
| 90 | + if draw_cleaned_area: |
| 91 | + cleaned_areas_layer = cleaned_areas_layer.resize( |
| 92 | + (int(trimmed_width * scale), int(trimmed_height * scale)), resample=Image.NEAREST) |
| 93 | + if len(unknown_pixels) > 0: |
| 94 | + _LOGGER.warning('unknown pixel_types: %s', unknown_pixels) |
| 95 | + return image, rooms, cleaned_areas, cleaned_areas_layer |
0 commit comments