I would like to use PyMuPDF
to draw a rectangle with rounded corners in a pdf. Apparently, there are no particular methods for rounded rectangles. But I was wondering if Shape.draw_bezier()
or Shape.draw_curve()
could be used for that purpose, making a stroke that recovers the shape of the rectangle.
Asked
Active
Viewed 182 times
0

Kikolo
- 212
- 1
- 10
1 Answers
2
Interest question! This is possible with PyMuPDF, but currently still a bit clumsy to do. The basic approach I would suggest is
- Define a normal rectangle within your final one should land.
- At each of the four corner define 2 points ("helper points"), which will become the start and end of method
draw_curve()
(which you correctly identified yourself already - chapeau!). - Then start drawing. The shape will consist of 4 curves and 4 lines, every line followed by a curve, followed by a line ...
Here is the code:
import fitz
doc = fitz.open()
page = doc.new_page()
rect = fitz.Rect(100, 100, 300, 200)
d = 10 # controls how round the edges are
# make a shape to get properly connect points
shape = page.new_shape()
lp = shape.draw_line(rect.bl + (d, 0), rect.br - (d, 0))
lp = shape.draw_curve(lp, rect.br, rect.br - (0, d))
lp = shape.draw_line(lp, rect.tr + (0, d))
lp = shape.draw_curve(lp, rect.tr, rect.tr - (d, 0))
lp = shape.draw_line(lp, rect.tl + (d, 0))
lp = shape.draw_curve(lp, rect.tl, rect.tl + (0, d))
lp = shape.draw_line(lp, rect.bl - (0, d))
lp = shape.draw_curve(lp, rect.bl, rect.bl + (d, 0))
shape.finish(color=(1, 0, 0), fill=(1, 1, 0), closePath=False)
shape.commit()
doc.save(__file__.replace(".py", ".pdf"))

Jorj McKie
- 2,062
- 1
- 13
- 17
-
@Kikolo - question: thinking about a new feature for PyMuPDF. The variable used for "roundness", `d` should be a parameter. Maybe different values for vertical and horizontal sides, and probably a percentage of the rect side lengths instead of absolute values. Have a position on this? – Jorj McKie Jan 28 '23 at 09:12
-
1Yes, in fact, for my application I have encapsulated your code snippet in a method that requires as optional parameter `d`. As default value for this parameter I use `min(abs(x0 - x1), abs(y0 - y1)) * 0.2`, where `(x0, y0)` and `(x1, y1)` are respectively the lower left and upper right corners of the rectangle. As you can see, I define it as a percentage with respect to the smallest side of the rectangle. It works very well for various aspect ratios. – Kikolo Jan 28 '23 at 21:24
-
@Kikolo - thanks for the feedback! So you are confirming that `d` **should** be provided (1) as a percentage of `min(rect.width, rect.height)` and (2) the curves should be symmetric with respect to the rectangle corners (no separate `d` values for width and height). – Jorj McKie Jan 29 '23 at 22:17