Пример #1
0
def plotTextString(stringToPlot, kerning=False, startXY=(0,0)):
    fontPath = "/home/meawoppl/Dropbox/repos/babyfood/cmr10.pfb"
    typeFace = Face(fontPath)
    typeFace.attach_file("/home/meawoppl/Dropbox/repos/babyfood/cmr10.pfm")
    typeFace.set_char_size(48 * 64)

    figure()
    startX, startY = startXY
    for n, char in enumerate(stringToPlot):
        typeFace.load_char(char)
        loopz = unpackCharacter(typeFace.glyph)
        loopz = shiftLoopSet(loopz, startX, startY)
        startX += typeFace.glyph.advance.x
        startY += typeFace.glyph.advance.y
        if kerning and (n != 0):
            kv = typeFace.get_kerning(char, stringToPlot[n-1])
            print(char, stringToPlot[n-1])
            print(kv.x, kv.y)
            print(dir(kv))
            startX += kv.x

        plotLoopSets(loopz)
    axis("equal")
    show()
    close()
Пример #2
0
    def __get_path(self, c, fname=expanduser('~/Library/Fonts/keifont.ttf')):
        """ This function is presented originally in freetype-py GitHub
            repository: we can refer the source 'glyph-vector.py' in
            the examples directory.
        """
        face = Face(fname)
        face.set_char_size(24 * 64)
        face.load_char(c)
        slot = face.glyph
        outline = slot.outline

        start, end = 0, 0
        VERTS, CODES = [], []
        for i in xrange(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],
                ],
            ]
            for j in range(1, len(points)):
                segments[-1].append(points[j])
                if tags[j] & (1 << 0) and j < (len(points) - 1):
                    segments.append([
                        points[j],
                    ])
            verts = [
                points[0],
            ]
            codes = [
                Path.MOVETO,
            ]
            for segment in segments:
                if len(segment) == 2:
                    verts.extend(segment[1:])
                    codes.extend([Path.LINETO])
                elif len(segment) == 3:
                    verts.extend(segment[1:])
                    codes.extend([Path.CURVE3, Path.CURVE3])
                else:
                    verts.append(segment[1])
                    codes.append(Path.CURVE3)
                    for i in range(1, len(segment) - 2):
                        A, B = segment[i], segment[i + 1]
                        C = ((A[0] + B[0]) / 2.0, (A[1] + B[1]) / 2.0)
                        verts.extend([C, B])
                        codes.extend([Path.CURVE3, Path.CURVE3])
                    verts.append(segment[-1])
                    codes.append(Path.CURVE3)
            VERTS.extend(verts)
            CODES.extend(codes)
            start = end + 1
        return Path(VERTS, CODES)
Пример #3
0
 def get_bounding_box(self):
     face = Face('UbuntuMono-R.ttf')
     face.set_char_size(self.size)
     face.load_char('g')
     total_width = 0
     total_height = 0
     for char in self.text:
         total_width += face.glyph.metrics.width
         total_height = max(total_height, face.glyph.metrics.width)
     # For the moment return
     return Box(self.position, [total_width, total_height])
Пример #4
0
 def get_bounding_box(self):
     face = Face('UbuntuMono-R.ttf')
     face.set_char_size(self.size)
     face.load_char('g')
     total_width = 0
     total_height = 0
     for char in self.text: 
         total_width += face.glyph.metrics.width
         total_height = max(total_height, face.glyph.metrics.width)
     # For the moment return
     return Box(self.position, [total_width, total_height])
Пример #5
0
    def __init__(self, face: freetype.Face, char: str) -> None:
        if face.load_char(char, freetype.FT_LOAD_RENDER):
            raise RuntimeError('failed to load char \'%s\'' % char)
        glyph = face.glyph
        bitmap = glyph.bitmap

        assert bitmap.pixel_mode == freetype.FT_PIXEL_MODE_GRAY, \
            "We haven't implemented support for other pixel modes"

        glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT)
        glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE)
        glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1)

        self._texture_id = glGenTextures(1)
        self._width = bitmap.width
        self._height = bitmap.rows

        self._descender = glyph.bitmap_top - self._height
        self._bearing_x = glyph.bitmap_left
        self._advance = numpy.array(
            [face.glyph.advance.x / 64.0, face.glyph.advance.y / 64.0])

        glBindTexture(GL_TEXTURE_2D, self._texture_id)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
        data = numpy.array(bitmap.buffer,
                           numpy.ubyte).reshape(self._height, self._width)
        glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, self._width, self._height, 0,
                     GL_ALPHA, GL_UNSIGNED_BYTE, numpy.flipud(data))

        glPopClientAttrib()
