def mktrafo(self, extend): if reff.scale.mode == 0: left, bottom = extend[0] right, top = extend[1] width = right - left height = top - bottom sc = 841 / (1.0 * max(abs(width) , abs(height))) else: left = 0 bottom = 0 width = 1 height = 1 sc = reff.scale.metric * 72 / 25.4 self.Scale = sc self.trafo = Scale(sign(width) * sc , sign(height) * sc)(Translation(-left , -bottom))
def get_trafo(self, trfd, scale=1): cdr_version=self.cdr_version ieeestart = 32 if cdr_version >= 13: ieeestart = 40 if cdr_version == 5: ieeestart = 18 (x_shift,y_shift)=self.doc_page [var0] = struct.unpack('<d', trfd.data[ieeestart:ieeestart+8]) [var1] = struct.unpack('<d', trfd.data[ieeestart+8:ieeestart+8+8]) [var2] = struct.unpack('<d', trfd.data[ieeestart+2*8:ieeestart+8+2*8]) [var3] = struct.unpack('<d', trfd.data[ieeestart+3*8:ieeestart+8+3*8]) [var4] = struct.unpack('<d', trfd.data[ieeestart+4*8:ieeestart+8+4*8]) [var5] = struct.unpack('<d', trfd.data[ieeestart+5*8:ieeestart+8+5*8]) self.scale_with=min(var0*cmp(var0,0), var4*cmp(var4,0)) obj_trafo=Trafo( var0, var3, var1, var4, (var2+x_shift/2)*scale, (var5+y_shift/2)*scale) if self.image_dpi_trafo is None: # return Trafo( var0, var3, var1, var4, (var2+x_shift/2)*scale, (var5+y_shift/2)*scale) return obj_trafo else: [w,h]=self.image_dpi_trafo image_scale=Scale(w,h) return obj_trafo(image_scale)
def update_trafo(self): wt = Translation(-self.wx, -self.wy) vt = Translation(self.vx, self.vy) scale = Scale( float(self.vwidth) / self.wwidth, float(self.vheight) / self.wheight) self.trafo = self.base_trafo(vt(scale(wt)))
def GetObjectHandle(self, multiple): trafo = self.trafo(self.atrafo(Scale(self.properties.font_size))) if multiple: return trafo(NullPoint) else: pts = self.properties.font.TypesetText(self.text, self.properties) return map(trafo, pts)
def DrawShape(self, device, rect=None, clip=0): RectangularPrimitive.DrawShape(self, device) base_trafo = self.trafo(self.atrafo) base_trafo = base_trafo(Scale(self.properties.font_size)) paths = self.properties.font.GetPaths(self.text, self.properties) obj = PolyBezier(paths, self.properties.Duplicate()) obj.Transform(base_trafo) device.MultiBezier(obj.paths, rect, clip)
def AsBezier(self): if self.text: text = split(self.text, '\n')[0] base_trafo = self.trafo(self.atrafo) base_trafo = base_trafo(Scale(self.properties.font_size)) paths = self.properties.font.GetPaths(self.text, self.properties) obj = PolyBezier(paths, self.properties.Duplicate()) obj.Transform(base_trafo) return obj
def arrow_trafos(path, properties): dir1, dir2 = arrow_vectors(path, properties.line_arrow1, properties.line_arrow2) width = properties.line_width if width < 1.0: width = 1.0 scale = Scale(width) t1 = t2 = None if dir1 is not None: t1 = Translation(path.Node(0))(Rotation(dir1.polar()[1]))(scale) if dir2 is not None: t2 = Translation(path.Node(-1))(Rotation(dir2.polar()[1]))(scale) return t1, t2
def SelectPoint(self, p, rect, device, mode): trafo = self.trafo(self.atrafo(Scale(self.properties.font_size))) trafo = trafo.inverse() p2 = trafo(p) pts = self.properties.font.TypesetText(self.text + ' ', self.properties) dists = [] for i in range(len(pts)): dists.append((abs(pts[i].x - p2.x), i)) caret = min(dists)[-1] self.SetCaret(caret) # print "CATCHED!" return 1
def SaveDocument(self, doc): # A dillema # Should the design fill the CGM-file or # Should it be placed approximately in # the same place as it is put on the page. if 0: left, bottom, right, top = doc.BoundingRect() width = right - left hight = top - bottom else: left, bottom = 0, 0 width = doc.page_layout.width hight = doc.page_layout.height right, top = width, hight #sc = 65534 / max(width , hight) sc = 1000 #self.trafo = Translation(-32767,-32767)(Scale(sc)(Translation(-left , -bottom))) self.trafo = Scale(sc)(Translation(-left, -bottom)) self.Scale = sc self.extend = map(rndtoint , \ tuple(self.trafo(left,bottom)) + tuple(self.trafo(right,top))) # Begin Metafile filename = os.path.basename(self.pathname) title = filename + " generated by sK1" self.putstr(0x0020, title) # Metafile Version self.pack("!H", 0x1022) self.pack("!H", 0x0001) # Metafile Description self.putstr(0x1040, filename + " created by sk1") # Metafile Element List self.pack("!HHHH", 0x1166, 0x0001, 0xffff, 0x0001) # Default Replacements self.pack("!H", 0x1184) # VDC Integer precision 32 bits self.pack("!Hh", 0x3022, 32) #Font List # self.SaveLayers(doc.Layers()) # End Meta File self.pack("!H", 0x0040)
def __init__(self, trafo = None, duplicate = None, loading = 0): PluginCompound.__init__(self, duplicate = duplicate) if duplicate is not None: self.trafo = duplicate.trafo else: if trafo is None: trafo = Identity elif type(trafo) == TupleType: trafo = apply(Trafo, trafo) elif isinstance(trafo, TrafoType): # trafo is already a trafo object pass else: # assume a number and interpret it as a scaling transformation trafo = Scale(trafo) self.trafo = trafo
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 convert_outline(outline): paths = [] trafo = Scale(0.001) for closed, sub in outline: if closed: sub.append(sub[0]) path = CreatePath() paths.append(path) for item in sub: if len(item) == 2: apply(path.AppendLine, item) else: apply(path.AppendBezier, item) if closed: path.load_close() for path in paths: path.Transform(trafo) return tuple(paths)
def parse_transform(self, trafo_string): trafo = self.trafo trafo_string = as_latin1(trafo_string) while trafo_string: match = rx_trafo.match(trafo_string) if match: function = match.group(1) args = argsf = string.translate(match.group(2), commatospace) args = map(str, split(args)) trafo_string = trafo_string[match.end(0):] if function == 'matrix': args = map(float, split(argsf)) trafo = trafo(apply(Trafo, tuple(args))) elif function == 'scale': if len(args) == 1: sx = sy = args[0] else: sx, sy = args sx, sy = self.user_point(sx, sy) trafo = trafo(Scale(sx, sy)) elif function == 'translate': if len(args) == 1: dx, dy = args[0], '0' else: dx, dy = args dx, dy = self.user_point(dx, dy) trafo = trafo(Translation(dx, dy)) elif function == 'rotate': if len(args) == 1: trafo = trafo(Rotation(float(args[0]) * degrees)) else: angle, cx, cy = args cx, cy = self.user_point(cx, cy) trafo = trafo( Rotation(float(angle) * degrees, Point(cx, cy))) elif function == 'skewX': trafo = trafo( Trafo(1, 0, tan(float(args[0]) * degrees), 1, 0, 0)) elif function == 'skewY': trafo = trafo( Trafo(1, tan(float(args[0]) * degrees), 0, 1, 0, 0)) else: trafo_string = '' self.trafo = trafo
def pathtext(path, start_pos, text, font, size, type, properties): metric = font.metric lengths = path.arc_lengths(start_pos) scale = Scale(size); factor = size / 2000.0 pos = font.TypesetText(text, properties) pos = map(scale, pos) trafos = [] for idx in range(len(text)): char = text[idx] width2 = metric.char_width(ord(char)) * factor x = pos[idx].x + width2 trafo = coord_sys_at(lengths, x, type) if trafo is not None: trafos.append(trafo(Translation(-width2, 0))) else: # we've reached the end of the path. Ignore all following # characters break return trafos
def svgView(self, attrs): self._print("basetrafo", self.basetrafo) viewbox = attrs.get("viewBox", "") if viewbox: # In early viewPort = viewBox self._print('viewBox', viewbox) viewbox = viewbox.replace(',', ' ') self.viewPort = map(float, split(viewbox)) x, y = self.user_point(attrs.get('x', '0'), attrs.get('y', '0')) width, height = self.user_point(attrs.get('width', '100%'), \ attrs.get('height', '100%')) self._print('svgView', x, y, width, height) if self.loader.page_layout is None: self.loader.page_layout = pagelayout.PageLayout(width=width * 0.8, height=height * 0.8) if self.trafo is None: # adjustment of the coordinate system and taking into account # the difference between 90dpi in svg against 72dpi in sk1 self.trafo = self.basetrafo = Trafo(0.8, 0, 0, -0.8, 0, height * 0.8) # initial values of x and y are ignored x = y = 0 # adjust to the values x, y in self.trafo self.trafo = self.trafo(Translation(x, y)) # evaluate viewBox # FIXME: Handle preserveAspectRatio as well if viewbox: t = Scale(width / self.viewPort[2], height / self.viewPort[3]) t = t(Translation(-self.viewPort[0], -self.viewPort[1])) self.trafo = self.trafo(t) # set viewPort taking into account the transformation self.viewPort = (x, y, width/(self.trafo.m11/self.basetrafo.m11),\ height/(self.trafo.m22/self.basetrafo.m22)) self._print("trafo", self.trafo) self._print("viewPort", self.viewPort)
def read_header(self): format = orientation = None if self.format_version >= 3.0: line = strip(self.readline()) if line: # portrait/landscape if lower(line) == 'landscape': orientation = pagelayout.Landscape else: orientation = pagelayout.Portrait else: raise SketchLoadError('No format specification') line = strip(self.readline()) if line: # centering line = lower(line) if line == 'center' or line == 'flush left': line = lower(strip(self.readline())) if not line: raise SketchLoadError( 'No Center/Flushleft or Units specification') if line == 'metric': # ignore for now pass if self.format_version >= 3.2: self.readline() # papersize self.readline() # magnification self.readline() # pages self.readline() # transparent color line = strip(self.readline()) if line: try: ppi, coord = map(atoi, split(line)) except: raise SketchLoadError('Invalid Resolution specification') self.trafo = self.trafo(Scale(72.0 / ppi))
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)
class CGMLoader(GenericLoader): def __init__(self, file, filename, match): GenericLoader.__init__(self, file, filename, match) self.file = file self.verbosity = 15 self.IntF = (self.i8, self.i16, self.i24, self.i32) self.CardF = (self.u8, self.u16, self.u24, self.u32) self.FloatF = (self.flp32, self.flp64) self.FixedF = (self.fip32, self.fip64) self.RealF = self.FixedF + self.FloatF self.VDCF = (self.IntF, self.RealF) def _print(self, pl , format, *args, **kw): if pl <= self.verbosity: try: if kw: text = format % kw elif args: text = format % args else: text = format except: text = string.join([format] + map(str, args)) if text[-1] != '\n': text = text + '\n' # sys.stdout.write(text) def unpack(self, format): size = struct.calcsize(format) return struct.unpack(format, self.file.read(size)) def u8(self): return self.unpack("!B")[0] def u16(self): return self.unpack("!H")[0] def u24(self): t = self.unpack("!BH") return (t[0] << 16) | t[1] def u32(self): return self.unpack("!I")[0] def i8(self): return self.unpack("!b")[0] def i16(self): return self.unpack("!h")[0] def i24(self): t = self.unpack("!bH") return (t[0] << 16) | t[1] def i32(self): return self.unpack("!i")[0] def fip32(self): t = self.unpack("!hH") return t[0] + t[1] / 65536.0 def fip64(self): t = self.unpack("!hH") return t[0] + t[1] / (65536.0 * 65536.0) def flp32(self): return self.unpack("!f")[0] def flp64(self): return self.unpack("!d")[0] def Int(self): return self.IntF[reff.intprec]() def Real(self): return self.RealF[reff.realprec]() def Inx(self): return self.IntF[reff.inxprec]() def Enum(self): return self.unpack("!h")[0] def VDC(self): return self.VDCF[reff.vdc.type][reff.vdc.prec]() def Pnt(self): return (self.VDC() , self.VDC()) def getstr(self): lng = self.u8() return self.unpack("!" + `lng` + "s")[0] def getcol(self): if reff.color.mode == 1: cgmcol = self.unpack(reff.color.absstruct) cgmcol = map(operator.sub , cgmcol , reff.color.offset) cgmcol = map(operator.div , cgmcol , reff.color.scale) return cgmcol else: cgmcol = self.unpack(reff.color.inxstruct)[0] return reff.color.table[cgmcol % reff.color.maxindex] # 0x0020: def BEGMF(self, size): self._print(10 , '======= 0.1 =======') global dflt, reff dflt = cp(init) reff = dflt self.document() self.fntmap = range(78) self.fntmap.insert(0, 0) # 0x0040: def ENDMF(self, size): pass # 0x0060: def BEGPIC(self, size): global curr, reff curr = cp(dflt) reff = curr if reff.vdc.extend == None: if reff.vdc.type == 0: reff.vdc.extend = reff.vdc.intextend reff.vdc.size = reff.vdc.intsize reff.vdc.prec = reff.vdc.intprec else: reff.vdc.extend = reff.vdc.realextend reff.vdc.size = reff.vdc.realsize reff.vdc.prec = reff.vdc.realprec if reff.vdc.prec == None: if reff.vdc.type == 0: reff.vdc.size = reff.vdc.intsize reff.vdc.prec = reff.vdc.intprec else: reff.vdc.size = reff.vdc.realsize reff.vdc.prec = reff.vdc.realprec Hgt = reff.vdc.extend[1][1] - reff.vdc.extend[0][1] Wdt = reff.vdc.extend[1][0] - reff.vdc.extend[0][0] LS = max(abs(Hgt), abs(Wdt)) if reff.clip.rect == None: reff.clip.rect = reff.vdc.extend if reff.marker.size == None: if reff.marker.sizemode == 0: reff.marker.size = LS / 100.0 else: reff.marker.size = 3 if reff.text.height == None: reff.text.height = LS / 100.0 if reff.edge.width == None: if reff.edge.widthmode == 0: reff.edge.width = LS / 1000.0 else: reff.edge.width = 1 if reff.line.width == None: if reff.line.widthmode == 0: reff.line.width = LS / 1000.0 else: reff.line.width = 1 ln = self.getstr() self.layer(name=ln) # 0x0080: def BEGPICBODY(self, size): self.mktrafo(reff.vdc.extend) # 0x00A0: def ENDPIC(self, size): pass # 0x1020: def mfversion(self, size): if self.u16() != 1: raise SketchLoadError("Can only load CGM version 1") # 0x1040: def mfdesc(self, size): pass # 0x1060: def vdctype(self, size): reff.vdc.type = self.Enum() if reff.vdc.type == 0: reff.vdc.size = reff.vdc.intsize reff.vdc.prec = reff.vdc.intprec reff.vdc.extend = reff.vdc.intextend else: reff.vdc.size = reff.vdc.realsize reff.vdc.prec = reff.vdc.realprec reff.vdc.extend = reff.vdc.realextend # 0x1080: def integerprec(self, size): bits = self.Int() if bits in (8, 16, 24, 32): reff.intsize = (bits / 8) reff.intprec = reff.intsize - 1 else: raise SketchLoadError("This implementation can't work with %d bit integers" % (bits,)) # 0x10a0: def realprec(self, size): type = self.Enum() prec = (self.Int(), self.Int()) if type == 1: if prec == (16, 16): reff.realprec = 0# 32 bit fixed precision elif prec == (32, 32): reff.realprec = 1# 64 bit fixed precision else: raise SketchLoadError("This implementation can't work with %d,%d bit fixed points" % prec) else: if prec == (9, 23): reff.realprec = 2# 32 bit floating point elif prec == (12, 52): reff.realprec = 3# 64 bit floating point else: raise SketchLoadError("This implementation can't work with %d,%d bit floatingpoints" % prec) # 0x10c0: 'indexprec', def indexprec(self, size): bits = self.Int() if bits in (8, 16, 24, 32): reff.inxsize = (bits / 8) reff.inxprec = reff.inxsize - 1 else: raise SketchLoadError("This implementation can't work with %d bit indices" % (bits,)) # 0x10e0: def colrprec(self, size): bits = self.Int() if bits == 8: reff.color.absstruct = "!BBB" elif bits == 16: reff.color.absstruct = "!HHH" elif bits == 32: reff.color.absstruct = "!III" else: raise SketchLoadError("This implementation can't work with %d bit color components" % (bits,)) # 0x1100: def colrindexprec(self, size): bits = self.Int() if bits == 8: reff.color.inxstruct = "!B" elif bits == 16: reff.color.inxstruct = "!H" elif bits == 32: reff.color.inxstruct = "!I" else: raise SketchLoadError("This implementation can't work with %d bit color indices" % (bits,)) # 0x1120: 'maxcolrindex', def maxcolrindex(self, size): reff.color.maxindex = self.unpack(reff.color.inxstruct)[0] reff.color.table = CreateColorTable(reff.color.maxindex) # 0x1140: def colrvalueext(self, size): bottom = self.unpack(reff.color.absstruct) top = self.unpack(reff.color.absstruct) reff.color.offset = map(operator.mul , bottom , (1.0, 1.0, 1.0)) reff.color.scale = map(operator.sub, top , reff.color.offset) # 0x1160: def mfelemlist(self, size): pass # 0x1180: def mfdfltrpl(self, size): self.interpret(size) # 0x11a0: def fontlist(self, size): tot = 0 fntinx = 1 while tot < size: fontname = self.getstr() bsteval = 100 bstinx = 0 for inx in range(len(fntlst)): fntname = fntlst[inx] if fntname is not None: baseinx = fntname.find('-') if baseinx == -1: baseinx = len(fntname) basename = fntname[0:baseinx] postfix = fntname[baseinx:] self._print(20 , "fontname = %s; basename = %s; postfix = %s\n" , fntname , basename , postfix) self._print(30 , "base = %s; baselst = %s\n" , basename , fntalias.get(basename , ())) baselst = (basename,) + fntalias.get(basename , ()) for suffix in ["" , "-Roman" , "-Regular" , "-Book"]: for base in baselst: score = strmatch(fontname + suffix , base + postfix) if score < bsteval: bsteval = score bstinx = inx self.fntmap[fntinx] = bstinx tot = tot + len(fontname) + 1 self._print(10 , 'font[%d]: %s => %s = %s\n' , fntinx , fontname , fntlst[bstinx] , fntlst[self.fntmap[fntinx]]) fntinx = fntinx + 1 # 0x2020: 'scalemode', def scalemode(self, size): reff.scale.mode = self.Enum() if reff.realprec in (2, 3):# floatingpoint precision reff.scale.metric = self.Real() else: reff.scale.metric = self.flp32() if reff.scale.mode == 1 and reff.scale.metric == 0: self._print(10 , "Scale metric set to zero; mode set back to absolute") reff.scale.mode = 0 # 0x2040: def colrmode(self, size): reff.color.mode = self.Enum() # 0x2060: def linewidthmode(self, size): reff.line.widthmode = self.Enum() # 0x2080: def markersizemode(self, size): reff.marker.sizemode = self.Enum() # 0x20a0: def edgewidthmode(self, size): reff.edge.widthmode = self.Enum() def mktrafo(self, extend): if reff.scale.mode == 0: left, bottom = extend[0] right, top = extend[1] width = right - left height = top - bottom sc = 841 / (1.0 * max(abs(width) , abs(height))) else: left = 0 bottom = 0 width = 1 height = 1 sc = reff.scale.metric * 72 / 25.4 self.Scale = sc self.trafo = Scale(sign(width) * sc , sign(height) * sc)(Translation(-left , -bottom)) # 0x20c0: def vdcext(self, size): ll = self.Pnt() ur = self.Pnt() reff.vdc.extend = (ll, ur) # 0x20e0: def backcolr(self, size): self.getcol() # 0x3020: def vdcintegerprec(self, size): bits = self.Int() if bits in (8, 16, 24, 32): reff.vdc.intsize = (bits / 8) reff.vdc.intprec = reff.vdc.intsize - 1 if reff.vdc.type == 0: reff.vdc.size = reff.vdc.intsize reff.vdc.prec = reff.vdc.intprec else: raise SketchLoadError("This implementation can't work with %d bit integers" % (bits,)) # 0x3040: def vdcrealprec(self, size): type = self.Enum() prec = (self.Int(), self.Int()) if type == 1: if prec == (16, 16): reff.vdc.realprec = 0# 32 bit fixed precision elif prec == (32, 32): reff.vdc.realprec = 1# 64 bit fixed precision else: raise SketchLoadError("This implementation can't work with %d,%d bit fixed points" % prec) else: if prec == (9, 23): reff.vdc.realprec = 2# 32 bit floating point elif prec == (12, 52): reff.vdc.realprec = 3# 64 bit floating point else: raise SketchLoadError("This implementation can't work with %d,%d bit floatingpoints" % prec) if reff.vdc.type == 1: reff.vdc.size = reff.vdc.realsize reff.vdc.prec = reff.vdc.realprec # 0x30a0: def cliprect(self, size): reff.clip.rect = (self.Pnt(), self.Pnt()) def Path(self, size): path = CreatePath() for i in range(size / (2 * reff.vdc.size)): path.AppendLine(self.trafo(self.Pnt())) return path def setlinestyle(self): style = basestyle.Duplicate() style.line_pattern = SolidPattern(apply(CreateRGBColor , reff.line.color)) style.line_width = reff.line.width if reff.line.widthmode == 0: style.line_width = style.line_width * self.Scale style.line_dashes = reff.line.dashtable[reff.line.type - 1] self.prop_stack.AddStyle(style) # 0x4020: def LINE(self, size): path = self.Path(size) self.setlinestyle() self.bezier((path,)) # 0x4040: def DISJTLINE(self, size): path = () for i in range(size / (4 * reff.vdc.size)): subpath = CreatePath() P = self.Pnt() subpath.AppendLine(self.trafo(P)) P = self.Pnt() subpath.AppendLine(self.trafo(P)) path = path + (subpath,) self.setlinestyle() self.bezier(path) # 0x4080: def TEXT(self, size): P = self.Pnt() F = self.Enum() S = self.getstr() T = Translation(self.trafo(P)) Py = Point(reff.text.orientation[0]).normalized() Px = Point(reff.text.orientation[1]).normalized() B = transform_base(Point(0.0, 0.0) , reff.text.expansion * Px , Py) self.style = basestyle.Duplicate() self.style.font = GetFont(fntlst[self.fntmap[reff.text.fontindex]]) self.style.font_size = reff.text.height * self.Scale self.style.fill_pattern = SolidPattern(apply(CreateRGBColor , reff.text.color)) O = text.SimpleText(text=S, trafo=T(B), halign=text.ALIGN_LEFT, valign=text.ALIGN_BASE, properties=self.get_prop_stack()) self.append_object(O) def setfillstyle(self): style = basestyle.Duplicate() if reff.fill.type == 1: style.fill_pattern = SolidPattern(apply(CreateRGBColor , reff.fill.color)) elif reff.fill.type == 3: style.fill_pattern = HatchingPattern(apply(CreateRGBColor , reff.fill.color), StandardColors.white, Point(2.0, 1.0), 5 , 1) if reff.edge.visible: style.line_pattern = SolidPattern(apply(CreateRGBColor , reff.edge.color)) style.line_width = reff.edge.width if reff.edge.widthmode == 0: style.line_width = style.line_width * self.Scale style.line_dashes = reff.edge.dashtable[reff.edge.type - 1] self.prop_stack.AddStyle(style) # 0x40e0: def POLYGON(self, size): path = self.Path(size) if path.Node(-1) != path.Node(0): path.AppendLine(path.Node(0)) path.load_close() self.setfillstyle() self.bezier((path,)) # 0x4100: def POLYGONSET(self, size): path = () subpath = CreatePath() for i in range(size / (2 * reff.vdc.size + 2)): P = self.Pnt() F = self.Enum() subpath.AppendLine(self.trafo(P)) if F in (2, 3): if subpath.Node(-1) != subpath.Node(0): subpath.AppendLine(subpath.Node(0)) subpath.load_close() path = path + (subpath,) subpath = CreatePath() if subpath.len != 0: if subpath.Node(-1) != subpath.Node(0): subpath.AppendLine(subpath.Node(0)) subpath.load_close() path = path + (subpath,) self.setfillstyle() self.bezier(path) def bugmark(self, P): P = P - Point(1, 1) style = basestyle.Duplicate() style.fill_pattern = SolidPattern(StandardColors.black) style.line_pattern = SolidPattern(StandardColors.black) self.prop_stack.AddStyle(style) self.rectangle(2, 0, 0, 2, P.x, P.y) # 0x4160: def RECT(self, size): ll = self.trafo(self.Pnt()) ur = self.trafo(self.Pnt()) lr = Point(ur.x , ll.y) ul = Point(ll.x , ur.y) T = transform_base(ll , lr , ul) self.setfillstyle() apply(self.rectangle , T.coeff()) # 0x4180: def CIRCLE(self, size): centre = self.trafo(self.Pnt()) radius = self.VDC() * self.Scale self.setfillstyle() self.ellipse(radius, 0, 0, radius, centre.x, centre.y) # 0x41a0: def ARC3PT(self, size): Po = self.trafo(self.Pnt()) Pm = self.trafo(self.Pnt()) Pe = self.trafo(self.Pnt()) Pc = Cnt3Pnt(Po, Pm, Pe) radius = abs(Po - Pc) if Angle2(Po - Pc , Pm - Pc) < Angle2(Po - Pc, Pe - Pc): Ao = Angle(Po - Pc) Ae = Angle(Pe - Pc) else: Ao = Angle(Pe - Pc) Ae = Angle(Po - Pc) self.setlinestyle() self.ellipse(radius, 0, 0, radius, Pc.x, Pc.y, Ao, Ae, 0) # 0x41c0: def ARC3PTCLOSE(self, size): Po = self.trafo(self.Pnt()) Pm = self.trafo(self.Pnt()) Pe = self.trafo(self.Pnt()) closetype = self.Enum() Pc = Cnt3Pnt(Po, Pm, Pe) radius = abs(Po - Pc) if Angle2(Po - Pc , Pm - Pc) < Angle2(Po - Pc, Pe - Pc): Ao = Angle(Po - Pc) Ae = Angle(Pe - Pc) else: Ao = Angle(Pe - Pc) Ae = Angle(Po - Pc) self.setfillstyle() self.ellipse(radius, 0, 0, radius, Pc.x, Pc.y, Ao, Ae, 2 - closetype) # 0x41e0: def ARCCTR(self, size): centre = self.trafo(self.Pnt()) Vo = self.trafo.DTransform(self.Pnt()) Ve = self.trafo.DTransform(self.Pnt()) radius = self.VDC() * self.Scale Ao = Angle(Vo) Ae = Angle(Ve) self.setlinestyle() self.ellipse(radius, 0, 0, radius, centre.x, centre.y, Ao, Ae, 0) # 0x4200: 'ARCCTRCLOSE', def ARCCTRCLOSE(self, size): centre = self.trafo(self.Pnt()) Vo = self.trafo.DTransform(self.Pnt()) Ve = self.trafo.DTransform(self.Pnt()) radius = self.VDC() * self.Scale closetype = self.Enum() Ao = Angle(Vo) Ae = Angle(Ve) self.setfillstyle() self.ellipse(radius, 0, 0, radius, centre.x, centre.y, Ao, Ae, 2 - closetype) # 0x4220: def ELLIPSE(self, size): centre = self.trafo(self.Pnt()) cdp1 = self.trafo(self.Pnt()) cdp2 = self.trafo(self.Pnt()) T = transform_base(centre , cdp1 , cdp2) self.setfillstyle() apply(self.ellipse , T.coeff()) # 0x4240: def ELLIPARC(self, size): centre = self.trafo(self.Pnt()) cdp1 = self.trafo(self.Pnt()) cdp2 = self.trafo(self.Pnt()) Vo = self.trafo.DTransform(self.Pnt()) Ve = self.trafo.DTransform(self.Pnt()) T = transform_base(centre , cdp1 , cdp2) Vo = T.inverse().DTransform(Vo) Ve = T.inverse().DTransform(Ve) Ao = Angle(Vo) Ae = Angle(Ve) self.setlinestyle() apply(self.ellipse , T.coeff() + (Ao, Ae, 0)) # 0x4260: def ELLIPARCCLOSE(self, size): centre = self.trafo(self.Pnt()) cdp1 = self.trafo(self.Pnt()) cdp2 = self.trafo(self.Pnt()) Vo = self.trafo.DTransform(self.Pnt()) Ve = self.trafo.DTransform(self.Pnt()) closetype = self.Enum() T = transform_base(centre , cdp1 , cdp2) Vo = T.inverse().DTransform(Vo) Ve = T.inverse().DTransform(Ve) Ao = Angle(Vo) Ae = Angle(Ve) self.setfillstyle() apply(self.ellipse , T.coeff() + (Ao, Ae, 2 - closetype)) # 0x5040 def linetype(self, size): reff.line.type = self.Inx() # 0x5060: def linewidth(self, size): if reff.line.widthmode == 0: reff.line.width = self.VDC() else: reff.line.width = self.Real() # 0x5080: def linecolr(self, size): reff.line.color = self.getcol() # 0x5100: def markercolr(self, size): reff.marker.color = self.getcol() # 0x5140: 'textfontindex', def textfontindex(self, size): reff.text.fontindex = self.Inx() self._print(10 , 'font[%d]: => %s\n' , reff.text.fontindex , fntlst[self.fntmap[reff.text.fontindex]]) # 0x5180: 'charexpan', def charexpan(self, size): reff.text.expansion = self.Real() # 0x51c0: def textcolr(self, size): reff.text.color = self.getcol() # 0x51e0: def charheight(self, size): reff.text.height = self.VDC() # 0x5200: def charori(self, size): reff.text.orientation = (self.Pnt(), self.Pnt()) # 0x52c0: def intstyle(self, size): reff.fill.type = self.Enum() # 0x52e0: def fillcolr(self, size): reff.fill.color = self.getcol() # 0x5360: def edgetype(self, size): reff.edge.type = self.Inx() # 0x5380: def edgewidth(self, size): if reff.edge.widthmode == 0: reff.edge.width = self.VDC() else: reff.edge.width = self.Real() # 0x53a0: def edgecolr(self, size): reff.edge.color = self.getcol() # 0x53c0: def edgevis(self, size): reff.edge.visible = self.Enum() # 0x5440: 'colrtable', def colrtable(self, size): i = self.unpack(reff.color.inxstruct)[0] size = size - struct.calcsize(reff.color.inxstruct) while size > struct.calcsize(reff.color.absstruct): cgmcol = self.unpack(reff.color.absstruct) cgmcol = map(operator.sub , cgmcol , reff.color.offset) cgmcol = map(operator.div , cgmcol , reff.color.scale) reff.color.table[i] = cgmcol size = size - struct.calcsize(reff.color.absstruct) i = i + 1 def interpret(self, sz): tell = self.file.tell Id = -1 pos = tell() start = pos while Id != 0x40 and pos < start + sz: head = self.u16() Id = head & 0xffe0 size = head & 0x001f hdsz = 2 if size == 31: size = self.u16() hdsz = 4 pdsz = ((size + 1) / 2) * 2 self._print(20 , '%4x at %5d) %5d(%5d): %4x: %s' , head, pos, size, pdsz, Id, CGM_ID.get(Id, '')) if hasattr(self, CGM_ID.get(Id, '')): self._print(30 , 'Calling %s' % (CGM_ID.get(Id, ''))) getattr(self, CGM_ID[Id])(size) else: if Id: self.file.read(pdsz) name = CGM_ID.get(Id, '') Class = Id >> 12 Elem = (Id & 0x0fff) >> 5 self._print(2, '*** unimplemented: %4x; class = %d, element = %2d %s' , Id , Class , Elem, name) pos = pos + hdsz + pdsz if tell() < pos: self.file.read(pos - tell()) elif tell() > pos: self._print(2, 'read too many bytes') self.file.seek(pos - tell(), 1) if pos != tell(): raise SketchLoadError("Lost position in File") def Load(self): self.file.seek(0, 2) where = self.file.tell() self.file.seek(0, 0) self.interpret(where) self.end_all() self.object.load_Completed() return self.object
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 foot_prints_along_path(context): doc = context.document objects = doc.SelectedObjects() # The requirement for this script is, as described in the module # doc-string, that exactly two objects are selected and that the # top-most of these is the path. if len(objects) == 2 and objects[1].is_curve: # First, we take the foot print. We copy the foot print since we # have to modify it and we don't want the original to be # affected. foot_print = objects[0].Duplicate() # The rest of the script is easier to write if we have a foot # print located at the origin of the coordinate system that we # can use as a stencil, so we move the copy accordingly. The # Transform method modifies the object in place. That's why it # was important to copy it. r = foot_print.coord_rect foot_length = r.right - r.left foot_print.Transform(Translation(-r.right + foot_length/2, -r.bottom)) # Now the path. The Paths() method of an object returns a tuple # of path-objects if the object can be represented as paths. All # objects whose is_curve attribute is true can be represented as # Paths. In this example script we only look at the first path. path = objects[1].Paths()[0] # arc_lengths returns a list of (LENGTH, POINT) pairs where # POINT is a point on the curve and LENGTH is the arc length # from the start of the curve to that point. The points are # placed so that the curve between successive points can be seen # as a straight line. We'll be using this list to determine the # positions and orientations of the individual foot prints. arc_lengths = path.arc_lengths() # In the loop below, we'll be positioning the foot prints one # after the other from the start of the curve to the end, # alternating between the left and right foot prints. # Total length of the path so that we know when we're done. total_length = arc_lengths[-1][0] # Distance along the path we've already covered. distance = 0 # Count the number of foot prints so that we can mirror produce # left and right footprints. count = 0 # List we put all the copies into. foot_prints = [] # Now loop until we've walked along the whole path. while total_length - distance > foot_length: # Determine the transformation that turns the stencil into a # foot print at the right place with the right orientation. # We can borrow this functionality from the path-text code. # Placing letters along the path is practically the same as # placing foot prints. trafo = coord_sys_at(arc_lengths, distance, PATHTEXT_ROTATE) # Right feet are created by mirroring the left foot which # serves as stencil if count % 2: trafo = trafo(Scale(1, -1)) # Create a transformed copy of the stencil. foot = foot_print.Duplicate() foot.Transform(trafo) foot_prints.append(foot) # Update the length and the counter distance = distance + foot_length count = count + 1 # As the last step, insert the foot prints into the document as # a group. The Insert method takes care of undo handling. if foot_prints: doc.Insert(Group(foot_prints))