def test_custom_HTML2FPDF(tmp_path): # issue 240 class CustomHTML2FPDF(HTML2FPDF): def render_toc(self, pdf, outline): pdf.cell(txt="Table of contents:", new_x=XPos.LMARGIN, new_y=YPos.NEXT) for section in outline: pdf.cell( txt=f"* {section.name} (page {section.page_number})", new_x=XPos.LMARGIN, new_y=YPos.NEXT, ) class CustomPDF(FPDF, HTMLMixin): HTML2FPDF_CLASS = CustomHTML2FPDF pdf = CustomPDF() pdf.add_page() pdf.write_html("""<toc></toc> <h1>Level 1</h1> <h2>Level 2</h2> <h3>Level 3</h3> <h4>Level 4</h4> <h5>Level 5</h5> <h6>Level 6</h6> <p>paragraph<p>""") assert_pdf_equal(pdf, HERE / "custom_HTML2FPDF.pdf", tmp_path)
def test_2_pages_outline(tmp_path): pdf = FPDF() pdf.set_font("Helvetica") pdf.set_section_title_styles( # Level 0 titles: TitleStyle( font_family="Times", font_style="B", font_size_pt=24, color=128, underline=True, t_margin=10, l_margin=10, b_margin=0, ), ) pdf.add_page() pdf.set_y(50) pdf.set_font(size=40) p(pdf, "Doc Title", align="C") pdf.set_font(size=12) pdf.insert_toc_placeholder(render_toc, pages=2) for i in range(40): pdf.start_section(f"Title {i}") p( pdf, "Lorem ipsum dolor sit amet, consectetur adipiscing elit," " sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", ) assert_pdf_equal(pdf, HERE / "test_2_pages_outline.pdf", tmp_path)
def test_setting_all_layout(layout_input, tmp_path): """This test executes some possible inputs to FPDF#set_display_mode.""" doc = fpdf.FPDF() document_operations(doc) doc.set_display_mode(zoom="default", layout=layout_input) assert_pdf_equal(doc, HERE / f"catalog-layout-{layout_input}.pdf", tmp_path)
def test_html_toc(tmp_path): pdf = MyFPDF() pdf.add_page() pdf.write_html("""<h1>Document title</h1> <br><br><br> <u>Table of content:</u> <br> <toc></toc> <section><h2>Subtitle 1</h2><br> <section><h3>Subtitle 1.1</h3> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. <section> <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br> <section><h3>Subtitle 1.2</h3><br> Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. <section> <section> <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br> <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br> <section><h2>Subtitle 2</h2><br> <section><h3>Subtitle 2.1</h3><br> Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. <section> <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br> <section><h3>Subtitle 2.2</h3><br> Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. <section> <section>""") assert_pdf_equal(pdf, HERE / "html_toc.pdf", tmp_path)
def test_graphics_context(tmp_path): pdf = FPDF() pdf.add_page() pdf.set_font("helvetica", "", 12) pdf.set_text_color(0x00, 0xFF, 0x00) pdf.set_fill_color(0xFF, 0x88, 0xFF) pdf.set_y(20) pdf.cell(txt="outer 01", new_x=XPos.LMARGIN, new_y=YPos.NEXT, fill=True) with pdf.local_context(): pdf.set_font("courier", "BIU", 30) pdf.set_text_color(0xFF, 0x00, 0x00) pdf.set_fill_color(0xFF, 0xFF, 0x00) pdf.cell(txt="inner 01", new_x=XPos.LMARGIN, new_y=YPos.NEXT, fill=True) pdf.set_x(70) with pdf.rotation(30, pdf.get_x(), pdf.get_y()): pdf.set_fill_color(0x00, 0xFF, 0x00) pdf.cell(txt="inner 02", new_x=XPos.LMARGIN, new_y=YPos.NEXT, fill=True) pdf.set_stretching(150) pdf.cell(txt="inner 03", new_x=XPos.LMARGIN, new_y=YPos.NEXT, fill=True) pdf.cell(txt="outer 02", new_x=XPos.LMARGIN, new_y=YPos.NEXT, fill=True) assert_pdf_equal(pdf, HERE / "graphics_context.pdf", tmp_path)
def test_clip_text_modes(tmp_path): pdf = FPDF(format=(420, 150)) pdf.add_page() pdf.set_font("Helvetica", size=80) pdf.line_width = 1 with pdf.local_context(text_mode=TextMode.FILL_CLIP, text_color=(0, 255, 255)): pdf.cell(txt="FILL_CLIP text mode") for r in range(0, 200, 2): pdf.circle(x=110 - r / 2, y=22 - r / 2, r=r) pdf.ln() with pdf.local_context(text_mode=TextMode.STROKE_CLIP): pdf.cell(txt="STROKE_CLIP text mode") for r in range(0, 200, 2): pdf.circle(x=110 - r / 2, y=50 - r / 2, r=r) pdf.ln() with pdf.local_context(text_mode=TextMode.FILL_STROKE_CLIP, text_color=(0, 255, 255)): pdf.cell(txt="FILL_STROKE_CLIP text mode") for r in range(0, 200, 2): pdf.circle(x=110 - r / 2, y=78 - r / 2, r=r) pdf.ln() with pdf.local_context(text_mode=TextMode.CLIP): pdf.cell(txt="CLIP text mode") for r in range(0, 200, 2): pdf.circle(x=110 - r / 2, y=106 - r / 2, r=r) pdf.ln() assert_pdf_equal(pdf, HERE / "clip_text_modes.pdf", tmp_path)
def test_multi_cell_ln_3_table(tmp_path): """ Test rendering of a table with multi-lines cell contents cf. https://github.com/PyFPDF/fpdf2/issues/63 """ pdf = FPDF() pdf.add_page() pdf.set_font("Times", size=10) line_height = pdf.font_size * 2.5 # Set column width to 1/4 of effective page width to distribute content # evenly across table and page col_width = pdf.epw / 4 for row in TABLE_DATA: for datum in row: pdf.multi_cell( col_width, line_height, str(datum), border=1, new_x=XPos.RIGHT, new_y=YPos.TOP, max_line_height=pdf.font_size, ) pdf.ln(line_height) assert_pdf_equal(pdf, HERE / "multi_cell_ln_3_table.pdf", tmp_path)
def test_dash_pattern(tmp_path): pdf = fpdf.FPDF() pdf.add_page() pdf.set_font("helvetica", "", 10) def draw_stuff(x, y): pdf.line(x, y, x + 50, y + 50) pdf.polyline( ((x, y), (x + 40, y + 20), (x + 10, y + 30), (x + 50, y + 50))) pdf.polygon(((x + 5, y + 20), (x + 25, y + 45), (x + 40, y + 10))) pdf.rect(x, y, 50, 50) pdf.ellipse(x, y, 50, 50) pdf.set_xy(x, y + 55) pdf.cell(w=50, h=5, txt="cell", border=1) # solid line draw_stuff(20, 20) # simple dash pdf.set_dash_pattern(3) draw_stuff(100, 20) # dashdot by overlap pdf.set_dash_pattern(4, 6) draw_stuff(20, 100) pdf.set_dash_pattern(0.5, 9.5, 3.25) # coverage: repeating the same pattern should not add it again pdf.set_dash_pattern(0.5, 9.5, 3.25) draw_stuff(20, 100) # reset to solid pdf.set_dash_pattern() draw_stuff(100, 100) assert_pdf_equal(pdf, HERE / "dash_pattern.pdf", tmp_path)
def test_arc_line_width(tmp_path): pdf = fpdf.FPDF(unit="mm") pdf.add_page() for line_width in [1, 2, 3]: pdf.set_line_width(line_width) pdf.arc( x=pdf.get_x(), y=pdf.get_y(), a=size, b=size, start_angle=start_angle, end_angle=end_angle, style=None, ) pdf.set_x(pdf.get_x() + size + margin) next_row(pdf) for line_width in [4, 5, 6]: pdf.set_line_width(line_width) pdf.arc( x=pdf.get_x(), y=pdf.get_y(), a=size, b=size, start_angle=start_angle, end_angle=end_angle, style=None, ) pdf.set_x(pdf.get_x() + size + margin) pdf.set_line_width(0.2) # reset assert_pdf_equal(pdf, HERE / "class_arc_line_width.pdf", tmp_path)
def test_link_with_zoom_and_shift(tmp_path): pdf = FPDF() pdf.set_font("helvetica", size=24) pdf.add_page() link = pdf.add_link() pdf.set_link(link, page=2, x=pdf.epw / 4, y=pdf.epw / 3, zoom=4) pdf.set_xy(30, 50) pdf.cell( w=140, h=10, txt="Link to 2nd page zoomed & shifted", border=1, align="C", link=link, ) pdf.add_page() pdf.multi_cell( pdf.epw, txt="Lorem ipsum dolor sit amet, consectetur adipiscing elit," " sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." " Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat." " Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur." " Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", ) # Drawing Adobe Reader viewport after clicking on the link, # with the right panel open. The initial zoom level does not matter. pdf.set_draw_color(r=255, g=0, b=0) pdf.rect(x=pdf.epw / 4, y=pdf.epw / 3, w=53.5, h=31) assert_pdf_equal(pdf, HERE / "link_with_zoom_and_shift.pdf", tmp_path)
def test_arc_end_at_center(tmp_path): pdf = fpdf.FPDF(unit="mm") pdf.add_page() for inclination in [0, 30, 90, 120]: pdf.arc( x=pdf.get_x(), y=pdf.get_y(), a=size, b=size, start_angle=start_angle, end_angle=end_angle, inclination=inclination, style=None, ) pdf.set_x(pdf.get_x() + size + margin) pdf.arc( x=pdf.get_x(), y=pdf.get_y(), a=size, b=size, start_angle=start_angle, end_angle=end_angle, inclination=inclination, end_at_center=True, style=None, ) next_row(pdf) assert_pdf_equal(pdf, HERE / "class_arc_end_at_center.pdf", tmp_path)
def test_setting_old_date(tmp_path): doc = fpdf.FPDF() doc.add_page() # 2017, April 18th, almost 7:09a date = datetime(2017, 4, 18, 7, 8, 55) doc.set_creation_date(date) assert_pdf_equal(doc, HERE / "setting_old_date.pdf", tmp_path)
def test_thai_text(tmp_path): pdf = FPDF() pdf.add_font("Waree", fname=HERE / "Waree.ttf") pdf.set_font("Waree") pdf.add_page() pdf.write(txt="สวัสดีชาวโลก ทดสอบฟอนต์, Hello world font test.") assert_pdf_equal(pdf, HERE / "thai_text.pdf", tmp_path)
def test_multi_cell_ln_1(tmp_path): doc = fpdf.FPDF() doc.add_page() doc.set_font("helvetica", size=TEXT_SIZE) doc.multi_cell(w=100, h=LINE_HEIGHT, border=1, txt="Lorem ipsum", ln=1) doc.multi_cell(w=100, h=LINE_HEIGHT, border=1, txt="Ut nostrud irure") assert_pdf_equal(doc, HERE / "multi_cell_ln_1.pdf", tmp_path)
def test_full_height_image(tmp_path): # issue-166 img = fpdf.image_parsing.get_img_info(IMAGE_PATH) pdf = fpdf.FPDF(format=(img["w"], img["h"])) pdf.set_margin(0) pdf.add_page() pdf.image(IMAGE_PATH, h=img["h"]) assert_pdf_equal(pdf, HERE / "full_height_image.pdf", tmp_path)
def test_code39(tmp_path): pdf = FPDF() pdf.add_page() pdf.code39("fpdf2", x=50, y=50, w=4, h=20) pdf.set_font("courier", "B", size=36) pdf.text(x=80, y=80, txt="fpdf2") assert_pdf_equal(pdf, HERE / "barcodes_code39.pdf", tmp_path)
def test_named_actions(tmp_path): pdf = FPDF() pdf.set_font("Helvetica", size=24) pdf.add_page() pdf.text(x=80, y=140, txt="First page") pdf.add_page() pdf.underline = True for x, y, named_action in ( (40, 80, "NextPage"), (120, 80, "PrevPage"), (40, 200, "FirstPage"), (120, 200, "LastPage"), ): pdf.text(x=x, y=y, txt=named_action) pdf.add_action( NamedAction(named_action), x=x, y=y - pdf.font_size, w=pdf.get_string_width(named_action), h=pdf.font_size, ) pdf.underline = False pdf.add_page() pdf.text(x=80, y=140, txt="Last page") assert_pdf_equal(pdf, HERE / "named_actions.pdf", tmp_path)
def test_png_url(tmp_path): pdf = fpdf.FPDF() pdf.compress = False pdf.add_page() png = "https://upload.wikimedia.org/wikipedia/commons/7/70/Example.png" pdf.image(png, x=15, y=15, w=30, h=25) assert_pdf_equal(pdf, HERE / "image_png_url.pdf", tmp_path)
def test_interleaved2of5(tmp_path): pdf = FPDF() pdf.add_page() pdf.interleaved2of5("1337", x=65, y=50, w=4, h=20) pdf.set_font("courier", "B", size=36) pdf.text(x=80, y=80, txt="1337") assert_pdf_equal(pdf, HERE / "barcodes_interleaved2of5.pdf", tmp_path)
def test_insert_pillow(tmp_path): pdf = fpdf.FPDF() pdf.add_page() file_path = HERE / "insert_images_insert_png.png" img = Image.open(file_path) pdf.image(img, x=15, y=15, h=140) assert_pdf_equal(pdf, HERE / "image_types_insert_png.pdf", tmp_path)
def test_transitions(tmp_path): pdf = FPDF() pdf.set_font("Helvetica", size=120) pdf.add_page() pdf.text(x=40, y=150, txt="Page 0") pdf.add_page(transition=SplitTransition("V", "O")) pdf.text(x=40, y=150, txt="Page 1") pdf.add_page(transition=BlindsTransition("H")) pdf.text(x=40, y=150, txt="Page 2") pdf.add_page(transition=BoxTransition("I")) pdf.text(x=40, y=150, txt="Page 3") pdf.add_page(transition=WipeTransition(90)) pdf.text(x=40, y=150, txt="Page 4") pdf.add_page(transition=DissolveTransition()) pdf.text(x=40, y=150, txt="Page 5") pdf.add_page(transition=GlitterTransition(315)) pdf.text(x=40, y=150, txt="Page 6") pdf.add_page(transition=FlyTransition("H")) pdf.text(x=40, y=150, txt="Page 7") pdf.add_page(transition=PushTransition(270)) pdf.text(x=40, y=150, txt="Page 8") pdf.add_page(transition=CoverTransition(270)) pdf.text(x=40, y=150, txt="Page 9") pdf.add_page(transition=UncoverTransition(270)) pdf.text(x=40, y=150, txt="Page 10") pdf.add_page(transition=FadeTransition()) pdf.text(x=40, y=150, txt="Page 11") assert_pdf_equal(pdf, HERE / "transitions.pdf", tmp_path)
def test_insert_png(tmp_path): pdf = fpdf.FPDF() pdf.compress = False pdf.add_page() file_path = HERE / "insert_images_insert_png.png" pdf.image(file_path, x=15, y=15, h=140) assert_pdf_equal(pdf, HERE / "image_types_insert_png.pdf", tmp_path)
def test_insert_gif(tmp_path): pdf = fpdf.FPDF() pdf.compress = False pdf.add_page() file_path = HERE / "circle.gif" pdf.image(file_path, x=15, y=15) assert_pdf_equal(pdf, HERE / "image_types_insert_gif.pdf", tmp_path)
def test_customize_ul(tmp_path): html = """<ul> <li><b>term1</b>: definition1</li> <li><b>term2</b>: definition2</li> </ul>""" # 1. Customizing through class attributes: class CustomPDF(FPDF, HTMLMixin): li_tag_indent = 5 ul_bullet_char = "\x86" pdf = CustomPDF() pdf.set_font_size(30) pdf.add_page() pdf.write_html(html) pdf.ln() # 2. Customizing through instance attributes: pdf.li_tag_indent = 10 pdf.ul_bullet_char = "\x9b" pdf.write_html(html) pdf.ln() # 3. Customizing through optional method arguments: for indent, bullet in ((15, "\xac"), (20, "\xb7")): pdf.write_html(html, li_tag_indent=indent, ul_bullet_char=bullet) pdf.ln() assert_pdf_equal(pdf, HERE / "test_customize_ul.pdf", tmp_path)
def test_html_heading_hebrew(tmp_path): pdf = MyFPDF() pdf.add_font("DejaVuSans", fname=HERE / "../fonts/DejaVuSans.ttf") pdf.set_font("DejaVuSans") pdf.add_page() pdf.write_html("<h1>Hebrew: שלום עולם</h1>") assert_pdf_equal(pdf, HERE / "html_heading_hebrew.pdf", tmp_path)
def test_alt_text_on_two_pages(tmp_path): pdf = fpdf.FPDF() pdf.add_page() pdf.image(IMG_FILE_PATH, alt_text=IMG_DESCRIPTION) pdf.add_page() pdf.image(IMG_FILE_PATH, alt_text=IMG_DESCRIPTION) assert_pdf_equal(pdf, HERE / "test_alt_text_on_two_pages.pdf", tmp_path)
def test_alt_text_and_title(tmp_path): pdf = fpdf.FPDF() pdf.add_page() pdf.image(IMG_FILE_PATH, alt_text=IMG_DESCRIPTION) pdf.image(IMG_FILE_PATH, title=IMG_DESCRIPTION) pdf.image(IMG_FILE_PATH, alt_text=IMG_DESCRIPTION, title=IMG_DESCRIPTION) assert_pdf_equal(pdf, HERE / "alt_text_and_title.pdf", tmp_path)
def test_render_en_dash(tmp_path): # issue-166 pdf = FPDF() font_file_path = HERE / "Roboto-Regular.ttf" pdf.add_font("Roboto-Regular", fname=str(font_file_path)) pdf.set_font("Roboto-Regular", size=120) pdf.add_page() pdf.cell(w=pdf.epw, txt="–") # U+2013 assert_pdf_equal(pdf, HERE / "render_en_dash.pdf", tmp_path)
def test_put_info_some(tmp_path): """This test tests some possible inputs to FPDF#_put_info.""" doc = fpdf.FPDF() document_operations(doc) doc.set_title("sample title") doc.set_keywords("sample keywords") doc.set_creator("sample creator") assert_pdf_equal(doc, HERE / "put_info_some.pdf", tmp_path)
def test_recorder_replay_ok(tmp_path): recorder = FPDFRecorder(init_pdf()) recorder.add_page() recorder.cell(w=recorder.epw, h=10, txt="Hello again!", align="C") expected = recorder.output() recorder.rewind() recorder.replay() assert_pdf_equal(recorder, expected, tmp_path)