Пример #6
0
def fn_SortGlyphs(o_FreetypeFace: freetype.Face,
                  s_Chars: str,
                  b_Invert: bool = False) -> list:
    """
    :
    :  Sorts glyphs based on pixel density.
    :
    :
    :  Args:
    :      freetype.Face o_FreetypeFace : Font face used to calculate pixel densities
    :      str           s_Chars        : Character set over which pixel densities will be taken
    :      bool          b_Invert       : Whether to invert pixel density mapping order (default False)
    :
    :  Returns
    :
    :
    """
    l_Output = []

    # Profile pixel density over character set
    # ...
    for c in s_Chars:
        o_FreetypeFace.load_char(c)
        b_Buffer = o_FreetypeFace.glyph.bitmap.buffer
        l_Output.append((sum(b_Buffer), c))

    # Sort output list by pixel density
    # ...
    l_Output = [y[1] for y in sorted(l_Output, key=lambda x: x[0])]

    # Optionally invert order
    # ...
    if b_Invert:
        l_Output = l_Output[::-1]

    # Return it
    # ...
    return l_Output
Пример #7
0
class TextRenderer(object):
    _VERT_SHADER_SRC_PATH = os.path.join(_here, 'shaders',
                                         'text_renderer_vert.glsl')
    _FRAG_SHADER_SRC_PATH = os.path.join(_here, 'shaders',
                                         'text_renderer_frag.glsl')
    _VERT_SHADER_SRC = None
    _FRAG_SHADER_SRC = None

    def __init__(self,
                 font_file=os.path.join(_here, 'fonts', 'VeraMono.ttf'),
                 size=72 * 16):
        _logger.debug('loading %s...', font_file)
        self._font_file = font_file
        self._face = Face(font_file)
        self._face.set_char_size(size)
        width, max_asc, max_desc = 0, 0, 0
        widths = []
        for c in range(32, 128):
            self._face.load_char(chr(c),
                                 FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT)
            bitmap = self._face.glyph.bitmap
            width = max(width, bitmap.width)
            max_asc = max(max_asc, self._face.glyph.bitmap_top)
            max_desc = max(max_desc, bitmap.rows - self._face.glyph.bitmap_top)
            widths.append(bitmap.width)
        self._max_asc = max_asc
        self._widths = np.array(widths)
        self._width = width
        self._height = max_asc + max_desc
        self._read_shader_src()
        self._screen_size = (800.0, 600.0)
        self._texcoords = np.zeros((32, 2), dtype=np.float32)
        self._gl_initialized = False

    def set_screen_size(self, screen_size):
        self._screen_size = screen_size

    def init_gl(self):
        if self._gl_initialized:
            return
        import OpenGL.GL as gl
        self._texture_unit = 4
        vs_id = gl.glCreateShader(gl.GL_VERTEX_SHADER)
        gl.glShaderSource(vs_id, self._VERT_SHADER_SRC)
        gl.glCompileShader(vs_id)
        if not gl.glGetShaderiv(vs_id, gl.GL_COMPILE_STATUS):
            raise Exception('failed to compile %s vertex shader:\n%s' %
                            (self.__class__.__name__,
                             gl.glGetShaderInfoLog(vs_id).decode()))
        fs_id = gl.glCreateShader(gl.GL_FRAGMENT_SHADER)
        gl.glShaderSource(fs_id, self._FRAG_SHADER_SRC)
        gl.glCompileShader(fs_id)
        if not gl.glGetShaderiv(fs_id, gl.GL_COMPILE_STATUS):
            raise Exception('failed to compile %s fragment shader:\n%s' %
                            (self.__class__.__name__,
                             gl.glGetShaderInfoLog(fs_id).decode()))
        self._program_id = gl.glCreateProgram()
        gl.glAttachShader(self._program_id, vs_id)
        gl.glAttachShader(self._program_id, fs_id)
        gl.glLinkProgram(self._program_id)
        gl.glDetachShader(self._program_id, vs_id)
        gl.glDetachShader(self._program_id, fs_id)
        if not gl.glGetProgramiv(self._program_id, gl.GL_LINK_STATUS):
            raise Exception('failed to link program for %s' %
                            self.__class__.__name__)
        self._attribute_locations = {
            attribute: gl.glGetAttribLocation(self._program_id, attribute)
            for attribute in self._ATTRIBUTES
        }
        self._uniform_locations = {
            uniform: gl.glGetUniformLocation(self._program_id, uniform)
            for uniform in self._UNIFORMS
        }
        width, height = self._width, self._height
        self._image_width, self._image_height = image_width, image_height = width * 16, height * 6
        bitmap_buffer = np.zeros((image_height, image_width), dtype=np.ubyte)
        self._char_to_texcoords = {}
        for j in range(6):
            for i in range(16):
                i_char = j * 16 + i
                char = chr(32 + i_char)
                self._char_to_texcoords[char] = (i / 16.0, j / 6.0)
                self._face.load_char(char,
                                     FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT)
                glyph = self._face.glyph
                bitmap = glyph.bitmap
                x = i * width + glyph.bitmap_left
                y = j * height + self._max_asc - glyph.bitmap_top
                bitmap_buffer[y:y + bitmap.rows,
                              x:x + bitmap.width].flat = bitmap.buffer
        self._texture_id = gl.glGenTextures(1)
        gl.glBindTexture(gl.GL_TEXTURE_2D, self._texture_id)
        self._sampler_id = gl.glGenSamplers(1)
        gl.glSamplerParameteri(self._sampler_id, gl.GL_TEXTURE_MIN_FILTER,
                               gl.GL_LINEAR)
        gl.glSamplerParameteri(self._sampler_id, gl.GL_TEXTURE_MAG_FILTER,
                               gl.GL_LINEAR)
        gl.glSamplerParameteri(self._sampler_id, gl.GL_TEXTURE_WRAP_S,
                               gl.GL_CLAMP_TO_EDGE)
        gl.glSamplerParameteri(self._sampler_id, gl.GL_TEXTURE_WRAP_T,
                               gl.GL_CLAMP_TO_EDGE)
        gl.glBindSampler(self._texture_unit, self._sampler_id)
        gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1)
        gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RED, image_width,
                        image_height, 0, gl.GL_RED, gl.GL_UNSIGNED_BYTE,
                        bitmap_buffer)
        gl.glGenerateMipmap(gl.GL_TEXTURE_2D)
        gl.glBindTexture(gl.GL_TEXTURE_2D, 0)
        if gl.glGetError() != gl.GL_NO_ERROR:
            raise Exception('failed to create font texture')
        self._gl_initialized = True
        _logger.debug('%s.init_gl: OK', self.__class__.__name__)

    def draw_text(self,
                  text,
                  color=(1.0, 1.0, 0.0, 0.0),
                  screen_position=(0.0, 0.0)):
        import OpenGL.GL as gl
        gl.glUseProgram(self._program_id)
        gl.glActiveTexture(gl.GL_TEXTURE0 + self._texture_unit)
        gl.glBindTexture(gl.GL_TEXTURE_2D, self._texture_id)
        #gl.glBindSampler(tex_unit, self._sampler_id)
        gl.glUniform1i(self._uniform_locations['u_fonttex'],
                       self._texture_unit)
        gl.glUniform4f(self._uniform_locations['u_color'], *color)
        gl.glUniform2f(self._uniform_locations['u_screen_size'],
                       *self._screen_size)
        gl.glUniform2f(self._uniform_locations['u_char_size'], self._width,
                       self._height)
        gl.glUniform2f(self._uniform_locations['u_screen_position'],
                       *screen_position)
        gl.glUniform2f(self._uniform_locations['u_fonttex_size'],
                       self._image_width, self._image_height)
        nchars = len(text)
        gl.glUniform1ui(self._uniform_locations['u_nchars'], nchars)
        self._texcoords[:nchars] = [self._char_to_texcoords[c] for c in text]
        gl.glUniform2fv(self._uniform_locations['u_texcoords'], nchars,
                        self._texcoords)
        gl.glEnable(gl.GL_BLEND)
        gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
        gl.glDrawArrays(gl.GL_TRIANGLE_STRIP, 0, 4)
        gl.glDisable(gl.GL_BLEND)

    def save_image(self, filename=None):
        from PIL import Image
        if filename is None:
            filename = os.path.split_ext(os.path.basename(
                self._font_file))[0] + '.png'
        _logger.debug('filename = %s', filename)
        width, height = self._width, self._height
        image_width, image_height = width * 16, height * 6
        bitmap_buffer = np.zeros((image_height, image_width), dtype=np.ubyte)
        for j in range(6):
            for i in range(16):
                i_char = j * 16 + i
                char = chr(32 + i_char)
                self._face.load_char(char,
                                     FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT)
                glyph = self._face.glyph
                bitmap = glyph.bitmap
                x = i * width + glyph.bitmap_left
                y = j * height + self._max_asc - glyph.bitmap_top
                bitmap_buffer[y:y + bitmap.rows,
                              x:x + bitmap.width].flat = bitmap.buffer
        image = Image.new('L',
                          (bitmap_buffer.shape[1], bitmap_buffer.shape[0]))
        image.putdata(list(bitmap_buffer.ravel()))
        image.save(filename)
        _logger.info('...saved to %s', filename)

    @classmethod
    def _read_shader_src(cls):
        if cls._VERT_SHADER_SRC is None:
            with open(cls._VERT_SHADER_SRC_PATH) as f:
                cls._VERT_SHADER_SRC = f.read()
            attr_matches = _ATTRIBUTE_DECL_RE.finditer(cls._VERT_SHADER_SRC)
            attributes = []
            for m in attr_matches:
                attributes.append(m['attribute_name'])
            cls._ATTRIBUTES = attributes
        if cls._FRAG_SHADER_SRC is None:
            with open(cls._FRAG_SHADER_SRC_PATH) as f:
                cls._FRAG_SHADER_SRC = f.read()
            unif_matches = _UNIFORM_DECL_RE.finditer(cls._FRAG_SHADER_SRC)
            uniforms = []
            for m in unif_matches:
                uniforms.append(m['uniform_name'])
            cls._UNIFORMS = uniforms
