@@ -7,11 +7,7 @@ class AnsiImage:
7
7
"""
8
8
Manages a rectangular image made of ansi character cells
9
9
"""
10
-
11
- CHAR_SIZE_X = 8
12
- CHAR_SIZE_Y = 16
13
-
14
- def __init__ (self , min_line_len = None ):
10
+ def __init__ (self , graphics , min_line_len = None ):
15
11
"""
16
12
Optionally allows the specification of a minimum
17
13
line length, used when loading
@@ -25,6 +21,10 @@ def __init__(self, min_line_len = None):
25
21
self .is_dirty = False
26
22
self .write_allowed = [True , True , True ]
27
23
24
+ self .ansi_graphics = graphics
25
+ self .char_size_x = self .ansi_graphics .get_char_size ()[0 ]
26
+ self .char_size_y = self .ansi_graphics .get_char_size ()[1 ]
27
+
28
28
# Selection related stuff
29
29
self .selection = None
30
30
self .selection_preliminary = set ()
@@ -35,20 +35,40 @@ def __init__(self, min_line_len = None):
35
35
self .cache_params = None
36
36
37
37
# The cursor
38
+ self .rebuild_cursor ()
39
+
40
+ def get_size (self ):
41
+ """
42
+ Return the current canvas size in characters
43
+ """
44
+ return (self .width , self .height )
45
+
46
+ def rebuild_cursor (self ):
38
47
self .cursor_shape = []
39
- for y in [0 , 1 , 14 , 15 ]:
40
- for x in range (0 , 8 ):
48
+ for y in [0 , 1 , self . char_size_y - 2 , self . char_size_y - 1 ]:
49
+ for x in range (0 , self . char_size_x ):
41
50
self .cursor_shape .append ((y , x ))
42
- for y in range (2 , 14 ):
43
- for x in [0 , 1 , 6 , 7 ]:
51
+ for y in range (2 , self . char_size_y - 2 ):
52
+ for x in [0 , 1 , self . char_size_x - 2 , self . char_size_x - 1 ]:
44
53
self .cursor_shape .append ((y , x ))
54
+
45
55
46
- def get_size (self ):
56
+ def get_char_size (self ):
47
57
"""
48
- Return the current canvas size in characters
58
+ Return the character size, in pixels
49
59
"""
50
- return (self .width , self .height )
60
+ return (self .char_size_x , self .char_size_y )
51
61
62
+ def change_graphics (self , new_graphics ):
63
+ """
64
+ Changes the graphics in use
65
+ """
66
+ self .ansi_graphics = new_graphics
67
+ self .char_size_x = self .ansi_graphics .get_char_size ()[0 ]
68
+ self .char_size_y = self .ansi_graphics .get_char_size ()[1 ]
69
+ self .have_cache = False
70
+ self .rebuild_cursor ()
71
+
52
72
def change_size (self , new_width , new_height , new_state = None ):
53
73
"""
54
74
Make the image larger or smaller, retaining contents.
@@ -125,7 +145,7 @@ def set_selection(self, new_selection_initial = None, append = False, remove = F
125
145
self .redraw_set .update (self .selection )
126
146
self .selection = None
127
147
128
- def get_selected (self , selection = None ):
148
+ def get_selected (self , skip_space = False , selection = None ):
129
149
"""
130
150
Returns the selected characters, offset-augmnented
131
151
"""
@@ -140,7 +160,8 @@ def get_selected(self, selection = None):
140
160
for x , y in selection :
141
161
min_x = min (x , min_x )
142
162
min_y = min (y , min_y )
143
- selected .append ([x , y , self .ansi_image [y ][x ]])
163
+ if not skip_space or self .ansi_image [y ][x ][0 ] != ord (' ' ):
164
+ selected .append ([x , y , self .ansi_image [y ][x ]])
144
165
145
166
for sel_item in selected :
146
167
sel_item [0 ] -= min_x
@@ -636,15 +657,15 @@ def save_ans(self, out_path):
636
657
with open (out_path , "wb" ) as f :
637
658
f .write (self .to_ans ())
638
659
639
- def to_bitmap (self , ansi_graphics , transparent = False , cursor = False , area = None ):
660
+ def to_bitmap (self , transparent = False , cursor = False , area = None ):
640
661
"""
641
662
Returns pixel representation of this image as a PIL Image object
642
663
643
664
Can be passed an area. If so, only character cells overlapping the requested area will be
644
665
drawn. In this case the return value is a tuple of (real x start, real y start, bitmap image, actual size w, actual size h)
645
666
"""
646
667
if self .have_cache == False or self .cache_params != [transparent , cursor ]:
647
- self .ansi_bitmap = np .ones ((AnsiImage . CHAR_SIZE_Y * self .height , AnsiImage . CHAR_SIZE_X * self .width , 4 ))
668
+ self .ansi_bitmap = np .ones ((self . char_size_y * self .height , self . char_size_x * self .width , 4 ))
648
669
for y in range (0 , self .height ):
649
670
for x in range (0 , self .width ):
650
671
self .redraw_set .add ((x , y ))
@@ -656,33 +677,33 @@ def to_bitmap(self, ansi_graphics, transparent = False, cursor = False, area = N
656
677
continue
657
678
658
679
char_info = self .ansi_image [y ][x ]
659
- char_col = ansi_graphics .coloured_char (char_info [0 ], char_info [1 ], char_info [2 ])
680
+ char_col = self . ansi_graphics .coloured_char (char_info [0 ], char_info [1 ], char_info [2 ])
660
681
self .ansi_bitmap [
661
- AnsiImage . CHAR_SIZE_Y * y : AnsiImage . CHAR_SIZE_Y * (y + 1 ),
662
- AnsiImage . CHAR_SIZE_X * x : AnsiImage . CHAR_SIZE_X * (x + 1 ),
682
+ self . char_size_y * y : self . char_size_y * (y + 1 ),
683
+ self . char_size_x * x : self . char_size_x * (x + 1 ),
663
684
0 :3
664
685
] = char_col
665
686
666
687
# Make pixels transparent or no
667
688
if transparent == True and char_info [0 ] == ord (' ' ):
668
689
self .ansi_bitmap [
669
- AnsiImage . CHAR_SIZE_Y * y : AnsiImage . CHAR_SIZE_Y * (y + 1 ),
670
- AnsiImage . CHAR_SIZE_X * x : AnsiImage . CHAR_SIZE_X * (x + 1 ),
690
+ self . char_size_y * y : self . char_size_y * (y + 1 ),
691
+ self . char_size_x * x : self . char_size_x * (x + 1 ),
671
692
3
672
- ] = np .zeros ((AnsiImage . CHAR_SIZE_Y , AnsiImage . CHAR_SIZE_X ))
693
+ ] = np .zeros ((self . char_size_y , self . char_size_x ))
673
694
else :
674
695
self .ansi_bitmap [
675
- AnsiImage . CHAR_SIZE_Y * y : AnsiImage . CHAR_SIZE_Y * (y + 1 ),
676
- AnsiImage . CHAR_SIZE_X * x : AnsiImage . CHAR_SIZE_X * (x + 1 ),
696
+ self . char_size_y * y : self . char_size_y * (y + 1 ),
697
+ self . char_size_x * x : self . char_size_x * (x + 1 ),
677
698
3
678
- ] = np .ones ((AnsiImage . CHAR_SIZE_Y , AnsiImage . CHAR_SIZE_X ))
699
+ ] = np .ones ((self . char_size_y , self . char_size_x ))
679
700
680
701
# Draw cursor on top
681
702
if cursor == True and x == self .cursor_x and y == self .cursor_y :
682
703
for cursor_pix_y , cursor_pix_x in self .cursor_shape :
683
- self .ansi_bitmap [AnsiImage . CHAR_SIZE_Y * y + cursor_pix_y , AnsiImage . CHAR_SIZE_X * x + cursor_pix_x , 0 :3 ] = \
684
- 1.0 - self .ansi_bitmap [AnsiImage . CHAR_SIZE_Y * y + cursor_pix_y , AnsiImage . CHAR_SIZE_X * x + cursor_pix_x , 0 :3 ]
685
- self .ansi_bitmap [AnsiImage . CHAR_SIZE_Y * y + cursor_pix_y , AnsiImage . CHAR_SIZE_X * x + cursor_pix_x , 3 ] = 1.0
704
+ self .ansi_bitmap [self . char_size_y * y + cursor_pix_y , self . char_size_x * x + cursor_pix_x , 0 :3 ] = \
705
+ 1.0 - self .ansi_bitmap [self . char_size_y * y + cursor_pix_y , self . char_size_x * x + cursor_pix_x , 0 :3 ]
706
+ self .ansi_bitmap [self . char_size_y * y + cursor_pix_y , self . char_size_x * x + cursor_pix_x , 3 ] = 1.0
686
707
687
708
# Invert selection
688
709
if cursor == True :
@@ -696,12 +717,12 @@ def to_bitmap(self, ansi_graphics, transparent = False, cursor = False, area = N
696
717
if not (x , y ) in self .redraw_set or x >= self .width or y >= self .height :
697
718
continue
698
719
self .ansi_bitmap [
699
- AnsiImage . CHAR_SIZE_Y * y : AnsiImage . CHAR_SIZE_Y * (y + 1 ),
700
- AnsiImage . CHAR_SIZE_X * x : AnsiImage . CHAR_SIZE_X * (x + 1 ),
720
+ self . char_size_y * y : self . char_size_y * (y + 1 ),
721
+ self . char_size_x * x : self . char_size_x * (x + 1 ),
701
722
0 :3
702
723
] = 1.0 - self .ansi_bitmap [
703
- AnsiImage . CHAR_SIZE_Y * y : AnsiImage . CHAR_SIZE_Y * (y + 1 ),
704
- AnsiImage . CHAR_SIZE_X * x : AnsiImage . CHAR_SIZE_X * (x + 1 ),
724
+ self . char_size_y * y : self . char_size_y * (y + 1 ),
725
+ self . char_size_x * x : self . char_size_x * (x + 1 ),
705
726
0 :3
706
727
]
707
728
@@ -718,21 +739,21 @@ def to_bitmap(self, ansi_graphics, transparent = False, cursor = False, area = N
718
739
self .redraw_set = set ()
719
740
720
741
if area != None :
721
- start_x = min (area [0 ] // self .CHAR_SIZE_X , redraw_start_x )
722
- end_x = max ((area [2 ] // self .CHAR_SIZE_X ) + 1 , redraw_end_y )
742
+ start_x = min (area [0 ] // self .char_size_x , redraw_start_x )
743
+ end_x = max ((area [2 ] // self .char_size_x ) + 1 , redraw_end_y )
723
744
724
- start_y = min (area [1 ] // self .CHAR_SIZE_Y , redraw_start_y )
725
- end_y = max ((area [3 ] // self .CHAR_SIZE_Y ) + 1 , redraw_end_y )
745
+ start_y = min (area [1 ] // self .char_size_y , redraw_start_y )
746
+ end_y = max ((area [3 ] // self .char_size_y ) + 1 , redraw_end_y )
726
747
727
748
return (
728
- start_x * AnsiImage . CHAR_SIZE_X ,
729
- start_y * AnsiImage . CHAR_SIZE_Y ,
749
+ start_x * self . char_size_x ,
750
+ start_y * self . char_size_y ,
730
751
Image .fromarray ((self .ansi_bitmap [
731
- start_y * AnsiImage . CHAR_SIZE_Y : end_y * AnsiImage . CHAR_SIZE_Y ,
732
- start_x * AnsiImage . CHAR_SIZE_X : end_x * AnsiImage . CHAR_SIZE_X
752
+ start_y * self . char_size_y : end_y * self . char_size_y ,
753
+ start_x * self . char_size_x : end_x * self . char_size_x
733
754
] * 255.0 ).astype ('int8' ), mode = 'RGBA' ),
734
- AnsiImage . CHAR_SIZE_X * self .width ,
735
- AnsiImage . CHAR_SIZE_Y * self .height ,
755
+ self . char_size_x * self .width ,
756
+ self . char_size_y * self .height ,
736
757
)
737
758
else :
738
759
return Image .fromarray ((self .ansi_bitmap * 255.0 ).astype ('int8' ), mode = 'RGBA' )
0 commit comments