11# -*- coding: UTF-8 -*-
22from .__common__ import Binary , COLORS
3- from ..__conf__ import save_figure
3+ from ..__conf__ import *
44from ..utils import human_readable_size
55
66
77def arguments (parser ):
88 parser .add_argument ("executable" , help = "executable sample to be plotted" )
9+ parser .add_argument ("-g" , "--grayscale" , action = "store_true" , help = "use grayscale colors instead of RGB" )
910 return parser
1011
1112
1213@save_figure
13- def plot (executable , height = 600 , ** kwargs ):
14+ def plot (executable , height = 600 , grayscale = False , ** kwargs ):
1415 """ draw a byte plot of the input binary """
1516 import matplotlib .colors as mcol
1617 import matplotlib .pyplot as plt
1718 from math import ceil , sqrt
1819 from matplotlib import font_manager , rcParams
1920 from PIL import Image , ImageDraw , ImageFont
21+ # ------------------------------------------------- DRAW THE PLOT --------------------------------------------------
2022 # determine base variables and some helper functions
21- images , binary = [], Binary (executable )
22- n_pixels = ceil (binary .size / 3 )
23+ images , binary , factor = [], Binary (executable ), [ 3 , 1 ][ grayscale ]
24+ n_pixels = ceil (binary .size / factor )
2325 s = int (ceil (sqrt (n_pixels )))
2426 sf = height / s
2527 _rgb = lambda c : tuple (map (lambda x : int (255 * x ), mcol .to_rgba (c )))
28+ _gs = lambda c : int (sum (a * b for a , b in zip ([.299 , .587 , .114 ], _rgb (c ))))
2629 # draw a byte plot
27- rawbytes = binary .rawbytes + int ((s * s * 3 ) - len (binary .rawbytes )) * b'\xff '
28- images .append (Image .frombuffer ("RGB" , (s , s ), rawbytes , "raw" , "RGB" , 0 , 1 ) \
30+ logger .debug ("> creating the main plot from raw bytes" )
31+ rawbytes = binary .rawbytes + int ((s * s * factor ) - len (binary .rawbytes )) * b'\xff '
32+ images .append (Image .frombuffer (m := ["RGB" , "L" ][grayscale ], (s , s ), rawbytes , "raw" , m , 0 , 1 ) \
2933 .resize ((int (s * sf ), height ), resample = Image .Resampling .BOX ))
34+ logger .debug ("> creating the side plot with sections" )
3035 if len (binary .sections ) > 0 :
3136 # map matplotlib font to PIL ImageFont path
3237 font_name = rcParams [f"font.{ kwargs ['config' ]['font_family' ]} " ][0 ]
@@ -35,7 +40,6 @@ def plot(executable, height=600, **kwargs):
3540 txt_spacing = txt_h // 2
3641 n_lab_per_col = int ((height - txt_spacing ) / (txt_h + txt_spacing ))
3742 n_cols = ceil ((len (binary .sections ) + 2 ) / n_lab_per_col )
38- #n_cols = 1
3943 max_txt_w = [0 ] * n_cols
4044 sections = ["Headers" ] + [s for s in binary .sections ] + ["Overlay" ]
4145 draw = ImageDraw .Draw (images [0 ])
@@ -49,44 +53,48 @@ def plot(executable, height=600, **kwargs):
4953 pass
5054 max_w = sum (max_txt_w ) + (n_cols - 1 ) * txt_spacing
5155 # draw a separator
52- images .append (Image .new ("RGB" , (int (.05 * height ), height ), "white" ))
56+ images .append (Image .new (m , (int (.05 * height ), height ), "white" ))
5357 # draw a sections plot aside
54- img = Image .new ("RGB" , (s , s ), "white" )
58+ img = Image .new (m , (s , s ), "white" )
5559 # draw the legend with section names
56- legend = Image .new ("RGB" , (max_w , height ), "white" )
60+ legend = Image .new (m , (max_w , height ), "white" )
5761 draw = ImageDraw .Draw (legend )
5862 _xy = lambda n , c : (txt_spacing + sum (max_txt_w [:c ]) + len (max_txt_w [:c ]) * txt_spacing , \
5963 txt_spacing + (n % n_lab_per_col ) * (txt_spacing + txt_h ))
64+ _c_func = [_rgb , _gs ][grayscale ]
6065 for i , name , start , end , color in binary :
6166 if start != end :
62- x0 , y0 = min (max (ceil (((start / 3 ) % s )) - 1 , 0 ), s - 1 ), \
63- min (max (ceil (start / s / 3 ) - 1 , 0 ), s - 1 )
64- xN , yN = min (max (ceil (((end / 3 ) % s )) - 1 , 0 ), s - 1 ), \
65- min (max (ceil (end / s / 3 ) - 1 , 0 ), s - 1 )
67+ x0 , y0 = min (max (ceil (((start / factor ) % s )) - 1 , 0 ), s - 1 ), \
68+ min (max (ceil (start / s / factor ) - 1 , 0 ), s - 1 )
69+ xN , yN = min (max (ceil (((end / factor ) % s )) - 1 , 0 ), s - 1 ), \
70+ min (max (ceil (end / s / factor ) - 1 , 0 ), s - 1 )
6671 if y0 == yN :
6772 xN = min (max (x0 + 1 , xN ), s - 1 )
73+ c = _c_func (color )
6874 for x in range (x0 , s if y0 < yN else xN ):
69- img .putpixel ((x , y0 ), _rgb ( color ) )
75+ img .putpixel ((x , y0 ), c )
7076 for y in range (y0 + 1 , yN ):
7177 for x in range (0 , s ):
72- img .putpixel ((x , y ), _rgb ( color ) )
78+ img .putpixel ((x , y ), c )
7379 if yN > y0 :
7480 for x in range (0 , xN ):
75- img .putpixel ((x , yN ), _rgb ( color ) )
81+ img .putpixel ((x , yN ), c )
7682 # fill the legend with the current section name
7783 if name .startswith ("TOTAL" ):
7884 color = "black"
79- draw .text (_xy (i , ceil ((i + 1 ) / n_lab_per_col ) - 1 ), name , fill = _rgb (color ), font = font )
85+ draw .text (_xy (i , ceil ((i + 1 ) / n_lab_per_col ) - 1 ), name , fill = _c_func (color ), font = font )
8086 images .append (img .resize ((int (img .size [0 ] * sf * .2 ), height ), resample = Image .Resampling .BOX ))
81- images .append (Image .new ("RGB" , (int (.03 * height ), height ), "white" )) # draw another separator
87+ images .append (Image .new (m , (int (.03 * height ), height ), "white" )) # draw another separator
8288 images .append (legend )
8389 # combine images horizontally
84- x , img = 0 , Image .new ("RGB" , (sum (i .size [0 ] for i in images ), height ))
90+ x , img = 0 , Image .new (m , (sum (i .size [0 ] for i in images ), height ))
8591 for i in images :
8692 img .paste (i , (x , 0 ))
8793 x += i .size [0 ]
94+ # ---------------------------------------------- CONFIGURE THE FIGURE ----------------------------------------------
8895 # plot combined PIL images
8996 #plt.tight_layout(pad=0)
97+ logger .debug ("> configuring the figure" )
9098 if not kwargs .get ('no_title' , False ):
9199 # set plot's title before displaying the image
92100 fsp = plt .gcf ().subplotpars
0 commit comments