Пример #8
0
	def setup(self):
		'''
		Construct the texture atlas for the font
		'''
		face = Face(self.filename)
		face.set_pixel_sizes(0, self.size)
	
		rowh, roww = 0,0
		
		# Determine image size
		for i in xrange(32,128):
			face.load_char( chr(i), FT_LOAD_RENDER)
			bitmap	= face.glyph.bitmap
			
			if roww + bitmap.width + 1 >= 1024: # max texture width
				self.w  = max(self.w, roww)
				self.h	+= rowh
				roww = 0
				rowh = 0
			roww += bitmap.width + 1
			rowh = max(rowh, bitmap.rows)
			
		self.w = max(self.w, roww)
		self.h += rowh
	
	
		## Create texture to hold ASCII glyphs
		
		# Ensure no texture is currently selected
		glActiveTexture(GL_TEXTURE0) 
		self.texid = glGenTextures(1)
		glBindTexture(GL_TEXTURE_2D, self.texid)
		
		glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, self.w, self.h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0)
		
		# We require 1 byte alignment when uploading texture data
		glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
		
		# Clamping to edges is important to prevent artifacts when scaling
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
		
		# Linear filtering looks better for text
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
		
	
		# Add glyphs to texture
		ox = 0
		oy = 0
		rowh = 0
		
		# class to hold data
		class CharInfo:
			pass
		
		for i in xrange(32,128):
			face.load_char( chr(i), FT_LOAD_RENDER)
			g = face.glyph
			bitmap = g.bitmap
			
			if ox + bitmap.width + 1 >= 1024: # max texture width
				oy += rowh
				rowh = 0
				ox = 0		
			
			glTexSubImage2D(GL_TEXTURE_2D, 0, ox, oy, bitmap.width, bitmap.rows, GL_ALPHA, GL_UNSIGNED_BYTE, bitmap.buffer)
			
			ci = CharInfo()
			ci.ax = float(g.advance.x >> 6)
			ci.ay = float(g.advance.y >> 6)
			
			ci.bw = float(bitmap.width)
			ci.bh = float(bitmap.rows)
			
			ci.bl = float(g.bitmap_left)
			ci.bt = float(g.bitmap_top)
			
			ci.tx = float(ox) / float(self.w)
			ci.ty = float(oy) / float(self.h)
			self.c[chr(i)] = ci
			
			rowh = max(rowh, bitmap.rows)
			ox += bitmap.width + 1
