Example #1
0
    def render(self, text):

        ch = ctypes.create_unicode_buffer(text)
        len_ch = len(text)

        # Layout rectangle; not clipped against so not terribly important.
        width = 10000
        height = self._bitmap_height
        rect = Rectf(
            0, self._bitmap_height - self.font.ascent + self.font.descent,
            width, height)

        # Set up GenericTypographic with 1 character measure range
        generic = ctypes.c_void_p()
        gdiplus.GdipStringFormatGetGenericTypographic(ctypes.byref(generic))
        format = ctypes.c_void_p()
        gdiplus.GdipCloneStringFormat(generic, ctypes.byref(format))
        gdiplus.GdipDeleteStringFormat(generic)

        # Measure advance

        # XXX HACK HACK HACK
        # Windows GDI+ is a filthy broken toy.  No way to measure the bounding
        # box of a string, or to obtain LSB.  What a joke.
        #
        # For historical note, GDI cannot be used because it cannot composite
        # into a bitmap with alpha.
        #
        # It looks like MS have abandoned GDI and GDI+ and are finally
        # supporting accurate text measurement with alpha composition in .NET
        # 2.0 (WinForms) via the TextRenderer class; this has no C interface
        # though, so we're entirely screwed.
        #
        # So anyway, we first try to get the width with GdipMeasureString.
        # Then if it's a TrueType font, we use GetCharABCWidthsW to get the
        # correct LSB. If it's a negative LSB, we move the layoutRect `rect`
        # to the right so that the whole glyph is rendered on the surface.
        # For positive LSB, we let the renderer render the correct white
        # space and we don't pass the LSB info to the Glyph.set_bearings

        bbox = Rectf()
        flags = (StringFormatFlagsMeasureTrailingSpaces
                 | StringFormatFlagsNoClip | StringFormatFlagsNoFitBlackBox)
        gdiplus.GdipSetStringFormatFlags(format, flags)
        gdiplus.GdipMeasureString(self._graphics, ch,
                                  len_ch, self.font._gdipfont,
                                  ctypes.byref(rect), format,
                                  ctypes.byref(bbox), None, None)
        lsb = 0
        advance = int(math.ceil(bbox.width))
        width = advance

        # This hack bumps up the width if the font is italic;
        # this compensates for some common fonts.  It's also a stupid
        # waste of texture memory.
        if self.font.italic:
            width += width // 2
            # Do not enlarge more than the _rect width.
            width = min(width, self._rect.Width)

        # GDI functions only work for a single character so we transform
        # grapheme \r\n into \r
        if text == '\r\n':
            text = '\r'

        abc = ABC()
        # Check if ttf font.
        if gdi32.GetCharABCWidthsW(self._dc, ord(text), ord(text), byref(abc)):

            lsb = abc.abcA
            if lsb < 0:
                # Negative LSB: we shift the layout rect to the right
                # Otherwise we will cut the left part of the glyph
                rect.x = -lsb
                width -= lsb
        # XXX END HACK HACK HACK

        # Draw character to bitmap

        gdiplus.GdipGraphicsClear(self._graphics, 0x00000000)
        gdiplus.GdipDrawString(self._graphics, ch, len_ch, self.font._gdipfont,
                               ctypes.byref(rect), format, self._brush)
        gdiplus.GdipFlush(self._graphics, 1)
        gdiplus.GdipDeleteStringFormat(format)

        bitmap_data = BitmapData()
        gdiplus.GdipBitmapLockBits(self._bitmap, byref(self._rect),
                                   ImageLockModeRead, self._format,
                                   byref(bitmap_data))

        # Create buffer for RawImage
        buffer = create_string_buffer(bitmap_data.Stride * bitmap_data.Height)
        memmove(buffer, bitmap_data.Scan0, len(buffer))

        # Unlock data
        gdiplus.GdipBitmapUnlockBits(self._bitmap, byref(bitmap_data))

        image = pyglet.image.ImageData(width, height, 'BGRA', buffer,
                                       -bitmap_data.Stride)

        glyph = self.font.create_glyph(image)
        # Only pass negative LSB info
        lsb = min(lsb, 0)
        glyph.set_bearings(-self.font.descent, lsb, advance)

        return glyph
