def drawSVG(self, svg_attributes, attributes, paths): global SCALE global SUBSAMPLING global SIMPLIFY global SIMPLIFYHQ global TRACEWIDTH out = '' svgWidth = 0 svgHeight = 0 if 'viewBox' in svg_attributes.keys(): if svg_attributes['viewBox'].split()[2] != '0': svgWidth = str( round(float(svg_attributes['viewBox'].split()[2]), 2)) svgHeight = str( round(float(svg_attributes['viewBox'].split()[3]), 2)) else: svgWidth = svg_attributes['width'] svgHeight = svg_attributes['height'] else: svgWidth = svg_attributes['width'] svgHeight = svg_attributes['height'] specifiedWidth = svg_attributes['width'] if 'mm' in specifiedWidth: specifiedWidth = float(specifiedWidth.replace('mm', '')) SCALE = specifiedWidth / float(svgWidth) if self.verbose: print("SVG width detected in mm \\o/") elif 'in' in specifiedWidth: specifiedWidth = float(specifiedWidth.replace('in', '')) * 25.4 SCALE = specifiedWidth / float(svgWidth) if self.verbose: print("SVG width detected in inches") else: SCALE = (self.scaleFactor * 25.4) / 150 if self.verbose: print("SVG width not found, guessing based on scale factor") self.exportHeight = float(svgHeight) * SCALE if len(paths) == 0: print("No paths found. Did you use 'Object to path' in Inkscape?") i = 0 out = [] while i < len(paths): if self.verbose: print('Translating Path ' + str(i + 1) + ' of ' + str(len(paths))) # Apply the tranform from this svg object to actually transform the points # We need the Matrix object from svgelements but we can only matrix multiply with # svgelements' version of the Path object so we're gonna do some dumb stuff # to launder the Path object from svgpathtools through a d-string into # svgelements' version of Path. Luckily, the Path object from svgelements has # backwards compatible .point methods pathTransform = Matrix('') if 'transform' in attributes[i].keys(): pathTransform = Matrix(attributes[i]['transform']) if self.verbose: print('...Applying Transforms') path = elPath(paths[i].d()) * pathTransform path = elPath(path.d()) # Another stage of transforms that gets applied to all paths # in order to shift the label around the origin tx = { 'l': 0, 'c': 0 - (float(svgWidth) / 2), 'r': 0 - float(svgWidth) } ty = {'t': 250, 'c': 150, 'b': 50} path = elPath(paths[i].d()) * Matrix.translate( tx[self.originPos[1]], ty[self.originPos[0]]) path = elPath(path.d()) style = 0 if 'style' in attributes[i].keys(): style = styleParse(attributes[i]['style']) if 'fill' in attributes[i].keys(): filled = attributes[i]['fill'] != 'none' and attributes[i][ 'fill'] != '' elif 'style' in attributes[i].keys(): filled = style['fill'] != 'none' and style['fill'] != '' else: filled = False if 'stroke' in attributes[i].keys(): stroked = attributes[i]['stroke'] != 'none' and attributes[i][ 'stroke'] != '' elif 'style' in attributes[i].keys(): stroked = style['stroke'] != 'none' and style['stroke'] != '' else: stroked = False if not filled and not stroked: i += 1 continue # not drawable (clip path?) SUBSAMPLING = self.subSampling TRACEWIDTH = str(self.traceWidth) l = path.length() divs = round(l * SUBSAMPLING) if divs < 3: divs = 3 maxLen = l * 2 * SCALE / divs p = path.point(0) p = complex(p.real * SCALE, p.imag * SCALE) last = p polys = [] points = [] s = 0 while s <= divs: p = path.point(s * 1 / divs) p = complex(p.real * SCALE, p.imag * SCALE) if dist(p, last) > maxLen: if len(points) > 1: points = simplify(points, SIMPLIFY, SIMPLIFYHQ) polys.append(points) points = [p] else: points.append(p) last = p s += 1 if len(points) > 1: points = simplify(points, SIMPLIFY, SIMPLIFYHQ) polys.append(points) if filled: polys = unpackPoly(polys) for points in polys: if len(points) < 2: return _points = [] if filled: points.append( points[0]) # re-add final point so we loop around for p in points: precisionX = round(p.real, 8) precisionY = round(p.imag - self.exportHeight, 8) _points += [(precisionX, precisionY)] out += [_points] i += 1 self.polys = out return out
def renderLabel(self, inString): dwg = svgwrite.Drawing() # SVG drawing in memory strIdx = 0 # Used to iterate over inString xOffset = 100 # Cumulative character placement offset yOffset = 0 # Cumulative character placement offset charSizeX = 8 # Character size constant charSizeY = 8 # Character size constant baseline = 170 # Y value of text baseline glyphBounds = [ ] # List of boundingBox objects to track rendered character size finalSegments = [] # List of output paths escaped = False # Track whether the current character was preceded by a '\' lineover = False # Track whether the current character needs to be lined over lineoverList = [] # If we can't find the typeface that the user requested, we have to quit try: face = Face( os.path.dirname(os.path.abspath(__file__)) + '/typeface/' + self.fontName + '.ttf') face.set_char_size(charSizeX, charSizeY, 200, 200) except Exception as e: print(e) print("WARN: No Typeface found with the name " + self.fontName + ".ttf") sys.exit(0) # quit Python # If the typeface that the user requested exists, but there's no position table for it, we'll continue with a warning try: table = __import__( 'KiBuzzard.KiBuzzard.buzzard.typeface.' + self.fontName, globals(), locals(), ['glyphPos']) glyphPos = table.glyphPos spaceDistance = table.spaceDistance except: glyphPos = 0 spaceDistance = 60 print( "WARN: No Position Table found for this typeface. Composition will be haphazard at best." ) # If there's lineover text, drop the text down to make room for the line dropBaseline = False a = False x = 0 while x < len(inString): if x > 0 and inString[x] == '\\': a = True if x != len(inString) - 1: x += 1 if inString[x] == '!' and not a: dropBaseline = True a = False x += 1 if dropBaseline: baseline = 190 # Draw and compose the glyph portion of the tag for charIdx in range(len(inString)): # Check whether this character is a space if inString[charIdx] == ' ': glyphBounds.append(boundingBox(0, 0, 0, 0)) xOffset += spaceDistance continue # Check whether this character is a backslash that isn't escaped # and isn't the first character (denoting a backslash-shaped tag) if inString[charIdx] == '\\' and charIdx > 0 and not escaped: glyphBounds.append(boundingBox(0, 0, 0, 0)) escaped = True continue # If this is a non-escaped '!' mark the beginning of lineover if inString[charIdx] == '!' and not escaped: glyphBounds.append(boundingBox(0, 0, 0, 0)) lineover = True # If we've hit the end of the string but not the end of the lineover # go ahead and finish it out if charIdx == len(inString) - 1 and len(lineoverList) > 0: linePaths = [] linePaths.append( Line(start=complex(lineoverList[0], 10), end=complex(xOffset, 10))) linePaths.append( Line(start=complex(xOffset, 10), end=complex(xOffset, 30))) linePaths.append( Line(start=complex(xOffset, 30), end=complex(lineoverList[0], 30))) linePaths.append( Line(start=complex(lineoverList[0], 30), end=complex(lineoverList[0], 10))) linepath = Path(*linePaths) linepath = elPath(linepath.d()) finalSegments.append(linepath) lineover = False lineoverList.clear() continue # All special cases end in 'continue' so if we've gotten here we can clear our flags if escaped: escaped = False face.load_char( inString[charIdx]) # Load character curves from font outline = face.glyph.outline # Save character curves to var y = [t[1] for t in outline.points] # flip the points outline_points = [(p[0], max(y) - p[1]) for p in outline.points] start, end = 0, 0 paths = [] box = 0 yOffset = 0 for i in range(len(outline.contours)): end = outline.contours[i] points = outline_points[start:end + 1] points.append(points[0]) tags = outline.tags[start:end + 1] tags.append(tags[0]) segments = [ [ points[0], ], ] box = boundingBox(points[0][0], points[0][1], points[0][0], points[0][1]) for j in range(1, len(points)): if not tags[j]: # if this point is off-path if tags[j - 1]: # and the last point was on-path segments[-1].append( points[j]) # toss this point onto the segment elif not tags[j - 1]: # and the last point was off-path # get center point of two newPoint = ((points[j][0] + points[j - 1][0]) / 2.0, (points[j][1] + points[j - 1][1]) / 2.0) segments[-1].append( newPoint ) # toss this new point onto the segment segments.append( [ newPoint, points[j], ] ) # and start a new segment with the new point and this one elif tags[j]: # if this point is on-path segments[-1].append( points[j]) # toss this point onto the segment if j < (len(points) - 1): segments.append( [ points[j], ] ) # and start a new segment with this point if we're not at the end for segment in segments: if len(segment) == 2: paths.append( Line(start=tuple_to_imag(segment[0]), end=tuple_to_imag(segment[1]))) elif len(segment) == 3: paths.append( QuadraticBezier(start=tuple_to_imag(segment[0]), control=tuple_to_imag(segment[1]), end=tuple_to_imag(segment[2]))) start = end + 1 # Derive bounding box of character for segment in paths: i = 0 while i < 10: point = segment.point(0.1 * i) if point.real > box.xMax: box.xMax = point.real if point.imag > box.yMax: box.yMax = point.imag if point.real < box.xMin: box.xMin = point.real if point.imag < box.yMin: box.yMin = point.imag i += 1 glyphBounds.append(box) path = Path(*paths) if glyphPos != 0: try: xOffset += glyphPos[inString[charIdx]].real yOffset = glyphPos[inString[charIdx]].imag except: pass if lineover and len(lineoverList) == 0: lineoverList.append(xOffset) lineover = False if (lineover and len(lineoverList) > 0): linePaths = [] linePaths.append( Line(start=complex(lineoverList[0], 10), end=complex(xOffset, 10))) linePaths.append( Line(start=complex(xOffset, 10), end=complex(xOffset, 30))) linePaths.append( Line(start=complex(xOffset, 30), end=complex(lineoverList[0], 30))) linePaths.append( Line(start=complex(lineoverList[0], 30), end=complex(lineoverList[0], 10))) linepath = Path(*linePaths) linepath = elPath(linepath.d()) finalSegments.append(linepath) lineover = False lineoverList.clear() pathTransform = Matrix.translate(xOffset, baseline + yOffset - box.yMax) path = elPath(path.d()) * pathTransform path = elPath(path.d()) finalSegments.append(path) xOffset += 30 if glyphPos != 0: try: xOffset -= glyphPos[inString[charIdx]].real except: pass xOffset += (glyphBounds[charIdx].xMax - glyphBounds[charIdx].xMin) strIdx += 1 if self.leftCap == '' and self.rightCap == '': for i in range(len(finalSegments)): svgObj = dwg.add(dwg.path(finalSegments[i].d())) svgObj['fill'] = "#000000" else: #draw the outline of the label as a filled shape and #subtract each latter from it tagPaths = [] if self.rightCap == 'round': tagPaths.append( Line(start=complex(100, 0), end=complex(xOffset, 0))) tagPaths.append( Arc(start=complex(xOffset, 0), radius=complex(100, 100), rotation=180, large_arc=1, sweep=1, end=complex(xOffset, 200))) elif self.rightCap == 'square': tagPaths.append( Line(start=complex(100, 0), end=complex(xOffset, 0))) tagPaths.append( Line(start=complex(xOffset, 0), end=complex(xOffset + 50, 0))) tagPaths.append( Line(start=complex(xOffset + 50, 0), end=complex(xOffset + 50, 200))) tagPaths.append( Line(start=complex(xOffset + 50, 200), end=complex(xOffset, 200))) elif self.rightCap == 'pointer': tagPaths.append( Line(start=complex(100, 0), end=complex(xOffset, 0))) tagPaths.append( Line(start=complex(xOffset, 0), end=complex(xOffset + 50, 0))) tagPaths.append( Line(start=complex(xOffset + 50, 0), end=complex(xOffset + 100, 100))) tagPaths.append( Line(start=complex(xOffset + 100, 100), end=complex(xOffset + 50, 200))) tagPaths.append( Line(start=complex(xOffset + 50, 200), end=complex(xOffset, 200))) elif self.rightCap == 'flagtail': tagPaths.append( Line(start=complex(100, 0), end=complex(xOffset, 0))) tagPaths.append( Line(start=complex(xOffset, 0), end=complex(xOffset + 100, 0))) tagPaths.append( Line(start=complex(xOffset + 100, 0), end=complex(xOffset + 50, 100))) tagPaths.append( Line(start=complex(xOffset + 50, 100), end=complex(xOffset + 100, 200))) tagPaths.append( Line(start=complex(xOffset + 100, 200), end=complex(xOffset, 200))) elif self.rightCap == 'fslash': tagPaths.append( Line(start=complex(100, 0), end=complex(xOffset, 0))) tagPaths.append( Line(start=complex(xOffset, 0), end=complex(xOffset + 50, 0))) tagPaths.append( Line(start=complex(xOffset + 50, 0), end=complex(xOffset, 200))) elif self.rightCap == 'bslash': tagPaths.append( Line(start=complex(100, 0), end=complex(xOffset, 0))) tagPaths.append( Line(start=complex(xOffset, 0), end=complex(xOffset + 50, 200))) tagPaths.append( Line(start=complex(xOffset + 50, 200), end=complex(xOffset, 200))) elif self.rightCap == '' and self.leftCap != '': tagPaths.append( Line(start=complex(100, 0), end=complex(xOffset, 0))) tagPaths.append( Line(start=complex(xOffset, 0), end=complex(xOffset, 200))) if self.leftCap == 'round': tagPaths.append( Line(start=complex(xOffset, 200), end=complex(100, 200))) tagPaths.append( Arc(start=complex(100, 200), radius=complex(100, 100), rotation=180, large_arc=0, sweep=1, end=complex(100, 0))) elif self.leftCap == 'square': tagPaths.append( Line(start=complex(xOffset, 200), end=complex(100, 200))) tagPaths.append( Line(start=complex(100, 200), end=complex(50, 200))) tagPaths.append( Line(start=complex(50, 200), end=complex(50, 0))) tagPaths.append(Line(start=complex(50, 0), end=complex(100, 0))) elif self.leftCap == 'pointer': tagPaths.append( Line(start=complex(xOffset, 200), end=complex(100, 200))) tagPaths.append( Line(start=complex(100, 200), end=complex(50, 200))) tagPaths.append( Line(start=complex(50, 200), end=complex(0, 100))) tagPaths.append(Line(start=complex(0, 100), end=complex(50, 0))) tagPaths.append(Line(start=complex(50, 0), end=complex(100, 0))) elif self.leftCap == 'flagtail': tagPaths.append( Line(start=complex(xOffset, 200), end=complex(100, 200))) tagPaths.append( Line(start=complex(100, 200), end=complex(0, 200))) tagPaths.append( Line(start=complex(0, 200), end=complex(50, 100))) tagPaths.append(Line(start=complex(50, 100), end=complex(0, 0))) tagPaths.append(Line(start=complex(0, 0), end=complex(100, 0))) elif self.leftCap == 'fslash': tagPaths.append( Line(start=complex(xOffset, 200), end=complex(100, 200))) tagPaths.append( Line(start=complex(100, 200), end=complex(50, 200))) tagPaths.append( Line(start=complex(50, 200), end=complex(100, 0))) elif self.leftCap == 'bslash': tagPaths.append( Line(start=complex(xOffset, 200), end=complex(100, 200))) tagPaths.append( Line(start=complex(100, 200), end=complex(50, 0))) tagPaths.append(Line(start=complex(50, 0), end=complex(100, 0))) elif self.leftCap == '' and self.rightCap != '': tagPaths.append( Line(start=complex(xOffset, 200), end=complex(100, 200))) tagPaths.append( Line(start=complex(100, 200), end=complex(100, 0))) path = Path(*tagPaths) for i in range(len(finalSegments)): path = elPath(path.d() + " " + finalSegments[i].reverse()) tagObj = dwg.add(dwg.path(path.d())) tagObj['fill'] = "#000000" dwg['width'] = xOffset + 100 dwg['height'] = 250 #dwg.saveas('out.svg') print('create svg') return dwg
def drawSVG(svg_attributes, attributes, paths): global SCALE global SUBSAMPLING global SIMPLIFY global SIMPLIFYHQ global TRACEWIDTH out = '' svgWidth = 0 svgHeight = 0 if 'viewBox' in svg_attributes.keys(): if svg_attributes['viewBox'].split()[2] != '0': svgWidth = str( round(float(svg_attributes['viewBox'].split()[2]), 2)) svgHeight = str( round(float(svg_attributes['viewBox'].split()[3]), 2)) else: svgWidth = svg_attributes['width'] svgHeight = svg_attributes['height'] else: svgWidth = svg_attributes['width'] svgHeight = svg_attributes['height'] specifiedWidth = svg_attributes.get('width') if specifiedWidth == None: specifiedWidth = "None" if 'mm' in specifiedWidth: specifiedWidth = float(specifiedWidth.replace('mm', '')) SCALE = specifiedWidth / float(svgWidth) if args.verbose: print("SVG width detected in mm \\o/") elif 'in' in specifiedWidth: specifiedWidth = float(specifiedWidth.replace('in', '')) * 25.4 SCALE = specifiedWidth / float(svgWidth) if args.verbose: print("SVG width detected in inches") else: SCALE = (args.scaleFactor * 25.4) / 150 if args.verbose: print("SVG width not found, guessing based on scale factor") exportHeight = float(svgHeight) * SCALE if args.outMode == "b": out += "CHANGE layer " + str(args.eagleLayerNumber) + \ "; CHANGE rank 3; CHANGE pour solid; SET WIRE_BEND 2;\n" if args.outMode == "ls": out += "CHANGE layer " + str(args.eagleLayerNumber) + \ "; CHANGE pour solid; Grid mm; SET WIRE_BEND 2;\n" if len(paths) == 0: print("No paths found. Did you use 'Object to path' in Inkscape?") anyVisiblePaths = False i = 0 while i < len(paths): if args.verbose: print('Translating Path ' + str(i + 1) + ' of ' + str(len(paths))) # Apply the tranform from this svg object to actually transform the points # We need the Matrix object from svgelements but we can only matrix multiply with # svgelements' version of the Path object so we're gonna do some dumb stuff # to launder the Path object from svgpathtools through a d-string into # svgelements' version of Path. Luckily, the Path object from svgelements has # backwards compatible .point methods pathTransform = Matrix('') if 'transform' in attributes[i].keys(): pathTransform = Matrix(attributes[i]['transform']) if args.verbose: print('...Applying Transforms') path = elPath(paths[i].d()) * pathTransform path = elPath(path.d()) # Another stage of transforms that gets applied to all paths # in order to shift the label around the origin tx = {'l': 0, 'c': 0 - (float(svgWidth) / 2), 'r': 0 - float(svgWidth)} ty = {'t': 250, 'c': 150, 'b': 50} path = elPath(paths[i].d()) * Matrix.translate(tx[args.originPos[1]], ty[args.originPos[0]]) path = elPath(path.d()) style = 0 if 'style' in attributes[i].keys(): style = styleParse(attributes[i].get('style')) if 'fill' in attributes[i].keys(): filled = attributes[i].get('fill') != 'none' and attributes[i].get( 'fill') != '' elif 'style' in attributes[i].keys(): filled = style.get('fill') != 'none' and style.get('fill') != '' else: filled = False if 'stroke' in attributes[i].keys(): stroked = attributes[i].get( 'stroke') != 'none' and attributes[i].get('stroke') != '' elif 'style' in attributes[i].keys(): stroked = style.get('stroke') != 'none' and style.get( 'stroke') != '' else: stroked = False if not filled and not stroked: i += 1 continue # not drawable (clip path?) SUBSAMPLING = args.subSampling TRACEWIDTH = str(args.traceWidth) anyVisiblePaths = True l = path.length() divs = round(l * SUBSAMPLING) if divs < 3: divs = 3 maxLen = l * 2 * SCALE / divs p = path.point(0) p = complex(p.real * SCALE, p.imag * SCALE) last = p polys = [] points = [] s = 0 while s <= divs: p = path.point(s * 1 / divs) p = complex(p.real * SCALE, p.imag * SCALE) if dist(p, last) > maxLen: if len(points) > 1: points = simplify(points, SIMPLIFY, SIMPLIFYHQ) polys.append(points) points = [p] else: points.append(p) last = p s += 1 if len(points) > 1: points = simplify(points, SIMPLIFY, SIMPLIFYHQ) polys.append(points) if filled: polys = unpackPoly(polys) for points in polys: if len(points) < 2: return scriptLine = '' if filled: points.append( points[0]) # re-add final point so we loop around if args.outMode != "lib": if args.outMode == "b": scriptLine += "polygon " + args.signalName + " " + TRACEWIDTH + "mm " if args.outMode == "ls": scriptLine += "polygon " + TRACEWIDTH + "mm " for p in points: precisionX = '{0:.2f}'.format(round(p.real, 6)) precisionY = '{0:.2f}'.format( round(exportHeight - p.imag, 6)) scriptLine += '(' + precisionX + 'mm ' + precisionY + 'mm) ' scriptLine += ';' else: scriptLine += "<polygon width=\"" + TRACEWIDTH + "\" layer=\"" + str( args.eagleLayerNumber) + "\">\n" for p in points: precisionX = '{0:.2f}'.format(round(p.real, 6)) precisionY = '{0:.2f}'.format( round(exportHeight - p.imag, 6)) scriptLine += "<vertex x=\"" + precisionX + "\" y=\"" + precisionY + "\"/>\n" scriptLine += "</polygon>" out += scriptLine + '\n' i += 1 if not anyVisiblePaths: print("No paths with fills or strokes found.") return out