Пример #9
0
    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
Пример #10
0
def text2pathd(text, group_transform=(1, 0, 0, 1, 0, 0)):
    attributes = dom2dict(text)
    if "font-size" in attributes:
        font_size = float(attributes["font-size"])
    elif "style" in attributes:
        if attributes["style"].find("font-size") >= 0:
            font_size = attributes["style"].split("font-size:")[1].split(
                ";")[0]
            font_size = float(font_size.replace("px", ""))
        else:
            font_size = 12
    else:
        font_size = 12
    if "x" in attributes:
        x_global_offset = float(attributes["x"])
    else:
        x_global_offset = 0
    if "y" in attributes:
        y_global_offset = float(attributes["y"])
    else:
        y_global_offset = 0
    if hasattr(text.childNodes[0], "data"):
        text_string = text.childNodes[0].data
    else:
        flow_para = text.getElementsByTagName('flowPara')
        if flow_para:
            text_string = flow_para[0].childNodes[0].data
    # strip newline characters from the string, they aren't rendered in svg
    text_string = text_string.replace("\n", "").replace("\r", "")

    def tuple_to_imag(t):
        return t[0] + t[1] * 1j

    # keep fonts with repository, as dealing with importing fonts across platforms is a
    # nightmare
    foldername = os_path.dirname(os_path.abspath(__file__))
    face = Face(os_path.join(foldername, 'Vera.ttf'))

    face.set_char_size(48 * 64)
    scale = font_size / face.size.height
    outlines = []
    current_x = 0
    transform = get_transform(text)
    transform = combine_transforms(transform, group_transform)
    x_global_offset, y_global_offset = transform_point(
        [x_global_offset, y_global_offset], transform)
    for i, letter in enumerate(text_string):
        face.load_char(letter)
        outline = face.glyph.outline
        if i != 0:
            kerning = face.get_kerning(text_string[i - 1], text_string[i])
            kerning_x = kerning.x
        else:
            kerning_x = 0

        if text_string[i] == ' ':
            # a space is usually 30% of the widest character, capital W
            char_width = face.size.max_advance * 0.3
            char_height = 0
            char_offset = 0
        else:
            char_width = outline.get_bbox().xMax
            char_offset = face.size.height - outline.get_bbox().yMax
            char_height = outline.get_bbox().yMax

        outline_dict = {}
        current_x += kerning_x
        outline_dict["points"] = [
            (scale * (p[0] + current_x) + x_global_offset,
             scale * (char_offset + char_height - p[1]) + y_global_offset)
            for p in outline.points
        ]
        outline_dict["contours"] = outline.contours
        outline_dict["tags"] = outline.tags
        outlines.append(outline_dict)
        current_x += char_width

    paths = []
    for outline in outlines:
        start, end = 0, 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],
                ],
            ]
            for j in range(1, len(points)):
                segments[-1].append(points[j])
                if tags[j] and j < (len(points) - 1):
                    segments.append([
                        points[j],
                    ])
            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])))
                elif len(segment) == 4:
                    C = ((segment[1][0] + segment[2][0]) / 2.0,
                         (segment[1][1] + segment[2][1]) / 2.0)

                    paths.append(
                        QuadraticBezier(start=tuple_to_imag(segment[0]),
                                        control=tuple_to_imag(segment[1]),
                                        end=tuple_to_imag(C)))
                    paths.append(
                        QuadraticBezier(start=tuple_to_imag(C),
                                        control=tuple_to_imag(segment[2]),
                                        end=tuple_to_imag(segment[3])))
            start = end + 1

    path = Path(*paths)
    return path.d()
