How to save text inside a circle using Cairo?

I draw a graph using Cairo (especially pycairo) and I need to know how to draw text inside a circle without overlapping it, holding it inside the borders of the circle. I have this simple code snippet that draws the letter "a" inside a circle:

''' Created on May 8, 2010 @author: mrios ''' import cairo, math WIDTH, HEIGHT = 1000, 1000 #surface = cairo.PDFSurface ("/Users/mrios/Desktop/exampleplaces.pdf", WIDTH, HEIGHT) surface = cairo.ImageSurface (cairo.FORMAT_ARGB32, WIDTH, HEIGHT) ctx = cairo.Context (surface) ctx.scale (WIDTH/1.0, HEIGHT/1.0) # Normalizing the canvas ctx.rectangle(0, 0, 1, 1) # Rectangle(x0, y0, x1, y1) ctx.set_source_rgb(255,255,255) ctx.fill() ctx.arc(0.5, 0.5, .4, 0, 2*math.pi) ctx.set_source_rgb(0,0,0) ctx.set_line_width(0.03) ctx.stroke() ctx.arc(0.5, 0.5, .4, 0, 2*math.pi) ctx.set_source_rgb(0,0,0) ctx.set_line_width(0.01) ctx.set_source_rgb(255,0,255) ctx.fill() ctx.set_source_rgb(0,0,0) ctx.select_font_face("Georgia", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) ctx.set_font_size(1.0) x_bearing, y_bearing, width, height = ctx.text_extents("a")[:4] print ctx.text_extents("a")[:4] ctx.move_to(0.5 - width / 2 - x_bearing, 0.5 - height / 2 - y_bearing) ctx.show_text("a") surface.write_to_png ("/Users/mrios/Desktop/node.png") # Output to PNG 

The problem is that my labels have a variable number of characters (with a limit of 20), and I need to set the font size dynamically. It should fit into the circle, regardless of the size of the circle or the size of the label. In addition, each label has one line of text, without spaces, without line breaks.

Any suggestion?

+4
source share
2 answers

I had a similar problem when I needed to adjust the font size to keep the name of my object within the borders of rectangles, not circles. I used a while loop and continued to check the extent size of the text in the string, reducing the font size to fit it.

Here is what I did: (this uses C ++ under Kylix, a Delphi derivative).

  double fontSize = 20.0; bool bFontFits = false; while (bFontFits == false) { m_pCanvas->Font->Size = (int)fontSize; TSize te = m_pCanvas->TextExtent(m_name.c_str()); if (te.cx < (width*0.90)) // Allow a little room on each side { // Calculate the position m_labelOrigin.x = rectX + (width/2.0) - (te.cx/2); m_labelOrigin.y = rectY + (height/2.0) - te.cy/2); m_fontSize = fontSize; bFontFits = true; break; } fontSize -= 1.0; } 

Of course, this does not show error checking. If the rectangle (or your circle) is too small, you will have to exit the loop.

+3
source

Since the size of the circle does not matter, you have to draw them in reverse order than your code.

  • Print text on screen
  • Calculate text borders (using text extents)
  • Draw a circle around the text, which is slightly larger than the text.
+3
source

Source: https://habr.com/ru/post/1309178/


All Articles