1919https://github.com/v1b3c0d3x3r/roborock-qseries-map-bridge
2020"""
2121
22- import colorsys
2322import io
2423import math
2524import statistics
2625from dataclasses import dataclass , field , replace
2726
2827from PIL import Image
28+ from vacuum_map_parser_base .config .color import ColorsPalette , SupportedColor
2929from vacuum_map_parser_base .config .image_config import ImageConfig
3030from vacuum_map_parser_base .map_data import ImageData , MapData
3131
4040 decompose_grid ,
4141)
4242from .map_parser import ParsedMapData
43+ from .room_colors import adjacency_aware_room_colors
4344
4445_MAP_FILE_FORMAT = "PNG"
4546
@@ -655,12 +656,12 @@ def parsed_from_packet(self, packet: Q10MapPacket) -> ParsedMapData:
655656 return ParsedMapData (image_content = image_bytes .getvalue (), map_data = map_data )
656657
657658 def _render (self , packet : Q10MapPacket ) -> Image .Image :
658- """Render the Q10 grid: rooms get distinct colors, walls white, rest dark ."""
659- palette = _build_palette (packet .grid )
660- rgb = bytearray ()
659+ """Render the Q10 grid with the V1 map palette ."""
660+ palette = _build_palette (packet .grid , packet . width )
661+ rgba = bytearray ()
661662 for value in packet .grid :
662- rgb .extend (palette [value ])
663- img = Image .frombytes ("RGB " , (packet .width , packet .height ), bytes (rgb ))
663+ rgba .extend (palette [value ])
664+ img = Image .frombytes ("RGBA " , (packet .width , packet .height ), bytes (rgba ))
664665 # The ss07 grid is stored top-down (row 0 = top of the home), so it is
665666 # rendered as-is -- unlike the V1/Q7 convention, no vertical flip.
666667 scale = self ._config .map_scale
@@ -669,15 +670,32 @@ def _render(self, packet: Q10MapPacket) -> Image.Image:
669670 return img
670671
671672
672- def _build_palette (grid : bytes ) -> list [tuple [int , int , int ]]:
673- """Map each grid value to an RGB color (rooms distinct, walls white)."""
674- palette : list [tuple [int , int , int ]] = [(28 , 30 , 38 )] * 256 # default: unknown/outside
675- room_values = sorted ({v for v in set (grid ) if 0 < v < _WALL_THRESHOLD })
676- for index , value in enumerate (room_values ):
677- hue = (index * 0.139 ) % 1.0
678- r , g , b = colorsys .hsv_to_rgb (hue , 0.5 , 0.95 )
679- palette [value ] = (int (r * 255 ), int (g * 255 ), int (b * 255 ))
673+ def _opaque (color : tuple [int , ...]) -> tuple [int , int , int , int ]:
674+ """Return a palette color as RGBA."""
675+ return (color [0 ], color [1 ], color [2 ], color [3 ] if len (color ) == 4 else 255 )
676+
677+
678+ def _build_palette (grid : bytes , width : int ) -> list [tuple [int , int , int , int ]]:
679+ """Map Q10 cells onto the same colors used by the V1 map renderer."""
680+
681+ def room_id (value : int ) -> int | None :
682+ return max (1 , value // 4 ) if 0 < value < _WALL_THRESHOLD else None
683+
684+ colors = ColorsPalette ()
685+ room_colors = adjacency_aware_room_colors (
686+ grid ,
687+ width ,
688+ colors ,
689+ room_id ,
690+ )
691+ outside = (0 , 0 , 0 , 0 )
692+ palette = [outside ] * 256
693+ for value in {value for value in grid if 0 < value < _WALL_THRESHOLD }:
694+ palette [value ] = _opaque (room_colors [max (1 , value // 4 )])
695+ wall = _opaque (colors .get_color (SupportedColor .GREY_WALL ))
680696 for value in range (_WALL_THRESHOLD , 256 ):
681- palette [value ] = (235 , 235 , 240 ) # walls / borders
682- palette [0 ] = (28 , 30 , 38 )
697+ palette [value ] = wall
698+ palette [_UNSEGMENTED_FLOOR_VALUE ] = _opaque (colors .get_color (SupportedColor .MAP_INSIDE ))
699+ palette [_BACKGROUND_VALUE ] = outside
700+ palette [0 ] = outside
683701 return palette
0 commit comments