def get_font_size(fontsize,text): width = 0 for char in text: width += glyphquery.width(font,glyphquery.glyphName(font,char)) scaling=2000/fontsize #no idea what this is if args.debug: print "label '%s' calculated to be %dx%d" % (text,width/scaling,glyphquery.charHeight(font)/scaling) return(width/scaling,glyphquery.charHeight(font)/scaling)
def _generalMetadata( self ): """Load general meta-data for this font (called via withFont) Guess the appropriate encoding, query line height, and character height. """ try: self.encoding = describe.guessEncoding( self.font, self.encoding ) self.lineHeight = glyphquery.lineHeight( self.font ) self.charHeight = glyphquery.charHeight( self.font ) except Exception: log.error( """Unable to load TrueType font from %r""", self.filename) raise
def text(pos=(0,0), text="", font=None, height=1.0, align='left', spacing=0.03, rotate=0.0, scale=1.0, xscale=1.0, yscale=1.0, thickness=None, vertical_spacing=None, info=False): # If info == True, the caller wants the additional info such as upper-left, etc. # In this case we return an instance of the class text_info, with the Polygon as # an attribute, text_info.Polygon. The main client of this extra info is the text object. if thickness is not None: raise AttributeError("Thickness is not allowed in a text shape.") if scale != 1.0: xscale = yscale = scale lines = text.split('\n') while lines[-1] == '\n': # strip off trailing newlines lines = lines[:-1] if font is None: font = "serif" font = describe.openFont(findFont(font)) try: fonth = glyphquery.charHeight(font) except: fonth = 1000 if fonth == 0: fonth = 1000 try: desc = glyphquery.charDescent(font) # charDescent may not be present fontheight = fonth+desc fontscale = 1./fontheight descent = fontscale*desc except: descent = -0.3*height # approximate value fontheight = 0.7*fonth fontscale = 1.3/fontheight if vertical_spacing is None: vertical_spacing = height*fontscale*glyphquery.lineHeight(font) excludef_list = [("ITCEdscr")] excludec_list = [("FRSCRIPT", "A"), ("jokerman", "O"), ("vivaldii", "O"), ("vivaldii", "Q"), ("vivaldii", "R")] ptext = [] widths = [] width = 0.0 starts = [] start = 0.0 for line in range(len(lines)): ptext.append(Polygon()) bb = 0 for newchar in lines[line]: if newchar == " ": try: if a: bx = a.boundingBox() bba = bx[1]-bx[0] bba = min(bba, 700) bb += bba except: pass continue n = glyphquery.glyphName(font, newchar) if n == ".notdef": print("The character '"+newchar+"' is not supported in the font "+font) continue g = glyph.Glyph(n) c = g.calculateContours(font) contours = [] for contour in c: contours.append(glyph.decomposeOutline(contour)) if len(contours[-1]) == 0: contours.pop() for contour in contours: pp = 0 for i in range(len(contour)-1): if (contour[i][0] == contour[i+1][0]) and (contour[i][1] == contour[i+1][1]): contour.pop(i) pp += 1 if i+pp >= len(contour)-1: break def lenctr(contour): totlen = 0 for j in range(len(contour)-1): totlen += (vis.vector(contour[j])-vis.vector(contour[j+1])).mag return totlen lc = len(contours) if lc >= 4: mli = 0 maxl = 0 lengths = [] for i in range(len(contours)): totlen = lenctr(contours[i]) lengths.append((totlen,i)) if totlen > maxl: mli = i maxl = totlen lengths.sort() lengths.reverse() ocontours = [] for ll in lengths: ocontours.append(contours[ll[1]]) contours = ocontours indxf = -1 indxc = -1 if (mli > 0 and newchar != "%"): try: indxf = excludef_list.index(self.font) except: pass if indxf == -1: try: indxc = excludec_list.index((self.font, newchar)) except: pass if (indxf == -1 and indxc == -1): maxc = contours.pop(mli) contours.insert(0, maxc) a = Polygon(contours[0]) for i in range(1,len(contours)): b = Polygon(contours[i]) if a.covers(b): a = a - b elif b.covers(a): a = b - a else: a = a + b a.shift(bb - a.boundingBox()[0] ,0) ptext[line] += a bx = ptext[line].boundingBox() bb = bx[1] - bx[0] + spacing*fontheight newwidth = fontscale*height*(ptext[line].boundingBox()[1]-ptext[line].boundingBox()[0]) widths.append(newwidth) if newwidth > width: width = newwidth ptext[line].scale(xscale*fontscale*height, yscale*fontscale*height, 0, 0) for line in range(len(lines)): if align == 'left': ptext[line].shift(-width/2,-line*vertical_spacing) elif align == 'right': ptext[line].shift(width/2-widths[line],-line*vertical_spacing) else: ptext[line].shift(-widths[line]/2,-line*vertical_spacing) ptext[line].shift(pos[0], pos[1]) if rotate != 0.0: ptext[line].rotate(rotate) if line == 0: shape = ptext[0] upper_left = vis.vector(ptext[line].boundingBox()[0],ptext[line].boundingBox()[3],0) upper_right = vis.vector(ptext[line].boundingBox()[1],ptext[line].boundingBox()[3],0) lower_left = vis.vector(ptext[line].boundingBox()[0],ptext[line].boundingBox()[2],0) lower_right = vis.vector(ptext[line].boundingBox()[1],ptext[line].boundingBox()[2],0) else: shape += ptext[line] xleft = ptext[line].boundingBox()[0] xright = ptext[line].boundingBox()[1] y = ptext[line].boundingBox()[2] if xleft < upper_left.x: upper_left.x = xleft if xright > upper_right.x: upper_right.x = xright lower_left = vis.vector(upper_left.x,ptext[line].boundingBox()[2],0) lower_right = vis.vector(upper_right.x,ptext[line].boundingBox()[2],0) dy = vis.vector(0,(upper_left.y-lower_left.y)/2-height,0) shape.shift(0,dy.y) if not info: return shape info = text_info() info.Polygon = shape info.upper_left = upper_left+dy info.upper_right = upper_right+dy info.lower_left = lower_left+dy info.lower_right = lower_right+dy if align == 'left': x = 0 elif align == 'right': x = -width elif align == 'center': x = -0.5*width info.start = vis.vector(x,0,0)+dy info.starts = [] for line in range(len(lines)): if align == 'left': x = 0 elif align == 'right': x = -widths[line] elif align == 'center': x = -0.5*widths[line] info.starts.append(vis.vector(x,line*vertical_spacing,0)+dy) info.width = width info.widths = widths info.descent = descent info.vertical_spacing = vertical_spacing info.align = align info.height = height return info
def convert_text(dict_values, fonts, mtext): layer = dict_values[8][0][0] text = ("".join(dict_values[3][0][0]) if 3 in dict_values else "") + dict_values[1][0][0] xoffset = float(dict_values[10][0][0]) yoffset = float(dict_values[20][0][0]) height = float(dict_values[40][0][0]) rotation = float( dict_values[50][0][0]) / 180.0 * math.pi if 50 in dict_values else 0 font = fonts[dict_values[7][0][0].lower() if 7 in dict_values else "standard"] print("using font", font) if mtext: boxwidth = float(dict_values[41][0][0]) if 41 in dict_values else 1 x_scale = 1 attachment = int(dict_values[71][0][0]) if 71 in dict_values else 1 text = re.sub("\\\\[^;]*;", "", text) text = re.sub("([^\\\\])\\\\P", "\g<1>\\n", text) spacing_fac = float(dict_values[44][0][0]) if 44 in dict_values else 1 else: boxwidth = 1 #None raised error x_scale = float(dict_values[41][0][0]) if 41 in dict_values else 1 xalign = float( dict_values[11][0][0] ) if 11 in dict_values else None #only used for Horizontal text justification typ == 3 yalign = float( dict_values[21][0][0] ) if 11 in dict_values else None #only used for Horizontal text justification typ == 3 drawdir = int( dict_values[71][0][0] ) if 71 in dict_values else 0 #mirroring in X (=2) or Y (=4) direction h_text_just = int( dict_values[72][0][0] ) if 72 in dict_values else 0 #0=left 1=center 2=right 3=aligned v_text_just = int( dict_values[73][0][0] ) if 73 in dict_values else 3 #0=baseline 1=bottom 2=middle 3=top spacing_fac = 1 for number, name in [(51, "'oblique angle'")]: if number in dict_values: print "INFO: sorry but option ", name, "(", number, ") is not supported yet" cheight = float(glyphquery.charHeight(font)) / 1.32 #magic number objects = [] boxwidth /= x_scale * height / cheight charoff = 0 lineno = 1 lines = [[]] for n, letter in enumerate(text): glname = glyphquery.glyphName(font, letter) glwidth = glyphquery.width(font, glname) print(glname, glwidth, letter, charoff) if letter == "\n" or (boxwidth and charoff + glwidth > boxwidth): lines.append(list()) #charoff = 0 # temprarily deactivated, sets charoff always to 0 else... lineno += 1 if letter != "\n": boundaries = [cheight * 10, cheight * 10, 0, 0] for c in glyph.Glyph(glname).calculateContours(font): outlines = glyph.decomposeOutline(c, 2) first = True lines[-1].append({"layer": layer, "command": "G36*"}) for l in outlines: org_x = (l[0] + charoff) * x_scale * height / cheight org_y = l[1] * height / cheight x = org_x * math.cos(rotation) - org_y * math.sin( rotation) + xoffset y = org_x * math.sin(rotation) + org_y * math.cos( rotation) + yoffset # changes polarity -> clear holes in fonts if first and (boundaries[0] < l[0] and l[0] < boundaries[2] and boundaries[1] < l[1] and l[1] < boundaries[3]): lines[-1].pop( ) #pop the last G36; the gerber file is not read correctly if LPC comes within a G36-G37 Block lines[-1].append({"layer": layer, "command": "%LPC*%"}) lines[-1].append({"layer": layer, "command": "G36*"}) boundaries[0] = min(boundaries[0], l[0]) boundaries[1] = min(boundaries[1], l[1]) boundaries[2] = max(boundaries[2], l[0]) boundaries[3] = max(boundaries[3], l[1]) #x*=scaling# #y*=scaling# lines[-1].append({ "layer": layer, "device": "C,0.001*", "x": x, "y": y, "style": "D02" if first else "D01" }) first = False lines[-1].append({"layer": layer, "command": "G37*"}) lines[-1].append({"layer": layer, "command": "%LPD*%"}) charoff += glwidth #print(lines)# #respect the alignment (only affects MTEXT. For TEXT it is already considered if mtext: spacing = height / 3 * 5 * spacing_fac textwidth = charoff * x_scale * height / cheight vertical = int((attachment - 1) / 3) #0=oben 1=mitte 2=unten horizontal = (attachment - 1) % 3 #0=links 1=mitte 2=rechts if horizontal == 0: shift_x = 0 #links elif horizontal == 1: shift_x = -textwidth / 2 #mitte elif horizontal == 2: shift_x = -textwidth #rechts lineno = 0 for line_objects in lines: if vertical == 0: shift_y = -height - (lineno - 1) * spacing #oben elif vertical == 1: shift_y = (len(lines) - lineno) * spacing / 2 #mitte elif vertical == 2: shift_y = (len(lines) - lineno) * spacing #unten lineno += 1 for o in line_objects: if "x" in o: o["x"] += shift_x if "y" in o: o["y"] += shift_y for line_objects in lines: objects.extend(line_objects) return objects, True