-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathart_manager.py
229 lines (206 loc) · 8.12 KB
/
art_manager.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
'''
This module defiens the ArtManager() class, which is designed so that
the software can be run as a script or as part of a gui without having
dependency issues and making sure file types are resolved. Also
encapsulates a few helper utilities for the cairo context.
Dependencies:
cairo
'''
import cairo
# from . import settings as s
import settings as s
class ArtManager():
'''
This is an intermediate class that wraps a small part of the cairo
details, such as what kind of file type, etc... Most of the cairo
API should be exposed to the DataManager object to do the actual rendering,
but for one the housekeeping related to making sure a Cairo surface and
context exist and are ready, and what file type. Also some functions are
nice to encapsulate, like drawing labels here and there.
'''
w = s.img_width
h = s.img_height
surf = None
draw_count = 0
use_tree_copy = False
node_labels_on = False
leaf_labels_on = False
write_image_to_path = False
image_path = None
image_written_ct = 0
show_root = False
# background_color = (1., 1., 1.)
background_color = None
tree_line_color = (0., 0., 0.)
matrix = None
image_path_ext = ''
valid_surface_types = ['png','wx','svg','pdf']
cairo_surface_type = None
def __init__(self, parent=None, image_path=None, type='png',ht=None, wd=None, *args, **kwargs):
'''
:param parent:
:param image_path:
:param type:
:param ht:
:param wd:
:param args:
:param kwargs:
'''
self.parent = parent
if ht is not None:
self.h = int(ht)
s.img_height = int(ht)
if wd is not None:
self.w = int(wd)
s.img_width = int(wd)
s.img_aspect = float(s.img_width) / float(s.img_height)
if image_path is not None:
self.image_path = image_path
elif self.image_path is None:
self.image_path = 'work\\temp_new.png'
self.init_cairo_context(type=type)
self.args = args
self.kwargs = kwargs
def set_image_path(self,path):
'''
Sets the path that the image should be saved as. Checks to see if there is a known extension
on the path and separates that out.
:param path:
:return:
'''
if path[-4:] in ['.png','.jpg','.pdf','.svg']:
if path[-4:]=='jpg':
print("Cairo does not output as a jpg so we will use a png instead.")
self.image_path_ext = 'png'
else:
self.image_path_ext = path[-3:]
self.image_path = path[:-4]
else:
self.image_path = path
def draw_label_on_screen(self, lab, point, size=16, color=(.35, .35, .35, 1.0), bold=False):
'''
You'll never guess what this method does.
:param lab: String with the text to draw.
:param point: (x,y) tuple or other size-2 iterable. Where to draw it.
:param size: Font size (default: 16)
:param color: Color (RGBA tuple). Default is a light grey.
:param bold: Boolean.
:return:
'''
oldm = self.ctx.get_matrix()
oldfm = self.ctx.get_font_matrix()
self.ctx.set_matrix(cairo.Matrix(1., 0., 0., 1., 0., 0.))
self.ctx.set_font_matrix(cairo.Matrix(float(size), 0., 0., float(size), 0., 0.))
oldf = self.ctx.get_font_face()
if bold:
self.ctx.set_font_face(cairo.ToyFontFace("sans-serif", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD))
te = self.ctx.text_extents(lab)
self.ctx.move_to(*point)
self.ctx.rel_move_to(2, + te[3])
cr=(.35, .35, .35, 1.0)
self.ctx.set_source_rgba(cr[0],cr[1],cr[2],cr[3])
self.ctx.show_text(lab)
self.ctx.fill()
self.ctx.set_matrix(oldm)
self.ctx.set_font_matrix(oldfm)
self.ctx.set_font_face(oldf)
def draw_white_rectangle(self, L, R, T, B):
'''
Helper method to make sure the background isn't opaque in e.g. png files.
:param L: Left Boundary
:param R: Right Boundary
:param T: Top Boundary
:param B: Bottom Boundary
:return: None
'''
self.ctx.set_matrix(cairo.Matrix(1., 0., 0., 1., 0., 0.))
self.ctx.set_source_rgba(1., 1., 1., 1.)
self.ctx.rectangle(L, T, abs(R - L), abs(B - T))
self.ctx.fill()
def init_cairo_context(self, type=None, svgsurf=None, newmatrix=True):
'''
This method creates the cairo surface and context used for drawing.
:param svgsurf:
:param newmatrix:
:return:
'''
# Create the surface object.
if self.surf is not None:
del self.surf
if svgsurf != None:
self.surf = svgsurf
else:
if type is None:
type = self.cairo_surface_type
else:
type = type.lower()
if type in ('png','wx'):
# This is the class to use if you want to render it to the screen.
# Drawing to a png file is available from any image surface, so
# if that option is specified just fall back on the type for rendering
# to a gui window.
self.surf = cairo.ImageSurface(cairo.FORMAT_ARGB32, self.w, self.h)
self.image_path_ext = 'png'
self.cairo_surface_type = 'wx'
elif type=='svg':
self.image_path_ext = 'svg'
self.cairo_surface_type = 'svg'
self.surf = cairo.SVGSurface(self.image_path + '.svg', self.w, self.h)
elif type=='pdf':
self.image_path_ext = 'pdf'
self.cairo_surface_type = 'pdf'
# self.surf = cairo.PDFSurface(self.image_path + '.pdf', self.w, self.h)
try:
self.surf =cairo.PDFSurface(self.image_path + '.pdf', self.w, self.h)
except IOError:
print('IOError in init_cairo_context (line 166 of art_manager)')
print (self.image_path)
print ('W: %s, H: %s' % (self.w, self.h))
import sys
sys.exit(0)
else:
print("surface type not recognized. Valid types are: \n%s" % str(self.valid_surface_types))
self.surf = cairo.ImageSurface(cairo.FORMAT_ARGB32,self.w, self.h)
self.cairo_surface_type = 'wx'
self.ctx = cairo.Context(self.surf)
if self.background_color is not None:
self.ctx.set_source_rgb(*self.background_color)
self.ctx.rectangle(0, 0, self.w, self.h)
self.ctx.fill()
else:
self.ctx.set_source_rgba(1., 1., 1., 1.)
self.ctx.rectangle(0, 0, self.w, self.h)
self.ctx.fill()
print ('\tw: %s, h: %s' % (self.w, self.h))
if self.matrix is not None and newmatrix == True:
self.ctx.set_matrix(self.matrix)
def write_image_to_png(self,filepath=None):
if filepath is not None:
self.set_image_path(filepath)
self.surf.write_to_png(self.image_path + '.png')
def finish_cairo_content(self):
'''
When the image is done, write it to a file and re-initialize a new context.
:return:
'''
if self.image_path_ext=='png':
self.surf.write_to_png(self.image_path + '.png')
self.init_cairo_context()
self.surf.finish()
self.image_written_ct += 1
def set_cairo_matrix(self, t11, t12, t13, t21, t22, t23):
'''
Sets the cairo coordinate transformation based on the six points of the
of the matrix
:param t11:
:param t12:
:param t13:
:param t21:
:param t22:
:param t23:
:return:
'''
# self.ctx.set_matrix(cairo.Matrix(t11, -t21, t12, -t22, t13, -t23))
# print 'matrix should be: [%.f, %.f, %.f, %.f, %.f, %.f]' % (t11, t12, t13, t21, t22, t23)
self.ctx.set_matrix(cairo.Matrix(t11, t21, t12, t22, t13, t23))
self.matrix = self.ctx.get_matrix()