diff --git a/docs/Shapes.md b/docs/Shapes.md index 8437d2256..9d4620ff8 100644 --- a/docs/Shapes.md +++ b/docs/Shapes.md @@ -164,18 +164,27 @@ pdf.output("solid_arc.pdf") ## Bezier Curve ## _New in [:octicons-tag-24: 2.7.10](https://github.com/py-pdf/fpdf2/blob/master/CHANGELOG.md)_ -Using [`bezier()`](fpdf/fpdf.html#fpdf.fpdf.FPDF.bezier) to create a cubic Bezier curve: +Using [`bezier()`](fpdf/fpdf.html#fpdf.fpdf.FPDF.bezier) to create a cubic Bézier curve: ```python from fpdf import FPDF pdf = FPDF() pdf.add_page() pdf.set_fill_color(r=255, g=0, b=255) -pdf.bezier([(20, 80), (40, 20), (60, 80)]) +pdf.bezier([(20, 80), (40, 20), (60, 80)], style="DF") pdf.output("bezier.pdf") ``` ![](bezier.png) +One of the nice properties of Bézier curves is that they can be chained: + +![](bezier-chaining.png) + +Note that, for smooth joining cubic Bézier curves, neighbor control points around the joining point must mirror each other +(_cf._ [Wikipedia](https://en.wikipedia.org/wiki/Composite_B%C3%A9zier_curve#Smooth_joining)). + +Source code: [test_bezier_chaining() in test_bezier.py](https://github.com/py-pdf/fpdf2/blob/master/test/shapes/test_bezier.py) + ## Regular Polygon ## Using [`regular_polygon()`](fpdf/fpdf.html#fpdf.fpdf.FPDF.regular_polygon): diff --git a/docs/bezier-chaining.png b/docs/bezier-chaining.png new file mode 100644 index 000000000..87678820e Binary files /dev/null and b/docs/bezier-chaining.png differ diff --git a/docs/table_with_gutter.jpg b/docs/table_with_gutter.jpg index e68c1cb29..09e92af38 100644 Binary files a/docs/table_with_gutter.jpg and b/docs/table_with_gutter.jpg differ diff --git a/docs/table_with_images_and_img_fill_width.jpg b/docs/table_with_images_and_img_fill_width.jpg index 14b84ab2f..8446c07b9 100644 Binary files a/docs/table_with_images_and_img_fill_width.jpg and b/docs/table_with_images_and_img_fill_width.jpg differ diff --git a/fpdf/drawing.py b/fpdf/drawing.py index 12d2eae9d..9c722e034 100644 --- a/fpdf/drawing.py +++ b/fpdf/drawing.py @@ -364,7 +364,10 @@ def rgb8(r, g, b, a=None): Raises: ValueError: if any components are not in their valid interval. """ - if a is not None: + if a is None: + if r == g == b: + return DeviceGray(r / 255.0) + else: a /= 255.0 return DeviceRGB(r / 255.0, g / 255.0, b / 255.0, a) diff --git a/fpdf/fpdf.py b/fpdf/fpdf.py index e60f23404..a5451c357 100644 --- a/fpdf/fpdf.py +++ b/fpdf/fpdf.py @@ -1857,13 +1857,9 @@ def bezier(self, point_list, closed=False, style=None): if points not in (3, 4): raise ValueError( "point_list should contain 3 tuples for a quadratic curve" - "or 4 tuples for a cubic curve." + " or 4 tuples for a cubic curve." ) - - if style is None: - style = RenderStyle.DF - else: - style = RenderStyle.coerce(style) + style = RenderStyle.coerce(style) # QuadraticBezierCurve and BezierCurve make use of `initial_point` when instantiated. # If we want to define all 3 (quad.) or 4 (cubic) points, we can set `initial_point` diff --git a/test/image/image_x_align_center.pdf b/test/image/image_x_align_center.pdf index 55903e6bd..de7beeef7 100644 Binary files a/test/image/image_x_align_center.pdf and b/test/image/image_x_align_center.pdf differ diff --git a/test/image/image_x_align_right.pdf b/test/image/image_x_align_right.pdf index 624c15e45..86c07f624 100644 Binary files a/test/image/image_x_align_right.pdf and b/test/image/image_x_align_right.pdf differ diff --git a/test/image/svg_image.pdf b/test/image/svg_image.pdf index a126bc477..4f6efb77f 100644 Binary files a/test/image/svg_image.pdf and b/test/image/svg_image.pdf differ diff --git a/test/image/svg_image_alt_text_title.pdf b/test/image/svg_image_alt_text_title.pdf index 22f59fd66..9bb5529e0 100644 Binary files a/test/image/svg_image_alt_text_title.pdf and b/test/image/svg_image_alt_text_title.pdf differ diff --git a/test/image/svg_image_alt_text_two_pages.pdf b/test/image/svg_image_alt_text_two_pages.pdf index d153399fd..f31273394 100644 Binary files a/test/image/svg_image_alt_text_two_pages.pdf and b/test/image/svg_image_alt_text_two_pages.pdf differ diff --git a/test/image/svg_image_fit_rect.pdf b/test/image/svg_image_fit_rect.pdf index 121e68312..b8d97e73e 100644 Binary files a/test/image/svg_image_fit_rect.pdf and b/test/image/svg_image_fit_rect.pdf differ diff --git a/test/image/svg_image_fixed_dimensions.pdf b/test/image/svg_image_fixed_dimensions.pdf index c099a6962..fb6d8d7f7 100644 Binary files a/test/image/svg_image_fixed_dimensions.pdf and b/test/image/svg_image_fixed_dimensions.pdf differ diff --git a/test/image/svg_image_no_dimensions.pdf b/test/image/svg_image_no_dimensions.pdf index 46e56fe42..0ad411228 100644 Binary files a/test/image/svg_image_no_dimensions.pdf and b/test/image/svg_image_no_dimensions.pdf differ diff --git a/test/image/svg_image_with_custom_size.pdf b/test/image/svg_image_with_custom_size.pdf index cc071b785..48f66cd9b 100644 Binary files a/test/image/svg_image_with_custom_size.pdf and b/test/image/svg_image_with_custom_size.pdf differ diff --git a/test/image/svg_image_with_custom_width.pdf b/test/image/svg_image_with_custom_width.pdf index ee7fe7384..38e1d1db4 100644 Binary files a/test/image/svg_image_with_custom_width.pdf and b/test/image/svg_image_with_custom_width.pdf differ diff --git a/test/image/svg_image_with_custom_width_and_no_dimensions.pdf b/test/image/svg_image_with_custom_width_and_no_dimensions.pdf index ee7fe7384..38e1d1db4 100644 Binary files a/test/image/svg_image_with_custom_width_and_no_dimensions.pdf and b/test/image/svg_image_with_custom_width_and_no_dimensions.pdf differ diff --git a/test/image/svg_image_with_no_dimensions_and_custom_width.pdf b/test/image/svg_image_with_no_dimensions_and_custom_width.pdf index ee7fe7384..38e1d1db4 100644 Binary files a/test/image/svg_image_with_no_dimensions_and_custom_width.pdf and b/test/image/svg_image_with_no_dimensions_and_custom_width.pdf differ diff --git a/test/shapes/bezier_chaining.pdf b/test/shapes/bezier_chaining.pdf new file mode 100644 index 000000000..344eb27ab Binary files /dev/null and b/test/shapes/bezier_chaining.pdf differ diff --git a/test/shapes/test_bezier.py b/test/shapes/test_bezier.py index 6e75ed94a..287f57c31 100644 --- a/test/shapes/test_bezier.py +++ b/test/shapes/test_bezier.py @@ -24,11 +24,11 @@ def test_quadratic_beziers(tmp_path): pl5 = [[20, 230], (40, 280), (60, 250)] pdf.set_fill_color(r=255, g=0, b=0) - pdf.bezier(pl1) + pdf.bezier(pl1, style="DF") pdf.set_fill_color(r=0, g=255, b=0) - pdf.bezier(pl2) + pdf.bezier(pl2, style="DF") pdf.set_fill_color(r=0, g=0, b=255) - pdf.bezier(pl3, closed=True) + pdf.bezier(pl3, style="DF", closed=True) pdf.bezier(pl4, style="F") pdf.bezier(pl5, style="D") @@ -48,11 +48,11 @@ def test_cubic_beziers(tmp_path): pl5 = [[20, 80], (40, 90), (60, 80)] pdf.set_fill_color(r=255, g=0, b=0) - pdf.bezier(pl1) + pdf.bezier(pl1, style="DF") pdf.set_fill_color(r=0, g=255, b=0) - pdf.bezier(pl2) + pdf.bezier(pl2, style="DF") pdf.set_fill_color(r=0, g=0, b=255) - pdf.bezier(pl3, closed=True) + pdf.bezier(pl3, style="DF", closed=True) pdf.bezier(pl4, style="F") pdf.bezier(pl5, style="D") @@ -70,12 +70,12 @@ def test_bezier_line_settings(tmp_path): pdf.set_fill_color(r=255, g=0, b=0) pdf.set_dash_pattern(dash=2, gap=3) - pdf.bezier(pl1) + pdf.bezier(pl1, style="DF") pdf.set_fill_color(r=0, g=255, b=0) pdf.set_dash_pattern(dash=4, gap=6) pdf.set_line_width(2) - pdf.bezier(pl2) + pdf.bezier(pl2, style="DF") # Reset for drawing points pdf.set_line_width(0.2) @@ -84,3 +84,52 @@ def test_bezier_line_settings(tmp_path): draw_points(pdf, [pl1, pl2]) assert_pdf_equal(pdf, HERE / "bezier_curve_line_settings.pdf", tmp_path) + + +def test_bezier_chaining(tmp_path): + pdf = fpdf.FPDF() + pdf.add_page() + pdf.set_font("Helvetica", size=12) + + pdf.x, pdf.y = 20, pdf.h / 4 - 30 + pdf.cell(text="Chaining cubic curves:") + for i in range(4): + shift = 20 if i % 2 else -20 + x1, y1 = (3 * i + 1) * pdf.w / 14, pdf.h / 4 + x2, y2 = (3 * i + 2) * pdf.w / 14, pdf.h / 4 + shift + x3, y3 = (3 * i + 3) * pdf.w / 14, pdf.h / 4 + shift + x4, y4 = (3 * i + 4) * pdf.w / 14, pdf.h / 4 + pdf.set_draw_color( + { + 0: "#000", + 1: "#f00", + 2: "#0f0", + 3: "#00f", + }[i % 4] + ) + pdf.circle(x=x1 - 0.5, y=y1 - 0.5, r=1) + pdf.circle(x=x2 - 0.5, y=y2 - 0.5, r=1) + pdf.circle(x=x3 - 0.5, y=y3 - 0.5, r=1) + pdf.circle(x=x4 - 0.5, y=y4 - 0.5, r=1) + pdf.bezier(((x1, y1), (x2, y2), (x3, y3), (x4, y4))) + + pdf.x, pdf.y = 20, pdf.h / 2 - 30 + pdf.cell(text="Chaining quadratic curves:") + for i in range(4): + shift = 20 if i % 2 else -20 + x1, y1 = (2 * i + 1) * pdf.w / 10, pdf.h / 2 + x2, y2 = (2 * i + 2) * pdf.w / 10, pdf.h / 2 + shift + x3, y3 = (2 * i + 3) * pdf.w / 10, pdf.h / 2 + pdf.set_draw_color( + { + 0: "#f00", + 1: "#0f0", + 2: "#00f", + }[i % 3] + ) + pdf.circle(x=x1 - 0.5, y=y1 - 0.5, r=1) + pdf.circle(x=x2 - 0.5, y=y2 - 0.5, r=1) + pdf.circle(x=x3 - 0.5, y=y3 - 0.5, r=1) + pdf.bezier(((x1, y1), (x2, y2), (x3, y3))) + + assert_pdf_equal(pdf, HERE / "bezier_chaining.pdf", tmp_path) diff --git a/test/svg/generated_pdf/Ghostscript_colorcircle.pdf b/test/svg/generated_pdf/Ghostscript_colorcircle.pdf index b1c130048..6aa80f541 100644 Binary files a/test/svg/generated_pdf/Ghostscript_colorcircle.pdf and b/test/svg/generated_pdf/Ghostscript_colorcircle.pdf differ diff --git a/test/svg/generated_pdf/Ghostscript_escher.pdf b/test/svg/generated_pdf/Ghostscript_escher.pdf index 983538b2c..c505e6b53 100644 Binary files a/test/svg/generated_pdf/Ghostscript_escher.pdf and b/test/svg/generated_pdf/Ghostscript_escher.pdf differ diff --git a/test/svg/generated_pdf/SVG_logo.pdf b/test/svg/generated_pdf/SVG_logo.pdf index bd9eaf361..50a0c0621 100644 Binary files a/test/svg/generated_pdf/SVG_logo.pdf and b/test/svg/generated_pdf/SVG_logo.pdf differ diff --git a/test/svg/generated_pdf/SVG_logo_notransparency.pdf b/test/svg/generated_pdf/SVG_logo_notransparency.pdf index ed2da036d..20b47b3d4 100644 Binary files a/test/svg/generated_pdf/SVG_logo_notransparency.pdf and b/test/svg/generated_pdf/SVG_logo_notransparency.pdf differ diff --git a/test/svg/generated_pdf/arcs02.pdf b/test/svg/generated_pdf/arcs02.pdf index f1dbc7fed..5ee9f8381 100644 Binary files a/test/svg/generated_pdf/arcs02.pdf and b/test/svg/generated_pdf/arcs02.pdf differ diff --git a/test/svg/generated_pdf/cubic01.pdf b/test/svg/generated_pdf/cubic01.pdf index 0bdf4f622..f23b8a3ba 100644 Binary files a/test/svg/generated_pdf/cubic01.pdf and b/test/svg/generated_pdf/cubic01.pdf differ diff --git a/test/svg/generated_pdf/cubic02.pdf b/test/svg/generated_pdf/cubic02.pdf index bd145015d..5166ab08e 100644 Binary files a/test/svg/generated_pdf/cubic02.pdf and b/test/svg/generated_pdf/cubic02.pdf differ diff --git a/test/svg/generated_pdf/issue-1076.pdf b/test/svg/generated_pdf/issue-1076.pdf index 03282bcb9..5434cd8f1 100644 Binary files a/test/svg/generated_pdf/issue-1076.pdf and b/test/svg/generated_pdf/issue-1076.pdf differ diff --git a/test/svg/generated_pdf/path_clippingpath.pdf b/test/svg/generated_pdf/path_clippingpath.pdf index f75d034e5..690026fa3 100644 Binary files a/test/svg/generated_pdf/path_clippingpath.pdf and b/test/svg/generated_pdf/path_clippingpath.pdf differ diff --git a/test/svg/generated_pdf/quad01.pdf b/test/svg/generated_pdf/quad01.pdf index 039ca56dc..c6e84f720 100644 Binary files a/test/svg/generated_pdf/quad01.pdf and b/test/svg/generated_pdf/quad01.pdf differ diff --git a/test/svg/generated_pdf/rgb-color-issue-480.pdf b/test/svg/generated_pdf/rgb-color-issue-480.pdf index 67b0fbf35..265300e71 100644 Binary files a/test/svg/generated_pdf/rgb-color-issue-480.pdf and b/test/svg/generated_pdf/rgb-color-issue-480.pdf differ diff --git a/test/svg/generated_pdf/search.pdf b/test/svg/generated_pdf/search.pdf index d012e1b3a..ce3f7e007 100644 Binary files a/test/svg/generated_pdf/search.pdf and b/test/svg/generated_pdf/search.pdf differ diff --git a/test/svg/generated_pdf/transforms/matrix.pdf b/test/svg/generated_pdf/transforms/matrix.pdf index a219e94b9..2d79f3cc9 100644 Binary files a/test/svg/generated_pdf/transforms/matrix.pdf and b/test/svg/generated_pdf/transforms/matrix.pdf differ diff --git a/test/svg/generated_pdf/transforms/multi.pdf b/test/svg/generated_pdf/transforms/multi.pdf index 174ea87ea..d1b990355 100644 Binary files a/test/svg/generated_pdf/transforms/multi.pdf and b/test/svg/generated_pdf/transforms/multi.pdf differ diff --git a/test/svg/generated_pdf/transforms/rotate.pdf b/test/svg/generated_pdf/transforms/rotate.pdf index 36a5b0cc5..e8847ac3f 100644 Binary files a/test/svg/generated_pdf/transforms/rotate.pdf and b/test/svg/generated_pdf/transforms/rotate.pdf differ diff --git a/test/svg/generated_pdf/transforms/scale.pdf b/test/svg/generated_pdf/transforms/scale.pdf index d809d86fd..728c4f62d 100644 Binary files a/test/svg/generated_pdf/transforms/scale.pdf and b/test/svg/generated_pdf/transforms/scale.pdf differ diff --git a/test/svg/generated_pdf/transforms/skew.pdf b/test/svg/generated_pdf/transforms/skew.pdf index ca3690ced..4403a1360 100644 Binary files a/test/svg/generated_pdf/transforms/skew.pdf and b/test/svg/generated_pdf/transforms/skew.pdf differ diff --git a/test/svg/generated_pdf/transforms/translate.pdf b/test/svg/generated_pdf/transforms/translate.pdf index bcf59e9b7..6ea16cedf 100644 Binary files a/test/svg/generated_pdf/transforms/translate.pdf and b/test/svg/generated_pdf/transforms/translate.pdf differ diff --git a/test/svg/generated_pdf/use-xlink-href.pdf b/test/svg/generated_pdf/use-xlink-href.pdf index 89387b981..96b3ff686 100644 Binary files a/test/svg/generated_pdf/use-xlink-href.pdf and b/test/svg/generated_pdf/use-xlink-href.pdf differ diff --git a/test/text_region/tcols_3cols.pdf b/test/text_region/tcols_3cols.pdf index 4dc414a87..8387cb3db 100644 Binary files a/test/text_region/tcols_3cols.pdf and b/test/text_region/tcols_3cols.pdf differ diff --git a/test/text_region/tcols_images.pdf b/test/text_region/tcols_images.pdf index 2e1c31770..240a1e31e 100644 Binary files a/test/text_region/tcols_images.pdf and b/test/text_region/tcols_images.pdf differ