Пример #11
0
def char(ch):
    def tuple_to_imag(t):
        return t[0] + t[1] * 1j

    from freetype import Face
    #face = Face('/usr/share/fonts/truetype/dejavu/DejaVuSerif.ttf')
    face = Face(ddd.DATA_DIR + '/fonts/OpenSansEmoji.ttf')
    face.set_char_size(48 * 64)
    face.load_char(ch)

    #kerning = face.get_kerning(ch, 'x')  # or from previous, actually?
    #print(kerning)

    outline = face.glyph.outline
    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 = []

    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],
            ],
        ]
        for j in range(1, len(points)):
            segments[-1].append(points[j])
            if tags[j] and j < (len(points) - 1):
                segments.append([
                    points[j],
                ])

        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])))
            elif len(segment) == 4:
                C = ((segment[1][0] + segment[2][0]) / 2.0,
                     (segment[1][1] + segment[2][1]) / 2.0)

                paths.append(
                    QuadraticBezier(start=tuple_to_imag(segment[0]),
                                    control=tuple_to_imag(segment[1]),
                                    end=tuple_to_imag(C)))
                paths.append(
                    QuadraticBezier(start=tuple_to_imag(C),
                                    control=tuple_to_imag(segment[2]),
                                    end=tuple_to_imag(segment[3])))

        start = end + 1

    path = Path(*paths)
    #wsvg(path, filename="/tmp/test.svg")
    path_d = path.d()

    # https://gis.stackexchange.com/questions/301605/how-to-create-shape-in-shapely-from-an-svg-path-element
    # This page also has info about SVG reading!

    from svgpath2mpl import parse_path
    #svgpath = 'M10 10 C 20 20, 40 20, 50 10Z'
    mpl_path = parse_path(path_d)
    coords = mpl_path.to_polygons()

    # Add or subtract
    char_2d = ddd.polygon(coords[0])
    for c in coords[1:]:
        ng = ddd.polygon(c)
        #print (ng.geom.is_valid)
        if not ng.geom.is_valid: continue
        if char_2d.contains(ng):
            char_2d = char_2d.subtract(ng)
        else:
            char_2d = char_2d.union(ng)

    #result = ddd.group([ddd.polygon(c) for c in coords], empty=2)
    result = char_2d
    result = result.scale([1.0 / (48 * 64), -1.0 / (48 * 64)])

    result = result.simplify(0.005)  #

    return result
