def load_seqend(self, line = None, path_flag = None): if line is None: line = self.vertex_path if path_flag is None: path_flag = self.path_flag if path_flag > 1: print 'FIXMY. Curves and smooth surface type', path_flag close_path = path_flag & 1 == 1 path = CreatePath() if len(line): for i in line: x, y, bulge = i #print x, y, bulge path.AppendLine(self.trafo(x, y)) if close_path: if path.Node(0) != path.Node(-1): path.AppendLine(path.Node(0)) path.ClosePath() self.prop_stack.AddStyle(self.curstyle.Duplicate()) self.bezier(path,)
def read_path(filename): path = CreatePath() paths = [path] points = [] file = open(filename) closed = 0 for line in file.readlines(): try: key, rest = split(line, ':', 1) except: continue if key == 'TYPE': rest = lstrip(rest) match = rx_point.match(rest) if match is not None: type = int(match.group('type')) p = Point(float(match.group('x')), float(match.group('y'))) if type == BEZIER_MOVE: if closed and points: path.AppendBezier(points[0], points[1], path.Node(0)) path.ClosePath() points = [] path = CreatePath() paths.append(path) path.AppendLine(p) elif type == BEZIER_ANCHOR: if path.len == 0: path.AppendLine(p) else: if path.Node(-1) == points[0] and points[1] == p: path.AppendLine(p) else: path.AppendBezier(points[0], points[1], p) points = [] elif type == BEZIER_CONTROL: points.append(p) elif key == 'CLOSED': closed = int(rest) if closed and points: if path.Node(-1) == points[0] and points[1] == path.Node(0): path.AppendLine(path.Node(0)) else: path.AppendBezier(points[0], points[1], path.Node(0)) path.ClosePath() return tuple(paths)
def create_star_path(corners, outer_radius, inner_radius): outer_radius = unit.convert(outer_radius) inner_radius = unit.convert(inner_radius) path = CreatePath() angle = math.pi * 2 / corners for i in range(corners): path.AppendLine(Polar(outer_radius, angle * i)) path.AppendLine(Polar(inner_radius, angle * i + angle / 2)) path.AppendLine(path.Node(0)) path.ClosePath() return path
def polygon(self, attrs): if self.in_defs: return points = as_latin1(attrs['points']) points = string.translate(points, commatospace) points = split(points) path = CreatePath() point = self.point for i in range(0, len(points), 2): path.AppendLine(point(points[i], points[i + 1])) path.AppendLine(path.Node(0)) path.ClosePath() self.parse_attrs(attrs) self.set_loader_style() self.loader.bezier(paths = (path,))
def makePageFrame(self): doc = self.doc layout = doc.Layout() hor_p = layout.Width() ver_p = layout.Height() path = CreatePath() path.AppendLine(Point(0, 0)) path.AppendLine(Point(hor_p, 0)) path.AppendLine(Point(hor_p, ver_p)) path.AppendLine(Point(0, ver_p)) path.AppendLine(Point(0, 0)) path.AppendLine(path.Node(0)) path.ClosePath() bezier = PolyBezier((path, )) doc.Insert(bezier)
def create_star_path(corners, step, radius): # create a star-like polygon. center = Point(300, 400) radius = 100 angle = step * 2 * pi / corners # create an empty path and append the line segments path = CreatePath() for i in range(corners): p = Polar(radius, angle * i + pi / 2) path.AppendLine(p) # close the path. path.AppendLine(path.Node(0)) path.ClosePath() return path
def convert_paths(self, paths_list): paths = () for path in paths_list: p = CreatePath() p.AppendLine(Point(*path[0])) points = path[1] for point in points: if len(point) == 2: p.AppendLine(Point(*point)) else: point0 = Point(*point[0]) point1 = Point(*point[1]) point2 = Point(*point[2]) p.AppendBezier(point0, point1, point2, point[3]) if path[2]: p.AppendLine(Point(*path[0])) p.ClosePath() paths = paths + (p,) return paths
def parse_path(self, str): paths = self.paths path = self.path trafo = self.trafo str = strip(string.translate(as_latin1(str), commatospace)) last_quad = None last_cmd = cmd = None f13 = 1.0 / 3.0; f23 = 2.0 / 3.0 #print '*', str while 1: match = rx_command.match(str) #print match if match: last_cmd = cmd cmd = str[0] str = str[match.end():] #print '*', str points = match.group(1) #print '**', points if points: # use tokenize_line to parse the arguments so that # we deal with signed numbers following another # number without intervening whitespace other # characters properls. # FIXME: tokenize_line works but is not the best way # to do it because it accepts input that wouldn't be # valid here. points = filter(operator.isNumberType, skread.tokenize_line(points)) #print cmd, points if cmd in 'mM': path = CreatePath() paths.append(path) if cmd == 'M' or len(paths) == 1: path.AppendLine(trafo(points[0], points[1])) else: p = trafo.DTransform(points[0], points[1]) path.AppendLine(paths[-2].Node(-1) + p) if len(points) > 2: if cmd == 'm': for i in range(2, len(points), 2): p = trafo.DTransform(points[i], points[i + 1]) path.AppendLine(path.Node(-1) + p) else: for i in range(2, len(points), 2): path.AppendLine(trafo(points[i], points[i+1])) elif cmd == 'l': for i in range(0, len(points), 2): p = trafo.DTransform(points[i], points[i + 1]) path.AppendLine(path.Node(-1) + p) elif cmd == 'L': for i in range(0, len(points), 2): path.AppendLine(trafo(points[i], points[i+1])) elif cmd =='H': for num in points: path.AppendLine(Point(num, path.Node(-1).y)) elif cmd =='h': for num in points: x, y = path.Node(-1) dx, dy = trafo.DTransform(num, 0) path.AppendLine(Point(x + dx, y + dy)) elif cmd =='V': for num in points: path.AppendLine(Point(path.Node(-1).x, num)) elif cmd =='v': for num in points: x, y = path.Node(-1) dx, dy = trafo.DTransform(0, num) path.AppendLine(Point(x + dx, y + dy)) elif cmd == 'C': if len(points) % 6 != 0: self.loader.add_message("number of parameters of 'C'"\ "must be multiple of 6") else: for i in range(0, len(points), 6): p1 = trafo(points[i], points[i + 1]) p2 = trafo(points[i + 2], points[i + 3]) p3 = trafo(points[i + 4], points[i + 5]) path.AppendBezier(p1, p2, p3) elif cmd == 'c': if len(points) % 6 != 0: self.loader.add_message("number of parameters of 'c'"\ "must be multiple of 6") else: for i in range(0, len(points), 6): p = path.Node(-1) p1 = p + trafo.DTransform(points[i], points[i + 1]) p2 = p + trafo.DTransform(points[i+2], points[i+3]) p3 = p + trafo.DTransform(points[i+4], points[i+5]) path.AppendBezier(p1, p2, p3) elif cmd == 'S': if len(points) % 4 != 0: self.loader.add_message("number of parameters of 'S'"\ "must be multiple of 4") else: for i in range(0, len(points), 4): type, controls, p, cont = path.Segment(-1) if type == Bezier: q = controls[1] else: q = p p1 = 2 * p - q p2 = trafo(points[i], points[i + 1]) p3 = trafo(points[i + 2], points[i + 3]) path.AppendBezier(p1, p2, p3) elif cmd == 's': if len(points) % 4 != 0: self.loader.add_message("number of parameters of 's'"\ "must be multiple of 4") else: for i in range(0, len(points), 4): type, controls, p, cont = path.Segment(-1) if type == Bezier: q = controls[1] else: q = p p1 = 2 * p - q p2 = p + trafo.DTransform(points[i], points[i + 1]) p3 = p + trafo.DTransform(points[i+2], points[i+3]) path.AppendBezier(p1, p2, p3) elif cmd == 'Q': if len(points) % 4 != 0: self.loader.add_message("number of parameters of 'Q'"\ "must be multiple of 4") else: for i in range(0, len(points), 4): q = trafo(points[i], points[i + 1]) p3 = trafo(points[i + 2], points[i + 3]) p1 = f13 * path.Node(-1) + f23 * q p2 = f13 * p3 + f23 * q path.AppendBezier(p1, p2, p3) last_quad = q elif cmd == 'q': if len(points) % 4 != 0: self.loader.add_message("number of parameters of 'q'"\ "must be multiple of 4") else: for i in range(0, len(points), 4): p = path.Node(-1) q = p + trafo.DTransform(points[i], points[i + 1]) p3 = p + trafo.DTransform(points[i+2], points[i+3]) p1 = f13 * p + f23 * q p2 = f13 * p3 + f23 * q path.AppendBezier(p1, p2, p3) last_quad = q elif cmd == 'T': if len(points) % 2 != 0: self.loader.add_message("number of parameters of 'T'"\ "must be multiple of 4") else: if last_cmd not in 'QqTt' or last_quad is None: last_quad = path.Node(-1) for i in range(0, len(points), 2): p = path.Node(-1) q = 2 * p - last_quad p3 = trafo(points[i], points[i + 1]) p1 = f13 * p + f23 * q p2 = f13 * p3 + f23 * q path.AppendBezier(p1, p2, p3) last_quad = q elif cmd == 't': if len(points) % 2 != 0: self.loader.add_message("number of parameters of 't'"\ "must be multiple of 4") else: if last_cmd not in 'QqTt' or last_quad is None: last_quad = path.Node(-1) for i in range(0, len(points), 2): p = path.Node(-1) q = 2 * p - last_quad p3 = p + trafo.DTransform(points[i], points[i + 1]) p1 = f13 * p + f23 * q p2 = f13 * p3 + f23 * q path.AppendBezier(p1, p2, p3) last_quad = q elif cmd in 'zZ': if round(path.Node(0).x, 3) != round(path.Node(-1).x, 3) or \ round(path.Node(0).y, 3) != round(path.Node(-1).y, 3): path.AppendLine(path.Node(0)) path.ClosePath() else: break self.path = path
class DXFLoader(GenericLoader): functions={ "POP_TRAFO": 'pop_trafo', "TABLE": 'load_TABLE', "BLOCK": 'load_BLOCK', "LINE": 'load_line', "LWPOLYLINE": 'load_lwpolyline', "POLYLINE": 'load_polyline', "SEQEND": 'load_seqend', "VERTEX": 'load_vertex', "CIRCLE": 'load_circle', "ARC": 'load_arc', "ELLIPSE": 'load_ellips', "POINT": 'load_point', "SOLID": 'load_solid', "INSERT": 'load_insert', "TEXT": 'load_text', #"MTEXT": 'load_text', "3DFACE": 'load_3dface', "SPLINE": 'load_spline', "VIEWPORT": 'load_bypass', } def __init__(self, file, filename, match): GenericLoader.__init__(self, file, filename, match) self.file = file self.DWGCODEPAGE = 'latin1' self.unit_to_pt = 2.83464566929 self.dynamic_style_dict = {} self.style_dict = {} self.ltype_dict = {'CONTINUOUS': { '2': 'CONTINUOUS', # Linetype name '3': 'Solid line', # Descriptive text for linetype '49': [], # Dash, dot or space length #(one entry per element) } } self.layer_dict = {'0': { '2': '0', # Layer name '6': 'CONTINUOUS', #Linetype name '62': 0, # Color number '370': None, #Line weight } } self.block_dict = {} self.stack = [] self.stack_trafo = [] self.default_layer = '0' self.default_style = 'STANDARD' self.default_block = None self.default_line_width = 30 self.EXTMIN = (1e+20, 1e+20) self.EXTMAX = (-1e+20, -1e+20) self.PEXTMIN = (1e+20, 1e+20) self.PEXTMAX = (-1e+20, -1e+20) self.general_param = { '8': self.default_layer, # Layer name '6': 'BYLAYER', # Linetype name '62': 256, # Color number '48': 1.0, # Linetype scale #'60': 0, # Object visibility. If 1 Invisible } self.curstyle = Style() self.update_trafo() def update_trafo(self, scale = 1): EXT_hight = self.EXTMAX[0] - self.EXTMIN[0] EXT_width = self.EXTMAX[1] - self.EXTMIN[1] PEXT_hight = self.PEXTMAX[0] - self.PEXTMIN[0] PEXT_width = self.PEXTMAX[1] - self.PEXTMIN[1] if EXT_hight > 0: scale = 840 / max(EXT_hight, EXT_width) self.unit_to_pt = scale x = self.EXTMIN[0] * scale y = self.EXTMIN[1] * scale elif PEXT_hight > 0: scale = 840 / max(PEXT_hight, PEXT_width) self.unit_to_pt = scale x = self.PEXTMIN[0] * scale y = self.PEXTMIN[1] * scale else: x = 0 y = 0 self.trafo = Trafo(scale, 0, 0, scale, -x, -y) def push_trafo(self, trafo = None): # save trafo in stack_trafo if trafo is None: trafo = self.trafo self.stack_trafo.append(trafo) def pop_trafo(self): self.trafo = self.stack_trafo.pop() def get_pattern(self, color_index): # 0 = Color BYBLOCK if color_index == 0: block_name = self.default_block if block_name is None: layer_name = '0' else: layer_name = self.block_dict[block_name]['8'] color_index = self.layer_dict[layer_name]['62'] # 256 = Color BYLAYER if color_index == 256 or color_index is None: layer_name = self.default_layer color_index = self.layer_dict[layer_name]['62'] ## FIXMY 257 = Color BYENTITY if color_index < 0: pattern = EmptyPattern else: pattern = SolidPattern(colors[color_index]) return pattern def get_line_width(self, layer_name = None): if layer_name is None: layer_name = self.default_layer layer = self.layer_dict[layer_name] if '370' in layer: width = layer['370'] if width == -3 or width is None: width = self.default_line_width width = width * 72.0 / 2.54 /1000 # th 100 mm to pt if width <= 0.0: # XXX width = 0.1 return width def get_line_type(self, linetype_name = None, scale = 1.0, width = 1.0, layer_name = None): #if linetype_name == 'BYBLOCK': #block_name = self.default_block #layer_name = self.block_dict[block_name]['8'] if layer_name is None: layer_name = self.default_layer if linetype_name is None or linetype_name == 'BYLAYER' or linetype_name == 'BYBLOCK': linetype_name = self.layer_dict[layer_name]['6'] linetype = self.ltype_dict[upper(linetype_name)]['49'] lscale = scale * self.unit_to_pt / width dashes = map(lambda i : abs(linetype[i]) * lscale, xrange(len(linetype))) return tuple(dashes) def get_line_style(self, **kw): if kw['8'] in self.layer_dict: self.default_layer = layer_name = kw['8'] else: layer_name = self.default_layer linetype_name = upper(kw['6']) scale = kw['48'] color_index = kw['62'] style = Style() style.line_width = self.get_line_width() style.line_join = const.JoinRound style.line_cap = const.CapRound style.line_dashes = self.get_line_type(linetype_name = linetype_name, scale = scale, width = style.line_width) style.line_pattern = self.get_pattern(color_index) return style ################ # HEADER Section # def load_HEADER(self): return_code = False header_dict = {} variable = None params = {} line1, line2 = self.read_record() while line1 or line2: if variable and (line1 == '9' or line1 == '0'): header_dict[variable] = params else: params[line1] = line2 if line1 == '0' and line2 == 'ENDSEC': return_code = True break elif line1 == '9': params = {} variable = line2 line1, line2 = self.read_record() return return_code, header_dict def process_header(self, header): if '$DWGCODEPAGE' in header: self.DWGCODEPAGE = 'cp'+ upper(header['$DWGCODEPAGE']['3']).replace('ANSI_', '').replace('DOS','') if '$INSUNITS' in header: INSUNITS = convert('70', header['$INSUNITS']['70']) if INSUNITS in unit: self.unit_to_pt = unit[INSUNITS] if '$EXTMIN' in header: param10 = convert('10', header['$EXTMIN']['10']) param20 = convert('20', header['$EXTMIN']['20']) self.EXTMIN = (param10, param20) if '$EXTMAX' in header: param10 = convert('10', header['$EXTMAX']['10']) param20 = convert('20', header['$EXTMAX']['20']) self.EXTMAX = (param10, param20) if '$PEXTMIN' in header: param10 = convert('10', header['$PEXTMIN']['10']) param20 = convert('20', header['$PEXTMIN']['20']) self.PEXTMIN = (param10, param20) if '$PEXTMAX' in header: param10 = convert('10', header['$PEXTMAX']['10']) param20 = convert('20', header['$PEXTMAX']['20']) self.PEXTMAX = (param10, param20) self.update_trafo() if '$CLAYER' in header: self.default_layer = convert('8', header['$CLAYER']['8'], self.DWGCODEPAGE) ################ # TABLES Section # def load_TABLE(self): param={ '2': '', # Table name '70': 0 # Maximum number of entries in table } param = self.read_param(param) table_name = param['2'] table_number = param['70'] print '****', table_name, table_number line1, line2 = self.read_record() while line1 or line2: if line1 == '0' and line2 == 'ENDTAB': break if table_name == 'LTYPE': self.load_LTYPE() elif table_name == 'LAYER': self.load_LAYER() elif table_name == 'STYLE': self.load_STYLE() line1, line2 = self.read_record() def load_LTYPE(self): param={ '2': '', # Linetype name '3': '', # Descriptive text for linetype #'73': 0, # The number of linetype elements #'40': 0, # Total pattern length '49': [], # Dash, dot or space length (one entry per element) } param = self.read_param(param, [0]) name = upper(param['2']) if name: self.ltype_dict[name] = param dashes = [] for i in xrange(len(param['49'])): dashes.append(abs(param['49'][i]) * self.unit_to_pt) name3 = param['3'] #print name3, dashes if name3 and dashes: style = Style() style.line_dashes = tuple(dashes) style = style.AsDynamicStyle() style.SetName(name + name3) self.dynamic_style_dict[name] = style def load_LAYER(self): param={ '2': None, # Layer name '6': None, #Linetype name '62': 0, # Color number '370': None, #Line weight } param = self.read_param(param, [0]) layer_name = param['2'] if layer_name: self.layer_dict[layer_name]=param self.layer(name = layer_name) def load_STYLE(self): param={ '2': None, # Style name '70': 0, # Flag '40': 0.0, # Fixed text height; 0 if not fixed '41': 0.0, # Width factor '42': 0.0, # Last height used '50': 0.0, # Oblique angle '71': 0, # Text generation flags '3': None, # Primary font file name '4': None, # Bigfont file name '1000': None, } param = self.read_param(param, [0]) style_name = upper(param['2']) self.style_dict[style_name] = param ################ # BLOCKS Section # def load_BLOCK(self): param={ '2': '', # Block name '10': 0.0, # X Base point '20': 0.0, # Y Base point #'30': 0.0, # Z Base point '8': self.default_layer, # Layer name 'data': [], # block data } param = self.read_param(param) block_name = param['2'] print '****', block_name line1, line2 = self.read_record() while line1 or line2: if line1 == '0' and line2 == 'ENDBLK': param = self.read_param(param) break param['data'].append(line1) param['data'].append(line2) line1, line2 = self.read_record() param['data'].reverse() self.block_dict[block_name] = param # print self.block_dict[block_name] ################ # ENTITIES Section # def load_line(self): param={ '10': None, # X coordinat '20': None, # y coordinat #'30': None, # Z coordinat '11': None, # X coordinat endpoint '21': None, # y coordinat endpoint #'31': None, # z coordinat endpoint } param.update(self.general_param) param = self.read_param(param) self.path = CreatePath() self.path.AppendLine(self.trafo(param['10'], param['20'])) self.path.AppendLine(self.trafo(param['11'], param['21'])) style = self.get_line_style(**param) self.prop_stack.AddStyle(style.Duplicate()) self.bezier(self.path,) def load_lwpolyline(self): param={ '90': 0, # Number of vertices '70': 0, # bit codes for Polyline entity '40': None, # Starting width '43': 0, '370': None, #Line weight } param.update(self.general_param) param = self.read_param(param,[10,20,42]) if param['40'] is not None: line_width = param['40'] * self.unit_to_pt else: line_width = param['43'] * self.unit_to_pt if param['370'] is not None: line_width = param['370'] * self.unit_to_pt * 72.0 / 2.54 /1000 self.curstyle = self.get_line_style(**param) # if Group 70 Flag bit value set 1 This is a closed Polyline path_flag = param['70'] vertex_path = [] for i in xrange(param['90']): vertex={ '10': None, # X coordinat '20': None, # Y coordinat '42': 0.0 # Bulge } # 10 line1, line2 = self.read_record() vertex[line1] = convert(line1, line2, self.DWGCODEPAGE) # 20 line1, line2 = self.read_record() vertex[line1] = convert(line1, line2, self.DWGCODEPAGE) # 42 line1, line2 = self.read_record() if line1 == '42': vertex[line1] = convert(line1, line2, self.DWGCODEPAGE) else: self.push_record(line1, line2) vertex_path.append((vertex['10'], vertex['20'], vertex['42'])) self.load_seqend(vertex_path, path_flag) def load_polyline(self): param={ '70': 0, # bit codes for Polyline entity '40': 0.01, #XXX FIXMY } param.update(self.general_param) param = self.read_param(param) self.vertex_path = [] self.curstyle.line_width=param['40'] * 72 # XXX self.unit_to_pt self.curstyle.line_pattern = self.get_pattern(param['62']) # if Group 70 Flag bit value set 1 This is a closed Polyline self.path_flag = param['70'] def load_vertex(self): param={#'62': 7, # color #'6': 'CONTINUOUS', # style '10': None, # X coordinat '20': None, # Y coordinat '42': 0.0 # Bulge } param = self.read_param(param) self.vertex_path.append((param['10'], param['20'], param['42'])) def load_seqend(self, line = None, path_flag = None): if line is None: line = self.vertex_path if path_flag is None: path_flag = self.path_flag if path_flag > 1: print 'FIXMY. Curves and smooth surface type', path_flag close_path = path_flag & 1 == 1 path = CreatePath() if len(line): for i in line: x, y, bulge = i #print x, y, bulge path.AppendLine(self.trafo(x, y)) if close_path: if path.Node(0) != path.Node(-1): path.AppendLine(path.Node(0)) path.ClosePath() self.prop_stack.AddStyle(self.curstyle.Duplicate()) self.bezier(path,) def load_circle(self): param={ '10': None, # X coordinat center '20': None, # Y coordinat center #'30': None, # Z coordinat center '40': 0.0 # radius } param.update(self.general_param) param = self.read_param(param) x = param['10'] y = param['20'] r = param['40'] t = self.trafo(Trafo(r,0,0,r,x,y)) style = self.get_line_style(**param) self.prop_stack.AddStyle(style.Duplicate()) apply(self.ellipse, t.coeff()) def load_arc(self): param={ '10': None, # X coordinat center '20': None, # Y coordinat center #'30': None, # Z coordinat center '40': 0.0, # radius '50': 0.0, # Start angle '51': 0.0 # End angle } param.update(self.general_param) param = self.read_param(param) cx = param['10'] cy = param['20'] rx = ry = param['40'] start_angle = param['50'] * degrees end_angle = param['51'] * degrees trafo = self.trafo(Trafo(rx, 0, 0, ry, cx, cy)) rx, w1, w2, ry, cx, cy = trafo.coeff() style = self.get_line_style(**param) self.prop_stack.AddStyle(style.Duplicate()) apply(self.ellipse, (rx, w1, w2, ry, cx, cy, start_angle, end_angle, ArcArc)) def load_ellips(self): param={ '10': 0.0, # X coordinat center '20': 0.0, # Y coordinat center #'30': 0.0, # Z coordinat center '11': 0.0, # Endpoint of major axis, relative to the center '21': 0.0, #'31': 0.0, '40': 0.0, # Ratio of minor axis to major axis '41': 0.0, # Start parameter (this value is 0.0 for a full ellipse) '42': 0.0, # End parameter (this value is 2pi for a full ellipse) } param.update(self.general_param) param = self.read_param(param) cx = param['10'] cy = param['20'] rx = sqrt(param['21']**2 + param['11']**2) ry = rx * param['40'] start_angle = param['41'] end_angle = param['42'] angle=atan2(param['21'], param['11']) center = self.trafo(cx, cy) radius = self.trafo.DTransform(rx, ry) trafo = Trafo(radius.x, 0, 0, radius.y) trafo = Rotation(angle)(trafo) trafo = Translation(center)(trafo) rx, w1, w2, ry, cx, cy = trafo.coeff() style = self.get_line_style(**param) self.prop_stack.AddStyle(style.Duplicate()) apply(self.ellipse, (rx, w1, w2, ry, cx, cy, start_angle, end_angle, ArcArc)) def load_point(self): param={ '10': None, # X coordinat center '20': None, # Y coordinat center #'30': None, # Z coordinat center } param.update(self.general_param) param = self.read_param(param) x = param['10'] y = param['20'] r = 0.3 t = self.trafo(Trafo(r,0,0,r,x,y)) style = self.curstyle.Duplicate() style.line_pattern = EmptyPattern style.fill_pattern = self.get_pattern(param['62']) self.prop_stack.AddStyle(style.Duplicate()) apply(self.ellipse, t.coeff()) def load_solid(self): param={ '10': None, '20': None, #'30': None, '11': None, '21': None, #'31': None, '12': None, '22': None, #'32': None, '13': None, '23': None, #'33': None, } param.update(self.general_param) param = self.read_param(param) style = self.curstyle.Duplicate() style.line_pattern = EmptyPattern style.fill_pattern = self.get_pattern(param['62']) self.path = CreatePath() self.path.AppendLine(self.trafo(param['10'], param['20'])) self.path.AppendLine(self.trafo(param['11'], param['21'])) self.path.AppendLine(self.trafo(param['12'], param['22'])) self.path.AppendLine(self.trafo(param['13'], param['23'])) self.path.ClosePath() self.prop_stack.AddStyle(style.Duplicate()) self.bezier(self.path,) def load_insert(self): param={ '2': None, # Block name '10': 0.0, # X coordinat '20': 0.0, # Y coordinat #'30': 0.0, # Z coordinat '41': 1.0, # X scale factor '42': 1.0, # Y scale factor #'43': 1.0, # Z scale factor '50': 0.0, # Rotation angle '66': 0, # Attributes-follow flag } param = self.read_param(param) block_name = self.default_block = param['2'] if block_name: self.stack += ['POP_TRAFO', '0'] + self.block_dict[block_name]['data'] self.push_trafo() x = param['10'] y = param['20'] block_x = self.block_dict[block_name]['10'] block_y = self.block_dict[block_name]['20'] scale_x = param['41'] * self.trafo.m11 scale_y = param['42'] * self.trafo.m22 angle = param['50'] * degrees translate = self.trafo(x, y) trafo = Trafo(1, 0, 0, 1, -block_x, -block_y) trafo = Scale(scale_x,scale_y)(trafo) trafo = Rotation(angle)(trafo) trafo = Translation(translate)(trafo) self.trafo = trafo if param['66'] != 0: line1, line2 = self.read_record() while line1 or line2: if line1 == '0' and line2 == 'SEQEND': break else: if line1 == '0': self.run(line2) line1, line2 = self.read_record() def load_text(self): param={ '10': 0.0, '20': 0.0, '40': None, # Text height '1': '', # Default value '50': 0, # Text rotation '41': 1, # Relative X scale factor—width # '8': self.default_layer, # Layer name '7': self.default_style, # Style name '72': 0, #Horizontal text justification type } param.update(self.general_param) param = self.read_param(param) x = param['10'] y = param['20'] scale_x = param['41'] scale_y = 1 angle = param['50'] * pi / 180 font_size = param['40'] * self.trafo.m11 halign = [ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT, \ ALIGN_LEFT, ALIGN_LEFT, ALIGN_LEFT][param['72']] text = unicode_decoder(param['1'], self.DWGCODEPAGE) #style = self.style_dict[param['7']] # print style style_text = self.curstyle.Duplicate() style_text.line_pattern = EmptyPattern style_text.fill_pattern = self.get_pattern(param['62']) style_name = upper(param['7']) style = self.style_dict[style_name] font_name = style['1000'] if font_name == 'Arial': # XXX font_name = 'ArialMT' style_text.font = GetFont(font_name) # print style_text.font style_text.font_size = font_size trafo_text = Translation(self.trafo(x, y))(Rotation(angle))(Scale(scale_x, scale_y)) self.prop_stack.AddStyle(style_text.Duplicate()) self.simple_text(strip(text), trafo_text, halign = halign) def load_3dface(self): param={ '10': None, '20': None, #'30': None, '11': None, '21': None, #'31': None, '12': None, '22': None, #'32': None, '13': None, '23': None, #'33': None, '70': 0, # Invisible edge flags } param.update(self.general_param) param = self.read_param(param) self.path = CreatePath() if param['70'] != 0: print 'FIXMY. 3dface Invisible edge flags', param['70'] self.path.AppendLine(self.trafo(param['10'], param['20'])) self.path.AppendLine(self.trafo(param['11'], param['21'])) self.path.AppendLine(self.trafo(param['12'], param['22'])) self.path.AppendLine(self.trafo(param['13'], param['23'])) self.path.ClosePath() style = self.get_line_style(**param) self.prop_stack.AddStyle(style.Duplicate()) self.bezier(self.path,) def load_spline(self): param={ '70': 0, # Spline flag '71': 0, # Degree of the spline curve '72': 0, # Number of knots '73': 0, # Number of control points '74': 0, # Number of fit points '40': [], # Knot value '10': [], # Control points X '20': [], # Control points Y #'30': [], # Control points Z } param.update(self.general_param) param = self.read_param(param) closed = param['70'] & 1 path = CreatePath() f13 = 1.0 / 3.0 f23 = 2.0 / 3.0 curve = path.AppendBezier straight = path.AppendLine pts = map(lambda x, y: self.trafo(x, y), param['10'],param['20']) print 'SPLINE', param['70'], len(pts) #for i in range(0, len(pts)-1): #self.ellipse(.2, 0, 0, .2, pts[i][0],pts[i][1]) if param['70'] <= 1: straight(pts[0]) for i in range(1, len(pts) / 4): node = pts[i * 4] c1 = pts[i * 4 - 3] c2 = pts[i * 4 - 2] print c1, c2, node curve(c1, c2, node) #straight(node) if closed: curve(pts[-3], pts[-2], pts[0]) else: curve(pts[-4], pts[-4], pts[-1]) if param['70'] & 4 == 4: last = pts[0] cur = pts[1] start = node = (last + cur) / 2 if closed: straight(node) else: straight(last) straight(node) last = cur for cur in pts[2:]: c1 = f13 * node + f23 * last node = (last + cur) / 2 c2 = f13 * node + f23 * last curve(c1, c2, node) last = cur if closed: curve(f13 * node + f23 * last, f13 * start + f23 * last, start) else: straight(last) if param['70'] & 8 == 8: node = pts[0] c1 = pts[1] c2 = pts[2] # first node straight(node) if len(pts) > 4: c2 = (pts[2] + pts[1]) / 2 c3 = pts[3] * f13 + pts[2] * f23 node = (c3 + c2) / 2 curve(c1, c2, node) c1 = c3 for i in range(3, len(pts) - 3): c2 = pts[i - 1] * f13 + pts[i] * f23 c3 = pts[i] * f23 + pts[i + 1] * f13 node = (c3 + c2) / 2 curve(c1, c2, node) c1 = c3 c2 = pts[-4] * f13 + pts[-3] * f23 c3 = (pts[-3] + pts[-2]) / 2 node = (c3 + c2) / 2 curve(c1, c2, node) c1 = c3 # last node curve(c1, pts[-2], pts[-1]) style = self.get_line_style(**param) self.prop_stack.AddStyle(style.Duplicate()) self.bezier(path,) def load_bypass(self): pass ########################################################################### def get_compiled(self): funclist={} for char, name in self.functions.items(): method = getattr(self, name) argc = method.im_func.func_code.co_argcount - 1 funclist[char] = (method, argc) return funclist def push_record(self, line1, line2): # save data in stack self.stack.append(line2) self.stack.append(line1) def read_record(self): # if the stack is empty read two lines from a file if self.stack: line1 = self.stack.pop() line2 = self.stack.pop() else: line1 = self.file.readline().strip() line2 = self.file.readline().strip() return line1, line2 def read_param(self, param, stop=None): # read data and fill in the dictionary if stop is None: stop = [0, 9] line1, line2 = self.read_record() while line1 or line2: if int(line1) in stop: self.push_record(line1, line2) return param else: if line1 in param: value = convert(line1, line2, self.DWGCODEPAGE) if type(param[line1]) == list: param[line1].append(value) else: param[line1] = value line1,line2 = self.read_record() return False def find_record(self, code1, code2): # read data until to not overlap line1 == code1 and line2 == code2 # return True # else return False line1, line2 = self.read_record() while line1 or line2: if line1 == code1 and line2 == code2: return True line1, line2 = self.read_record() return False def load_section(self): return_code = False file = self.file parsed = self.parsed parsed_interval = self.parsed_interval line1, line2 = self.read_record() while line1 or line2: interval_count = file.tell() / parsed_interval if interval_count > parsed: parsed += 10 # 10% progress app.updateInfo(inf2 = '%u' % parsed + _('% of file is parsed...'), inf3 = parsed) if line1 == '0' and line2 == 'ENDSEC': return_code = True break elif line1 == '0': self.run(line2) line1, line2 = self.read_record() self.parsed = parsed return return_code def load_sections(self): return_code = False param={ '2': '', # name section } param = self.read_param(param) name=param['2'] print '**',name if name == 'HEADER': return_code, header_dict = self.load_HEADER() self.process_header(header_dict) elif name == 'CLASSES': return_code = self.find_record('0','ENDSEC') elif name == 'OBJECTS': return_code = self.find_record('0','ENDSEC') elif name == 'THUMBNAILIMAGE': return_code = self.find_record('0','ENDSEC') else: return_code = self.load_section() return return_code def interpret(self): file = self.file if type(file) == StringType: file = open(file, 'r') file.seek(0) readline = file.readline fileinfo = os.stat(self.filename) totalsize = fileinfo[6] self.parsed = 0 self.parsed_interval = totalsize / 99 + 1 line1, line2 = self.read_record() while line1 or line2: if line1 == '0': if line2 == 'EOF': break elif not self.load_sections(): warn_tb(INTERNAL, _('DXFLoader: error. Non find end of sections')) line1, line2 = self.read_record() def run(self,keyword, *args): if keyword is None: return return_code = False unknown_operator = (None, None) funclist = self.funclist if keyword is not None: method, argc = funclist.get(keyword, unknown_operator) if method is not None: try: ##print '******', keyword if len(args): i = 0 while i<len(args): return_code = apply(method, args[i:argc+i]) i+=argc else: return_code = method() except: warn_tb(INTERNAL, 'DXFLoader: error') else: self.add_message(_('Not interpreted %s') % keyword) return return_code def Load(self): import time start_time = time.clock() #print ' ************ "DXF_objects" **************' self.funclist = self.get_compiled() self.document() self.layer(name = _("DXF_objects")) self.interpret() self.end_all() for style in self.dynamic_style_dict.values(): self.object.load_AddStyle(style) self.object.load_Completed() print 'times',time.clock() - start_time return self.object
def average_points(context): # find a bezier polygon selected selection = [] for object in context.document.SelectedObjects(): if not object.is_Bezier: continue selection.append(object) if len(selection) != 1: context.application.MessageBox(title="Average Points", message="Select one polygon.") return None # count selected points object = selection[0] object_paths = object.Paths() npoints = 0 for path in object_paths: for i in range(path.len): if path.SegmentSelected(i): npoints = npoints + 1 if npoints == 0: context.application.MessageBox(title="Average Points", message="Select two or more points.") return None # inquiry parameters which = AverageDialog(context.application.root).RunDialog() if which is None: return None # compute average coordinates of the selected points ax = 0 ay = 0 modified_paths = [] for path in object_paths: modified_paths.append([]) for i in range(path.len): type, controls, point, cont = path.Segment(i) modified_paths[-1].append([type, list(controls), point, cont]) if path.SegmentSelected(i): ax = ax + point.x ay = ay + point.y ax = float(ax) / npoints ay = float(ay) / npoints # translate the selected points for i in range(len(object_paths)): path = object_paths[i] new_path = modified_paths[i] for j in range(path.len): if path.SegmentSelected(j): point = new_path[j][2] if which == AVERAGE_X: new_point = Point(ax, point.y) elif which == AVERAGE_Y: new_point = Point(point.x, ay) else: new_point = Point(ax, ay) new_path[j][2] = new_point offset = point - new_point if len(new_path[j][1]) == 2: new_path[j][1][1] = new_path[j][1][1] - offset if j < path.len - 1 and len(new_path[j + 1][1]) == 2: new_path[j + 1][1][0] = new_path[j + 1][1][0] - offset # create new paths new_paths = [] for i in range(len(object_paths)): path = object_paths[i] new_path = CreatePath() for type, controls, point, cont in modified_paths[i]: new_path.AppendSegment(type, tuple(controls), point, cont) if path.closed: new_path.AppendLine(new_path.Node(0)) new_path.ClosePath() new_paths.append(new_path) # set the new paths undo = object.SetPaths(new_paths) # return Undo info return undo
def loda_coords(self, chunk, type, offset, version, trafo): if type == 1: # rectangle CoordX1 = 0 CoordY1 = 0 [CoordX2] = struct.unpack('<L', chunk.data[offset:offset + 4]) [CoordY2] = struct.unpack('<L', chunk.data[offset + 4:offset + 8]) if CoordX2 > 0x7FFFFFFF: CoordX2 = CoordX2 - 0x100000000 if CoordY2 > 0x7FFFFFFF: CoordY2 = CoordY2 - 0x100000000 CoordX1, CoordY1 = trafo(CoordX1, CoordY1) CoordX2, CoordY2 = trafo(CoordX2, CoordY2) path = CreatePath() path.AppendLine(Point(CoordX1 * self.scale, CoordY1 * self.scale)) path.AppendLine(Point(CoordX2 * self.scale, CoordY1 * self.scale)) path.AppendLine(Point(CoordX2 * self.scale, CoordY2 * self.scale)) path.AppendLine(Point(CoordX1 * self.scale, CoordY2 * self.scale)) path.AppendLine(Point(CoordX1 * self.scale, CoordY1 * self.scale)) path.AppendLine(path.Node(0)) path.ClosePath() self.current_paths.append(path) if type == 3: # line and curve [pointnum] = struct.unpack('<L', chunk.data[offset:offset + 4]) path = None point1 = None point2 = None cont = ContSymmetrical for i in range(pointnum): [CoordX] = struct.unpack( '<L', chunk.data[offset + 4 + i * 8:offset + 8 + i * 8]) [CoordY] = struct.unpack( '<L', chunk.data[offset + 8 + i * 8:offset + 12 + i * 8]) if CoordX > 0x7FFFFFFF: CoordX = CoordX - 0x100000000 if CoordY > 0x7FFFFFFF: CoordY = CoordY - 0x100000000 CoordX, CoordY = trafo(CoordX, CoordY) Type = ord(chunk.data[offset + 4 + pointnum * 8 + i]) if Type & 2 == 2: pass if Type & 4 == 4: pass if Type & 0x10 == 0 and Type & 0x20 == 0: cont = ContAngle if Type & 0x10 == 0x10: cont = ContSmooth if Type & 0x20 == 0x20: cont = ContSymmetrical if Type & 0x40 == 0 and Type & 0x80 == 0: if path: self.current_paths.append(path) path = CreatePath() path.AppendLine( Point(CoordX * self.scale, CoordY * self.scale)) point1 = None point2 = None if Type & 0x40 == 0x40 and Type & 0x80 == 0: if path: path.AppendLine( Point(CoordX * self.scale, CoordY * self.scale)) point1 = None point2 = None if Type & 0x40 == 0 and Type & 0x80 == 0x80: path.AppendBezier( point1, point2, Point(CoordX * self.scale, CoordY * self.scale), cont) point1 = None point2 = None if Type & 0x40 == 0x40 and Type & 0x80 == 0x80: if point1: point2 = Point(CoordX * self.scale, CoordY * self.scale) else: point1 = Point(CoordX * self.scale, CoordY * self.scale) if Type & 8 == 8: if path: path.ClosePath() if path: self.current_paths.append(path) if type == 5: # bitmap bmp_color_models = ('Invalid', 'Pal1', 'CMYK255', 'RGB', 'Gray', 'Mono', 'Pal6', 'Pal7', 'Pal8') bmp_clrmode = ord(chunk.data[offset + 0x30]) clrdepth = ord(chunk.data[offset + 0x22]) [width] = struct.unpack('<L', chunk.data[offset + 0x24:offset + 0x28]) [height] = struct.unpack('<L', chunk.data[offset + 0x28:offset + 0x2c]) [idx1] = struct.unpack('<L', chunk.data[offset + 0x2c:offset + 0x30]) numbmp = ord(chunk.data[offset + 0x30]) [idx2] = struct.unpack('<L', chunk.data[offset + 0x34:offset + 0x38]) [idx3] = struct.unpack('<L', chunk.data[offset + 0x38:offset + 0x3c]) self.extract_bmp(numbmp, width, height)
def read_objects(self, objects): n_objects = 0 # Traverse the list of drawfile object for object in objects: if isinstance(object, drawfile.group): # Start a group object in the document self.begin_group() # Descend into the group n_objects_lower = self.read_objects(object.objects) # If the group was empty then don't try to end it if n_objects_lower == 0: # self.__pop() (self.composite_class, self.composite_args, self.composite_items, self.composite_stack) = self.composite_stack else: # End group object self.end_group() n_objects = n_objects + 1 elif isinstance(object, drawfile.tagged): # Tagged object n_objects_lower = self.read_objects([object.object]) if n_objects_lower != 0: n_objects = n_objects + 1 elif isinstance(object, drawfile.path): # Path object n_objects = n_objects + 1 # Set the path style self.style.line_width = object.width / scale if object.style['join'] == 'mitred': self.style.line_join = const.JoinMiter if object.style['start cap'] == 'butt': self.style.line_cap = const.CapButt elif object.style['start cap'] == 'round': if object.width > 0: width = 0.5 length = 0.5 else: width = 0.0 length = 0.0 # Draw arrow path = [(0.0, width), (0.5 * length, width, length, 0.5 * width, length, 0.0), (length, -0.5 * width, 0.5 * length, -width, 0.0, -width), (0.0, width)] self.style.line_arrow1 = Arrow(path, 1) elif object.style['start cap'] == 'square': if object.width > 0: width = 0.5 length = 0.5 else: width = 0.0 length = 0.0 # Draw arrow path = [(0.0, width), (length, width), (length, -width), (0.0, -width), (0.0, width)] self.style.line_arrow1 = Arrow(path, 1) elif object.style['start cap'] == 'triangular': if object.width > 0: width = object.style['triangle cap width'] / 16.0 length = object.style['triangle cap length'] / 16.0 else: width = 0.0 length = 0.0 # Draw arrow path = [(0.0, width), (length, 0.0), (0.0, -width), (0.0, width)] self.style.line_arrow1 = Arrow(path, 1) if (object.width / scale) < 1.0: self.style.line_arrow1.path.Transform( Scale(object.width / scale, object.width / scale)) if object.style['end cap'] == 'butt': self.style.line_cap = const.CapButt elif object.style['end cap'] == 'round': if object.width > 0: width = 0.5 length = 0.5 else: width = 0.0 length = 0.0 # Draw arrow path = [(0.0, width), (0.5 * length, width, length, 0.5 * width, length, 0.0), (length, -0.5 * width, 0.5 * length, -width, 0.0, -width), (0.0, width)] self.style.line_arrow2 = Arrow(path, 1) elif object.style['end cap'] == 'square': if object.width > 0: width = 0.5 length = 0.5 else: width = 0.0 length = 0.0 # Draw arrow path = [(0.0, width), (length, width), (length, -width), (0.0, -width), (0.0, width)] self.style.line_arrow2 = Arrow(path, 1) elif object.style['end cap'] == 'triangular': if object.width > 0: width = object.style['triangle cap width'] / 16.0 length = object.style['triangle cap length'] / 16.0 else: width = 0.0 length = 0.0 # Draw arrow path = [(0.0, width), (length, 0.0), (0.0, -width), (0.0, width)] self.style.line_arrow2 = Arrow(path, 1) if (object.width / scale) < 1.0: self.style.line_arrow2.path.Transform( Scale(object.width / scale, object.width / scale)) # Outline colour if object.outline == [255, 255, 255, 255]: self.style.line_pattern = EmptyPattern else: self.style.line_pattern = SolidPattern( CreateRGBColor( float(object.outline[1]) / 255.0, float(object.outline[2]) / 255.0, float(object.outline[3]) / 255.0)) # Fill colour if object.fill == [255, 255, 255, 255]: self.style.fill_pattern = EmptyPattern else: self.style.fill_pattern = SolidPattern( CreateRGBColor( float(object.fill[1]) / 255.0, float(object.fill[2]) / 255.0, float(object.fill[3]) / 255.0)) # Dash pattern if object.style['dash pattern'] == 'present': line_dashes = [] for n in object.pattern: line_dashes.append(int(n / scale)) self.style.line_dashes = tuple(line_dashes) # Create a list of path objects in the document paths = [] path = None # Examine the path elements for element in object.path: if element[0] == 'move': x, y = self.relative(element[1][0], element[1][1]) # Add any previous path to the list if path != None: # path.load_close() paths.append(path) path = CreatePath() path.AppendLine(x, y) elif element[0] == 'draw': x, y = self.relative(element[1][0], element[1][1]) path.AppendLine(x, y) elif element[0] == 'bezier': x1, y1 = self.relative(element[1][0], element[1][1]) x2, y2 = self.relative(element[2][0], element[2][1]) x, y = self.relative(element[3][0], element[3][1]) path.AppendBezier(x1, y1, x2, y2, x, y) elif element[0] == 'close': path.ClosePath() elif element[0] == 'end': # Should be the last object in the path # path.load_close() paths.append(path) break # Create a bezier object if paths != []: self.bezier(tuple(paths)) elif isinstance(object, drawfile.font_table): # Font table n_objects = n_objects + 1 # Set object level instance self.font_table = object.font_table elif isinstance(object, drawfile.text): # Text object n_objects = n_objects + 1 # Determine the font if self.font_table.has_key(object.style): self.style.font = RISCOSFont(self.font_table[object.style]) else: self.style.font = GetFont('Times Roman') # The size self.style.font_size = object.size[0] / scale # Outline colour if object.background == [255, 255, 255, 255]: self.style.line_pattern = EmptyPattern else: self.style.line_pattern = SolidPattern( CreateRGBColor( float(object.background[1]) / 255.0, float(object.background[2]) / 255.0, float(object.background[3]) / 255.0)) # Fill colour if object.foreground == [255, 255, 255, 255]: self.style.fill_pattern = EmptyPattern else: self.style.fill_pattern = SolidPattern( CreateRGBColor( float(object.foreground[1]) / 255.0, float(object.foreground[2]) / 255.0, float(object.foreground[3]) / 255.0)) # Transformation if hasattr(object, 'transform'): x, y = object.transform[4] / scale, object.transform[ 5] / scale ox, oy = self.relative(object.baseline[0], object.baseline[1]) transform = Trafo(object.transform[0] / 65536.0, object.transform[1] / 65536.0, object.transform[2] / 65536.0, object.transform[3] / 65536.0, ox + x, oy + y) else: transform = Translation( self.relative(object.baseline[0], object.baseline[1])) # Write the text self.simple_text(object.text, transform) elif isinstance(object, drawfile.jpeg): # JPEG object n_objects = n_objects + 1 # Transformation matrix x, y = self.relative(object.transform[4], object.transform[5]) # Scale the object using the dpi information available, noting # that unlike Draw which uses 90 dpi, Sketch uses 72 dpi. # (I assume this since 90 dpi Drawfile JPEG objects appear 1.25 # times larger in Sketch if no scaling is performed here.) scale_x = (object.transform[0] / 65536.0) * (72.0 / object.dpi_x) scale_y = (object.transform[3] / 65536.0) * (72.0 / object.dpi_y) transform = Trafo(scale_x, object.transform[1] / 65536.0, object.transform[2] / 65536.0, scale_y, x, y) # Decode the JPEG image image = Image.open(StringIO.StringIO(object.image)) # # Read dimensions of images in pixels # width, height = image.size # # # Divide these by the dpi values to obtain the size of the # # image in inches # width, height = width/float(object.dpi_x), \ # height/float(object.dpi_y) # image.load() self.image(image, transform) elif isinstance(object, drawfile.sprite): # Sprite object n_objects = n_objects + 1 # Transformation matrix if hasattr(object, 'transform'): x, y = self.relative(object.transform[4], object.transform[5]) # Multiply the scale factor by that in the transformation matrix scale_x = (object.transform[0] / 65536.0) * (72.0 / object.sprite['dpi x']) scale_y = (object.transform[3] / 65536.0) * (72.0 / object.sprite['dpi y']) transform = Trafo(scale_x, (object.transform[1] / 65536.0) * \ (72.0 / object.sprite['dpi y']), (object.transform[2] / 65536.0) * \ (72.0 / object.sprite['dpi x']), scale_y, x, y) else: x, y = self.relative(object.x1, object.y1) # Draw scales the Sprite to fit in the object's # bounding box. To do the same, we need to know the # actual size of the Sprite # In points: # size_x = 72.0 * float(object.sprite['width']) / \ # object.sprite['dpi x'] # size_y = 72.0 * float(object.sprite['height']) / \ # object.sprite['dpi y'] # # # Bounding box dimensions in points: # bbox_width = (object.x2 - object.x1)/scale # bbox_height = (object.y2 - object.y1)/scale # # # Scale factors # scale_x = (bbox_width / size_x) * \ # (72.0 / object.sprite['dpi x']) # scale_y = (bbox_height / size_y) * \ # (72.0 / object.sprite['dpi y']) scale_x = (object.x2 - object.x1) / (scale * object.sprite['width']) scale_y = (object.y2 - object.y1) / (scale * object.sprite['height']) transform = Trafo(scale_x, 0.0, 0.0, scale_y, x, y) # Create an Image object image = Image.fromstring( object.sprite['mode'], (object.sprite['width'], object.sprite['height']), object.sprite['image']) self.image(image, transform) elif isinstance(object, drawfile.options): # Options object n_objects = n_objects + 1 # Read page size paper_size = object.options['paper size'] orientation = object.options['paper limits'] if paper_size in papersizes: if orientation == 'landscape': self.page_layout = pagelayout.PageLayout( object.options['paper size'], orientation=pagelayout.Landscape) else: self.page_layout = pagelayout.PageLayout( object.options['paper size'], orientation=pagelayout.Portrait) if object.options['grid locking'] == 'on': spacing = object.options['grid spacing'] if object.options['grid units'] == 'in': spacing = spacing * 72.0 else: spacing = spacing * 72.0 / 2.54 if object.options['grid shown'] == 'on': visible = 1 else: visible = 0 # self.begin_layer_class( GridLayer, # ( # (0, 0, int(spacing), int(spacing)), # visible, # CreateRGBColor(0.0, 0.0, 0.0), # _("Grid") # ) ) # self.end_composite() elif isinstance(object, drawfile.text_area): # Text area n_objects = n_objects + 1 # The text area object contains a number of columns. self.columns = len(object.columns) # Start in the first column and move to subsequent # columns as required, unless the number is overidden # by details in the text area. self.column = 0 # The cursor position is initially undefined. cursor = [None, None] # The column margins self.margin_offsets = [1.0, 1.0] self.margins = [ (object.columns[self.column].x1 / scale) + \ self.margin_offsets[0], (object.columns[self.column].x2 / scale) - \ self.margin_offsets[1] ] # The column base self.column_base = object.columns[self.column].y1 / scale # Line and paragraph spacing self.linespacing = 0.0 paragraph = 10.0 # Current font name and dimensions font_name = '' font_size = 0.0 font_width = 0.0 # Text colours background = (255, 255, 255) foreground = (0, 0, 0) # Build lines (lists of words) until the column width # is reached then write the line to the page. line = [] width = 0.0 # Current text alignment align = 'L' # Last command to be executed last_command = '' # Execute the commands in the text area: for command, args in object.commands: if command == '!': # Version number # print 'Version number', args pass elif command == 'A': # print 'Align:', args # Write current line self.ta_write_line(align, cursor, line, 0) # Empty the line list line = [] # Set the line width width = 0.0 # Align text align = args # Start new line cursor = self.ta_new_line(cursor, object, self.linespacing) elif command == 'B': # print 'Background:', args # Background colour background = args elif command == 'C': # print 'Foreground:', args # Foreground colour foreground = args elif command == 'D': # print 'Columns:', args # Number of columns if self.column == 0 and cursor == [None, None]: # Nothing rendered yet, so change number of columns self.columns = args elif command == 'F': # print 'Define font:', args # Define font (already defined in object.font_table) pass elif command == 'L': # print 'Line spacing:', args # Set line spacing self.linespacing = args elif command == 'M': # print 'Margins:', args # Change margins self.margin_offsets = [args[0], args[1]] self.margins = [ (object.columns[self.column].x1 / scale) + args[0], (object.columns[self.column].x2 / scale) - args[1] ] elif command == 'P': # print 'Paragraph spacing:', args # Change paragraph spacing paragraph = args elif command == 'U': # print 'Underlining' # Underlining pass elif command == 'V': # print 'Vertical displacement' # Vertical displacement pass elif command == '-': # print 'Hyphen' # Hyphen pass elif command == 'newl': # print 'New line' # New line # Write current line self.ta_write_line(align, cursor, line, 0) # Start new line cursor = self.ta_new_line(cursor, object, self.linespacing) # Can't position cursor? if cursor == [None, None]: break # Empty the line list line = [] # Set the line width width = 0.0 elif command == 'para': # print 'New paragraph' # New paragraph # Write current line self.ta_write_line(align, cursor, line, 0) # Start new line if last_command != 'newl': cursor = self.ta_new_line( cursor, object, paragraph + self.linespacing) else: cursor = self.ta_new_line(cursor, object, paragraph) # Can't position cursor? if cursor == [None, None]: break # Empty the line list line = [] # Set the line width width = 0.0 elif command == ';': # print 'Comment:', args # Comment pass elif command == 'font': # print 'Use font:', args # Font change font_name, font_size, font_width = object.font_table[ args] # Select font use_font = RISCOSFont(font_name) # Move cursor to start of a line if the cursor is # undefined if cursor == [None, None]: cursor[0] = self.margins[0] cursor[1] = (object.columns[self.column].y2 / scale) - font_size # Set line spacing self.linespacing = font_size elif command == 'text': # print args # Text. Add it to the line, checking that the line # remains within the margins. text, space = self.make_safe(args[0]), args[1] # Add the width of the text to the current total width textobj = SimpleText() width = width + use_font.TextCoordBox( text, font_size, textobj.properties)[2] # print width, margins[1] - margins[0] # Compare current total width with column width while width > (self.margins[1] - self.margins[0]): # First write any text on this line if line != []: # Width will exceed column width # print 'Width will exceed column width' # Write current line self.ta_write_line(align, cursor, line, 1) # Start new line cursor = self.ta_new_line( cursor, object, self.linespacing) # Can't position cursor? if cursor == [None, None]: break # Clear the list line = [] # Reset the width width = 0.0 # Now attempt to fit this word on the next line width = use_font.TextCoordBox( text, font_size, textobj.properties)[2] br = len(text) # Continue to try until the word fits, or none of it fits while width > (self.margins[1] - self.margins[0]) and br > 0: # Keep checking the size of the word width = use_font.TextCoordBox( text[:br], font_size, textobj.properties)[2] br = br - 1 if br == 0: # Word couldn't fit in the column at all, so # break out of this loop break elif br < len(text): # Write the subword to the line self.ta_write_line( align, cursor, [(text[:br], font_name, font_size, font_width, self.ta_set_colour(foreground), self.ta_set_colour(background))], 0) # Start new line cursor = self.ta_new_line( cursor, object, self.linespacing) # Can't position cursor? if cursor == [None, None]: break # keep the remaining text text = text[br:] # The width is just the width of this text width = use_font.TextCoordBox( text, font_size, textobj.properties)[2] # If the whole string fit onto the line then # control will flow to the else clause which will # append the text to the line list for next time. else: # The text fits within the margins so add the text # to the line line.append( (text, font_name, font_size, font_width, self.ta_set_colour(foreground), self.ta_set_colour(background))) # Also append any trailing space if space != '': line.append( (space, font_name, font_size, font_width, self.ta_set_colour(foreground), self.ta_set_colour(background))) width = width + use_font.TextCoordBox( space, font_size, textobj.properties)[2] # Can't position cursor? if cursor == [None, None]: break # Remember this command last_command = command # Render any remaining text if line != [] and cursor != [None, None]: # Write current line self.ta_write_line(align, cursor, line, 0) else: pass # Return the number of recognised objects return n_objects
def loda_coords(self,chunk,type,offset,version,trafo): if type == 1: # rectangle [CoordX2] = struct.unpack('<L', chunk.data[offset:offset+4]) [CoordY2] = struct.unpack('<L', chunk.data[offset+4:offset+8]) if CoordX2 > 0x7FFFFFFF: CoordX2 = CoordX2 - 0x100000000 if CoordY2 > 0x7FFFFFFF: CoordY2 = CoordY2 - 0x100000000 [R1] = struct.unpack('<L', chunk.data[offset+8:offset+12]) CoordX2=CoordX2*self.scale CoordY2=CoordY2*self.scale radiuses=[] R1=R1*self.scale if R1: radiuses=[abs(R1/CoordX2),abs(R1/CoordY2)] rect_trafo=Trafo(CoordX2,0,0,CoordY2,0,0) self.rectangle=[trafo(rect_trafo),radiuses] if type == 2: # ellipse [CoordX2] = struct.unpack('<L', chunk.data[offset:offset+4]) [CoordY2] = struct.unpack('<L', chunk.data[offset+4:offset+8]) [startangle] = struct.unpack('<L', chunk.data[offset+8:offset+12]) [endangle] = struct.unpack('<L', chunk.data[offset+12:offset+16]) [rotangle] = struct.unpack('<L', chunk.data[offset+16:offset+20]) ellipse_type=False if not startangle==endangle and rotangle == 0: ellipse_type=True startangle /=1000000.0 endangle /=1000000.0 startangle=math.radians(startangle) endangle=math.radians(endangle) angles=[startangle,endangle] if CoordX2 > 0x7FFFFFFF: CoordX2 = CoordX2 - 0x100000000 if CoordY2 > 0x7FFFFFFF: CoordY2 = CoordY2 - 0x100000000 v1=CoordX2/2 v2=CoordY2/2 CoordX2=CoordX2*self.scale/2 CoordY2=CoordY2*self.scale/2 ellipse_trafo=Trafo(CoordX2,0,0,CoordY2,v1,v2) self.ellipse=[trafo(ellipse_trafo),angles,ellipse_type] if type == 3: # line and curve [pointnum] = struct.unpack('<L', chunk.data[offset:offset+4]) path=None point1=None point2=None cont=ContSymmetrical for i in range (pointnum): [CoordX] = struct.unpack('<L', chunk.data[offset+4+i*8:offset+8+i*8]) [CoordY] = struct.unpack('<L', chunk.data[offset+8+i*8:offset+12+i*8]) if CoordX > 0x7FFFFFFF: CoordX = CoordX - 0x100000000 if CoordY > 0x7FFFFFFF: CoordY = CoordY - 0x100000000 CoordX, CoordY=trafo(CoordX, CoordY) Type = ord(chunk.data[offset+4+pointnum*8+i]) if Type&2 == 2: pass if Type&4 == 4: pass if Type&0x10 == 0 and Type&0x20 == 0: cont=ContAngle if Type&0x10 == 0x10: cont=ContSmooth if Type&0x20 == 0x20: cont=ContSymmetrical if Type&0x40 == 0 and Type&0x80 == 0: if path: self.current_paths.append(path) path = CreatePath() path.AppendLine(Point(CoordX*self.scale, CoordY*self.scale)) point1=None point2=None if Type&0x40 == 0x40 and Type&0x80 == 0: if path: path.AppendLine(Point(CoordX*self.scale, CoordY*self.scale)) point1=None point2=None if Type&0x40 == 0 and Type&0x80 == 0x80: path.AppendBezier(point1,point2,Point(CoordX*self.scale, CoordY*self.scale),cont) point1=None point2=None if Type&0x40 == 0x40 and Type&0x80 == 0x80: if point1: point2=Point(CoordX*self.scale, CoordY*self.scale) else: point1=Point(CoordX*self.scale, CoordY*self.scale) if Type&8 == 8: if path: path.ClosePath() if path: self.current_paths.append(path) if type == 5: # bitmap bmp_color_models = ('Invalid','Pal1','CMYK255','RGB','Gray','Mono','Pal6','Pal7','Pal8') bmp_clrmode = ord(chunk.data[offset+0x30]) clrdepth = ord(chunk.data[offset+0x22]) [width] = struct.unpack('<L', chunk.data[offset+0x24:offset+0x28]) [height] = struct.unpack('<L', chunk.data[offset+0x28:offset+0x2c]) [idx1] = struct.unpack('<L', chunk.data[offset+0x2c:offset+0x30]) numbmp = ord(chunk.data[offset+0x30]) [idx2] = struct.unpack('<L', chunk.data[offset+0x34:offset+0x38]) [idx3] = struct.unpack('<L', chunk.data[offset+0x38:offset+0x3c]) if version == 7: shift = 0x3c if version == 8: shift = 0x40 if version > 8: shift = 0x48 offset = offset + shift points=[] #For bitmaps always should be 4 points [pointnum] = struct.unpack('<L', chunk.data[offset:offset+4]) for i in range (pointnum): [CoordX] = struct.unpack('<L', chunk.data[offset+4+i*8:offset+8+i*8]) [CoordY] = struct.unpack('<L', chunk.data[offset+8+i*8:offset+12+i*8]) if CoordX > 0x7FFFFFFF: CoordX -= 0x100000000 if CoordY > 0x7FFFFFFF: CoordY -= 0x100000000 points.append([round(CoordX/10000.0,2),round(CoordY/10000.0,2)]) w=abs(points[2][0]-points[0][0]) h=abs(points[2][1]-points[0][1]) #Calc dpi trafo width_mm=width*25.4/72 height_mm=height*25.4/72 self.image_dpi_trafo=[w/width_mm, h/height_mm] self.extract_bmp(numbmp,width,height)
def GetPaths(self, text, prop): # convert glyph data into bezier polygons paths = [] fheight = self.getFontHeight(prop) voffset = 0 tab = 1 lastIndex = 0 lines = split(text, '\n') for line in lines: offset = c = 0 align_offset = self.getAlignOffset(line, prop) for c in line: if c == '\t': c = ' ' tab = 3 else: tab = 1 try: thisIndex = self.enc_vector[ord(c)] except: thisIndex = self.enc_vector[ord('?')] glyph = ft2.Glyph(self.face, thisIndex, 1) kerning = self.face.getKerning(lastIndex, thisIndex, 0) lastIndex = thisIndex offset += kerning[0] / 4.0 voffset += kerning[1] / 4.0 for contour in glyph.outline: # rotate contour so that it begins with an onpoint x, y, onpoint = contour[0] if onpoint: for j in range(1, len(contour)): x, y, onpoint = contour[j] if onpoint: contour = contour[j:] + contour[:j] break else: print "unsupported type of contour (no onpoint)" # create a sK1 path object path = CreatePath() j = 0 npoints = len(contour) x, y, onpoint = contour[0] last_point = Point(x, y) while j <= npoints: if j == npoints: x, y, onpoint = contour[0] else: x, y, onpoint = contour[j] point = Point(x, y) j = j + 1 if onpoint: path.AppendLine(point) last_point = point else: c1 = last_point + (point - last_point) * 2.0 / 3.0 x, y, onpoint = contour[j % npoints] if onpoint: j = j + 1 cont = ContAngle else: x = point.x + (x - point.x) * 0.5 y = point.y + (y - point.y) * 0.5 cont = ContSmooth last_point = Point(x, y) c2 = last_point + (point - last_point) * 2.0 / 3.0 path.AppendBezier(c1, c2, last_point, cont) path.ClosePath() path.Translate(offset, voffset) path.Transform(Scale(0.5 / 1024.0)) path.Translate(align_offset, 0) paths.append(path) if c == ' ': offset = offset + glyph.advance[ 0] * prop.chargap * prop.wordgap * tab / 1000 else: offset = offset + glyph.advance[0] * prop.chargap / 1000 voffset -= fheight return tuple(paths)