def parse(raw_data: bytes, width: int, height: int, colors: Colors, image_config: ImageConfig, room_numbers: List[int]) \ -> Tuple[ImageType, Dict[int, Tuple[int, int, int, int]]]: rooms = {} scale = image_config[CONF_SCALE] trim_left = int(image_config[CONF_TRIM][CONF_LEFT] * width / 100) trim_right = int(image_config[CONF_TRIM][CONF_RIGHT] * width / 100) trim_top = int(image_config[CONF_TRIM][CONF_TOP] * height / 100) trim_bottom = int(image_config[CONF_TRIM][CONF_BOTTOM] * height / 100) trimmed_height = height - trim_top - trim_bottom trimmed_width = width - trim_left - trim_right if trimmed_width == 0 or trimmed_height == 0: return ImageHandler.create_empty_map_image(colors), rooms image = Image.new('RGBA', (trimmed_width, trimmed_height)) pixels = image.load() unknown_pixels = set() for img_y in range(trimmed_height): for img_x in range(trimmed_width): pixel_type = raw_data[img_x + trim_left + width * (img_y + trim_bottom)] x = img_x y = trimmed_height - 1 - img_y if pixel_type == ImageHandlerRoidmi.MAP_OUTSIDE: pixels[x, y] = ImageHandler.__get_color__(COLOR_MAP_OUTSIDE, colors) elif pixel_type == ImageHandlerRoidmi.MAP_WALL: pixels[x, y] = ImageHandler.__get_color__(COLOR_MAP_WALL_V2, colors) elif pixel_type == ImageHandlerRoidmi.MAP_UNKNOWN: pixels[x, y] = ImageHandler.__get_color__(COLOR_UNKNOWN, colors) elif pixel_type in room_numbers: room_x = img_x + trim_left room_y = img_y + trim_bottom room_number = pixel_type if room_number not in rooms: rooms[room_number] = (room_x, room_y, room_x, room_y) else: rooms[room_number] = (min(rooms[room_number][0], room_x), min(rooms[room_number][1], room_y), max(rooms[room_number][2], room_x), max(rooms[room_number][3], room_y)) default = ImageHandler.ROOM_COLORS[room_number % len(ImageHandler.ROOM_COLORS)] pixels[x, y] = ImageHandler.__get_color__(f"{COLOR_ROOM_PREFIX}{room_number}", colors, default) else: pixels[x, y] = ImageHandler.__get_color__(COLOR_UNKNOWN, colors) unknown_pixels.add(pixel_type) if image_config["scale"] != 1 and trimmed_width != 0 and trimmed_height != 0: image = image.resize((int(trimmed_width * scale), int(trimmed_height * scale)), resample=Image.NEAREST) if len(unknown_pixels) > 0: _LOGGER.warning('unknown pixel_types: %s', unknown_pixels) return image, rooms
def parse(buf: ParsingBuffer, width: int, height: int, colors: Colors, image_config: ImageConfig, draw_cleaned_area: bool) \ -> Tuple[ImageType, Dict[int, Tuple[int, int, int, int]], Set[int], Optional[ImageType]]: rooms = {} cleaned_areas = set() scale = image_config[CONF_SCALE] trim_left = int(image_config[CONF_TRIM][CONF_LEFT] * width / 100) trim_right = int(image_config[CONF_TRIM][CONF_RIGHT] * width / 100) trim_top = int(image_config[CONF_TRIM][CONF_TOP] * height / 100) trim_bottom = int(image_config[CONF_TRIM][CONF_BOTTOM] * height / 100) trimmed_height = height - trim_top - trim_bottom trimmed_width = width - trim_left - trim_right if trimmed_width == 0 or trimmed_height == 0: return ImageHandler.create_empty_map_image(colors), rooms, cleaned_areas, None image = Image.new('RGBA', (trimmed_width, trimmed_height)) pixels = image.load() cleaned_areas_layer = None cleaned_areas_pixels = None if draw_cleaned_area: cleaned_areas_layer = Image.new('RGBA', (trimmed_width, trimmed_height)) cleaned_areas_pixels = cleaned_areas_layer.load() buf.skip('trim_bottom', trim_bottom * width) unknown_pixels = set() for img_y in range(trimmed_height): buf.skip('trim_left', trim_left) for img_x in range(trimmed_width): pixel_type = buf.get_uint8('pixel') x = img_x y = trimmed_height - 1 - img_y if pixel_type == ImageHandlerViomi.MAP_OUTSIDE: pixels[x, y] = ImageHandler.__get_color__(COLOR_MAP_OUTSIDE, colors) elif pixel_type == ImageHandlerViomi.MAP_WALL: pixels[x, y] = ImageHandler.__get_color__(COLOR_MAP_WALL_V2, colors) elif pixel_type == ImageHandlerViomi.MAP_SCAN: pixels[x, y] = ImageHandler.__get_color__(COLOR_SCAN, colors) elif pixel_type == ImageHandlerViomi.MAP_NEW_DISCOVERED_AREA: pixels[x, y] = ImageHandler.__get_color__(COLOR_NEW_DISCOVERED_AREA, colors) elif ImageHandlerViomi.MAP_ROOM_MIN <= pixel_type <= ImageHandlerViomi.MAP_SELECTED_ROOM_MAX: room_x = img_x + trim_left room_y = img_y + trim_bottom if pixel_type < ImageHandlerViomi.MAP_SELECTED_ROOM_MIN: room_number = pixel_type else: room_number = pixel_type - ImageHandlerViomi.MAP_SELECTED_ROOM_MIN + ImageHandlerViomi.MAP_ROOM_MIN cleaned_areas.add(room_number) if draw_cleaned_area: cleaned_areas_pixels[x, y] = ImageHandler.__get_color__(COLOR_CLEANED_AREA, colors) if room_number not in rooms: rooms[room_number] = (room_x, room_y, room_x, room_y) else: rooms[room_number] = (min(rooms[room_number][0], room_x), min(rooms[room_number][1], room_y), max(rooms[room_number][2], room_x), max(rooms[room_number][3], room_y)) default = ImageHandler.ROOM_COLORS[room_number % len(ImageHandler.ROOM_COLORS)] pixels[x, y] = ImageHandler.__get_color__(f"{COLOR_ROOM_PREFIX}{room_number}", colors, default) else: pixels[x, y] = ImageHandler.__get_color__(COLOR_UNKNOWN, colors) unknown_pixels.add(pixel_type) buf.skip('trim_right', trim_right) buf.skip('trim_top', trim_top * width) if image_config["scale"] != 1 and trimmed_width != 0 and trimmed_height != 0: image = image.resize((int(trimmed_width * scale), int(trimmed_height * scale)), resample=Image.NEAREST) if draw_cleaned_area: cleaned_areas_layer = cleaned_areas_layer.resize( (int(trimmed_width * scale), int(trimmed_height * scale)), resample=Image.NEAREST) if len(unknown_pixels) > 0: _LOGGER.warning('unknown pixel_types: %s', unknown_pixels) return image, rooms, cleaned_areas, cleaned_areas_layer
def draw_elements(colors, drawables, sizes, map_data: MapData, image_config): scale = float(image_config[CONF_SCALE]) for drawable in drawables: if DRAWABLE_CHARGER == drawable and map_data.charger is not None: ImageHandler.draw_charger(map_data.image, map_data.charger, sizes, colors) if DRAWABLE_VACUUM_POSITION == drawable and map_data.vacuum_position is not None: ImageHandler.draw_vacuum_position(map_data.image, map_data.vacuum_position, sizes, colors) if DRAWABLE_OBSTACLES == drawable and map_data.obstacles is not None: ImageHandler.draw_obstacles(map_data.image, map_data.obstacles, sizes, colors) if DRAWABLE_IGNORED_OBSTACLES == drawable and map_data.ignored_obstacles is not None: ImageHandler.draw_ignored_obstacles(map_data.image, map_data.ignored_obstacles, sizes, colors) if DRAWABLE_OBSTACLES_WITH_PHOTO == drawable and map_data.obstacles_with_photo is not None: ImageHandler.draw_obstacles_with_photo( map_data.image, map_data.obstacles_with_photo, sizes, colors) if DRAWABLE_IGNORED_OBSTACLES_WITH_PHOTO == drawable and map_data.ignored_obstacles_with_photo is not None: ImageHandler.draw_ignored_obstacles_with_photo( map_data.image, map_data.ignored_obstacles_with_photo, sizes, colors) if DRAWABLE_PATH == drawable and map_data.path is not None: ImageHandler.draw_path(map_data.image, map_data.path, colors, scale) if DRAWABLE_GOTO_PATH == drawable and map_data.goto_path is not None: ImageHandler.draw_goto_path(map_data.image, map_data.goto_path, colors, scale) if DRAWABLE_PREDICTED_PATH == drawable and map_data.predicted_path is not None: ImageHandler.draw_predicted_path(map_data.image, map_data.predicted_path, colors, scale) if DRAWABLE_NO_GO_AREAS == drawable and map_data.no_go_areas is not None: ImageHandler.draw_no_go_areas(map_data.image, map_data.no_go_areas, colors) if DRAWABLE_NO_MOPPING_AREAS == drawable and map_data.no_mopping_areas is not None: ImageHandler.draw_no_mopping_areas(map_data.image, map_data.no_mopping_areas, colors) if DRAWABLE_VIRTUAL_WALLS == drawable and map_data.walls is not None: ImageHandler.draw_walls(map_data.image, map_data.walls, colors) if DRAWABLE_ZONES == drawable and map_data.zones is not None: ImageHandler.draw_zones(map_data.image, map_data.zones, colors) if DRAWABLE_CLEANED_AREA == drawable and DRAWABLE_CLEANED_AREA in map_data.image.additional_layers: ImageHandler.draw_layer(map_data.image, drawable)
def create_empty(colors) -> MapData: map_data = MapData() empty_map = ImageHandler.create_empty_map_image( colors, "Vacuum not supported") map_data.image = ImageData.create_empty(empty_map) return map_data
def create_empty(colors, text) -> MapData: map_data = MapData() empty_map = ImageHandler.create_empty_map_image(colors, text) map_data.image = ImageData.create_empty(empty_map) return map_data
def parse(raw_data: bytes, width: int, height: int, colors: Colors, image_config: ImageConfig) -> Tuple[ImageType, dict]: rooms = {} scale = image_config[CONF_SCALE] trim_left = int(image_config[CONF_TRIM][CONF_LEFT] * width / 100) trim_right = int(image_config[CONF_TRIM][CONF_RIGHT] * width / 100) trim_top = int(image_config[CONF_TRIM][CONF_TOP] * height / 100) trim_bottom = int(image_config[CONF_TRIM][CONF_BOTTOM] * height / 100) trimmed_height = height - trim_top - trim_bottom trimmed_width = width - trim_left - trim_right image = Image.new('RGBA', (trimmed_width, trimmed_height)) if width == 0 or height == 0: return ImageHandler.create_empty_map_image(colors), {} pixels = image.load() for img_y in range(trimmed_height): for img_x in range(trimmed_width): pixel_type = raw_data[img_x + trim_left + width * (img_y + trim_bottom)] x = img_x y = trimmed_height - img_y - 1 if pixel_type == ImageHandlerXiaomi.MAP_OUTSIDE: pixels[x, y] = ImageHandler.__get_color__( COLOR_MAP_OUTSIDE, colors) elif pixel_type == ImageHandlerXiaomi.MAP_WALL: pixels[x, y] = ImageHandler.__get_color__( COLOR_MAP_WALL, colors) elif pixel_type == ImageHandlerXiaomi.MAP_INSIDE: pixels[x, y] = ImageHandler.__get_color__( COLOR_MAP_INSIDE, colors) elif pixel_type == ImageHandlerXiaomi.MAP_SCAN: pixels[x, y] = ImageHandler.__get_color__(COLOR_SCAN, colors) else: obstacle = pixel_type & 0x07 if obstacle == 0: pixels[x, y] = ImageHandler.__get_color__( COLOR_GREY_WALL, colors) elif obstacle == 1: pixels[x, y] = ImageHandler.__get_color__( COLOR_MAP_WALL_V2, colors) elif obstacle == 7: room_number = (pixel_type & 0xFF) >> 3 room_x = img_x + trim_left room_y = img_y + trim_bottom if room_number not in rooms: rooms[room_number] = (room_x, room_y, room_x, room_y) else: rooms[room_number] = (min(rooms[room_number][0], room_x), min(rooms[room_number][1], room_y), max(rooms[room_number][2], room_x), max(rooms[room_number][3], room_y)) default = ImageHandler.ROOM_COLORS[room_number >> 1] pixels[x, y] = ImageHandler.__get_color__( f"{COLOR_ROOM_PREFIX}{room_number}", colors, default) else: pixels[x, y] = ImageHandler.__get_color__( COLOR_UNKNOWN, colors) if image_config["scale"] != 1 and width != 0 and height != 0: image = image.resize( (int(trimmed_width * scale), int(trimmed_height * scale)), resample=Image.NEAREST) return image, rooms
def parse(raw_data: bytes, header, colors, image_config, map_data_type: str) -> Tuple[ImageType, Dict[int, Room]]: scale = image_config[CONF_SCALE] trim_left = int(image_config[CONF_TRIM][CONF_LEFT] * header.image_width / 100) trim_right = int(image_config[CONF_TRIM][CONF_RIGHT] * header.image_width / 100) trim_top = int(image_config[CONF_TRIM][CONF_TOP] * header.image_height / 100) trim_bottom = int(image_config[CONF_TRIM][CONF_BOTTOM] * header.image_height / 100) trimmed_height = header.image_height - trim_top - trim_bottom trimmed_width = header.image_width - trim_left - trim_right image = Image.new('RGBA', (trimmed_width, trimmed_height)) if header.image_width == 0 or header.image_height == 0: return ImageHandler.create_empty_map_image(colors), {} pixels = image.load() rooms = {} for img_y in range(trimmed_height): for img_x in range(trimmed_width): x = img_x y = trimmed_height - img_y - 1 room_x = img_x + trim_left room_y = img_y + trim_bottom # TODO : use MapDataParserDreame.MapDataTypes enum if map_data_type == "regular": px = raw_data[img_x + trim_left + header.image_width * (img_y + trim_bottom)] segment_id = px >> 2 if 0 < segment_id < 62: if segment_id not in rooms: rooms[segment_id] = Room(segment_id, room_x, room_y, room_x, room_y) rooms[segment_id] = Room( segment_id, min(rooms[segment_id].x0, room_x), min(rooms[segment_id].y0, room_y), max(rooms[segment_id].x1, room_x), max(rooms[segment_id].y1, room_y)) default = ImageHandler.ROOM_COLORS[segment_id >> 1] pixels[x, y] = ImageHandler.__get_color__( f"{COLOR_ROOM_PREFIX}{segment_id}", colors, default) else: masked_px = px & 0b00000011 if masked_px == ImageHandlerDreame.PixelTypes.NONE: pixels[x, y] = ImageHandler.__get_color__( COLOR_MAP_OUTSIDE, colors) elif masked_px == ImageHandlerDreame.PixelTypes.FLOOR: pixels[x, y] = ImageHandler.__get_color__( COLOR_MAP_INSIDE, colors) elif masked_px == ImageHandlerDreame.PixelTypes.WALL: pixels[x, y] = ImageHandler.__get_color__( COLOR_MAP_WALL, colors) else: _LOGGER.warning(f'unhandled pixel type: {px}') elif map_data_type == "rism": px = raw_data[img_x + trim_left + header.image_width * (img_y + trim_bottom)] segment_id = px & 0b01111111 wall_flag = px >> 7 if wall_flag: pixels[x, y] = ImageHandler.__get_color__( COLOR_MAP_WALL, colors) elif segment_id > 0: if segment_id not in rooms: rooms[segment_id] = Room(segment_id, room_x, room_y, room_x, room_y) rooms[segment_id] = Room( segment_id, min(rooms[segment_id].x0, room_x), min(rooms[segment_id].y0, room_y), max(rooms[segment_id].x1, room_x), max(rooms[segment_id].y1, room_y)) default = ImageHandler.ROOM_COLORS[segment_id >> 1] pixels[x, y] = ImageHandler.__get_color__( f"{COLOR_ROOM_PREFIX}{segment_id}", colors, default) if image_config[ "scale"] != 1 and header.image_width != 0 and header.image_height != 0: image = image.resize( (int(trimmed_width * scale), int(trimmed_height * scale)), resample=Image.NEAREST) return image, rooms