from svgpathtools import wsvg, Line, QuadraticBezier, Path

from freetype import Face


def tuple_to_imag(t):
    return t[0] + t[1] * 1j


face = Face('./Vera.ttf')
face.set_char_size(48 * 64)
face.load_char('a')
outline = face.glyph.outline
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 = []

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], ], ]
    for j in range(1, len(points)):
        segments[-1].append(points[j])
        if tags[j] and j < (len(points) - 1):
            segments.append([points[j], ])
Пример #13
0
class TextRenderer(object):
    _VERT_SHADER_SRC_PATH = os.path.join(_here, 'shaders', 'text_renderer_vert.glsl')
    _FRAG_SHADER_SRC_PATH = os.path.join(_here, 'shaders', 'text_renderer_frag.glsl')
    _VERT_SHADER_SRC = None
    _FRAG_SHADER_SRC = None

    def __init__(self,
                 font_file=os.path.join(_here, 'fonts', 'VeraMono.ttf'),
                 size=72*16):
        _logger.debug('loading %s...', font_file)
        self._font_file = font_file
        self._face = Face(font_file)
        self._face.set_char_size(size)
        width, max_asc, max_desc = 0, 0, 0
        widths = []
        for c in range(32, 128):
            self._face.load_char(chr(c), FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT)
            bitmap = self._face.glyph.bitmap
            width = max(width, bitmap.width)
            max_asc = max(max_asc, self._face.glyph.bitmap_top)
            max_desc = max(max_desc, bitmap.rows-self._face.glyph.bitmap_top)
            widths.append(bitmap.width)
        self._max_asc = max_asc
        self._widths = np.array(widths)
        self._width = width
        self._height = max_asc + max_desc
        self._read_shader_src()
        self._screen_size = (800.0, 600.0)
        self._texcoords = np.zeros((32, 2), dtype=np.float32)
        self._gl_initialized = False

    def set_screen_size(self, screen_size):
        self._screen_size = screen_size

    def init_gl(self):
        if self._gl_initialized:
            return
        import OpenGL.GL as gl
        self._texture_unit = 4
        vs_id = gl.glCreateShader(gl.GL_VERTEX_SHADER)
        gl.glShaderSource(vs_id, self._VERT_SHADER_SRC)
        gl.glCompileShader(vs_id)
        if not gl.glGetShaderiv(vs_id, gl.GL_COMPILE_STATUS):
            raise Exception('failed to compile %s vertex shader:\n%s' %
                            (self.__class__.__name__, gl.glGetShaderInfoLog(vs_id).decode()))
        fs_id = gl.glCreateShader(gl.GL_FRAGMENT_SHADER)
        gl.glShaderSource(fs_id, self._FRAG_SHADER_SRC)
        gl.glCompileShader(fs_id)
        if not gl.glGetShaderiv(fs_id, gl.GL_COMPILE_STATUS):
            raise Exception('failed to compile %s fragment shader:\n%s' %
                            (self.__class__.__name__, gl.glGetShaderInfoLog(fs_id).decode()))
        self._program_id = gl.glCreateProgram()
        gl.glAttachShader(self._program_id, vs_id)
        gl.glAttachShader(self._program_id, fs_id)
        gl.glLinkProgram(self._program_id)
        gl.glDetachShader(self._program_id, vs_id)
        gl.glDetachShader(self._program_id, fs_id)
        if not gl.glGetProgramiv(self._program_id, gl.GL_LINK_STATUS):
            raise Exception('failed to link program for %s' % self.__class__.__name__)
        self._attribute_locations = {attribute: gl.glGetAttribLocation(self._program_id, attribute)
                                     for attribute in self._ATTRIBUTES}
        self._uniform_locations = {uniform: gl.glGetUniformLocation(self._program_id, uniform)
                                   for uniform in self._UNIFORMS}
        width, height = self._width, self._height
        self._image_width, self._image_height = image_width, image_height = width * 16, height * 6
        bitmap_buffer = np.zeros((image_height, image_width), dtype=np.ubyte)
        self._char_to_texcoords = {}
        for j in range(6):
            for i in range(16):
                i_char = j * 16 + i
                char = chr(32 + i_char)
                self._char_to_texcoords[char] = (i / 16.0, j / 6.0)
                self._face.load_char(char, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT)
                glyph = self._face.glyph
                bitmap = glyph.bitmap
                x = i*width + glyph.bitmap_left
                y = j*height + self._max_asc - glyph.bitmap_top
                bitmap_buffer[y:y+bitmap.rows,x:x+bitmap.width].flat = bitmap.buffer
        self._texture_id = gl.glGenTextures(1)
        gl.glBindTexture(gl.GL_TEXTURE_2D, self._texture_id)
        self._sampler_id = gl.glGenSamplers(1)
        gl.glSamplerParameteri(self._sampler_id, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR)
        gl.glSamplerParameteri(self._sampler_id, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR)
        gl.glSamplerParameteri(self._sampler_id, gl.GL_TEXTURE_WRAP_S, gl.GL_CLAMP_TO_EDGE)
        gl.glSamplerParameteri(self._sampler_id, gl.GL_TEXTURE_WRAP_T, gl.GL_CLAMP_TO_EDGE)
        gl.glBindSampler(self._texture_unit, self._sampler_id)
        gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1)
        gl.glTexImage2D(gl.GL_TEXTURE_2D, 0,
                        gl.GL_RED,
                        image_width, image_height, 0,
                        gl.GL_RED, gl.GL_UNSIGNED_BYTE,
                        bitmap_buffer)
        gl.glGenerateMipmap(gl.GL_TEXTURE_2D)
        gl.glBindTexture(gl.GL_TEXTURE_2D, 0)
        if gl.glGetError() != gl.GL_NO_ERROR:
            raise Exception('failed to create font texture')
        self._gl_initialized = True
        _logger.debug('%s.init_gl: OK', self.__class__.__name__)

    def draw_text(self, text,
                  color=(1.0, 1.0, 0.0, 0.0),
                  screen_position=(0.0, 0.0)):
        import OpenGL.GL as gl
        gl.glUseProgram(self._program_id)
        gl.glActiveTexture(gl.GL_TEXTURE0+self._texture_unit)
        gl.glBindTexture(gl.GL_TEXTURE_2D, self._texture_id)
        #gl.glBindSampler(tex_unit, self._sampler_id)
        gl.glUniform1i(self._uniform_locations['u_fonttex'], self._texture_unit)
        gl.glUniform4f(self._uniform_locations['u_color'], *color)
        gl.glUniform2f(self._uniform_locations['u_screen_size'], *self._screen_size)
        gl.glUniform2f(self._uniform_locations['u_char_size'], self._width, self._height)
        gl.glUniform2f(self._uniform_locations['u_screen_position'], *screen_position)
        gl.glUniform2f(self._uniform_locations['u_fonttex_size'], self._image_width, self._image_height)
        nchars = len(text)
        gl.glUniform1ui(self._uniform_locations['u_nchars'], nchars)
        self._texcoords[:nchars] = [self._char_to_texcoords[c] for c in text]
        gl.glUniform2fv(self._uniform_locations['u_texcoords'], nchars, self._texcoords)
        gl.glEnable(gl.GL_BLEND)
        gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
        gl.glDrawArrays(gl.GL_TRIANGLE_STRIP, 0, 4)
        gl.glDisable(gl.GL_BLEND)

    def save_image(self, filename=None):
        from PIL import Image
        if filename is None:
            filename = os.path.split_ext(os.path.basename(self._font_file))[0] + '.png'
        _logger.debug('filename = %s', filename)
        width, height = self._width, self._height
        image_width, image_height = width * 16, height * 6
        bitmap_buffer = np.zeros((image_height, image_width), dtype=np.ubyte)
        for j in range(6):
            for i in range(16):
                i_char = j * 16 + i
                char = chr(32 + i_char)
                self._face.load_char(char, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT)
                glyph = self._face.glyph
                bitmap = glyph.bitmap
                x = i*width + glyph.bitmap_left
                y = j*height + self._max_asc - glyph.bitmap_top
                bitmap_buffer[y:y+bitmap.rows,x:x+bitmap.width].flat = bitmap.buffer
        image = Image.new('L', (bitmap_buffer.shape[1], bitmap_buffer.shape[0]))
        image.putdata(list(bitmap_buffer.ravel()))
        image.save(filename)
        _logger.info('...saved to %s', filename)

    @classmethod
    def _read_shader_src(cls):
        if cls._VERT_SHADER_SRC is None:
            with open(cls._VERT_SHADER_SRC_PATH) as f:
                cls._VERT_SHADER_SRC = f.read()
            attr_matches = _ATTRIBUTE_DECL_RE.finditer(cls._VERT_SHADER_SRC)
            attributes = []
            for m in attr_matches:
                attributes.append(m['attribute_name'])
            cls._ATTRIBUTES = attributes
        if cls._FRAG_SHADER_SRC is None:
            with open(cls._FRAG_SHADER_SRC_PATH) as f:
                cls._FRAG_SHADER_SRC = f.read()
            unif_matches = _UNIFORM_DECL_RE.finditer(cls._FRAG_SHADER_SRC)
            uniforms = []
            for m in unif_matches:
                uniforms.append(m['uniform_name'])
            cls._UNIFORMS = uniforms