Example #2
0
    def render(self, text):

        ch = ctypes.create_unicode_buffer(text)
        len_ch = len(text)

        # Layout rectangle; not clipped against so not terribly important.
        width = 10000
        height = self._bitmap_height
        rect = Rectf(
            0, self._bitmap_height - self.font.ascent + self.font.descent,
            width, height)

        # Set up GenericTypographic with 1 character measure range
        generic = ctypes.c_void_p()
        gdiplus.GdipStringFormatGetGenericTypographic(ctypes.byref(generic))
        format = ctypes.c_void_p()
        gdiplus.GdipCloneStringFormat(generic, ctypes.byref(format))
        gdiplus.GdipDeleteStringFormat(generic)

        # Measure advance

        # XXX HACK HACK HACK
        # Windows GDI+ is a filthy broken toy.  No way to measure the bounding
        # box of a string, or to obtain LSB.  What a joke.
        #
        # For historical note, GDI cannot be used because it cannot composite
        # into a bitmap with alpha.
        #
        # It looks like MS have abandoned GDI and GDI+ and are finally
        # supporting accurate text measurement with alpha composition in .NET
        # 2.0 (WinForms) via the TextRenderer class; this has no C interface
        # though, so we're entirely screwed.
        #
        # So anyway, we first try to get the lsb and width from GDI
        # GetCharABCWidthsW function. If it does not work (because we don't
        # use a TrueType font), we try to use GdipMeasureString.
        # Tests show that it's not working well for .fon fonts.

        # GDI functions only work for a single character so we transform
        # grapheme \r\n into \r
        if text == '\r\n':
            text = '\r'
        abc = ABC()
        # Check if ttf font.
        if gdi32.GetCharABCWidthsW(self._dc, ord(text), ord(text), byref(abc)):
            lsb = abc.abcA
            width = abc.abcB
            advance = abc.abcA + abc.abcB + abc.abcC
            rect.x = -lsb
        else:
            # What font could this be ???
            # Revert to the old way to check bounding box.
            bbox = Rectf()
            flags = (StringFormatFlagsMeasureTrailingSpaces
                     | StringFormatFlagsNoClip
                     | StringFormatFlagsNoFitBlackBox)
            gdiplus.GdipSetStringFormatFlags(format, flags)
            gdiplus.GdipMeasureString(self._graphics, ch,
                                      len_ch, self.font._gdipfont,
                                      ctypes.byref(rect), format,
                                      ctypes.byref(bbox), None, None)
            lsb = 0
            advance = int(math.ceil(bbox.width))
            width = advance

        # XXX END HACK HACK HACK

        # Draw character to bitmap

        gdiplus.GdipGraphicsClear(self._graphics, 0x00000000)
        gdiplus.GdipDrawString(self._graphics, ch, len_ch, self.font._gdipfont,
                               ctypes.byref(rect), format, self._brush)
        gdiplus.GdipFlush(self._graphics, 1)
        gdiplus.GdipDeleteStringFormat(format)

        bitmap_data = BitmapData()
        gdiplus.GdipBitmapLockBits(self._bitmap, byref(self._rect),
                                   ImageLockModeRead, self._format,
                                   byref(bitmap_data))

        # Create buffer for RawImage
        buffer = create_string_buffer(bitmap_data.Stride * bitmap_data.Height)
        memmove(buffer, bitmap_data.Scan0, len(buffer))

        # Unlock data
        gdiplus.GdipBitmapUnlockBits(self._bitmap, byref(bitmap_data))

        image = pyglet.image.ImageData(width, height, 'BGRA', buffer,
                                       -bitmap_data.Stride)

        glyph = self.font.create_glyph(image)
        glyph.set_bearings(-self.font.descent, lsb, advance)

        return glyph