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 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 parse_transform(self, trafo_string): trafo = self.trafo #print trafo trafo_string = as_latin1(trafo_string) while trafo_string: #print trafo_string match = rx_trafo.match(trafo_string) if match: function = match.group(1) args = string.translate(match.group(2), commatospace) args = map(float, split(args)) trafo_string = trafo_string[match.end(0):] if function == 'matrix': trafo = trafo(apply(Trafo, tuple(args))) elif function == 'scale': trafo = trafo(Scale(args[0])) elif function == 'translate': dx, dy = args trafo = trafo(Translation(dx, dy)) elif function == 'rotate': trafo = trafo(Rotation(args[0] * degrees)) elif function == 'skewX': trafo = trafo(Trafo(1, 0, tan(args[0] * degrees), 1, 0, 0)) elif function == 'skewY': trafo = trafo(Trafo(1, tan(args[0] * degrees), 0, 1, 0, 0)) else: trafo_string = '' #print trafo self.trafo = trafo
def GetObjectHandle(self, multiple): trafo = Translation(self._offset) handle = self._original.GetObjectHandle(multiple) if type(handle) == PointType: return trafo(handle) else: return map(trafo, handle)
def write_gradient(self, gradient, style): pattern, rect = gradient key = self.gradient_id(pattern) write = self.file.write #write('Bb\n') if pattern.is_AxialGradient: vx, vy = pattern.Direction() angle = atan2(vy, vx) - pi / 2 center = rect.center() rot = Rotation(angle, center) left, bottom, right, top = rot(rect) height = (top - bottom) * (1.0 - pattern.Border()) trafo = rot(Translation(center)) start = trafo(0, height / 2) write("1 %s %g %g %g %g 1 0 0 1 0 0 Bg\n" % (key[0], start.x, start.y, atan2(-vy, -vx) * 180.0 / pi, height)) elif pattern.is_RadialGradient: cx, cy = pattern.Center() cx = cx * rect.right + (1 - cx) * rect.left cy = cy * rect.top + (1 - cy) * rect.bottom radius = max(hypot(rect.left - cx, rect.top - cy), hypot(rect.right - cx, rect.top - cy), hypot(rect.right - cx, rect.bottom - cy), hypot(rect.left - cx, rect.bottom - cy)) radius = radius * (1.0 - pattern.Border()) write("0 0 0 0 Bh\n") write("1 %s %g %g 0 %g 1 0 0 1 0 0 Bg\n" % (key[0], cx, cy, radius))
def read_text(self, line): args = tokenize(line, 12) # don't tokenize the text itself if len(args) != 13: # including the unparsed rest of the line raise SketchLoadError('Invalid text specification') sub_type, color, depth, pen_style, font, size, angle, flags, \ height, length, x, y, rest = args self.fill(color, None) self.font(font, size * 0.9, flags) if len(rest) > 2: #at least a space and a newline # read the actual text. This implementation may fail in # certain cases! string = rest[1:] while string[-5:] != '\\001\n': line = self.readline() if not line: raise SketchLoadError('Premature end of string') string = string + line globals = {'__builtins__': {}} try: # using eval here might be a security hole! string = eval('"""' + string[:-5] + '"""', globals) except: string = eval("'''" + string[:-5] + "'''", globals) else: raise SketchLoadError('Invalid text string') trafo = Translation(self.trafo(x, y))(Rotation(angle)) self.simple_text(string, trafo=trafo, halign=align[sub_type]) self.set_depth(depth)
def execute_axial_gradient(self, device, rect): vx, vy = self.direction angle = atan2(vy, vx) - pi / 2 center = rect.center() rot = Rotation(angle, center) left, bottom, right, top = rot(rect) height = (top - bottom) * (1.0 - self.border) trafo = rot(Translation(center)) device.AxialGradient(self.gradient, trafo(0, height / 2), trafo(0, -height / 2))
def recompute(self): path = Sketch.CreatePath() newpaths = [path] h = self.h path.AppendLine((5, 5)) path.AppendBezier((7, 5 + h / 2.), (12, 5 + h), (15, 5 + h)) path.AppendBezier((18, 5 + h), (22, 5 + h / 2), (25, 5)) path.Transform(self.trafo) if self.objects: self.objects[1].SetPaths(tuple(newpaths)) else: skull = Sketch.Ellipse(Scale(22)) skull.Transform(Translation(15, 16)) mouth = Sketch.PolyBezier(tuple(newpaths)) r_eye = Sketch.Ellipse(Scale(3)) l_eye = Sketch.Ellipse(Scale(3)) l_eye.Transform(Translation(7, 21)) r_eye.Transform(Translation(22, 21)) self.set_objects([skull, mouth, r_eye, l_eye])
def eps(self, trafo, filename): if len(trafo) == 2: trafo = Translation(trafo) else: trafo = apply(Trafo, trafo) if not os.path.isabs(filename): if self.directory: filename = os.path.join(self.directory, filename) else: filename = os.path.join(os.getcwd(), filename) self.append_object(eps.EpsImage(filename=filename, trafo=trafo))
def RemoveTransformation(self): if self.trafo.matrix() != IdentityMatrix: a = self.properties trafo = self.trafo llx, lly, urx, ury = a.font.TextCoordBox(self.text, a.font_size) try: undostyle = Primitive.Transform(self, trafo.inverse()) except SingularMatrix: undostyle = None undotrafo = self.set_transformation(Translation(trafo.offset())) return CreateMultiUndo(undostyle, undotrafo) return NullUndo
def Paths(self): paths = [] if self.text: base_trafo = self.trafo(self.atrafo) base_trafo = base_trafo(Scale(self.properties.font_size)) pos = self.properties.font.TypesetText(self.text) for i in range(len(self.text)): outline = self.properties.font.GetOutline(self.text[i]) trafo = base_trafo(Translation(pos[i])) for path in outline: path.Transform(trafo) paths.append(path) return tuple(paths)
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 Skencil" self.putstr(0x0020, title) # Metafile Version self.pack("!H", 0x1022) self.pack("!H", 0x0001) # Metafile Description self.putstr(0x1040, filename + " created by skencil") # 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 initsvg(self, attrs): width = self.user_length(attrs.get('width', '100%')) height = self.user_length(attrs.get('height', '100%')) self._print('initsvg', width, height) self.trafo = Trafo(1, 0, 0, -1, 0, height) self.basetrafo = self.trafo # evaluate viewBox # FIXME: Handle preserveAspectRatio as well viewbox = attrs.get("viewBox", "") if viewbox: vx, vy, vwidth, vheight = map(float, split(viewbox)) t = Scale(width / vwidth, height / vheight) t = t(Translation(-vx, -vy)) self.trafo = self.trafo(t) self._print("basetrafo", self.basetrafo)
def txt(self, thetext, trafo, halign=text.ALIGN_LEFT, valign=text.ALIGN_BASE): if len(trafo) == 2: trafo = Translation(trafo) else: trafo = apply(Trafo, trafo) object = text.SimpleText(text=thetext, trafo=trafo, halign=halign, valign=valign, properties=self.get_prop_stack()) self.append_object(object)
def AsBezier(self): if self.text: objects = [] base_trafo = self.trafo(self.atrafo) base_trafo = base_trafo(Scale(self.properties.font_size)) pos = self.properties.font.TypesetText(self.text) for i in range(len(self.text)): paths = self.properties.font.GetOutline(self.text[i]) if paths: props = self.properties.Duplicate() props.AddStyle(EmptyLineStyle) obj = PolyBezier(paths=paths, properties=props) trafo = base_trafo(Translation(pos[i])) obj.Transform(trafo) objects.append(obj) return Group(objects)
def create_text(context): # Create the text 'xyzzy' at 100,100. The first parameter to the # constructor is an affine transformation. text = SimpleText(Translation(100, 100), "xyzzy") # Set the font to 36pt Times-Bold and fill with solid green. # The text object is modified by this method, but the text object is # not yet part of the document, so we don't have to deal with undo # here. text.SetProperties(fill_pattern = SolidPattern(StandardColors.green), font = GetFont('Times-Bold'), font_size = 36) # Finally, insert the text object at the top of the current layer # and select it. Like all public document methods that modify the # document, the Insert method takes care of undo information itself. context.document.Insert(text)
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 recompute(self): back, l1, l2, l3, d1, d2, d3 = self.back, self.l1, self.l2, self.l3, \ self.d1, self.d2, self.d3 new = Sketch.CreatePath() newpaths1 = [new] #draw the arrow head for p in ((0, -d1), (0, -d1 - d2), (-l1, 0), (0, d1 + d2), (0, d1)): new.AppendLine(Point(p)) # the upper part of the arrow bar k = 1.2 new.AppendBezier(Point(l2, d1), Point(l2, d1 - d3 / k), Point(l2, d1 - d3)) new.AppendLine(Point(l2, -d1 - d3)) new.AppendBezier(Point(l2, -d1 - d3 / k), Point(l2, -d1), Point(0, -d1)) # the lower part of the arrow bar new = Sketch.CreatePath() newpaths2 = [new] new.AppendLine(Point(-l3, -d1)) new.AppendLine(Point(-l3, d1)) new.AppendBezier(Point(l2, d1), Point(l2, d1 - d3 / 3.), Point(l2, d1 - d3)) new.AppendLine(Point(l2, -d1 - d3)) new.AppendBezier(Point(l2, -d1 - d3 / 3.), Point(l2, -d1), Point(-l3, -d1)) new.Transform(Scale(1, -1)) new.Transform(Translation(0, -2 * d3)) if back: newpaths2, newpaths1 = newpaths1, newpaths2 for path in newpaths1 + newpaths2: path.Transform(self.trafo) if self.objects: self.objects[0].SetPaths(newpaths1) self.objects[1].SetPaths(newpaths2) else: obj1 = Sketch.PolyBezier(tuple(newpaths1)) obj2 = Sketch.PolyBezier(tuple(newpaths2)) self.set_objects([obj1, obj2])
def RemoveTransformation(self): # In the implemetation of the TrafoPlugin it is assumed, that all # childs are rebuild after the transformation is removed. Here, # recompute() usually only changes the children. Therefore # RemoveTransformation has to be modified. The solution below has the # dissadvantage that only invertable transformation can be removed. try: inv = self.trafo.inverse() except: return NullUndo offset = self.trafo.offset() shift = Translation(offset) undo = self.Transform(shift(inv)) if self.editor is not None: self.editor.UpdateTransientObject() return undo
def axial_gradient(self, properties, rect): pattern = properties.fill_pattern vx, vy = pattern.Direction() angle = atan2(vy, vx) - pi / 2 center = rect.center() rot = Rotation(angle, center) left, bottom, right, top = rot(rect) trafo = rot(Translation(center)) image = PIL.Image.new('RGB', (1, 200)) border = int(round(100 * pattern.Border())) _sketch.fill_axial_gradient(image.im, pattern.Gradient().Colors(), 0, border, 0, 200 - border) self.pdf.saveState() apply(self.pdf.transform, trafo.coeff()) self.pdf.drawInlineImage(image, (left - right) / 2, (bottom - top) / 2, right - left, top - bottom) self.pdf.restoreState()
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 update_atrafo(self): a = self.properties llx, lly, urx, ury = a.font.TextCoordBox(self.text, a.font_size) hj = self.halign if hj == ALIGN_RIGHT: xoff = llx - urx elif hj == ALIGN_CENTER: xoff = (llx - urx) / 2 else: xoff = 0 vj = self.valign if vj == ALIGN_TOP: yoff = -ury elif vj == ALIGN_CENTER: yoff = (lly - ury) / 2 - lly elif vj == ALIGN_BOTTOM: yoff = -lly else: yoff = 0 self.atrafo = Translation(xoff, yoff)
def pathtext(path, start_pos, text, font, size, type): metric = font.metric lengths = path.arc_lengths(start_pos) scale = Scale(size) factor = size / 2000.0 pos = font.TypesetText(text) 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 read_ellipse(self, line): readline = self.readline tokenize = skread.tokenize_line args = tokenize(line) if len(args) != 19: raise SketchLoadError('Invalid Ellipse specification') sub_type, line_style, thickness, pen_color, fill_color, depth, \ pen_style, area_fill, style, direction, angle, \ cx, cy, rx, ry, sx, sy, ex, ey = args self.fill(fill_color, area_fill) self.line(pen_color, thickness, const.JoinMiter, const.CapButt, line_style, style) 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) apply(self.ellipse, trafo.coeff()) self.set_depth(depth)
def GetSnapPoints(self): return map(Translation(self._offset), self._original.GetSnapPoints())
def ta_write_line(self, align, cursor, line, wrapped): # print 'ta_write_line:', align, cursor, margins if line == [] or cursor == [None, None]: return # Remove leading and trailing spaces if line[0][0] == ' ': line = line[1:] if line != [] and line[-1][0] == ' ': line = line[:-1] if line == []: return # Depending on the justification of the text, either just write the # text to the page striaght from the line list (L, R, C) or space it # out appropriately (D) if align == 'L': # Left justification cursor[0] = self.margins[0] for word, font_name, font_size, font_width, fg, bg in line: # Set the font name self.style.font = RISCOSFont(font_name) # Set the font size self.style.font_size = font_size # Set the text colour self.style.line_pattern = bg self.style.fill_pattern = fg # Determine the horizontal position of the next word next = cursor[0] + \ self.style.font.TextCoordBox(word, font_size)[2] # Write the text to the page self.simple_text(word, Translation(cursor)) # Reposition the cursor cursor[0] = next elif align == 'R': # Right justification line.reverse() cursor[0] = self.margins[1] for word, font_name, font_size, font_width, fg, bg in line: # Set the font name self.style.font = RISCOSFont(font_name) # Set the font size self.style.font_size = font_size # Set the text colour self.style.line_pattern = bg self.style.fill_pattern = fg # Determine the horizontal position of the this word cursor[0] = cursor[0] - \ self.style.font.TextCoordBox(word, font_size)[2] # Write the text to the page self.simple_text(word, Translation(cursor)) elif align == 'C': # Centred text # Determine the total width of the line total_width = 0.0 for word, font_name, font_size, font_width, fg, bg in line: # Set the font self.style.font = RISCOSFont(font_name) # Increase the width total_width = total_width + \ self.style.font.TextCoordBox(word, font_size)[2] # Place the cursor at a suitable place and render the text as if it # was left justified cursor[0] = self.margins[0] + \ (self.margins[1] - self.margins[0] - total_width)/2.0 for word, font_name, font_size, font_width, fg, bg in line: # Set the font name self.style.font = RISCOSFont(font_name) # Set the font size self.style.font_size = font_size # Set the text colour self.style.line_pattern = bg self.style.fill_pattern = fg # Determine the horizontal position of the next word next = cursor[0] + \ self.style.font.TextCoordBox(word, font_size)[2] # Write the text to the page self.simple_text(word, Translation(cursor)) # Reposition the cursor cursor[0] = next elif align == 'D' and wrapped == 1: # Text is wrapped due to an overflow # Double (full) justification # Take the width of each word which is not a space and create a # total width. # Subtract this from the column width and divide the remainder by # the number of spaces that should occur. # Also, remove the spaces from the list by creating a new list. total_width = 0.0 new_line = [] for word, font_name, font_size, font_width, fg, bg in line: if word != '': # Set the font self.style.font = RISCOSFont(font_name) # Increase the width total_width = total_width + \ self.style.font.TextCoordBox( word, font_size)[2] # Add this word to the new list new_line.append( (word, font_name, font_size, font_width, fg, bg)) # If there are no words then return to the caller if len(new_line) == 0: return # Determine the spacing required between each word if len(new_line) > 1: spacing = (self.margins[1] - self.margins[0] - total_width) / \ (len(new_line) - 1) else: spacing = 0.0 # Place the cursor and render the new line cursor[0] = self.margins[0] for word, font_name, font_size, font_width, fg, bg in new_line: # Set the font name self.style.font = RISCOSFont(font_name) # Set the font size self.style.font_size = font_size # Set the text colour self.style.line_pattern = bg self.style.fill_pattern = fg # Determine the horizontal position of the end of this word next = cursor[0] + \ self.style.font.TextCoordBox(word, font_size)[2] # Write the text to the page self.simple_text(word, Translation(cursor)) # Reposition the cursor cursor[0] = next + spacing elif align == 'D' and wrapped == 0: # Text is not wrapped due to an overflow # Left justification cursor[0] = self.margins[0] for word, font_name, font_size, font_width, fg, bg in line: # Set the font name self.style.font = RISCOSFont(font_name) # Set the font size self.style.font_size = font_size # Set the text colour self.style.line_pattern = bg self.style.fill_pattern = fg # Determine the horizontal position of the next word next = cursor[0] + \ self.style.font.TextCoordBox(word, font_size)[2] # Write the text to the page self.simple_text(word, Translation(cursor)) # Reposition the cursor cursor[0] = next else: # Can't align the text return
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 width = width + \ use_font.TextCoordBox(text, font_size)[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)[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)[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)[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)[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 main(): import Sketch global doc global tbase_style Sketch.init_lib() draw_printable = 1 draw_visible = 0 embed_fonts = 0 eps_for = util.get_real_username() eps_date = util.current_date() eps_title = None rotate = 0 #doc = load.load_drawing('') # from mainwindow.py: self.SetDocument(Document(create_layer = 1)) doc = Document(create_layer = 1) # get font info first Graphics.font.read_font_dirs() # indicate start of coord system first # coord system:: + goes upward / rightward # from RectangleCreator: trafo = Trafo(off.x, 0, 0, off.y, end.x, end.y) # actually, there 'end' seems to correspond to start (llc: lower left corner of rectangle) - and 'off' to the length extended in each direction (i.e. width, height - but can be negative) ; so instead of 'end' - calling it 'start' start_x = 5 start_y = 5 off_x = -10 off_y = -10 trec = Rectangle(trafo = Trafo(off_x, 0, 0, off_y, start_x, start_y)) trec.update_rects() doc.Insert(trec) # from create_text.py textfld = SimpleText(Translation(50, 50), "xyzzy") textfld.SetProperties(fill_pattern = SolidPattern(StandardColors.green), font = GetFont('Courier-Bold'),#('Times-Bold'), font_size = 36) #copy textfld textfld2 = textfld.Duplicate() textfld2.SetProperties(fill_pattern = SolidPattern(StandardColors.blue)) # change color only # rotate textfld angleDeg = 45 angleRad = pi*(angleDeg/180.0) # ensure float op - could use math.radians instead textfld.Transform(Rotation(angleRad)) # Rotation(angle, center) textfld.update_rects() # probably a good idea # change textfld's text with the current width (that we see) # get bounding box of text a = textfld.properties llx, lly, urx, ury = a.font.TextBoundingBox(textfld.text, a.font_size) # calculate width - its of UNTRANSFORMED text twidth = urx - llx # insert this width as text in textbox now: #~ textfld.text = str(twidth) #~ textfld.update_rects() # probably a good idea - again # get textfield as bezier textbez = textfld.AsBezier() #~ print textbez # returns Sketch.Graphics.group.Group; subclass of EditableCompound # the bounding rectangle - from Compound (type is Rect): textbez_bRect = textbez.bounding_rect # calc width now t2width = textbez_bRect.right - textbez_bRect.left # insert this width as text in textbox now: textfld.text = str(t2width) textfld.update_rects() # probably a good idea - again #~ doc.Insert(textfld) # create a line # using create_spiral.py technique below (see syntax note #(A1)) tpath = CreatePath() # Note - apparently, the first appended point is "moveTo"; # .. the ubsequent ones being "LineTo" tp = Point(textbez_bRect.left,textbez_bRect.bottom) tpath.AppendLine(tp) # moveto tp = Point(textbez_bRect.left,textbez_bRect.top) tpath.AppendLine(tp) # lineto tp = Point(textbez_bRect.right,textbez_bRect.top) tpath.AppendLine(tp) # lineto tp = Point(textbez_bRect.right,textbez_bRect.bottom) tpath.AppendLine(tp) # lineto tline = PolyBezier((tpath,)) tline.AddStyle(tbase_style) # of Graphics.properties (also in compound, document) - seems to add a 'layer' if dynamic; else seems to 'replace' ?! #~ doc.Insert(tline) # group tline and textfld ... # footprints.py has Group(foot_prints = []) tgrp = Group([textfld, textfld2, tline]) tgrp.update_rects() doc.Insert(tgrp) # add a box.. around textfld2 # use radius1, radius2 != 0 AND 1 (logarithmic) to get RoundedRectangle (best between 0.0 and 1.0) tfbr = textfld2.bounding_rect start_x = tfbr.left start_y = tfbr.bottom off_x = tfbr.right - tfbr.left off_y = tfbr.top - tfbr.bottom twid = abs(off_x - start_x) thei = abs(off_y - start_y) radfact = 1.2*twid/thei tradius = 0.05 # if we want to specify a single one, then the actual look will depend on the dimesions of the rectangle - so must 'smooth' it with radfact... trec = Rectangle(trafo = Trafo(off_x, 0, 0, off_y, start_x, start_y), radius1 = tradius, radius2 = tradius*radfact) trec.update_rects() doc.Insert(trec) # add another box - any where start_x = 100.0 start_y = 100.0 off_x = 50.0 off_y = 50.0 trec2 = Rectangle(trafo = Trafo(off_x, 0, 0, off_y, start_x, start_y)) trec2.update_rects() doc.Insert(trec2) # try change props post insert - OK trec2.SetProperties(fill_pattern = SolidPattern(StandardColors.yellow), line_width = 2.0, line_pattern = SolidPattern(CreateRGBColor(0.5, 0.5, 0.7))) # try move the group as a whole (Translate - syntax: spread.py) # say, align the right edge of tline to left edge of trec2 (x direction) # NOTE: group does not define own .AsBezier(self); # but it has tgrp.bounding_rect (although python doesn't show it in dir(tgrp)) # also there is Rectangle.bounding_rect # NOTE though - it seems bounding_rect is somehow padded, with (at least) 10 units in each direction! (also, bounding rect of line will include the arrow) xmove = (trec2.bounding_rect.left+10)-(tline.bounding_rect.right-10) #~ print xmove, trec2.bounding_rect.left, tline.bounding_rect.right tgrp.Translate(Point(xmove, 0)) tgrp.update_rects() # add temporary line to indicate bounding boxes # and effect of padding (may cover the very first trec) tmpbr = trec2.bounding_rect doc.Insert( getQuickLine( (0,0), (trec2.bounding_rect.left+10, tline.bounding_rect.top-10) ) ) # end of draw - generate output file filename = '' psfile = 'vectorout.ps' sk2ps(filename, psfile, printable= draw_printable, visible = draw_visible, For = eps_for, CreationDate = eps_date, Title = eps_title, rotate = rotate, embed_fonts = embed_fonts)
def Translate(self, offset): return self.Transform(Translation(offset))
def RemoveTransformation(self): return self.set_transformation(Translation(self.trafo.offset()))