diff --git a/doc/example/report.md b/doc/example/report.md index 47f9455..62c79d3 100644 --- a/doc/example/report.md +++ b/doc/example/report.md @@ -1,8 +1,8 @@ ![memory map diagram](report.png) |name|origin|size|remaining|collisions |:-|:-|:-|:-|:-| -|kernel|0x10|0x50|-0x10|{'rootfs': '0x50'}| -|uboot|0xD0|0x50|-0x10|{'uboot-scr': '0x110'}| -|rootfs|0x50|0x30|0x10|{'kernel': '0x50'}| -|dtb|0x90|0x30|0x10|{}| -|uboot-scr|0x110|0x30|0x50|{'uboot': '0x110'}| +|kernel|0x10|0x50|-0x10|{'rootfs': '0x50'}| +|uboot|0xD0|0x50|-0x10|{'uboot-scr': '0x110'}| +|rootfs|0x50|0x30|0x10|{'kernel': '0x50'}| +|dtb|0x90|0x30|0x10|{}| +|uboot-scr|0x110|0x30|0x50|{'uboot': '0x110'}| diff --git a/doc/example/report.png b/doc/example/report.png index 2a6951f..a5560a1 100644 Binary files a/doc/example/report.png and b/doc/example/report.png differ diff --git a/mm/diagram.py b/mm/diagram.py index be2ce6e..c9d304c 100644 --- a/mm/diagram.py +++ b/mm/diagram.py @@ -25,9 +25,9 @@ @typeguard.typechecked class MemoryMap: - height = 400 + height: int = 400 """height of the diagram image""" - width = 400 + width: int = 400 """width of the diagram image""" bgcolour = "oldlace" @@ -64,41 +64,10 @@ def _create_diagram(self, region_list: List[mm.types.MemoryRegion]): # to the main image object (img_main) for region in region_list: - logging.info(region) - if not region.size: - logging.warning("Zero size region skipped") + region.create_img(img_width=MemoryMap.width - self._legend_width) + if not region.img: continue - # MemoryRegion Blocks and text - region_img = PIL.Image.new("RGBA", (MemoryMap.width - self._legend_width, region.size), color=(255, 255, 0, 5)) - region_canvas = PIL.ImageDraw.Draw(region_img) - - region_canvas.rectangle( - (0, 0, MemoryMap.width - 1, region.size - 1), - fill=region.colour, - outline="black", - width=1, - ) - - # draw name text - ntext_img_width = 60 - ntext_img_height = 7 - ntext_font = PIL.ImageFont.load_default(ntext_img_height) - ntext_img = PIL.Image.new("RGB", (ntext_img_width, ntext_img_height), color=MemoryMap.bgcolour) - - ntext_canvas = PIL.ImageDraw.Draw(ntext_img) - - _, _, ntext_width, ntext_height = ntext_canvas.textbbox( - (0, 0), region.name, font=ntext_font) - - ntext_canvas.text(((ntext_img_width-ntext_width)/2, - (ntext_img_height-ntext_height)/2-1), - region.name, fill="black", - font=ntext_font) - - ntext_img = ntext_img.rotate(180) - region_img.paste(ntext_img, (5, 5)) - # Address Text addr_text_font = PIL.ImageFont.load_default(8) # add text for the region origin @@ -118,9 +87,9 @@ def _create_diagram(self, region_list: List[mm.types.MemoryRegion]): for x in range(40, 90, 4): line_canvas.line((x, endaddr - line_width, x+2, endaddr - line_width), fill="black", width=line_width) line_canvas.line((x, region.origin - line_width, x+2, region.origin - line_width), fill="black", width=1) - + # paste all the layers onto the main image - img_main.paste(region_img, (self._legend_width + region.draw_indent, region.origin), region_img) + img_main.paste(region.img, (self._legend_width + region.draw_indent, region.origin), region.img) img_main.paste(endaddr_text_img, (0, endaddr - 6)) img_main.paste(origin_text_img, (0, region.origin - 4)) diff --git a/mm/types.py b/mm/types.py index 93c19f2..b0d711c 100644 --- a/mm/types.py +++ b/mm/types.py @@ -1,5 +1,7 @@ import typeguard import random +import PIL.Image +import PIL.ImageDraw import PIL.ImageColor from typing import List, Dict import logging @@ -21,11 +23,19 @@ def __init__(self, name: str, origin: str, size: str): """size in bytes""" self.colour = self._pick_available_colour() """random colour for region block""" + self.bordercolour = "black" + """The border colour to use for the region""" self.remain: str = None """Number of bytes until next region block""" self.collisons: Dict(str, str) = {} """Map of collision regions by name (str) and distance (hex)""" self.draw_indent = 0 + """Index counter for incrementally shrinking the drawing indent""" + self.txtlbl_bgcolour = "oldlace" + """The background colour to use for the region text label""" + self.txtlbl_fgcolour = "black" + """The foreground colour to use for the region text label""" + self.img: PIL.Image # both 'lightslategray' and 'lightslategrey' are the same colour # and we don't want duplicate colours in our diagram @@ -131,9 +141,51 @@ def calc_nearest_region(self, region_list: List['MemoryRegion']): @typeguard.typechecked class MemoryRegion(Region): - pass + + def create_img(self, img_width: int): + + logging.info(self) + if not self.size: + logging.warning("Zero size region skipped") + return None + + # MemoryRegion Blocks and text + region_img = PIL.Image.new("RGBA", (img_width, self.size), color="white") + self.region_canvas = PIL.ImageDraw.Draw(region_img) + + # height is -1 to avoid clipping the top border + self.region_canvas.rectangle( + (0, 0, img_width, self.size - 1), + fill=self.colour, + outline=self.bordercolour, + width=1, + ) + + # draw name text + ntext_img_width = 60 + ntext_img_height = 7 + ntext_font = PIL.ImageFont.load_default(ntext_img_height) + ntext_img = PIL.Image.new("RGB", (ntext_img_width, ntext_img_height), color=self.txtlbl_bgcolour) + + ntext_canvas = PIL.ImageDraw.Draw(ntext_img) + + _, _, ntext_width, ntext_height = ntext_canvas.textbbox( + (0, 0), self.name, font=ntext_font) + + ntext_canvas.text(((ntext_img_width-ntext_width)/2, + (ntext_img_height-ntext_height)/2-1), + self.name, fill=self.txtlbl_fgcolour, + font=ntext_font) + + ntext_img = ntext_img.rotate(180) + region_img.paste(ntext_img, (5, 5)) + + self.img = region_img @typeguard.typechecked class SkippableRegion(Region): pass + + +