Пример #14
0
    def char(self, ch):
        def tuple_to_imag(t):
            return t[0] + t[1] * 1j

        #face = Face('/usr/share/fonts/truetype/dejavu/DejaVuSerif.ttf')
        face = Face(ddd.DATA_DIR + '/fonts/OpenSansEmoji.ttf')
        face.set_char_size(self.char_size)
        face.load_char(ch)

        #kerning = face.get_kerning(ch, 'x')  # or from previous, actually?
        #print(kerning)

        outline = face.glyph.outline
        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 = []

        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],
                ],
            ]
            for j in range(1, len(points)):
                segments[-1].append(points[j])
                if tags[j] and j < (len(points) - 1):
                    segments.append([
                        points[j],
                    ])

            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])))
                elif len(segment) == 4:
                    paths.append(
                        CubicBezier(start=tuple_to_imag(segment[0]),
                                    control1=tuple_to_imag(segment[1]),
                                    control2=tuple_to_imag(segment[2]),
                                    end=tuple_to_imag(segment[3])))
                    #C = ((segment[1][0] + segment[2][0]) / 2.0,
                    #     (segment[1][1] + segment[2][1]) / 2.0)
                    #paths.append(QuadraticBezier(start=tuple_to_imag(segment[0]),
                    #                             control=tuple_to_imag(segment[1]),
                    #                             end=tuple_to_imag(C)))
                    #paths.append(QuadraticBezier(start=tuple_to_imag(C),
                    #                             control=tuple_to_imag(segment[2]),
                    #                             end=tuple_to_imag(segment[3])))

            start = end + 1

        path = Path(*paths)
        #wsvg(path, filename="/tmp/test.svg")
        path_d = path.d()

        # https://gis.stackexchange.com/questions/301605/how-to-create-shape-in-shapely-from-an-svg-path-element
        # This page also has info about SVG reading!

        #svgpath = 'M10 10 C 20 20, 40 20, 50 10Z'
        mpl_path = parse_path(path_d)

        coords = mpl_path.to_polygons(closed_only=True)

        item = None
        for c in coords:  # coords[1:]:
            if len(c) < 3: continue
            ng = ddd.polygon(c)  #.clean(eps=char_size / 100)  #.convex_hull()
            #ng.show()
            if item is None:
                item = ng
            elif item.contains(ng):
                item = item.subtract(ng)
            else:
                item = item.union(ng)
            item = item.clean(
                eps=self.char_size /
                200)  # Note that this is effectively limiting resolution

        #result = ddd.group([ddd.polygon(c) for c in coords], empty=2)
        result = item
        result = result.scale([1.0 / self.char_size, -1.0 / self.char_size])
        result = result.simplify(
            0.005)  # Note that this is effectively limiting resolution

        return (result, face)