skia-python icon indicating copy to clipboard operation
skia-python copied to clipboard

Getting correct text bounds

Open prashant-saxena opened this issue 4 years ago • 4 comments

Describe the bug I'm trying to render a text at certain point and a rectangle around it. This example is doing exactly what I need. In python implementation font.measureText returns only advance of text. As per the doc only "TextBlob" class is having "bounds" method and to calculate it first you need to create an instance of it:

textblob = skia.TextBlob(txt, self.font)
bounds = textblob.bounds()

I think it's an unnecessary step to calculate bounds. We already have our font instance available to calculate bounds. The doc also suggests about paint.getTextBounds(...) method but it's not implemented yet.

To Reproduce Steps to reproduce the behavior: As shown in the above example at link:

# Init
typeface = skia.Typeface('Arial')
font = skia.Font(typeface, 16.0, 1.0, 0.0)
textblob = skia.TextBlob('Hello World', font)
bounds = textblob.bounds()
bounds = bounds.makeOffset(100,100)

# Draw
canvas.drawString('Hello World', 100, 100, font, p)
canvas.drawRect(bounds, strokePaint)

bug3 Neither rect is having correct size nor it's drawn properly around the text. Expected behavior Get correct text bounds.

Desktop (please complete the following information):

  • OS: Windows 10
  • Python: 3.9.5
  • skia-python version: 87.3

Additional context A simple example that shows getting the correct text bounds.

Regards.

prashant-saxena avatar Dec 19 '21 01:12 prashant-saxena

Ok, I have created this little function for text alignment and hope other users would find it useful.

# Horizontal align
ALIGN_LEFT 		= 1 << 0 # Default, align text horizontally to left.
ALIGN_CENTER 	= 1 << 1 # Align text horizontally to center.
ALIGN_RIGHT 	= 1 << 2 # Align text horizontally to right.
# Vertical align
ALIGN_TOP 		= 1 << 3 # Align text vertically to top.
ALIGN_MIDDLE	= 1 << 4 # Align text vertically to middle.
ALIGN_BOTTOM	= 1 << 5 # Align text vertically to bottom.
ALIGN_BASELINE	= 1 << 6 # Default, align text vertically to baseline.


def draw_text(canvas, txt, x, y, font, paint, flags):
    # Get bounds of txt
    rect = skia.Rect.MakeXYWH(0, 0, 0, 0)
    font.measureText(txt, bounds=rect)
     
    px = 0.0
    py = 0.0
    if ALIGN_LEFT & flags:
        px = rect.x()
    elif ALIGN_CENTER & flags:
        px = rect.width()/2.0
    elif ALIGN_RIGHT & flags:
        px = rect.width()
        
    if ALIGN_TOP & flags:
        py = rect.y()
    elif ALIGN_MIDDLE & flags:
        py = -rect.height()/2.0
    elif ALIGN_BOTTOM & flags:
        py = 0.0
    elif ALIGN_BASELINE & flags:
        pass
    
    canvas.drawString('Hello World', x-px, y-py, font, paint)

#Example
draw_text(canvas, "Hello World", 100, 100, font, paint, ALIGN_CENTER|ALIGN_MIDDLE)

prashant-saxena avatar Dec 20 '21 04:12 prashant-saxena