From 0684aee370739f4ca46e61c92ed159aaa0e681e8 Mon Sep 17 00:00:00 2001 From: Lucas Cimon <925560+Lucas-C@users.noreply.github.com> Date: Mon, 20 Feb 2023 23:13:37 +0100 Subject: [PATCH 01/17] Implement FPDF.table() - close #701 --- docs/Images.md | 2 +- fpdf/fpdf.py | 5 + fpdf/table.py | 88 ++++++++++++ test/table/table_simple.pdf | Bin 0 -> 1507 bytes test/table/table_with_fixed_col_width.pdf | Bin 0 -> 1507 bytes test/table/table_with_fixed_row_height.pdf | Bin 0 -> 1489 bytes test/table/table_with_fixed_width.pdf | Bin 0 -> 1503 bytes test/table/table_with_multiline_cells.pdf | Bin 0 -> 3146 bytes ...h_multiline_cells_and_fixed_row_height.pdf | Bin 0 -> 3118 bytes test/table/table_with_varying_col_widths.pdf | Bin 0 -> 1504 bytes test/table/test_table.py | 128 ++++++++++++++++++ test/text/test_cell.py | 23 ++-- test/text/test_multi_cell.py | 4 +- test/text/test_multi_cell_markdown.py | 9 +- 14 files changed, 241 insertions(+), 18 deletions(-) create mode 100644 fpdf/table.py create mode 100644 test/table/table_simple.pdf create mode 100644 test/table/table_with_fixed_col_width.pdf create mode 100644 test/table/table_with_fixed_row_height.pdf create mode 100644 test/table/table_with_fixed_width.pdf create mode 100644 test/table/table_with_multiline_cells.pdf create mode 100644 test/table/table_with_multiline_cells_and_fixed_row_height.pdf create mode 100644 test/table/table_with_varying_col_widths.pdf create mode 100644 test/table/test_table.py diff --git a/docs/Images.md b/docs/Images.md index 925091e84..aa0d26982 100644 --- a/docs/Images.md +++ b/docs/Images.md @@ -56,7 +56,7 @@ When you want to scale an image to fill a rectangle, while keeping its aspect ra and ensuring it does **not** overflow the rectangle width nor height in the process, you can set `w` / `h` and also provide `keep_aspect_ratio=True` to the [`image()`](fpdf/fpdf.html#fpdf.fpdf.FPDF.image) method. -The following unit test illustrates that: +The following unit tests illustrate that: * [test_image_fit.py](https://github.com/PyFPDF/fpdf2/blob/master/test/image/test_image_fit.py) * resulting document: [image_fit_in_rect.pdf](https://github.com/PyFPDF/fpdf2/blob/master/test/image/image_fit_in_rect.pdf) diff --git a/fpdf/fpdf.py b/fpdf/fpdf.py index 83563e00e..3b766390c 100644 --- a/fpdf/fpdf.py +++ b/fpdf/fpdf.py @@ -86,6 +86,7 @@ class Image: from .sign import Signature from .svg import Percent, SVGObject from .syntax import DestinationXYZ, PDFDate +from .table import Table from .util import ( escape_parens, get_scale_factor, @@ -4675,6 +4676,10 @@ def _apply_style(self, title_style): self.text_color = prev_text_color self.underline = prev_underline + @check_page + def table(self, *args, **kwargs): + return Table(self, *args, **kwargs) + def output( self, name="", dest="", linearize=False, output_producer_class=OutputProducer ): diff --git a/fpdf/table.py b/fpdf/table.py new file mode 100644 index 000000000..374b523ae --- /dev/null +++ b/fpdf/table.py @@ -0,0 +1,88 @@ +from numbers import Number + + +class Table: + def __init__(self, fpdf, line_height=None, width=None): + self.fpdf = fpdf + self.line_height = line_height or 2 * self.fpdf.font_size + self.width = width or fpdf.epw + self.col_widths = None + self.rows = [] + + def __enter__(self): + return self + + def row(self): + row = Row(self) + self.rows.append(row) + return row + + def __exit__(self, exc_type=None, exc_val=None, exc_tb=None): + for i, row in enumerate(self.rows): + lines_count_per_cell = self._get_lines_count_per_cell(i) + row_height = max(lines_count_per_cell) * self.line_height + for j in range(len(row.cells)): + cell_line_height = row_height / lines_count_per_cell[j] + self._render_table_cell( + i, j, h=row_height, max_line_height=cell_line_height + ) + self.fpdf.ln(row_height) + + def _render_table_cell(self, i, j, h, **kwargs): + row = self.rows[i] + col_width = self._get_col_width(i, j) + return self.fpdf.multi_cell( + w=col_width, + h=h, + txt=row.cells[j], + border=1, + new_x="RIGHT", + new_y="TOP", + **kwargs, + ) + + def _get_col_width(self, i, j): + if not self.col_widths: + cols_count = len(self.rows[i].cells) + return self.width / cols_count + if isinstance(self.col_widths, Number): + return self.col_widths + if j >= len(self.col_widths): + raise ValueError( + f"Invalid .col_widths specified: missing width for table() column {j + 1} on row {i + 1}" + ) + # pylint: disable=unsubscriptable-object + col_ratio = self.col_widths[j] / sum(self.col_widths) + return col_ratio * self.width + + def _get_lines_count_per_cell(self, i): + row = self.rows[i] + lines_count = [] + for j in range(len(row.cells)): + lines_count.append( + len( + self._render_table_cell( + i, + j, + h=self.line_height, + max_line_height=self.line_height, + split_only=True, + ) + ) + ) + return lines_count + + +class Row: + def __init__(self, table): + self.table = table + self.cells = [] + + def __enter__(self): + return self + + def __exit__(self, exc_type=None, exc_val=None, exc_tb=None): + pass + + def cell(self, text): + self.cells.append(text) diff --git a/test/table/table_simple.pdf b/test/table/table_simple.pdf new file mode 100644 index 0000000000000000000000000000000000000000..174442a4f732c5848989855d31329e42ae98abc2 GIT binary patch literal 1507 zcmah}eM}Q)7_V*)ICLM%<_E*QQxQ!D*Xtc^&o!{p(u_evZ5;^Z!-Kw*BjpZz*H|cM zGFhDrH8Po|6SHZkpK(r2bQ)3AuuR5+1IJ9GlMUGb-7pb#V8Y%jAkF+^??3O|?|q-& z^Lw8>zbDqDH^dVOBt`%^;ET#IjRwPYyo(b7f#K<_O#oIB9hvhn+z4$flft`!RgREE zIx#_^25O2(P}AsiO=SfHxQVet0ZU54AZL^46d|;k6_C>wi!9Ggasu4Iithu?zcKBCQTagnC%a+aQK#K+Z0fq9UlJC_!{WrW|wc-PYK_ z1>~>R{=E@f{6*x_y5xrKX`OG@zc_2|1=)4=;pp_2mPM!DPRfdJXwSDiT>tatn=>At z%0D@BX9{OVfE#GuLQ2_-qg8gf6kHqvTMVzY58k^w8rXWH=>UJK6*A#|H<`_ zV=7yQjZOZA$5*&y23=PV=XtXEN!~9F_Q=8;tgqK+4!c8AjacuuCzkBU(nP%M>n$^f zU7DvkbpPgPsi*c(a(hnQU|GvBGs*qlLtB$4DbO1^&sVVX-~>sPISf!yHQ(IYc(vAl zrf=Z#7MHK&tiO9k_#9(nTdhC4Z=f!&RZHd>2W7Qh-$ifJ{a+u2n>IC$|I|HNc5XP| zZd}se8oN2Hn`#^XF~F$)^88R*mA((J?#bzzUD&v4=7BGVF5FL!I4}^8p2OOWWVK~5 zy#6Eq{?>ZL{!d-7EJg|PWsdE;JsNkI$Le+%aFW(qw~8nkq4*J5v||8hF&-_!_nx3h`#XoI$QhpWsdR1~PGWmpYC5{jSNalEE0Eu3s!3_kEGMiDu<0dCxY=I)M;%I=N+|Z2_ zq?IEVrA+R+$vrJUgjN+ot3#fVhJha03arqtB4{N|C`f{!2N~=}KNrO(8LMl}$ gBtcVZrCgo#|2KkF7DUD=2Frx1sKjDpQ!@?NzwgBwPyhe` literal 0 HcmV?d00001 diff --git a/test/table/table_with_fixed_col_width.pdf b/test/table/table_with_fixed_col_width.pdf new file mode 100644 index 0000000000000000000000000000000000000000..5d4ac8ad909f37f95cd7fdfb5e1c1715f3be87a0 GIT binary patch literal 1507 zcmah}YfKbZ6gGjfGSbScB}K5eraS~;c6N7QN01`>h$|wnND&dp0GDN9cLru=13qfo zgfu>Y6kBTrCGt#4R8k)$mViYK&{EtAR)VMvAyTlSpe0Zmuy=Uqru^vrGc(`0=R4n= zobUL=skK2wupA?R6tEe&Sa>*wt5^#o00P6KjafWMk)x146~kj-mXVHPi$IDLAtXfx z%alN=AcBDO&L+*YxRr(8G#3i#hf^rL!ZkGddRaD zE)((~#FkPlZo?<0F7s)PCINCttBDq%8fLOt5W{ys#vtUNCMd-$Uf>{Y#)?jtp6Fo) zrOw6A4q@vn*90D|J5;9o)vLt)4bRq9x0T6o#tViJ}5Y;rD1gVT*oE5aYLBL zV2rPM<26dZ zkoLkU{i`tN+Ul|BmJjEA4_+|oE@_$`lh%ott9Fy`R^+NC_9mBW^C-u+s)q77$#u8Z zxc(#K0~Y&uWw)mBd3M_<-J0!kvYk{#3YTwfxz;lOrK@LpdBd@^-}0)44senU3ir9O zd&7~ArL3+`v-ZzLY8TH6&uGWerfq#!PTNbY6XaDp7th@J(X|&2Y;lbo3U~?Q2P(&E z3eS+ozLE4ht;&h_m@0av{EY%LD^d7w3cdNn> znecRVNlimzLrF(c-QRn5{@5-*>nq;t`C}M7ZJG9-UFYN6)BCvc{o3ZK3e9eBx&6*H zc8S(&UUN<91LeLYX?OFgXv;63`M(+S-n4lpqQ1G#v9@!n!m!($2isK%=U3MU2KE*Q z`L(yp&y`Wm_0=QloVCp_B_Ut@lr36mX~33DMcPbf6wN~|i{=~OWi&%RNY9#STuT74vK|dQ9>=kn z2~YqjI9ed6HY`F4bY|qDsHLZB>8VS#p$)a6RUyxa%Rr561^m^U2`YplWO9O_r0DD+ zC_kyxZ=+3e5eKs|DNtf!eDQz~l9ZDm8@$FSun+>wYm7pFBOV)!pjO_Kg|5UX#R`m& zDwO}_BM7A8RSkiojV8z~?9v3|euyOFdX^P{xDC-3(=pjB5L+R>t3gV*hSDk(p&B(M t(`czEN<}JU8U?9T$>bWTTuX#R{Qr%GF7pD-2@7pPT@1l|d^E9I>|gY*7SsR$ literal 0 HcmV?d00001 diff --git a/test/table/table_with_fixed_row_height.pdf b/test/table/table_with_fixed_row_height.pdf new file mode 100644 index 0000000000000000000000000000000000000000..81b59a94d6f661cbe1f6c1507bf6248176c4f64a GIT binary patch literal 1489 zcmah}ZA?>V6gIlJctzr(G8naI~4X_K1Mfx?EHD}ea?HH zbKaBloKTHIbr6pdAUMDPlbMT1BnT>JoHPq?1bxe5asYz>y0k_FO{Pp1QpOYj0|pU7 zOhoZTKopHfiNw>9{7(R70962ND;DP_&7o(8Ls-`J9V|Ci-HP`{T^0XUCiV!O*9l_2{kcSbJHKDe}Zc<@L{lV|7ds`~yLro&w+zdX!~dG*xI;PY`KMcARS zlHQK5T)KpbiZAMyju#hcWcRv0Qmp8TXJh(nZl8NQXtpD8sNPz)@+W9`!F%jphRZmX zCXYSmA8_4oN^mSUC{!O=*IQGy?^*Yg`Oe1a>cD56OW}Y0IMIGzdAIp9)p)?gT&a$)KiX1e9_sz!rYGA10e#qUQe$8-g zf1I=$sGjRv?75xLc5-xd=}um8Q-rcI`cs_>4UVqF(zli7W_|t8+gZP(HS&pdMOd%EOoZJJ04oVqxjos?sKz8|;hZQxI?49i9 z?Pz&j+A~K#sNC=J9LNm%+`L6`_4|dZjmIOJz5A&C8U4${f=u+azT$+?dA@P>wb%kx$2TDrn#*2W?2|vdm$o8lh1GMe{uyIg_DfND z6{X|E(~+fFj2HjqjJuY9V)0|?g5O2wme$L^4e(Yps=jgWLMz_IT?)e$ECUyKw_}O+E%WXqe*2gc z&iXj5ONj89MH%U!R1BPEG}U6G90#?Gjf5Ie(r_v*v>Bjj7FtR>EE@oV>YSPEsxmo! zLP@X5l;iLjcTNibj5|j!k)SFZaGAAmyitvv$;tRTS#H6vR;>iIZD6dOv{)(o>gLp0 ziYQnzs%01!aJvugtOPon0bDD%Zv`+&lmeMtp->71QlW_8V>l)yV6n28n-LZ@&YzZj%h7F2?a(nwlyA(EBs3JB%%cq^N3tUR2y_ekHM(lu~ z*6>XxVK~3KMF&IFbQ>c$4P?uRGL%6#79ui0rxRR27_bp^xc3$q-Tblh=e_qi?|II7 zPtJ3K5@S?6EL@0SfDfqb{fJzSpi0U@G5|x+ctfrk=!DRv*@vKNBG-T`s3M@_LqseS zhYO@YD#F60GU!b{SV#ag5!VxDBq|Ca$Xu3A;6|HJNRZJvjDaFoIRUCNFuMS0F&ZHO z8@dNSNLd(wCXj@ZGFnXJ3Ty^!d78B(N}R!sl-?~3TjF~4Btwvl8HiS55^);-t}$o` zGi9N32s4nlQ?kk3_}I`jK9#}95HzgSh%-bCkwfJY2)c(L^-Ml&f{2YWGcjwR!TCKJr8V z{I_&X=?=tDFiR~AR66>1x9ooP=tODdr(}vmqjQGvE^#`gH?AbLjZ~&Zccl&YAoIow z?)bZ$8{_qNlH)_q`z3WWU96oL?LPisO6uP|zSMVSV)>?euDa!%=%`VhF0q##(Z8*m zmbRx{X$)?Ce0SIFC&3Q~nj4A1br-L;(K7hQvcL7$1BvCIf3*Fueb#fE+`~#=zgfo1 zV7vmFIfA8#oFmDi`~t`-g3vqo^!7x416OjR!?u4@d{|!+PyTf`EbbT z`(Y_1!mRnvGTSQV#_ONsL}nbfkBuxwzo2&X{21$aDDIz${OUE}Q@vdHSLs<>bH}~O zv*imX^^46T9PcW1ZIi7z?cQV+cVgVPEBJt?ExYg0FWqt@ZrIj{U)|DODT z5c(+&@MuWyU>$>hY<<=#3u zKL17LoYw_yU75zXba`s_&xWyjZcV^YfgQK>auTc5?ST!M8OOL`_K%O~)6dYJ4cUDs z1~}x??Qh6?H?uNY9j;YDiQOhsftv{x1!o&gHkb%APeYk-sF+w1&ZvRZ12oM*Mw4d4 z8i1f$OE%-uDXUf}@D z!Us}>^{*I^h{ZxN$OG$`47gl?T*qYaHLST|nC#hmf{14^nFv1l-?1291Xsgt}dGyoMv2Yf?X6KK|!$zD&%hz3?GjG literal 0 HcmV?d00001 diff --git a/test/table/table_with_multiline_cells.pdf b/test/table/table_with_multiline_cells.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3cc55e00af20a79887964daa03068a1f345d7b0c GIT binary patch literal 3146 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 literal 0 HcmV?d00001 diff --git a/test/table/table_with_multiline_cells_and_fixed_row_height.pdf b/test/table/table_with_multiline_cells_and_fixed_row_height.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4ba56376b9b06384c9fae8487593b62d10408811 GIT binary patch literal 3118 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 kk}yKrPz{+bMNCClJ-jCP;hGppP4BZ)Eml(jN zfntk-BBj(C3srnkTUwJw5e=0#JeoqOq!tQFqzK8DvZ97ZOYiWg+wi0J&&+)1p6{GF z`Mx7cP;341011Kv46xY+h*F85Dz=E>0gj+CbS?)nBrv4QLeMxWmnI`w3&_AAA|qr0 zfk7ZhiU$M{Fq&vBqyU;g8Ym744Miv>SD*`Ypp7r2n1~#nW|?(PfNE*}0APxYMo1u} z#*$XHhzDpqL#bF}k%?J@IUuyB+bE(UdD6%l9LfkSzUZFeDTe2ObS)==G{esg1|7w* zMdloe19C@7p|}H|kh;OArHwpghP@g|o>EgeY%YbMu@qzA^MxS@SsZVsNE2c?Q**kH z8Nu8%&;LdOMqU;-ZHw;n&3{dM%&DfVB7gMfHj(qm8t?MMTZd~~cIoHMkKYe*J$uR` zF8(<3SKac6Qa;i5)%M<=X15>Ex$F0h;!AB8>l=pOOV0ehT{mQLzxK|N&o8GBXEe6n zv5S0DyO#^aST-$667`mfV|kS)bgFKd~bCcE6H?M08YUtf#&W1AAxYViKHhgL|_TW)< z-H`j~MA`30g3p9)sZW)jxX?KgSen+D*8TKhGB`Gayg8b6eCcS=jdq_|k6ZitJDkI< zPK0Ol;gN3_6muLEGv;5K)M$0BwY%6QCks^bnQ3(?Z!K)!(cz3)ou;ch6UM85>n>3r z%Ks=TY0T!a|MmW>6N`mnx1C-sk}1V_d4g(4Y%dd-`Q&(b?~cJk>dOT) z`K6k%Ym+et{ybjM1EF^p%$|2u&pV^STGY+fuNRq~$0jmwXL764px)p#GuhgD`>8m@ zUOCtY`@VWmRC~T|etO`$+pWtD9pwBs*ppYT=(pz5zW0u$-e~t`f3b`9SgP(_a%q=l zAFO=#@Y%{s>d*T23O-s_*Se!*4$_PyIZDeyaifW}iQ@cqtciq{(J)Y?G-Cj03e7|? z9K8V`sJKB~xulfagr4rTRK&Y&PYDW{yY>uAdK?Vx92dqt5 zU z9)f`&M2N2)AeYG`GLQ#eU<6nV0p$ zHZa~y(niX>x=8hODFs_bbu7yRVHLs^7R}_bKp2Jat_B&(K#fYHl@JPz0*k;jkqQkF lA(v|jTrMTl5t2wO^#5 Date: Tue, 21 Feb 2023 08:58:35 +0100 Subject: [PATCH 02/17] Implementing table headings styles --- fpdf/enums.py | 1 - fpdf/fonts.py | 57 +++++++++---- fpdf/fpdf.py | 78 +++++++++++------- fpdf/table.py | 78 +++++++++++------- test/fonts/test_set_font.py | 6 +- test/table/table_simple.pdf | Bin 1507 -> 1640 bytes test/table/table_with_fixed_col_width.pdf | Bin 1507 -> 1640 bytes test/table/table_with_fixed_row_height.pdf | Bin 1489 -> 1624 bytes test/table/table_with_fixed_width.pdf | Bin 1503 -> 1636 bytes test/table/table_with_headings_styled.pdf | Bin 0 -> 1653 bytes test/table/table_with_multiline_cells.pdf | Bin 3146 -> 3284 bytes ...h_multiline_cells_and_fixed_row_height.pdf | Bin 3118 -> 3256 bytes test/table/table_with_varying_col_widths.pdf | Bin 1504 -> 1637 bytes test/table/table_without_headings.pdf | Bin 0 -> 1507 bytes test/table/test_table.py | 27 ++++++ 15 files changed, 164 insertions(+), 83 deletions(-) create mode 100644 test/table/table_with_headings_styled.pdf create mode 100644 test/table/table_without_headings.pdf diff --git a/fpdf/enums.py b/fpdf/enums.py index b5849fb09..66b8f8411 100644 --- a/fpdf/enums.py +++ b/fpdf/enums.py @@ -225,7 +225,6 @@ def coerce(cls, value): return cls.I if value.upper() == "UNDERLINE": return cls.U - return super(cls, cls).coerce(value) class RenderStyle(CoerciveEnum): diff --git a/fpdf/fonts.py b/fpdf/fonts.py index e0568b26c..f6d0302ea 100644 --- a/fpdf/fonts.py +++ b/fpdf/fonts.py @@ -1,16 +1,21 @@ """ Definition of the character widths of all PDF standard fonts. """ +from numbers import Number +from typing import Optional, Union -courier = {chr(i): 600 for i in range(256)} -fpdf_charwidths = { - "courier": courier, - "courierB": courier, - "courierI": courier, - "courierBI": courier, +from .drawing import DeviceRGB +from .enums import TextEmphasis + +COURIER_FONT = {chr(i): 600 for i in range(256)} +CORE_FONTS_CHARWIDTHS = { + "courier": COURIER_FONT, + "courierB": COURIER_FONT, + "courierI": COURIER_FONT, + "courierBI": COURIER_FONT, } -fpdf_charwidths["helvetica"] = { +CORE_FONTS_CHARWIDTHS["helvetica"] = { "\x00": 278, "\x01": 278, "\x02": 278, @@ -269,7 +274,7 @@ "\xff": 500, } -fpdf_charwidths["helveticaB"] = { +CORE_FONTS_CHARWIDTHS["helveticaB"] = { "\x00": 278, "\x01": 278, "\x02": 278, @@ -528,7 +533,7 @@ "\xff": 556, } -fpdf_charwidths["helveticaBI"] = { +CORE_FONTS_CHARWIDTHS["helveticaBI"] = { "\x00": 278, "\x01": 278, "\x02": 278, @@ -787,7 +792,7 @@ "\xff": 556, } -fpdf_charwidths["helveticaI"] = { +CORE_FONTS_CHARWIDTHS["helveticaI"] = { "\x00": 278, "\x01": 278, "\x02": 278, @@ -1046,7 +1051,7 @@ "\xff": 500, } -fpdf_charwidths["symbol"] = { +CORE_FONTS_CHARWIDTHS["symbol"] = { "\x00": 250, "\x01": 250, "\x02": 250, @@ -1305,7 +1310,7 @@ "\xff": 0, } -fpdf_charwidths["times"] = { +CORE_FONTS_CHARWIDTHS["times"] = { "\x00": 250, "\x01": 250, "\x02": 250, @@ -1564,7 +1569,7 @@ "\xff": 500, } -fpdf_charwidths["timesB"] = { +CORE_FONTS_CHARWIDTHS["timesB"] = { "\x00": 250, "\x01": 250, "\x02": 250, @@ -1823,7 +1828,7 @@ "\xff": 500, } -fpdf_charwidths["timesBI"] = { +CORE_FONTS_CHARWIDTHS["timesBI"] = { "\x00": 250, "\x01": 250, "\x02": 250, @@ -2082,7 +2087,7 @@ "\xff": 444, } -fpdf_charwidths["timesI"] = { +CORE_FONTS_CHARWIDTHS["timesI"] = { "\x00": 250, "\x01": 250, "\x02": 250, @@ -2341,7 +2346,7 @@ "\xff": 444, } -fpdf_charwidths["zapfdingbats"] = { +CORE_FONTS_CHARWIDTHS["zapfdingbats"] = { "\x00": 0, "\x01": 0, "\x02": 0, @@ -2599,3 +2604,23 @@ "\xfe": 918, "\xff": 0, } + + +class FontStyle: + def __init__( + self, + family: Optional[str] = None, + emphasis: Optional[Union[str, TextEmphasis]] = None, + size_pt: Optional[int] = None, + color: Optional[Union[int, tuple, DeviceRGB]] = None, # grey scale or (red, green, blue) + ): + self.family = family + self.emphasis = TextEmphasis.coerce(emphasis) + self.size_pt = size_pt + # Convert color to a RGB tuple of numbers: + if isinstance(color, DeviceRGB): + self.color = (255 * color.r, 255 * color.g, 255 * color.b) + elif isinstance(color, Number): + self.color = (color, color, color) + else: + self.color = color diff --git a/fpdf/fpdf.py b/fpdf/fpdf.py index 3b766390c..24bc6008b 100644 --- a/fpdf/fpdf.py +++ b/fpdf/fpdf.py @@ -73,7 +73,7 @@ class Image: YPos, ) from .errors import FPDFException, FPDFPageFormatException, FPDFUnicodeEncodingException -from .fonts import fpdf_charwidths +from .fonts import CORE_FONTS_CHARWIDTHS, FontStyle from .graphics_state import GraphicsStateMixin from .html import HTML2FPDF from .image_parsing import SUPPORTED_IMAGE_FILTERS, get_img_info, load_image @@ -143,15 +143,23 @@ def __str__(self): return f"ImageInfo({d})" -class TitleStyle(NamedTuple): - font_family: Optional[str] = None - font_style: Optional[str] = None - font_size_pt: Optional[int] = None - color: Union[int, tuple] = None # grey scale or (red, green, blue) - underline: bool = False - t_margin: Optional[int] = None - l_margin: Optional[int] = None - b_margin: Optional[int] = None +class TitleStyle(FontStyle): + def __init__( + self, + font_family: Optional[str] = None, + font_style: Optional[str] = None, # "B", "I" or "BI" + font_size_pt: Optional[int] = None, + color: Union[int, tuple] = None, # grey scale or (red, green, blue), + underline: bool = False, + t_margin: Optional[int] = None, + l_margin: Optional[int] = None, + b_margin: Optional[int] = None, + ): + super().__init__(font_family, font_style, font_size_pt, color) + self.underline = underline + self.t_margin = t_margin + self.l_margin = l_margin + self.b_margin = b_margin class ToCPlaceholder(NamedTuple): @@ -1951,7 +1959,7 @@ def set_font(self, family=None, style="", size=0): "name": self.core_fonts[fontkey], "up": -100, "ut": 50, - "cw": fpdf_charwidths[fontkey], + "cw": CORE_FONTS_CHARWIDTHS[fontkey], "fontkey": fontkey, "emphasis": TextEmphasis.coerce(style), } @@ -4622,7 +4630,7 @@ def start_section(self, name, level=0, strict=True): # We first check if adding this multi-cell will trigger a page break: with self.offset_rendering() as pdf: # pylint: disable=protected-access - with pdf._apply_style(pdf.section_title_styles[level]): + with pdf._use_title_style(pdf.section_title_styles[level]): pdf.multi_cell( w=pdf.epw, h=pdf.font_size, @@ -4635,7 +4643,7 @@ def start_section(self, name, level=0, strict=True): self.add_page() with self._marked_sequence(title=name) as struct_elem: outline_struct_elem = struct_elem - with self._apply_style(self.section_title_styles[level]): + with self._use_title_style(self.section_title_styles[level]): self.multi_cell( w=self.epw, h=self.font_size, @@ -4648,37 +4656,45 @@ def start_section(self, name, level=0, strict=True): ) @contextmanager - def _apply_style(self, title_style): - prev_font = (self.font_family, self.font_style, self.font_size_pt) - self.set_font( - title_style.font_family or self.font_family, - title_style.font_style - if title_style.font_style is not None - else self.font_style, - title_style.font_size_pt or self.font_size_pt, - ) - prev_text_color = self.text_color - if title_style.color is not None: - if isinstance(title_style.color, Sequence): - self.set_text_color(*title_style.color) - else: - self.set_text_color(title_style.color) + def _use_title_style(self, title_style: TitleStyle): prev_underline = self.underline self.underline = title_style.underline if title_style.t_margin: self.ln(title_style.t_margin) if title_style.l_margin: self.set_x(title_style.l_margin) - yield + with self.use_font_style(title_style): + yield if title_style.b_margin: self.ln(title_style.b_margin) + self.underline = prev_underline + + @contextmanager + def use_font_style(self, font_style: FontStyle): + prev_font = (self.font_family, self.font_style, self.font_size_pt) + self.set_font( + font_style.family or self.font_family, + font_style.emphasis.value + if font_style.emphasis is not None + else self.font_style, + font_style.size_pt or self.font_size_pt, + ) + prev_text_color = self.text_color + if font_style.color is not None: + if isinstance(font_style.color, Sequence): + self.set_text_color(*font_style.color) + else: + self.set_text_color(font_style.color) + yield self.set_font(*prev_font) self.text_color = prev_text_color - self.underline = prev_underline @check_page + @contextmanager def table(self, *args, **kwargs): - return Table(self, *args, **kwargs) + table = Table(self, *args, **kwargs) + yield table + table.render() def output( self, name="", dest="", linearize=False, output_producer_class=OutputProducer diff --git a/fpdf/table.py b/fpdf/table.py index 374b523ae..47b4d3512 100644 --- a/fpdf/table.py +++ b/fpdf/table.py @@ -1,37 +1,58 @@ +from contextlib import contextmanager from numbers import Number +from .fonts import FontStyle + + +DEFAULT_HEADINGS_STYLE = FontStyle(emphasis="BOLD") + class Table: - def __init__(self, fpdf, line_height=None, width=None): - self.fpdf = fpdf - self.line_height = line_height or 2 * self.fpdf.font_size + def __init__( + self, + fpdf, + line_height=None, + width=None, + first_row_as_headings=True, + headings_style: FontStyle = DEFAULT_HEADINGS_STYLE, + ): + self.line_height = line_height or 2 * fpdf.font_size self.width = width or fpdf.epw self.col_widths = None - self.rows = [] - - def __enter__(self): - return self + self._fpdf = fpdf + self._first_row_as_headings = first_row_as_headings + self._headings_style = headings_style + self._rows = [] + @contextmanager def row(self): - row = Row(self) - self.rows.append(row) - return row + row = Row() + self._rows.append(row) + yield row - def __exit__(self, exc_type=None, exc_val=None, exc_tb=None): - for i, row in enumerate(self.rows): - lines_count_per_cell = self._get_lines_count_per_cell(i) - row_height = max(lines_count_per_cell) * self.line_height - for j in range(len(row.cells)): - cell_line_height = row_height / lines_count_per_cell[j] - self._render_table_cell( - i, j, h=row_height, max_line_height=cell_line_height - ) - self.fpdf.ln(row_height) + def render(self): + for i in range(len(self._rows)): + if i == 0 and self._first_row_as_headings: + with self._fpdf.use_font_style(self._headings_style): + self._render_table_row(i) + else: + self._render_table_row(i) + + def _render_table_row(self, i): + row = self._rows[i] + lines_count_per_cell = self._get_lines_count_per_cell(i) + row_height = max(lines_count_per_cell) * self.line_height + for j in range(len(row.cells)): + cell_line_height = row_height / lines_count_per_cell[j] + self._render_table_cell( + i, j, h=row_height, max_line_height=cell_line_height + ) + self._fpdf.ln(row_height) def _render_table_cell(self, i, j, h, **kwargs): - row = self.rows[i] + row = self._rows[i] col_width = self._get_col_width(i, j) - return self.fpdf.multi_cell( + return self._fpdf.multi_cell( w=col_width, h=h, txt=row.cells[j], @@ -43,7 +64,7 @@ def _render_table_cell(self, i, j, h, **kwargs): def _get_col_width(self, i, j): if not self.col_widths: - cols_count = len(self.rows[i].cells) + cols_count = len(self._rows[i].cells) return self.width / cols_count if isinstance(self.col_widths, Number): return self.col_widths @@ -56,7 +77,7 @@ def _get_col_width(self, i, j): return col_ratio * self.width def _get_lines_count_per_cell(self, i): - row = self.rows[i] + row = self._rows[i] lines_count = [] for j in range(len(row.cells)): lines_count.append( @@ -74,15 +95,8 @@ def _get_lines_count_per_cell(self, i): class Row: - def __init__(self, table): - self.table = table + def __init__(self): self.cells = [] - def __enter__(self): - return self - - def __exit__(self, exc_type=None, exc_val=None, exc_tb=None): - pass - def cell(self, text): self.cells.append(text) diff --git a/test/fonts/test_set_font.py b/test/fonts/test_set_font.py index 7044bdc4e..fa9d34834 100644 --- a/test/fonts/test_set_font.py +++ b/test/fonts/test_set_font.py @@ -5,7 +5,7 @@ from fpdf import FPDF from fpdf.errors import FPDFException -from fpdf.fonts import fpdf_charwidths +from fpdf.fonts import CORE_FONTS_CHARWIDTHS from test.conftest import assert_pdf_equal HERE = Path(__file__).resolve().parent @@ -105,7 +105,7 @@ def test_set_font_core_font_attributes(): "name": "Courier", "up": -100, "ut": 50, - "cw": fpdf_charwidths["courier"], + "cw": CORE_FONTS_CHARWIDTHS["courier"], "fontkey": "courier", "emphasis": 0, } @@ -115,7 +115,7 @@ def test_set_font_core_font_attributes(): "name": "Times-Roman", "up": -100, "ut": 50, - "cw": fpdf_charwidths["times"], + "cw": CORE_FONTS_CHARWIDTHS["times"], "fontkey": "times", "emphasis": 0, } diff --git a/test/table/table_simple.pdf b/test/table/table_simple.pdf index 174442a4f732c5848989855d31329e42ae98abc2..87c7704b922d67035586d940286bafaf103ed4ca 100644 GIT binary patch delta 902 zcmaFN{eox0Z$|Tpf1K;h42-$#?6`_cic%AExhm%LPCc7<+d!b@eI=LNZEo!@`$>JC z7i4-^Sf%zdT(sy6_GVL&cD-j8raS3$Y~Yu|Yt1(qzi*D+bk_G^>Cu08?`(Z@ygA{} zheZi*wSV7?b4xYR%GNVo-TEYIV_$4aXt(FPo5s%bxr09~E37g)BK%&VUhs3m$%1vN ztm3AtXH5$4+N%HN_TfB<{x#e0ezVTDU$*S0>y1D&QFE?oz3TTIjccM`S!@?|`y6#> zSHIZSv-yYkRK4Te{H6W(G^hR8cExaSZeT&^!EM{~_odgdmt`bZC?}q;cqD6b`1_K+ zVt-Xran(1K`>pGCE#kIN-jKF(*6R9$hmV)da*1K{Zac6}Gv@8t%>A;0+qA7eop@+$ z?Q0wp_=@31+p_a_-~H&D5PNgdabEdbnX?|w3SxIKGnvXIxOipOLF@`* zHY?uVe3nxEf0?2EW|6B`YaSl9@>SAnR&{pxk~6p3?&d>b;aPDLmvhHo1sYNX)L~LD z@;7();SNsU{F9ek`CpryE%05*EFd*YtC!Pv{fWz>{!PtkJ7!&Bm26<#wXIT-BM3D(`vvHP<6A^TbcJVp_c5_1w4r zh1@Pjf2w(S`P{6uAIq)?O0fF6HcJ9c|19dirydw?vp`~|^8CuX-`?N$AYa7M#9McL z8_)e~nL-OwPYGCWah1~rk(Gux(VvM(?(*?YhA;qNK;C#mzuU(cKc zRLZEq>$}up%DOctgvCG(&zM=n;N^U_^TNUV|F{=$UNzxL%}ar%G$1QKDT{0JR_1&W zr^Mn^xBR>k1^tlB+|*)Sr~I6h$=8^j7|kb3vPiRW>AM*zm`yfdv1hcHT)^VYXgPTc zORk-%iGl$LDC8+{ff)vd2ByXsVuq%M7-B{y7L&bMrE4v@^n>#AOB9S03>1R6^gZ*^ z@)azgY!`)S8&?-YXHx@XLvuG*GfOvDS66dqM@KUQ6LTXIHzzYoQ#-;cVj;OJv8be? TC^e1C(AdC|OI6j?-;E0ZsqkJC z7i4-^ScUd7T(npz?aihl?Rw8HOn1`h*x)aP*P3rKe%~Cs>FcToyOREgeb?PxE8-&& zC$gqC-TroHWbw*KU6t!yrEhdrNBI;TkCXfrGh>o@@8!vg^D5XoXRuGN=UE;VR1mm% zm1gDAh~LNRZ1UPa9;mvVn-}rBJZn~bi)?Ce;o^jw6^~?14sT!D7aW~vvR-w~@07sX zf7IRtYBeB3C`jI`tuSu3Ej|^Mk6+3|B?gJ^r=hc2CE}R@usZAAIL7lU%1! z%HZaF`FdXUkLDjSHzuWX$6w8y^>9`Y`vYT>say|tZcyqEv*F~M^)M@l{eZB|inlj^ zWmLDUus*q|B|hyZw+`cvjrR6H*LUi%mSy2jUUsP;bTp3feZ|nyHfw*|+_(3?aRk&){eS7oudH1k zV$*$Vaaj{C`ip`&C~0gL#+2tfkY!o!jzXn{-|npdee|FB{Tr11CHAekY~p-+3Uh$eEW4cDA8JqKpA>HEe{FL1g3(ikDQ(Mw6uiX4 zo^W=99KOZJl40q>XD%-uW|#n#h2x{G=={Qw0Ns{K@;7vnF@52uxne zV$Eni`5}ulqs3%Z)?6(UO9cZEP{>o@0y7K@4NNRB#0-s1CtqNduC?IO56aIkQ7{4; z8pNgVnU|KYU=C%wC`8*B8yGuU7+JcRxSBgU8W|Y7IXgQUo0&Tq8(NxJm>F2u5mpfk Z$tQ_LB^5=fXTSTmUVgZD9Za diff --git a/test/table/table_with_fixed_col_width.pdf b/test/table/table_with_fixed_col_width.pdf index 5d4ac8ad909f37f95cd7fdfb5e1c1715f3be87a0..6d0b291e5ddb94b6147faa831a2702fa4dcefe21 100644 GIT binary patch delta 902 zcmaFN{eox0Z$|Tpf1K;h42-$#?6`_cic%AExhm%LPCc7<+d!b@eI=LNZEo!@`$>JC z7i4-wSf%zdT(npj?aihl?RsxtknW_@v4LL-!yeyk{I)rE)7{vErAPnWv)%IM^yGv? z9~LFNmHvGz&OOycD_hTWb?cL;jeW7Hq1};kH@Th9x6ZN4o->d4;}L6*`XfdW#y(q@ zJXn+#8vMy?@KCNm?ecV}of#?1-t7Y4quIzR3C`<2U!nYQ(+-*YssiGDTX*0fUv!H2eef4?uij=fCd?uSh+wh)bztMfm}DOIB(q!nprdh&?<0_h^{-6M7TB(27Lcm% z`nTb3=8=|V+n>BV)LuF(ZO5`Jj2yhaQ;)SQ3xD#m3ubmp+pPQTi{Hlka|F~+{eS7o zue4nsV#R%xrX8GhkU2~0as98i1v37&X(oGB&x`MSy(qJ7y_alb;DxUTztwXreyLlz z??a}zuW?QAD~_I~Ws45>08RhdrGBp-7;e5Gv03MrPrUp6ef0D zUNB1Km?QOcbzEK4pZNV7mHj35t+{OCe0mCVfYdBIxm_P>PvxH!ZtH(-a`uAJQ-&$P zKvD1l1_~!QP`3D3GAv#A%;&{}{Qvw%-(GCyO3h1wrZgZcKPiiA@>b@25vRoBRJZ)R z5(WK`%-qysU8nqHh6bj_7-EK|h8SW-CKi*uS*2?&x%7kb^Gg(r6buxCxb!{q(()B7plla~ zXd81=Q#V&9M;Bv5GjmfjGczL#S7!?|14~O+Q&%G+R~I|NDqfFM9c_HA5yY3dr|nC~|y zZhPr_W#QW&8i#YI3m1Ig$v7>WeEW{brW1v?f0w_QdCyVy*fpc`h3A3R*f3WW9Y4}w z8kBwKb7B3j7V%w6GNvutH`Aypa(!g|k<@~-0uH)H_Y14--mo2dajMTG{>!qs&ph!{ ztOXV?eCfU0{;yiix*X5VuIpc!p8w#xlli0MtSsjbF_9D9vMo9J<~__VVm~CjH{g2b z+nc2|O71dFvb&_VXW1cQOk~W&L}>zpmO=$l;;Z|J1;n zvtKSMpKIDZgZ(-WLq?$Z2kZC04i~)9So~2pbKi^D^s~kbw8~lB0`uLj@)q3KtWzS12J=3Vc>nr~~_lMom?MpZpAOAWlJwmov z!OJ;#Eyq%A?Mp4X>IV-Ruj#WCSi10;O9ub;|LkTHPNs3C=A}Rr8IYBql*MJLV4#pc zc|UX3GhZ$|Tpe_ZR$x$Nw?ic5-86LYyL=JZZGn|Iqlpyhofm)vY_x;V1_jfCoES{LRWaFYhw_8D99_hUPwf|0+xuae9)M>e|zn&EEZ)$cuQ{U{}maMyY zNtVl9lTCWA-}Uy{<{rz`XS=>W-}U?RD<=CptV*I!uR4CV*Ocex5`#Nc`(p1|s6=|jf7 zKP^wM+B;9b>PF<|j>>|Q3>{(%pLa{!Yc6~#TDj{*X!==WC;xX2ElwB1ufJFGs?VtM zo~H*?{JH1C6l;Nn7q)Dfa^XvtP3%V%iwd_DCuKVVR{Tu9v+H54I5StcrFXS$?3Zl8iusE#ds{3_!$J{dJ#F9jBppD_{E8Bdn8Un9;J;+;yz*QILuaw*8|5LZ}(2GJ~=xDuknBo+?SYs*BUxyxXT2!=oSqUr+ z`0VmRBJV$Iapo0~$rG6yMVu0gQ{D3ON)+@%GILXlb)E8aQYIf^c2Y7|Fi^-(%Hp!I z;nD{yu(8p1GgL4I3I_p2j1 w#m&gT$<58&!p+6l*~HPn%)*YaidaY%N-Qd=C`wJ^GBmO@=2BI4^>^a}0R3)n1poj5 delta 804 zcmcb?bCG+(Z$`6;e_ZPgxa{n>ic5-86LYyL=JZZGn|IqlpyhoXm)vb`?SC(y&k#9# z&?9icMQ(xK*}Jx;IBW`h@;2LCseGq&m)*H41M3TQ+twT{3--L;v48gOxSFZ}r>mP* zx%>~Vd1=0D>aor+$(L&+j?B)P_5YK?JeHp^SEI^eFN8Z=b@GXAmoW1nk{60OVp z5C8kp{bA>(rDw$UW?is3oFd!dpOK|=usGFKa%~9{-@L?4d@br#3+hB}ZXvPV#@}(BgFQeVxU*DHr}sGm8DP zp}zZ>c_{QGnlx-D<{7z+w~&0IZaS6 zyQATn>7R4IUmD1}A9`_Wno<0hb&j8Trk64-Uh#Ub{Qm&A@NH9mE?UkzD}BcrW(il{ zPh^-jmQzv#BLKfHiG1tsL6@9AZ;$vXogj{RXXkF$O==E9qRLfG~f)6}XOBK8pKAU<$ z^WH!C%U-9yPoBZtIJufdVDeNJYew_Q7g?McEhdYy=4l!#7=VC6o&pz`VPI%rY=9wV zXlOq90IPJZ1($wMetwC9k%ECj5SPAZURu6_Ih5_95N+dX?Bwj?;%a8>Xl7w*1T@Rh r)Y;6^($(3;$;H&!!r6|nidabMPb?~_C`wJ^0@`fBrK;-c@5TiH7588O diff --git a/test/table/table_with_fixed_width.pdf b/test/table/table_with_fixed_width.pdf index 1176eee7b9e039798e0040d1a46084e384c69c0c..37d74b0394069663887a4a020405bf4818d635dd 100644 GIT binary patch delta 915 zcmcc5{e)-2Z$|Tpe_ZP=x$Nw?ic5-86LYyL=JZZIn|Iqlpyhofm)vD;?XD$teV!L& zdPG>I_A*S|u~OKZO-0)E-o7v&y_2zlU(RlpJHxkS{@O{od0gwVzrBC9FZsSatFWj( z*R{Wi_Pb86=y6Luyfm$MLX7sc&E0FH4Nu!vr@g3F6kYFdzO90ZPbiVS-n*?>S93>3 z#NBCo!q!x$Ztve+Xtn9!m)rSks^`ysCZ6cNlIz~84LLT9>}MOcT`A1dPB|MI^8Mt3 zZ9jc)D2ARry&@Mb6|Hsh^@_K5rN5kce}Hf4emfT1$D9@!Y+si2&18)Ip!DkJ2J5?SHd-cJ?WNTlgdc9`V=Jf4aF>lXi?w>2LP22j@iHFA4zQ!?uuQ)b*^_~Cw z?niy6vQ%$5^O}t1nQhr#vW%Pdtqke7F;%qk)}zky3q0YIt(cOU*|XTTSY{zK^lKuPdmc&Mkn*8p-r8-?{f+CAoGxpBDtWlt3TU?fD-MpYuJyD38Pq2_U5*9{ z9|j2rgM@vj9&1?^{^Vts`aMVE7+;W(X?<_C@g6yW1qD;}BTav0?fMYAR!y*MLkfe# z>TON?>x|zmKinYcn}70i>-#Lzvkj}RJe1_!b#L~=W`kMxCOzk#e=TbkqwmVY#!@Dt zx@jhRmClEQ18vrohv|~MS$48&W#)Two3Cp$o$%6K-^O$QTBgv#)Kd>E*NTML?v?nn zF8=03b)NWZnX`bRf&s5)+r6p!Uwtb7q;OmRYm>7VjGl66eDz)GFlF7E6T)Ktdz#ZS zW)`tb`8CUUq4J%7_Pc*xQl31YxlzO^u{hN&Kd(eVKO{3ZwOH3FKPP4KC1$6|*(^L_ zU*(c2S77 zF*h}KvvdwOG`2J|GBtNHb8>VuvNSR@aW=3pGcmSwHL`;$!J{G;lGzfAN-By{)3^+c N4NSRIRbBnvxB%GVblv~} delta 821 zcmaFDbDw*{Z$`6;e_ZQLxa{n>ic5-86LYyL=JZZIn|IqlpyhoXm)vY_?XD$teV!9! zdPG>I_A*@Du`=45O-0)E-o7xMcawH6dpSGZc7|+*ee}|Z^<0_RAM?Ln=v;r^YlW9s z>x;V1<$0lILD3gAbk_>*wK%;iaPytcaL0Y&w@z?<$>~skkRW*a!K8;F_1@Ymr2@Av zUDNyG-jV6g-&)8XdGPD(+!z1O_zKiR5hVM&&agFagjt@L?E2NM7dcoGDG3TjHXsvPl zmkn{7J3c>{#3*PRIep&!J3kybeb=A3?7IGy>G=<~JCzkgy8jjYty|QxZ2Ob?my6oJ z&PxBW?2e#7mv8UVmSy2jUUsR!cp$k?t(>JL>FoQ*=Xmq0nKWXa28Z?TovBxK-F0(E zYQaf{hOk`L|DW^j`2KD*nssjy(CMWYZJ1XTu^UO1)D|3$KbBGDJx{;tmg{Gpj8n2F zGA@K{opSL@mrXo4T(UswuGHL2@_$rUai3*Hh6W}k7-ELThLg{*O4nL&=?CTKmnax17$^jB>3im-lu`N;iXg|(F2|rGGRz7=&7|JtL#}Mc{-UjMgUqkDaHQF4+8XRVG(Q)O`mCj^ zw_^EMUS9ZVqFj={ZaC%ZL$AglA*L?{f`7=>deFQ0_SUdNr$$}H*5Nc~@}=aVU!SVn z-{SP0b>{4v72Weaau$1ZKi|_@w)4)JkeZ6#{vErC10@CfGPL&CG$T#@P1^@E zTRh)y^$C0jYc25!ySl@(YEBI+(aIW+?_YeqeeC+Y#z&s^sIQf+%WP@-WOhQyoZgR& zU?sQ2`(*f{cT1!RWtpWXKKT9yQPmg0N`f9URNuby!yAE1`QWq{_@C0k+DpFhl&g2I zyo`0qI{F)`_S7ge0jp=EoSJ!brn&m6&p!4_u`JSlB;n@4lL6A^qK4&h!Yg52XhwFs zb0EI->go6qNKLYmM;Ao2xyIDAZrI$B(bxXl-mahPl^*vO)vvVZhGiWYcd2#Kf!<#> z7gR_eRBpVS%bIeIY`WRp93b6j3HI?Ms=StsWoV*4_IPsdCFAIQm(HCNsO1eW4hC&L zajc#1PknCH1vJ|fe|G-%(tz5!yg1=}&+mnY6WBn%!I$$4b9>h2-4ZI#Up(l_Z(HlP zOLnw%1D(vdSdG&S8f%2_{Ye#p&(x;`eRy{u5+Vg{Q|?H(VXn+4s(aI?^~F6 zH(oKLoH7RQY`FGTkZ*ZLV*Vub=}WI$-n+BRbnKh&L}^V9+@#0|w`tYVc822NyrXe! zI%8jIYOAxCwC67zxuBj~j-O_rAkJ@5M+JEdH;)m|O*y)88=cA23`6cjnYP!A7%I#x}m) zW7%gJSO#k3c>##~88+9zCG$XRkNB+zW{rvn4UMF9`UsrVlDLXeP?U;L>O-{(wJMU7 cYs3Hh#dzoK0&Nq6S zb&R3c0#(c`%p;TSmNZ0nhgkQ-Sq-56Z01>jM?Poj>AP8{Y!fRxD>um>Rvch|`+7*D zgJe3bOSy{5ND5=hCf)UOV(9j1E`2&MR5H|3dW$eylgPZp9f`gle?_@yp=lSELjhqZgm zQe*uRhUEm|4TPbtUj9TqJ4w>TBR1~bQz?2<{KU+fLlqrNSwgy*H?sMU;RVdLnQ%1+ zy0r&cr())uFQb%5v>M|ZD;#~=rSYQ#Dj8B!*&f=Do^K-;`ZV7?jSSAZffXf{k_UUg zi|w}^*Q|(oiZfBVClDy%}$o zG5uB|0FmAS(^V_NgU`d%BaQrxn793-PwMo}!n=E2{T`BDs7gC`Gs9*@layR2a!?WMg*U_;#v6x9w}B^)*YtYT^1eXaRdqDe`4XthKNo4Y+9wF6&IqQj zs_hgM!E)wuB0=k;A)%}YODFExVE!w0>RQqQFn|Hp&Nd(h&8Gs65F36nK!afU-2jJ2 z1kvjct(_`zujctf%BEK48cmWGo zdvUpupbdxyy#Q-h4x0;NzI|w*zb%DEr8-kcP8d7}OT%Gk`=~e)oDSNaX5M-$UhqFW`QLxN&Zfe+D^Gl+>_2wZ@b=Hr<_qEAj+z(w z{!uaWUWxnL-}il2uFe*|^y_q_XJU-ZG>*#07d9=}v|^&w?fDO$p3f9yp741W|AX6X z$1?9u+sj;ZQ#{e|U_9d$o!5?6ojBXYZ&+wB)wlmjKfJJlL^Fp#m3s*4o21%DsdY{PICLy1XZZS6;GeF%3;YRpY`+C&M@Do&zE@rz^?w= zi=W(RwdM3)ZO@S-BhuIs?0tyq%o)k8mv?lP3D0)AdBnhkG3zpI#mmSQe}1%ci~m*DC(aM~ljh<9>EEo(SpDVpovLeONCay#M^FIF^j%i8FR_ znl$g&ur>D9;YU}lIVL2}xjjqpowaZ8%rwEG_^bOI`qsWlDgR+9akqXK!=Z`0Gw1HI z<^YBXi^7XLzTI6?<^K8ko2K?^rOaItyn8acYDVh)_s)DN*S|a1d@UEaG2{8aWlKMA zKNXVM;5Rd{EN<#?exclV^=uKhV;_7tabINlQDGLdV>|b2ma_VA<=ytJG2QZ8XSbW^ zg^5zV=H}fw+dfZpW#Q|%@-kMGMa@o=NucEFpGB7x%&y*cll(66JHP)sXH(96NGR+9 zhQeP(SST27SvBv=3=_#YwO>Q!)4HGUQ+s;ydg{v4OC%5cte+R+Zh9iQ$DscB;=HMQ zKkeH3x;kmnFDs55pQ3o-S2exdOxoGX!SnBztekhVXYt+A%0?HZbm19R)*LxJ#p%LN z=Jax%+38jkW_f^T&b}j`AHHtlbo+M9W^1{?j2}xr_}sYf-_?0FbNkEL^~+pU-L^aY z{{EutS8!JT?tSb^nTo9SjlG^p*1sQk33RMn|84u%{E>QG;m2i97ApNPyK;DHzO$YW$Ia=*Q=N85Jll8lME}htD;8>cC7(4A z-|=QuqThMmi#k6AnXTeNmaXGu5}q$2#~ylRyP#XajICE)m)BhQ*;p2Gc1$O}Rd+Y4H?7QUK5)#y zT=&q0evT=^zA5$989Yy!a_=Mu1x%^7U+uO#{=k7B+moXl9#&hMKF|9S-mg`hcJB3# z{?OO<$ChT8T*x@KiSeoZR2|N2uGGAg;>l-Oofr)^3$Tem3#H8t?Ejf~-175E6l`qt z-3%2hC-3BPU^JZki_3-4XtF(bUcG^W0SGAMDR6-q28O2Qh8SYzX66`T7A6+xVn(J0 z#u#E|21b}-mQZ^qJMf6r8FA?c<>!|u0M#i3ap`;JrR6Ia0v!S7xF|&1Sh`wTx;Z*K z8@idAxVgBwnOm5eIysw~m>8Nn8Cse++7VU}3n`fsi%KerQq#DM%uS8BR8?L5-M9cp Cn|>?+ diff --git a/test/table/table_with_multiline_cells_and_fixed_row_height.pdf b/test/table/table_with_multiline_cells_and_fixed_row_height.pdf index 4ba56376b9b06384c9fae8487593b62d10408811..28c57defc5426778306534cf01d0eec2c73702d2 100644 GIT binary patch delta 1267 zcmZ1{u|skL2P325WLZ|}$tsLmjFyxA8O7==yEglnYwc>hS*8|Svg_rQN(L^kMSSAy zE{~3{7f`sss(#mES`AyR-Jkmh6+b-IbF^vxzB@nt$1hoCzraZcesap4`z%(t?F45a zpSq7=`h^2~&KPZ8^U(aq{O6KhH+Pw_p6gr7p|>&T2$zZ2QI7cv)^h`nJ%~B@_i*S} z*OmJY{H$Mp@XrsC^-aq)PraOXL~!E9;`&>giL>Fa5c` zK=AXVx_yCm_jfIu7`922KV9Rv)Fat<^<{fA9OBwGHoCLsny;u^iA#Z8GhR|AWuaYs*b=m4sD%)uGyX`xiJ&pq`z z-=YwwOcB*t-q)KYu9thyR^F3)n^lJ?Rpv*-|Scm0IN3(m9N zoVIDw)hD0TcGZeA7QIbtynANzY}Yqw*Yeu@a<=WRu9~z|r(}Zf?LdaXM{5Z2FdS&1E%8hDG8VGQ=MRT+f$kX|I}hq2vA)wi$~` zB+cI~UMQo#Nvot`*)@qh-WN|hz0IHLT)%;7;)6)ny(W`AX07!7yf?2oplaLJOLGlX z{y&hJBtP$Q{6YO4)&lxAPma|Tl;<4fy|5u^wxP~W)8s#CAN=dD9?o;!qgK6s^O++{ zG7|pJxw3uL#LMS9er}yxwE8Pov3JaR&j+R-_oxZ3@BBJTL3XC=V$1pcYOAWZ-F)%2 zP|~sJZ2hsun@5bL-On7mmeb=gOKM5zRL-0>WB!jHj)$LUiQQYc!2H{nV}g4PZySER zGvBQAxc9RvIsCnX`;FjZ)Aj6sRV=7R++>tnw54A(Q)%Ez2u zvhIk&FV6eFk00Ux^#8@PcQ?8o2({18-AM*z7#d7g=W<{)nw-Jq!e~5sEmv;6nX!Ta z2q@$!aDf>HhQ=l)7-Ht;h8SWNrbg&uMkW>*<{6n8@WX?fo3TLap`-yC`8*BnwlB7Sy~#HIvSc7TNoI)IU1R` txf(jVxHwxHnL3->5mph)WoO4#T#{H+Qc;we#${w-V#KAY>gw;t1ptTHA3Oj6 delta 1222 zcmdlXxlUpO2P31wWJPxA$tsLmjE0l_8O7@Bx;B@XYwc>hS*8|Svg_rQN(L^kMSR;E zJpTL;HE-0jczJB&2gxr#U;O9eYm{Hk@sZ`8|NV6zzFM=%EY@gxEo>9x|D;KyoqJh_ z@rr~vwUb+P9-8l%znrt{=B{~MYqXag+I_T0F=W9;4YwamC!aP6v0Z06$8UZ$b>}ap z>-&YD9k1VQA!^eX==FWcH__mS_YW`lC90eyqB!kMm=@{X!IO*R6OE=y>cQ16Z3fJW>xWd#M+~0gl zW_MSwa+IaglmN5Dl0|Qibg$sP=*b$XtKA%AvNWwFPQ*Z?UOw~YL4`u`Ozntkcig*@ zFVEsW^u@@~_D<17EyEJ+LkkwjXO&)=^YmET5%2$D8`cyyw5(B)5wx2hc<;*I6H^1E zTsv3gS_vHfm6sXJaD3a;>Y1Igz7+>d^FFQqzpOa^8uP?mqL0*e#jNr$JV~f;!bD10l&+P*&OrRH=S9vhwcwdwrT(x6mHT(7l zB@5>5KRMSkG2T$L+~IFm?yV!y)gB@{gO6phdE5UD?ca5jsqAxxw@=ISBQGo(PN=os zpH-Am8pra)H`LUXIZ~A=$~ZdvS>{=pwUG|lV)>KRRBMt1i(Y))r|>#PtbUV3?L8Os z_e>7k?w;8^+p=tP!`(AC&R%FeTW0R>Z!~=--=`}}?(UeZtome=PP-OE%5PuW{WBk% z^ZxMdy>I9>NiyTQ$Wz`s_< zNOr+SQ{lMTrAEQOl{a&QDLk@Wy<&1&y^x2oX{Oz4GmfR{(YkLXoiFi!Q+)Z*?w#zN zrpt{L|J2H#HP;>uxx@HXdz<9pMb*Z~a@qcW3AcR{b|8DxcPr0jGg3s~%%A*gg_h;N zo*D744Yx<>+iySeZB|8`@bPS+53?lJb6%PlX)^2cPYc)5^Jda}?ev&Ew%xp8Jli7e zal_5}8#8(ZJ0EjqhNiO2ez>fC$N$Ht(+_RCcjL0Ob=BjBdo$k7sCeZ!+vxY@l3j+E zIb!0Due8`({PozjdvSdm7WZh!R(<*Cwp;aYX2rE$>3W8Bm!s@=O!JKGh$~Uv_c^{p z`pN%`XZIy(?TMDD+xK(V(}ef0?R{mv!?{xPQi@B8QWGaXW3hwe$;}R|4}jTovm!ea z^W-)zfyoQGY$jK6@l1ZnWyxqXS(!Vx-qcjV00b2B6u7_)14CnDGYm0vGh+-f3lkG` zF(VUm4D*ak%`w%PnHhogPFCg-uQTG(56aIkQ2+`l1aawm=B4E;7#c!3E(*~$macA& zj;3zr#-_&3W^PVqCT4CHW~SyAMy`&oMg~rXc7#>La@pB&6_+Fyl~fd^rg0gW8<}va Ks=E5SaRC4VMhFK0 diff --git a/test/table/table_with_varying_col_widths.pdf b/test/table/table_with_varying_col_widths.pdf index ded59f62c070a68fdb7e457b4ddedc9264909675..1c0be47bb6cbbf4b8cea23cf112fda14bb1c11d3 100644 GIT binary patch delta 918 zcmaFB{gh|IZ$|Tpf1K;h3=FvJ?6`_cic%AExhm%LPCb}++kmI-eJz*l_3pIDX*u$@ z7umANvaP9OOgy_QXCw0s&bEDjb8bw@xYSjo^0)aI+j8%6a@sK)R5D3+$E|pM zk1^tlB+|*)Sr~I6h$(Na( zCg-s5h=C<+Z1mj>6-*Tj6oR<)-Ha5>ChM};Gg?f}WpQS-oV<}Gx8BrH!2kpl@)Wqh z3S$`<>Spd@>}qakYHDf+Rf0!FEF`xj X7L`;KrKWKi8XK5#sj9mAyKw;kr?q~4 delta 850 zcmaFL^MHH8Z$`6;f1K-0Els)X?6`_cic%AExhm%LPCcD>+d#ne`#&zd+q~Md_&ran zWQe(SG4<9pWZb#3R+V{DuTp(H=d}roC4;{dz38@PpEtQeyKJ`8t)M@*ZOk5>-Yj(L z0h?*woz5&jL4()Umu1kbiLwAxD(s=yU}9TCgu0ydo|DOVRoowvXt_S zzkT?p`N!f^?|Zscp))GkCwyZ0WIQR$`AbaX#PIB&Lc)8P4Jw&lcJ2$f-+A|Fxl3Ti zO!v@xZ^dnO&a8R#t3X>oRCclPbMyQ40nV4TKb2ivedvsJ!({ad3kAQl=le68n$+)A z%?GL8!|YMXBq`at_>;F$`;M@@XYiTl(B^jL{ojk_`RYmVFnV9dZ7?&)t5p%c9CHzw%DL$W2TW4O`B1 zF*u#+)zjt6_kY#4{?vByG|=U1{8T3_o%rSDg=71d|CzQY@yiZ_&wQ(cIa4xKu69N2 z+N6|!TSTmaB}Z@B;f diff --git a/test/table/table_without_headings.pdf b/test/table/table_without_headings.pdf new file mode 100644 index 0000000000000000000000000000000000000000..174442a4f732c5848989855d31329e42ae98abc2 GIT binary patch literal 1507 zcmah}eM}Q)7_V*)ICLM%<_E*QQxQ!D*Xtc^&o!{p(u_evZ5;^Z!-Kw*BjpZz*H|cM zGFhDrH8Po|6SHZkpK(r2bQ)3AuuR5+1IJ9GlMUGb-7pb#V8Y%jAkF+^??3O|?|q-& z^Lw8>zbDqDH^dVOBt`%^;ET#IjRwPYyo(b7f#K<_O#oIB9hvhn+z4$flft`!RgREE zIx#_^25O2(P}AsiO=SfHxQVet0ZU54AZL^46d|;k6_C>wi!9Ggasu4Iithu?zcKBCQTagnC%a+aQK#K+Z0fq9UlJC_!{WrW|wc-PYK_ z1>~>R{=E@f{6*x_y5xrKX`OG@zc_2|1=)4=;pp_2mPM!DPRfdJXwSDiT>tatn=>At z%0D@BX9{OVfE#GuLQ2_-qg8gf6kHqvTMVzY58k^w8rXWH=>UJK6*A#|H<`_ zV=7yQjZOZA$5*&y23=PV=XtXEN!~9F_Q=8;tgqK+4!c8AjacuuCzkBU(nP%M>n$^f zU7DvkbpPgPsi*c(a(hnQU|GvBGs*qlLtB$4DbO1^&sVVX-~>sPISf!yHQ(IYc(vAl zrf=Z#7MHK&tiO9k_#9(nTdhC4Z=f!&RZHd>2W7Qh-$ifJ{a+u2n>IC$|I|HNc5XP| zZd}se8oN2Hn`#^XF~F$)^88R*mA((J?#bzzUD&v4=7BGVF5FL!I4}^8p2OOWWVK~5 zy#6Eq{?>ZL{!d-7EJg|PWsdE;JsNkI$Le+%aFW(qw~8nkq4*J5v||8hF&-_!_nx3h`#XoI$QhpWsdR1~PGWmpYC5{jSNalEE0Eu3s!3_kEGMiDu<0dCxY=I)M;%I=N+|Z2_ zq?IEVrA+R+$vrJUgjN+ot3#fVhJha03arqtB4{N|C`f{!2N~=}KNrO(8LMl}$ gBtcVZrCgo#|2KkF7DUD=2Frx1sKjDpQ!@?NzwgBwPyhe` literal 0 HcmV?d00001 diff --git a/test/table/test_table.py b/test/table/test_table.py index 6ff0ac9de..6ad21b8ab 100644 --- a/test/table/test_table.py +++ b/test/table/test_table.py @@ -3,6 +3,8 @@ import pytest from fpdf import FPDF +from fpdf.drawing import DeviceRGB +from fpdf.fonts import FontStyle from test.conftest import assert_pdf_equal, LOREM_IPSUM @@ -126,3 +128,28 @@ def test_table_with_fixed_width(tmp_path): for datum in data_row: row.cell(datum) assert_pdf_equal(pdf, HERE / "table_with_fixed_width.pdf", tmp_path) + + +def test_table_without_headings(tmp_path): + pdf = FPDF() + pdf.add_page() + pdf.set_font("Times", size=16) + with pdf.table(first_row_as_headings=False) as table: + for data_row in TABLE_DATA: + with table.row() as row: + for datum in data_row: + row.cell(datum) + assert_pdf_equal(pdf, HERE / "table_without_headings.pdf", tmp_path) + + +def test_table_with_headings_styled(tmp_path): + pdf = FPDF() + pdf.add_page() + pdf.set_font("Times", size=16) + red = DeviceRGB(r=1, g=0, b=0) + with pdf.table(headings_style=FontStyle(emphasis="ITALICS", color=red)) as table: + for data_row in TABLE_DATA: + with table.row() as row: + for datum in data_row: + row.cell(datum) + assert_pdf_equal(pdf, HERE / "table_with_headings_styled.pdf", tmp_path) From 4df865ac91539d1f5c4cd004cb214faa9e8e3764 Mon Sep 17 00:00:00 2001 From: Lucas Cimon <925560+Lucas-C@users.noreply.github.com> Date: Tue, 21 Feb 2023 10:56:54 +0100 Subject: [PATCH 03/17] Handling page breaks in tables --- CHANGELOG.md | 3 +- fpdf/enums.py | 13 +++++ fpdf/fonts.py | 21 +++++--- fpdf/fpdf.py | 33 ++++++++---- fpdf/table.py | 43 ++++++++------- test/table/table_with_headings_styled.pdf | Bin 1653 -> 1691 bytes test/table/table_with_multiline_cells.pdf | Bin 3284 -> 3071 bytes ...h_multiline_cells_and_fixed_row_height.pdf | Bin 3256 -> 2995 bytes ...multiline_cells_and_split_over_3_pages.pdf | Bin 0 -> 5292 bytes ...h_multiline_cells_and_without_headings.pdf | Bin 0 -> 4966 bytes test/table/test_table.py | 49 +++++++++++++++--- 11 files changed, 118 insertions(+), 44 deletions(-) create mode 100644 test/table/table_with_multiline_cells_and_split_over_3_pages.pdf create mode 100644 test/table/table_with_multiline_cells_and_without_headings.pdf diff --git a/CHANGELOG.md b/CHANGELOG.md index 33f8e2c11..5de6ee083 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,8 +18,9 @@ This can also be enabled programmatically with `warnings.simplefilter('default', ## [2.6.2] - Not released yet ### Added -* [`FPDF.multi_cell()`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.multi_cell) and [`FPDF.write()`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.write) now accept a `wrapmode` argument for word or character based line wrapping ("WORD"/"CHAR"). +- new method [`FPDF.table()`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.table): [documentation](https://pyfpdf.github.io/fpdf2/Tables.html) - [`FPDF.image()`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.image) has a new `keep_aspect_ratio` optional boolean parameter, to fit it inside a given rectangle: [documentation](https://pyfpdf.github.io/fpdf2/Images.html#fitting-an-image-inside-a-rectangle) +- [`FPDF.multi_cell()`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.multi_cell) and [`FPDF.write()`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.write) now accept a `wrapmode` argument for word or character based line wrapping ("WORD"/"CHAR"). - new method `FPDF.preload_image()`: [documentation](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.preload_image) - new translation of the tutorial in [简体中文](https://pyfpdf.github.io/fpdf2/Tutorial-zh.html) - thanks to @Bubbu0129 - new method [`FPDF.set_fallback_fonts()`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.set_fallback_fonts) allow alternative fonts to be provided if a character on the text is not available on the currently set font - thanks to @andersonhc diff --git a/fpdf/enums.py b/fpdf/enums.py index 66b8f8411..1f5c0caf0 100644 --- a/fpdf/enums.py +++ b/fpdf/enums.py @@ -109,13 +109,26 @@ class CoerciveIntFlag(IntFlag): def coerce(cls, value): """ Attempt to coerce `value` into a member of this enumeration. +<<<<<<< HEAD +======= + +>>>>>>> Handling page breaks in tables If value is already a member of this enumeration it is returned unchanged. Otherwise, if it is a string, attempt to convert it (case insensitively, by upcasing) as an enumeration name. Otherwise, if it is an int, attempt to convert it as an enumeration value. +<<<<<<< HEAD Otherwise, an exception is raised. Args: value (IntEnum, str, int): the value to be coerced. +======= + + Otherwise, an exception is raised. + + Args: + value (IntEnum, str, int): the value to be coerced. + +>>>>>>> Handling page breaks in tables Raises: ValueError: if `value` is an int but not a member of this enumeration. ValueError: if `value` is a string but not a member by name. diff --git a/fpdf/fonts.py b/fpdf/fonts.py index f6d0302ea..49efe27f8 100644 --- a/fpdf/fonts.py +++ b/fpdf/fonts.py @@ -1,7 +1,6 @@ """ Definition of the character widths of all PDF standard fonts. """ -from numbers import Number from typing import Optional, Union from .drawing import DeviceRGB @@ -2612,15 +2611,25 @@ def __init__( family: Optional[str] = None, emphasis: Optional[Union[str, TextEmphasis]] = None, size_pt: Optional[int] = None, - color: Optional[Union[int, tuple, DeviceRGB]] = None, # grey scale or (red, green, blue) + color: Optional[ + Union[int, tuple, DeviceRGB] + ] = None, # grey scale or (red, green, blue) + fill_color: Optional[ + Union[int, tuple, DeviceRGB] + ] = None, # grey scale or (red, green, blue) ): self.family = family - self.emphasis = TextEmphasis.coerce(emphasis) + self.emphasis = TextEmphasis.coerce(emphasis) if emphasis else None self.size_pt = size_pt - # Convert color to a RGB tuple of numbers: if isinstance(color, DeviceRGB): self.color = (255 * color.r, 255 * color.g, 255 * color.b) - elif isinstance(color, Number): - self.color = (color, color, color) else: self.color = color + if isinstance(fill_color, DeviceRGB): + self.fill_color = ( + 255 * fill_color.r, + 255 * fill_color.g, + 255 * fill_color.b, + ) + else: + self.fill_color = fill_color diff --git a/fpdf/fpdf.py b/fpdf/fpdf.py index 24bc6008b..30f93e604 100644 --- a/fpdf/fpdf.py +++ b/fpdf/fpdf.py @@ -147,7 +147,7 @@ class TitleStyle(FontStyle): def __init__( self, font_family: Optional[str] = None, - font_style: Optional[str] = None, # "B", "I" or "BI" + font_style: Optional[str] = None, font_size_pt: Optional[int] = None, color: Union[int, tuple] = None, # grey scale or (red, green, blue), underline: bool = False, @@ -155,8 +155,12 @@ def __init__( l_margin: Optional[int] = None, b_margin: Optional[int] = None, ): - super().__init__(font_family, font_style, font_size_pt, color) - self.underline = underline + super().__init__( + font_family, + (font_style or "") + ("U" if underline else ""), + font_size_pt, + color, + ) self.t_margin = t_margin self.l_margin = l_margin self.b_margin = b_margin @@ -4657,8 +4661,6 @@ def start_section(self, name, level=0, strict=True): @contextmanager def _use_title_style(self, title_style: TitleStyle): - prev_underline = self.underline - self.underline = title_style.underline if title_style.t_margin: self.ln(title_style.t_margin) if title_style.l_margin: @@ -4667,32 +4669,41 @@ def _use_title_style(self, title_style: TitleStyle): yield if title_style.b_margin: self.ln(title_style.b_margin) - self.underline = prev_underline @contextmanager def use_font_style(self, font_style: FontStyle): prev_font = (self.font_family, self.font_style, self.font_size_pt) self.set_font( font_style.family or self.font_family, - font_style.emphasis.value + font_style.emphasis.style if font_style.emphasis is not None else self.font_style, font_style.size_pt or self.font_size_pt, ) prev_text_color = self.text_color - if font_style.color is not None: + if font_style.color is not None and font_style.color != self.text_color: if isinstance(font_style.color, Sequence): self.set_text_color(*font_style.color) else: self.set_text_color(font_style.color) + prev_fill_color = self.fill_color + if ( + font_style.fill_color is not None + and font_style.fill_color != self.fill_color + ): + if isinstance(font_style.fill_color, Sequence): + self.set_fill_color(*font_style.fill_color) + else: + self.set_fill_color(font_style.fill_color) yield - self.set_font(*prev_font) + self.fill_color = prev_fill_color self.text_color = prev_text_color + self.set_font(*prev_font) @check_page @contextmanager - def table(self, *args, **kwargs): - table = Table(self, *args, **kwargs) + def table(self): + table = Table(self) yield table table.render() diff --git a/fpdf/table.py b/fpdf/table.py index 47b4d3512..3b1d196ab 100644 --- a/fpdf/table.py +++ b/fpdf/table.py @@ -8,21 +8,14 @@ class Table: - def __init__( - self, - fpdf, - line_height=None, - width=None, - first_row_as_headings=True, - headings_style: FontStyle = DEFAULT_HEADINGS_STYLE, - ): - self.line_height = line_height or 2 * fpdf.font_size - self.width = width or fpdf.epw - self.col_widths = None + def __init__(self, fpdf): self._fpdf = fpdf - self._first_row_as_headings = first_row_as_headings - self._headings_style = headings_style self._rows = [] + self.col_widths = None + self.first_row_as_headings = True + self.headings_style = DEFAULT_HEADINGS_STYLE + self.line_height = 2 * fpdf.font_size + self.width = fpdf.epw @contextmanager def row(self): @@ -32,20 +25,30 @@ def row(self): def render(self): for i in range(len(self._rows)): - if i == 0 and self._first_row_as_headings: - with self._fpdf.use_font_style(self._headings_style): - self._render_table_row(i) - else: - self._render_table_row(i) + with self._fpdf.offset_rendering() as test: + self._render_table_row_styled(i) + if test.page_break_triggered: + # pylint: disable=protected-access + self._fpdf._perform_page_break() + if self.first_row_as_headings: # repeat headings on top: + self._render_table_row_styled(0) + self._render_table_row_styled(i) + + def _render_table_row_styled(self, i): + if i == 0 and self.first_row_as_headings: + with self._fpdf.use_font_style(self.headings_style): + self._render_table_row(i, fill=bool(self.headings_style.fill_color)) + else: + self._render_table_row(i) - def _render_table_row(self, i): + def _render_table_row(self, i, **kwargs): row = self._rows[i] lines_count_per_cell = self._get_lines_count_per_cell(i) row_height = max(lines_count_per_cell) * self.line_height for j in range(len(row.cells)): cell_line_height = row_height / lines_count_per_cell[j] self._render_table_cell( - i, j, h=row_height, max_line_height=cell_line_height + i, j, h=row_height, max_line_height=cell_line_height, **kwargs ) self._fpdf.ln(row_height) diff --git a/test/table/table_with_headings_styled.pdf b/test/table/table_with_headings_styled.pdf index 1614ddea90703befccf0344fb63f46e89197e4d9..9c45c728ee39b28e786eea1cc4e85b7c103c0312 100644 GIT binary patch delta 846 zcmey$Gn;pV17p3Z5tp4ES8+*EYGN)|#hl)$r;Bbm2)KT)an*n9swQ>T`O>Abqui%f zh9uQFq$WG{xVSnj{qtQgQO@@6r1qq%XP7Hfp%h#=`&#Kfb|KM_e`Zf{Y z$FDalyk%kCT+plOXt+;>M_R%>FzAHTs%0Wm+pcogRNdffSN@W_eP83%_l1@}4A)Kd zn|niBzFX_mGNG`?S1X&J|Am^YtcgUOIQd z1Gz-=bsq1+M4ZAaw%_*M6lzspkhHo+X_djXF1LqkAx4OXKUllP$Z1-|>fdia+O9MG zXd-kgcIE8V^Vv>KSwHjWQbW~_^AmMzK0M9bZnxt}_n#h{n^XAXi}~fJXkTy^oNQNm z`?3Cf6MNP3ntOMy-`VbeN|fW{jF3!uV|yk3xLciE?;a)>u_lStF3jaW9bA9A{k_T4 z<5M^7nx$VA5pUe>o$MtbD7#ee`S!AkPh56g|0?_4!{Q=VB@?#4H_LuAtCrMx z&C>&_F6N&?z-d`Qot`i86@=Vd*bzP`qfMsJ5K$-bnRKzt{1Vf zXLVwLhBIvK<+cC!c7yes>QgWN)K9UA|FUk~GdV@Aa2L10YrD7AC-?o z!AV7~DI%&mjFVT-URRN*ljVXKzg|CwFO{|ay3%>0Vc!O+0KSit}U6!H|fzzhRJLjxlW zF(YhZmX?$6vRcQQyBbp WMI{wQscBq>#%2aws;aL3Zd?GhPj37G delta 815 zcmbQu`;}*d17p3R374H6S8+*EYGN)|#hl)$r}J(b2)KU#$EA0hSG$Yf^R!Bam|NGP z-ui|Nnd@s+7fT$`<&f9Y4_9Kd&eT09v37TYZVzU zv|ijZb;941dJCpsf7CL`bp7P^d1X#b=Qv)NOtksB>d~sk7v;NIcI^>R-(t9DvVhgw z7M8h!3o@CUv{&w2q4?$Szb|6-E5+j&mn_l_E#JNB1V{X2!RyC@6uk1Z`1je#Z=0+f zKec?y-XqVyo6ddcn8~Ce>pB1T-=p^WO^0%Y4O%WYRc<+mpX)$^jV$LFRMA+_AGqL+e7u? zUx8*@W->`gIqtvx&mz(JbM&dQhlhX7I`?6T2_sMM60c&9Oh$ty5EuN!Ao#F`dh4|F6u(=QyMFtouRVxbI)RTH@xgwDW~V!rtwN z^B-l@dEeBpi3-0g**HaQ(c*@X`jQ(L|8#AN&s0}=(bM25d@-=$XUUu!cQ@Q_+8?Mg zQG4s2NTZr)V7Np*W4ai;nCaEe_M`v5zJH@3-KPIK+sgTL3{!-Zr~J3tn)#=qPqjUK z40QMfqv;IO+=4VGEPcO5LwZ_SQWI3@O!va%9e?ekwm*2nm713VN_3kaGCyK;Ft9W; zRWJYng**i=FvGymz{~_g%n*y1k(uFSW;W|sGgEVOS2t%DMdT5Qxg|+ nCu0jUS4#sYI~#&3Vj+1Uv8be?C^e1C(Ada`OI6j?-;E0ZKC58{ diff --git a/test/table/table_with_multiline_cells.pdf b/test/table/table_with_multiline_cells.pdf index 2d2ba66456057065dfe06a1b9b5feb400dce4605..73f1bff61daa4b14de1d6d188cce5bd538f1a49a 100644 GIT binary patch delta 2285 zcmai0c|6o>7q=wlN3xH-NtAglv)E?rW*AwzN+HH_5mK0psToT%xiOYV49QRt&27>s zVI-04Wr;|OeMy!PnTQJ4?f&t8?%N;l^VfO4pYM6T=X{=Xp7Zo8ZGo?-NFf23Q|O5( z2;Kk!hqwYpnTP>FG(&2q3PV#+n}#+-0+yCQ6p0w*9}Z9o(sMhA1#l_5uYCDBlJSl& zLR>acfgR?mL=zBv=bqZ8m|$^pPrNS#AxmJfKA3T^r3CSPYmtt!%%-;4L8W@?OGuyt zvvFNX{bdYj;p*Yc-vK+itYe|D+O!=vLGK5BX))*qJYdr80X{NSJCWvzlF`;J(DD?F zPRS~0sEJQ%D^)G^qQ>(_<@sB+JAfC*T_^NrsV&e6RY@av-8-SoD{&n$(;gtbMZc-i z4;I>+_+w&fS<8Kiz^Jsev?=nchosg^2|(kgG8dmq{x0;`Gz8mtHvT!1k>fI0_BZ4qPN+4E%-0mrX}kkdsc$0PVypN0B;bX zEHhk{@DlA*)zbH#Zt!cE>Ri!0J@~@iNl~sbTTK@TU-&yh4m3F8Rd#Zju6HNnJ=oUo z63+0_&AQ&9x`i%0&9g;xqK5Fe?BEXG%0@;SAc{ ziwhR)%XeivPA6>ga_ikzQ@;;Pk(*Ips=(J2+v;1JzbR{>^wQEvG)oTWaZul7?wb#S zG9ze}KZ`2r8k$3SVFjKcA)tUTyNB+c4TeK8DQz%6QRmt2k>teHRUtKk++|SBcLzi- zvcNceB}CE9e?a=AWiI;>ReT|Q*$fL&HO|^r66G3*+Y7lkdskb%gx#fdI2B%hJGYGN zdps_?C)ZwV6Aj8ovz|=WY~QS^IkcX=RKK$EU}eFoeuujkqg@2|v!k&z6dL~TZoc}A zm=BktFGi>&%RjYlthYR|t)+baop^W@d-w<=nChx3kL`y@6r%M3gk z@MG7XbT12S^jvHSONvk|%4H1sKZLsPcbDHQ3xvfLTkm%_Xv@~hX3=Lm{bD5P_l{t? z_AU9|@XxAiJas76jR?AOM{L)Gi2f?z(oD2(&MF9^A57r~ol#s6P}{OdBMKEkKYnVY z*>sx0TUxu*=xS3U`mAy#PnPz&I?49F*-w}s#kXR=&(@*m$v}^zR3)f?3 z+cDL{am7ozCl;nJnyq9>B{eN{f0d24$<`j)D`!3&>02=MjQ6&za6<6py(NB<+i@Ak zcCXaaBsmp@5B3=`)n0bIxj#5%zsa&_leg`t(32G=a%)+dx>-iv!X2fBdszLI8{S6{~T`?T6{F|~@j457!TJ8P794e$2eQgQisb|w_| z;B$JTZ074eL-z6TWIAj7R_{PLL-O4Z+y1J2GAqsLf~~G07yRhjcFInv)wt6%{Jx{| z{;d1z1jyiuOh{FlvIWzpMT1r=k!;(9TNVQMHJsZnk+Hle-Z{RH)O6DYzg@8{as7Pz zj4+@6v0*9WDChNts6qK-yn^fzH_GTY>RUeNej=#i@sBecj2L({Y`oOr$D3io953`|pMV%j$fDR?!9r)g@EINRCn z$Ox%^aA4^U)bgN7AbBOZrp<#tf74w`QETo-@`??E;BmM-$~SA|C}nr?iM2m0O47;- zwge_UfqBO8PIbm0$U_jt=mDuPTmYN~dV2^H0!{(u<^T*wh#*1C&0#nM#N_8}hT)J9 z6r%>P7KAgt0k(n&hLt#yhJ?WXUXTa~@Y8_9k#M75G1M;@0*T(1`?oK`z~mPUX<&%> zUmnuX5dIIQ@n2!2kpb!#qOpMy!&E|*iU44)1Of@N9q#rw1LhDBOn@M^&-l5qh2YIG zC>s>k))<2_gkz0tFg92O+7NAPhrpn1uxJA#wB`S2`26#_`4dSLVo)%EG)9{MT3U84 GIN&eAYxOe# delta 2486 zcmai0c{tQ-8#XbFpE``OmY9e>`}}5@r5VeZ84{HxOJvRHsEh_>s|ML3DZ`hHI@E+A zOOz!CqeR)2EJ-GbHl-qBs&D8!*LP0+@x6b%%X2-?`#kS`-S2%p-<1bc&u&n{0LFGf z0bxi_3=)NO0!&wD+&TThH6X}d1EH`$5Q72C&4IA+P`Y0*5Sf>L{(k5atX$IjXh1Dn zCjH{1sY}PEY&*T@Qu(&qlF~SJ!_mT6cj;KnApOAlPqMSu`&r_xg7;h8E9HgJOP?g0 zgo$Dk&;-F}z?%^Wv!T@K!Ne6cp;vsxbPV*v6U-K6xy?iL7GBy-3+do3f)l)`ay>D9b@P(7V5nKIX1?}myK3M zSQ;&B8W0w7vAIEJ#kv1tJ)2##L5e1DU}4o#lO58pr$oWW?+%}$G4fSk2pn(m+)n!{ zZXB+a*<2k@nNYMl_b0z~OQOw$X#|f4Q1!a!KK7?ZA(kiPKCipBTsLNS=Hf8BazKvk z`#c}EInP7h)i>~S@x?Zm8=PT<4xOYZkJ#Zc9H&r5O-VK9`HjGM7QYQ&tFfh=`{>dm z9b*QCyFGDH&Q8BJko^#r>)rG|RMLWGyo;z<_WrQDOA#J#^o*@3uyniK8#9ih5Fyvg zZwL3G=9`FlZuQN-%LSwrVz}`|#KBJGs6NsJydqL8SKmr}B72u?Qs31Hvls)N>NU_zR z?be&bD2I60&tJ_aEsvg%ZFOcz#id8R3-Q>>Dz(p+e3_-nqEEX-36cF%jM$rF(BCqI zJD46MvhTjUWsZ{@pDU;tYqg;?^j00*4cW-+j|{867f1}*LlwksyLick>^s5M6eGKJ z_v)?lcWw;MVrE=tH8k&(3wXm_#i4Bl2aUgQ$S81`&u{167rb4CfV5z$yNlIiWap*R zE!H#5eOy9TAA)@%s2?ePn>|!^aU8)O7!s9|xt!}TeQ>Xw`<@LKmV_mC^Id^zGiN$w zHp>$@{DBdXM-GvLoIbSMx5qTIx&sm@nA>#8r^zVCHz1_TIYuh()GnYm;p-P}j{C)< zoTe{WLp|^o^l|SM{nsHpR^yCNJ%yX7Ac566HS?CAjg)itnW4&Ugx(YwYo z!e6oT1MGgMtw$H(g?R5>EpO%r?qs>%{BgHwZ zE%%wXpsLg;Z0V`onD+QS%l5R6ftxFU-F}{*x`e$A`z<2)NS`iCBmA2cv81!C#e_!a zaGA0{D&0$U9+iws4`O(>R$4$n>)fEh@fb@U+DGZ;KK3iQCBatF7DxJfs5>{xRXtbN(pbM zbYHW)TD#ekjti74{RS*bl(e=^aaX}B!S<@R;wCKD9;vfHzb3R|V|fp7?Q2Q@gl|3;wN|0Jg>Z&&;htZf5}~vQa%Um-Eg&&@ z**@iR%d3|#DzsD$PNS38!riKpmr19}HMG|Xr%lqJOSJg)lB^R4x2Ozp5SpGyxpSJ@ zfMn4XEqTYO6j+ISa7tm#i{qVF4b?^-2kl)-ejqzHq8nuuAQO4{&q7^ClzStSdf7nM zOY5eYR+wHRqX(AO_kuW1)h?Kxb@=Gfg!FC?Pt<>O9WeU&a*G{OQKZ_JI|R(WA$puS%Mmu9R} znReJWi29^0E}@Vo^7v7EO760|PeilVAMl6m%~J;|gCp4a+=pQS$M@Y^&~IUWY|Jtb zYt8T5N>#^95Wb5y5B1gmN>IYz2x{dQMz9od9ENG!jIy*8-LhG<=63e~Hniza~awLDbK|XdLR7BxpS9Z^eX%`UM@L zhpv8S=b&gh5)}1IP9Y)TNYN`+ps-~Gh9JR}1AXO0MS7CRR0_qKOt1p6AckrRQcWnP p1T29n3{9h z*>M$@6s0ESa#hUfop!e9wt_&z`^qlcW#XZKI8I*oyX>4lcNf2d>ZD5(Rim3!`r}(v z4D8E_Kk`(#*XaD#P5ALIKrECupFh6u!%u0ZBVC(X9vj=pUe}cIdALkL)TBd1v{iV` z;a%Gf%hfsk`M*$4;_h)Xg&Bo{C)Kyrcg8dvR9fM{d&M{Sib$WVjoseWo!egt%lwZz z^MAdNYeJTD7e_xV`uAqf%qQ`aT-G>$`si}B z=J$-0AkT7}&3BzoKKQ}b-~6tcZ+-Im^Ih7Ek3VnDQEk6`<9kq}f&Fc^2kp;Q8TGAI zEL7@`?Cknr@w6{_)#L>4%YBD+^k!*4ko^!Bx5ehL0pEtCvSfQdgA8?^$|}3r%v3MWpid>RR5b$o=LMy zI?k=BnM7I{m$lOP-!c zy&_-5j>NcKC+6N01O}A#g3Olp_Ggx}On*AB%X^ck^^$h}{I6l#GLF4E71_&`cFeo; zPtb)^`>rovs&}M*_l&5_E*Gh_;oI8^!zRDGv}ozV%O-`h-25*0T>f(EWtDc+I^WgS z{)^wVY`no~q8;(;%u3noZIczb<}T~JY*I8UZO*cDnK34B5;~7y-63MWvZ*y!wrv^9h1yIc{Mj?+Uo6LEN`Fu-8E;&*^i&JHn={ts*9R#Q6jGX z?$L?ZIfdfJ@zYB;&q~U(xg7Auu(*E0WHWaA?BuS$h4)hOQ)F&+3s)DW=%2gMeK%7v zCM;A0K;O&1U2i{mGtrp{(5fjpe>u@&C6p zc}&?+6?DzoRSukBSL~B~=z1`&^2mpCKlv*iIB#*K=A}S$8jzKrl*KjqH5e8(QvXd zw^6;3f&mC9I{vIF~p3F%rNvC8Jn3v^eQ1NHZn28 zaEy_uspVuj9+^5rF8!eV{1OGA3Sfz(@0pjDuV82Z<+vzB+c+DVyBQgpSsJ;xIk}mc vIa!z(7&uwFS(rMxIJ;PyTG$a*5eq5H5{pVIic-_KjLeJ-xl~nM{oS|#yBQU3 delta 1451 zcmdlizC&_?w3soMzISFyu|l-5f`LL1mnoPupQwF}$nyg(Zn&Z{!r`Z35$0;OsHDRx-RUyueudybm*%UELp3! zzEZgRnDyxT%a5`@{dzZf`Z~+v1J_I1C-=x~SCHbLwb*p6&G$vk8j4%2zOQQB$X1?~ zxpnV>6=82@yf}2^b8n}fFMsDvkv=uAM;1~(TP-9T9n0RNT#r}iS#?qCvhVGz@7tcR z`zURz7dy)szjN`8P;ssP?8)OYkYfWnpy1UgY{qk zJJ@SQl+@XEEcIt!YrTf~pnSO1+bvwFc`4BFPMv(2Lx{^cKd&S;ucTPPV)8#0IcO|R zw&CQNtjQ=-Z)$3Z5<|69&R&|WAky}IXV+#Q^ALwWH_LA6?RtIXJ=2O?e6ou>o%YAo z39_>InECPTo9KS7Qsu+jNs3{Iem@OnmfxRrfc2D7M%}^b&zxQfiCTutP?~m__uH(g z%j6!gAK?rWS+Q(eobbag?P?fZKjp2lifgK+iENDLwAzMe=TH4)2vR)t zNBP^NU$%>WpN~`VyuiSu9K(28m)Wg#-R$xm`#dv_8my4+5d2mD_YT*|r8C@ie7vvR zUKsUc%`RDqebp&a3eQWOT$~p<9}-TT*0E@kp!1QbZywtDFM93H$^75)Y*J(0#071Q z_iu3?`|4irwI%;SM}*H4=IXOSi}q}AVF`83?O3+$Y3=E!+cu_WFE4y4?{)t|`tm27 zg4~@2PDhlKYMfkZu6yjAJJE7#oOybS>x;M6w_Q{hKK~H#?Fe50W3%g`lL}8K8XrIM zQ9qsWxX<4$<(Crzjw&_qJ1xGOm~A+pb$V9Z?X21gqcfUMx$B=F5}ocb-*LYBp6zvV z=k_dJxZUL2x1*6q1-99JoMx48{I~P=9#bU^_4m)WK7Q8o+mZi>mB`v%-F?|JFYjEk zaJNd~bhmetgv&FZJ>Rs(EO-~^7xtrDW;V~5n)heX7R_gm_FOE{6y|)Z+PPO{)ATtv zykoW-xc$`YJ}Q|w|ERh08>Nu44H1GuQQkt?o+)n)3;&#sJh0em?fQf1*R7I%{kR^( z`|a9Yk0}*ZLD$5c<<{*ua`N}1<(&FlA5T4Qia7V*b=ieA$muOFB|j;P%W|?Ur}X5n z9PUhp20&&aD9O#|6yvc37Zv($MhZaj1DpSC<>!|u0CfQiNqx_}w0s3a7{^5++Q!h-%)rgk(!kWw(8Sonz`)JX s$i&Un(AmYs+0w|=+1!q>idaa-O)M&@C`wJ^GO{o+;!;(0^>^a}00bFID*ylh diff --git a/test/table/table_with_multiline_cells_and_split_over_3_pages.pdf b/test/table/table_with_multiline_cells_and_split_over_3_pages.pdf new file mode 100644 index 0000000000000000000000000000000000000000..a6941948e67de4e8d3396d7dae0ae2a75a26be4a GIT binary patch literal 5292 zcmb_gc|4Ts+qYDh5h811ju0ozVw~vm*h;=6+Bw(JLYWkF0x~;7e(4pBfZy2z&{`8KpFB2#dY+^3Fzn-Skeu%2)C{=M+ zHl9=PSnpWngy7T3Zi(l-xiv{ukvLv;UJ;Qdpz$n!M(6=OB%l6@@M}HoMO)7TbIEyy zW_Ewth;cHP`^OiJoK(%Rz0!td+d?$?k{89Vyvx`mtYp`3T&s+`aZr!j`q*11k6@p- zk)1|!t5xs^GJ2v9Nbh5s#&T#>@d;WI0%0!KbFaKu|w5Oc?oiDr{xc zWB!=IUvwNQKMo`}&%1|jPv%Y({iWT(0 zOI23S=TdO2Du6rD)+Zqc^k%quxgy`-u86OEkJC^DmG^u%%}bCqd5bHY`gN6suVP?C zvg)hNjc3YTxv*z15|-AH0`wqBh zB^6W$0_WV8)Ip*u@pMOQG)3TX7BgeJD(#oxLQ2QU+vx+-OR(PB_k7|>$JxIkI8qV0 zbz?R3s)}mJHWVy0tZbLA%xO35v9V=f)c1w^9jzFsx4Y{9h7pzj07e+Py9WOaMxan7 z$WJ)((lbYer)@qkQcF!xf`iB1q!p3lX@p;8W`AOTS4e2NeWv|dT#CRS&x^tL+%_;P z*KC61(T$mAa!-Nli=PMg25yJ2CUM~0eW^)N7~ZQ=7SgUaEL@fm5|2T4BVR&XwY`lz`VU_ui|K(=&9F#n+h^swTZ3@`1rfQQot&{9^4}&R21@ ziu^Zog})fpgI74cf!=u|f&n3cA0K0BdaBV~Ge((^nuCWDZ(3G>8T&SFG&B4cGAturSgscM0Bo!s&jifD4DizJR=|o?= zeDAA|(8``?<_g0l`zq5K$Jx|R9=I4Mcvj9)@tGBm@r{Q^HqGnrnINn#l#h@xsVXeP z>b3nJO!^=8h{luTe9=_7(Sc5Nsxua&sy%kDAx`d(nRA)RAAZ6;A1?C8*pRhDRj*(r^c424qHnbzpqLHI`-VZnspT;V>1m)ky7 zchm5e$GvENzc)a;I!lTK&DU1)Zn0cBMAHT10grde0q^62Z6g@ku{6Yb;{c9 zLc|2U7J41i9E0LWrlfPmy2h>_?ZJ)knBi2XL06BAb1pac=dsPUlKM(lua{n-3OtU9 z2&LXzVTndBP}-=9!N)&*25CkQcOF?4)t)u`_TWmRjK!LMF?Y&VH8L_`9>0~*bV%y1 z;H+Yjgi_@F@cq={2D>sIma$<0D@)y^VqY_xv_Hqbb%@r~3=AqfI6ZU=a8a?TuCcC&8+GK2s zbmif=jo$h7=r&C;N&M^joWB}!h2D_TExQc~yOOS%{f*7EP~h~hXvo<8?Sj|eXbArg z(2$|KYw+LEP*wRSH0-!YN5inSK!CjFAqh#I(oVz+$BT$54f?JsTU5bKL2-Ni0Lo}D zFS%}N4E61%R^beoKiWU&j*)$w1NhO%6H-u)BtOU9@m15e#ETJ!Z=OzGNK2G8TZ;bN z5@wK0#2)`D@qW$vdie8JL-*5*kuJc~a6T8g3~5)R$Ve#zL!!KIz$H1$VY!hfa}FUJ z-}3fE+J)zgUg{Z(Jk@fE^6GTi9aPG>){GTtap2VWLfMvk-O;DtqIt2+#a}$LkXnLc z0=G`+GT%4Ok0m{Nav@JZ;sUJW=9cKgm4;VQlAQxp3;K@wx6Nn-cvT-_)4PH`PHF6Tig?4p8zIbh3Dv z5~c8l`@7b^-V?FrL!?Sp;#5t0#!t8<=2)DmT7~k=&Id1b3Cmm-;%AqHG4-6K?tO!w z@Um9Cek~^F)2m6_gvy!e24OSzrI3WZz$mu8JQV|1uRMG+5s^<=G+xqrD(>m>A*UlB zJzrSj&FoeHrL6g(R?5FU<=Vp~11{nTKV0OSrvsWU+_28mRT$3`O`PAq8FT-ot}fZM zT2F>j1F`pilF;X2w-|Z!b{WgyHJJcIp}PwFncdj~5OBkn{G>mh;T$F%Cug!Cc+^^L zHfIGvpdbpnS>UIfFQ#?1gjiWWT1(y5gaQL%Si;e>GimA$6`{SngmW{?B+J4}Dl;xK zGTz#{j%?1()*lH6>C>VkIh~d+ZOk4rUR)lGu132ii66F^@ozPD4|V3fQ*Xgk7Cx8G z&zZdR`>e{D?U(SWmRkbsnV3^bLDbc-ZA~5^kb^!AjTcMZrFBN1pW58~awp+eLOgR2Zd` zR%EO!Fo}IBaKY-?Rh;w0zU>1^M`l0y8ho@ps3Ygtzl2;@iT84Hi8fm?$P4IFyBd!b zy&W=;CHkt^^j6DbTG~~b0dtE6P5vb;h!u8IB)8$K(6k=gpBm@uXUdf`og&1IJ6v7p zwv2JTONko?e&ZYBkuQIA?ed*7XQLmQ08%{XKGk;LI|})H_Ox^p02v(P1K@7nn#(?> zS*88wMX8xjk4%iOPBnI+`@=d}X{&M?X$lrh&}&7>_GrgE;auAvh+5_FgEYfa;6F0!@@Qz4=D4-?{t(d|apC$%5b4cp9O5K_xBHl5X zB~mjCnOo4aQ%cT(_OjIa@b=sSe0B*=J>9uEHs7l%gDebhJlkhy%Tt<6-pwflBC z0*1bxyE(l|s}F6wR-K|Mwdq-or~lZ}-i?Sgt2NDI{kV)z9Tar9^tMM(Et+XC{T-Nd zbEeky^c+Y?Y28z$kG6R zOC-ylEp%M67h*gxZTt)6jj!Y=eEyT=kS5C9P=kBw&}xCgMpV3b0tji$%1edooD}OV zDqdh&3uxj1#)xr7MS2(0gn*cRRDN?LZlUFe&b=VqQSd_xL|89Sy&#JBp&8-WUKdgcKPP<5#1VpLow| zh0|<=fZ7+FHC4`?UplrOY>IJXLD}z)wiCkg(|>#B-@LIuO;kkY*Y1G+NV*`gUU)+~ zQ2_#5xw_%KByAkx_dSE4fre9D!mOZ0Nx6#&4N-j3uQiiJV6KzFGSh7CsH zzaL=$9=N zaTEeMD*J;r#S`xYfPkRN0LFm7E|7|{vZ6A`3H0AG`f6odAmZOL`YG%e84OC_2K_V+ zhM@0c{waehGLrsThM>>YKV>i#2>nd>vkd-=4@Cq$+MmWLL4J)zNlEn=T_xrJL8hYm zi(k6x4>GbR)|G(w+@S<5UH$Nk`2(X!Br=H6Q}n_b5uHdN#tiMe=z}mCx(HpU9zsdg z0IrNg=;;~g!E})@C77ZC9I1pxns zROTThrEDo0*?VVt((mc%cRlZQz3=_U_rB)b=X}nY@43F8`#vA}6NYG2s2Usq1wlY0 zM|XgZ4ghRG@+Fc%2mts9&e;cK2WLI90H}XoHNUS~?A0CsK8kh5Vf0B9kR60&QP)ye zgCRjk1XK;F#d>Px?}-J0PhecJJ^)=^0G8;?P5@(hZYDbJi6!bek#QvAk1QZC8b>}1 zBKqR-EC6<>8OERFO9p|D6R`#)yf1eQk7nn+lvX}upDfVQq8nBs zab)|E8;aQ6?nN%C;2pAas57}$R}}fyAy2)CsMv+J?Fwu2cMedwtfM%0C_+k4Qg$$% zy0R#cQ&4p9?q!uZ30(l6HTXb8-!`gaXp|$*V_Thp{ z_(wNkdtUe4vfB*^XaSnVI+j53t0!-rDwuZUH_W&Aq_WpTT17crs?esk>ka2ztw?&} z;4I0@%{(0GHu^*&tkr}7Jk&|B^JQ`brd1xiLv$NfVtn)tumneHY=?(l?%zJ$oc`*j z@Ty2&C6~C$+Cxm33cqQ;XM1S#on_a(OqX)E8DcwN0E)}iMwfGaaxee1+S4ue0xUU| zH68A9sc@X9LZe{MegI*1s{*=|s_a7SONuPsf2K2WP|VOF291cxtm_@7bAcZEXet}{ z1%$+F0{D|o`z7Xp28SCLX!%C>#QjzKTwXxwa!RY-5pAh{hO|qi@(G zx2yN$!rHqN=a=-$(rP%JYPcjT7BuxR3zU#3^BIypo@+exrWfsz_|&pYnyGq^MViQ* zMO=2mknE74E$B?RU$WQ-%H2<>g4qck>wl@ez)v>^x1?qckF)}_gPv^5dQEPmd{*$A zXbf&v{&=YcaLDPf`Ky~y40PA}%-xauqA@{n3vne2frP}uE3*d+;tPd3JVG~SQtGW2 zqgP+P^=m?YDHluK)mq=uv?4B#RE>=zU(}^itFis@6$9_K>>SaO$jhSDH8kO7@ENCE zUHKgGMrAgq8W688M74q)c+4idMTRUF0 z9&IV9qg-F`sh+w1fH`}p%m3IxHaYz`u|H^vO?R8e{U?8D{15!Wj@<xI)P^M3nvd#MGrI7#Rd=yr`LO? z=<+`E&%#`cOoHtrMgg#FGzVt#j`C+f2M26qGG4kQ;D#i?v;?m!5NaG?LKUD(qsgqx0-MRraR2%>%DoJro;Q%1 z(!GkX52rFARl;pe?WufQSpnx@4(H8e#xqXk+ATP_Map}KmERY_{VPb8CMA0RW#DP~ zlm?-vg^^JwUcb4;8Re`Ra@eIx_=cM~eU*3D@Zpt-RpjJNC4;KPui^RXVIk#$xslpR zyr3P?9I`&41wcA>&b=p2IbzCevF4+AKiZH#{-f`DR=PcI$J6U!wA6dZ^9#oWZA0fK z#3<9M(mBRP%OeQ1G;_a9^sw@{BciAF8ln5uVDI(}q3k!WCoi|&-oY8^ zKQ*aOIlgc|p*@2n4aFr1hNY5N|Ho1l4bWNR3PcyGscj&y4-ao4=k)C=hf~(8-y@^EMmAh53CC}LV$EigT*=860 z%F%2}w;jjzEO< zNJK8mcdJt;p-n^jSl4p!+N^KeRiwYp^c9XbIs}Z(owzk$<1X5~gmdu9o|4`NEr~f= z0ZE9n(xPXiY{5t8o%JO%@4Vr2E9A8dkD+;d`BvTCSn@lcu|M24>E|b(A^!(HW5;d+ z{v)43q0qnaSw}*VhCuk&V1TNkgbbOhqTs+O=alFL4sL{^sn=&uEmx^S`tHv`m;t;F zaf1G(_sgjJuH|tw{M5Bf`sl~E1EW3(MX?s%7Zpc8()pjX#~!hm&`G@fML-l=AGT*% zW%;7Dv*}E!P)0F#Gls7Q{ESvBXVhG#e=Xohd+gxSMq;h6i*&UDjrjCxsomZqb#8sJ zL5C`23j*ra^gn((Wi{`5DeNBC{d^fwVN@)@*<9Gx%?3JY`|y-&4H#)>uJN`y* zOH)2dQl2BiwQ#-}KG~Y{?S(;+q8++x1wtSI-HyaH20TwJNEw&a7UTxqXhqGR>EhYS z`MEA_6fgcoKlsDrhGX>pC*VcQGA)SBXR}eC`;K1L-U8f(w_NHE^*GQ59Kv~e;20z6epH-bu} z*7a3~F}X@(gW_0}GUZWl-hmd|zZ3s`RY|F5#rl4%uE-+ZBRUUlM0#QhcTV#mmXE(N48MvzBkdrZT|;|-yi+&mZ4kmER% z&Ec3lctdPo#--SI@dYK1_?ZP)@KVf?VVb%FmQRD%P)9=*0GcSkRS94W1){aHjlNzL zgxm*ac+pKBTNDpBY78g8Udy>TM2(G2!g}4*f@WLemK;rR?6ykigUPcLbGqA@h zfVCR@7z()RIMGmmsp zRlLA8+zd__WoCJtCV9{v)%&uD;CmH^ppG1`??Np;yuvr6nE{l!Fi$?)bQ>LVl|LGl zlp@oqa&MmJGXqghyzd*B2gEZ32_Ij^sBuYf%Lq!aIv?|#QRR#jx6(CMQyKJi7#gWa z5uijC1z665742GfUToa4C8{MXlrs|NtX=6Tk8%+$+%s`$_8f0s_{FBxHf*B!b{;Qi zUJ_WxuYRYnn4f9pz8<ztz|GQoj=(dq&;lr=NreWzVUs3Gcs}0KW%sLjDuw z!C{DB7|%DMix>*pW%O0I+5VWOmGJT(8U(Rn^>Y4m&lM0Go%!UIB`kOE?mVE0n$*&c zKsic`V*+2s-8{*wCBjLGNc2Wnip~M)>vCNnoGC2)rLpv+yv7n^{p4lOinqHf)A*WP zfOeYqLQQ#-1s-2J8A-it7~GQO)*pFjnmmzTETEpF9Mx3^{uSPyrd_scjF z_1dtRYRM6JHtNMwwZ&sekmSmu`2%|j>nEuR)(8$4!meq5w-c8<}9)G6OJy={bqQ3H;Ib+Xt-RqcDbx_CvJcKbP7*A7F zYmIVx5=!8=>o)K&qik#eH@8{+-d^Zm1q*$Q4;IZD@;NgPp+=!4rd0Kk^Mj^yw11Y4wlZpsL340h*!%mCl@fS(O#i6vIDbp6jpXDg;j$Ifu$Vi|F|3cxSQDj75Eo*f+ZBNB@jcFmH<*RJOI_w z(1OC?P^cD!b)AN4DMBEM%72Nbcw=1v5D*jrU_1PIfi%?B;p!k4(Er(32Y`Knh(B#m zC`-inn+*nKeHr}Srp0=>|7wH6A*_k$?=~cBsQJ|fQ-}YC2h)K5h6hJNSYpesv2Y~v zxB3t;B&*TC`XS)|j}4*8I@+6lWN!=(kM;g8W?AAcVA*>GwjhznpdSj43DJcFg8nIN zflUlSb~>6!Jp%(c1Z@aKBN0d>45p4S&{WqlfEXemhUzd)-T& Date: Tue, 21 Feb 2023 18:51:33 +0100 Subject: [PATCH 04/17] Implementing table cells filling --- docs/Tables.md | 179 ++++++++++++---------- docs/table-simple.jpg | Bin 0 -> 24560 bytes docs/table-styled.jpg | Bin 0 -> 24132 bytes docs/table-with-cells-filled.jpg | Bin 0 -> 23937 bytes docs/table-with-cells-filled2.jpg | Bin 0 -> 19463 bytes docs/table-with-fixed-column-widths.jpg | Bin 0 -> 23447 bytes fpdf/fonts.py | 20 +-- fpdf/fpdf.py | 73 +++++---- fpdf/table.py | 24 ++- test/table/table_with_headings_styled.pdf | Bin 1691 -> 1694 bytes test/table/test_table.py | 28 ++++ 11 files changed, 191 insertions(+), 133 deletions(-) create mode 100755 docs/table-simple.jpg create mode 100644 docs/table-styled.jpg create mode 100755 docs/table-with-cells-filled.jpg create mode 100755 docs/table-with-cells-filled2.jpg create mode 100755 docs/table-with-fixed-column-widths.jpg diff --git a/docs/Tables.md b/docs/Tables.md index b7ba46343..36163699e 100644 --- a/docs/Tables.md +++ b/docs/Tables.md @@ -1,42 +1,108 @@ -# Tables # +# Tables -Tables can be built either using **cells** -or with [`write_html`](HTML.md). - - -## Using cells ## - -There is a method to build tables allowing for multilines content in cells: +Tables can be built using the `table()` method. +Here is a simple example: ```python from fpdf import FPDF -data = ( +TABLE_DATA = ( ("First name", "Last name", "Age", "City"), ("Jules", "Smith", "34", "San Juan"), ("Mary", "Ramos", "45", "Orlando"), ("Carlson", "Banks", "19", "Los Angeles"), ("Lucas", "Cimon", "31", "Saint-Mahturin-sur-Loire"), ) - pdf = FPDF() pdf.add_page() -pdf.set_font("Times", size=10) -line_height = pdf.font_size * 2.5 -col_width = pdf.epw / 4 # distribute content evenly -for row in data: - for datum in row: - pdf.multi_cell(col_width, line_height, datum, border=1, - new_x="RIGHT", new_y="TOP", max_line_height=pdf.font_size) - pdf.ln(line_height) -pdf.output('table_with_cells.pdf') +pdf.set_font("Times", size=16) +with pdf.table() as table: + for data_row in TABLE_DATA: + with table.row() as row: + for datum in data_row: + row.cell(datum) +pdf.output('table.pdf') +``` +Result: + +![](table-simple.jpg) + +## Features +* control over column & row sizes (automatically computed by default) +* allow to style table headings, or disable them +* handle splitting a table over page breaks, with headings repeated +* control over cell background color + +* allow to embed images in cells + +## Setting table & column widths +```python +... +with pdf.table() as table: + table.width = 150 + table.col_widths = (30, 30, 10, 30) + ... +``` +Result: + +![](table-with-fixed-column-widths.jpg) + +## Setting row height +```python +... +with pdf.table() as table: + table.line_height = 2.5 * pdf.font_size + ... ``` +## Disable table headings +```python +... +with pdf.table() as table: + table.first_row_as_headings = False + ... +``` -## Using write_html ## +## Style table headings +```python +... +with pdf.table() as table: + blue = (0, 0, 255) + grey = (128, 128, 128) + table.headings_style = FontStyle(emphasis="ITALICS", color=blue, fill_color=grey) + ... +``` +Result: -An alternative method using [`FPDF.write_html`](HTML.md), -with the same `data` as above, and column widths defined as percent of the effective width: +![](table-styled.jpg) + +## Set cells background +```python +... +with pdf.table() as table: + table.cell_fill_color = 200 # grey + table.cell_fill_logic = lambda i, j: i % 2 + ... +``` +Result: + +![](table-with-cells-filled.jpg) + +```python +... +with pdf.table() as table: + table.cell_fill_color = (0, 0, 200) # light blue + table.cell_fill_logic = lambda i, j: j % 2 + ... +``` +Result: + +![](table-with-cells-filled2.jpg) + +## Using write_html + +Tables can also be defined in HTML using [`FPDF.write_html`](HTML.md). +With the same `data` as above, and column widths defined as percent of the effective width: ```python from fpdf import FPDF @@ -46,18 +112,18 @@ pdf.set_font_size(16) pdf.add_page() pdf.write_html( f""" - - - - + + + + - + - + - + - +
{data[0][0]}{data[0][1]}{data[0][2]}{data[0][3]}{TABLE_DATA[0][0]}{TABLE_DATA[0][1]}{TABLE_DATA[0][2]}{TABLE_DATA[0][3]}
{''.join(data[1])}{''.join(TABLE_DATA[1])}
{''.join(data[2])}{''.join(TABLE_DATA[2])}
{''.join(data[3])}{''.join(TABLE_DATA[3])}
{''.join(data[4])}{''.join(TABLE_DATA[4])}
""", table_line_separators=True, ) @@ -65,56 +131,3 @@ pdf.output('table_html.pdf') ``` Note that `write_html` has [some limitations, notably regarding multi-lines cells](HTML.html#supported-html-features). - - -## Recipes ## - -- our 5th tutorial provides examples on how to build tables: [Tuto 5 - Creating Tables](Tutorial.md#tuto-5-creating-tables) -- `@bvalgard` wrote a custom `table()` method: [YouTube video](https://www.youtube.com/watch?v=euNvxWaRQMY) - [`create_table()` source code](https://github.com/bvalgard/create-pdf-with-python-fpdf2/blob/main/create_table_fpdf2.py) -- [code snippet by @RubendeBruin to adapt row height to the highest cell](https://github.com/PyFPDF/fpdf2/issues/91#issuecomment-813033012) -- detect if adding a table row will result in a page break: this can be done using [`.offset_rendering()`](https://pyfpdf.github.io/fpdf2/PageBreaks.html#unbreakable-sections) - - -## Repeat table header on each page ## - -The following recipe demonstrates a solution to handle this requirement: - -```python -from fpdf import FPDF - -TABLE_COL_NAMES = ("First name", "Last name", "Age", "City") -TABLE_DATA = ( - ("Jules", "Smith", "34", "San Juan"), - ("Mary", "Ramos", "45", "Orlando"), - ("Carlson", "Banks", "19", "Los Angeles"), - ("Lucas", "Cimon", "31", "Angers"), -) - -pdf = FPDF() -pdf.add_page() -pdf.set_font("Times", size=16) -line_height = pdf.font_size * 2 -col_width = pdf.epw / 4 # distribute content evenly - -def render_table_header(): - pdf.set_font(style="B") # enabling bold text - for col_name in TABLE_COL_NAMES: - pdf.cell(col_width, line_height, col_name, border=1) - pdf.ln(line_height) - pdf.set_font(style="") # disabling bold text - -render_table_header() -for _ in range(10): # repeat data rows - for row in TABLE_DATA: - if pdf.will_page_break(line_height): - render_table_header() - for datum in row: - pdf.cell(col_width, line_height, datum, border=1) - pdf.ln(line_height) - -pdf.output("table_with_headers_on_every_page.pdf") -``` - -Note that if you want to use [`multi_cell()`](fpdf/fpdf.html#fpdf.fpdf.FPDF.multi_cell) method instead of `cell()`, -some extra code will be required: an initial call to `multi_cell` with `split_only=True` -will be needed in order to compute the number of lines in the cell. diff --git a/docs/table-simple.jpg b/docs/table-simple.jpg new file mode 100755 index 0000000000000000000000000000000000000000..cb0f0ae2c12f91d68153ca9e505ff900a7ecf0e2 GIT binary patch literal 24560 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 z%0D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 PaoZ`SQI39O{j2Y9*I4W; literal 0 HcmV?d00001 diff --git a/docs/table-with-cells-filled2.jpg b/docs/table-with-cells-filled2.jpg new file mode 100755 index 0000000000000000000000000000000000000000..1b2e015ec4888f111b1ca8a475f6713ecb5c9747 GIT binary patch literal 19463 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 aHS+O4L|jyCKBf2x|B{Zo_fY@%?f(PvKVnn> literal 0 HcmV?d00001 diff --git a/docs/table-with-fixed-column-widths.jpg b/docs/table-with-fixed-column-widths.jpg new file mode 100755 index 0000000000000000000000000000000000000000..240261a96b5b3c4558cdbbe4563b9f16b6db25ea GIT binary patch literal 23447 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 literal 0 HcmV?d00001 diff --git a/fpdf/fonts.py b/fpdf/fonts.py index 49efe27f8..78005bf19 100644 --- a/fpdf/fonts.py +++ b/fpdf/fonts.py @@ -3,7 +3,7 @@ """ from typing import Optional, Union -from .drawing import DeviceRGB +from .drawing import DeviceGray, DeviceRGB from .enums import TextEmphasis COURIER_FONT = {chr(i): 600 for i in range(256)} @@ -2612,24 +2612,14 @@ def __init__( emphasis: Optional[Union[str, TextEmphasis]] = None, size_pt: Optional[int] = None, color: Optional[ - Union[int, tuple, DeviceRGB] + Union[int, tuple, DeviceGray, DeviceRGB] ] = None, # grey scale or (red, green, blue) fill_color: Optional[ - Union[int, tuple, DeviceRGB] + Union[int, tuple, DeviceGray, DeviceRGB] ] = None, # grey scale or (red, green, blue) ): self.family = family self.emphasis = TextEmphasis.coerce(emphasis) if emphasis else None self.size_pt = size_pt - if isinstance(color, DeviceRGB): - self.color = (255 * color.r, 255 * color.g, 255 * color.b) - else: - self.color = color - if isinstance(fill_color, DeviceRGB): - self.fill_color = ( - 255 * fill_color.r, - 255 * fill_color.g, - 255 * fill_color.b, - ) - else: - self.fill_color = fill_color + self.color = color + self.fill_color = fill_color diff --git a/fpdf/fpdf.py b/fpdf/fpdf.py index 30f93e604..c1af656aa 100644 --- a/fpdf/fpdf.py +++ b/fpdf/fpdf.py @@ -963,15 +963,21 @@ def set_draw_color(self, r, g=-1, b=-1): The method can be called before the first page is created and the value is retained from page to page. Args: - r (int): if `g` and `b` are given, this indicates the red component. + r (int, tuple, fpdf.drawing.DeviceGray, fpdf.drawing.DeviceRGB): if `g` and `b` are given, this indicates the red component. Else, this indicates the grey level. The value must be between 0 and 255. g (int): green component (between 0 and 255) b (int): blue component (between 0 and 255) """ - if (r == 0 and g == 0 and b == 0) or g == -1: - self.draw_color = drawing.DeviceGray(r / 255) + if isinstance(r, (drawing.DeviceGray, drawing.DeviceRGB)): + # Note: in this case, r is also a Sequence + self.draw_color = r else: - self.draw_color = drawing.DeviceRGB(r / 255, g / 255, b / 255) + if isinstance(r, Sequence): + r, g, b = r + if (r, g, b) == (0, 0, 0) or g == -1: + self.draw_color = drawing.DeviceGray(r / 255) + else: + self.draw_color = drawing.DeviceRGB(r / 255, g / 255, b / 255) if self.page > 0: self._out(self.draw_color.serialize().upper()) @@ -982,15 +988,21 @@ def set_fill_color(self, r, g=-1, b=-1): The method can be called before the first page is created and the value is retained from page to page. Args: - r (int): if `g` and `b` are given, this indicates the red component. + r (int, tuple, fpdf.drawing.DeviceGray, fpdf.drawing.DeviceRGB): if `g` and `b` are given, this indicates the red component. Else, this indicates the grey level. The value must be between 0 and 255. g (int): green component (between 0 and 255) b (int): blue component (between 0 and 255) """ - if (r == 0 and g == 0 and b == 0) or g == -1: - self.fill_color = drawing.DeviceGray(r / 255) + if isinstance(r, (drawing.DeviceGray, drawing.DeviceRGB)): + # Note: in this case, r is also a Sequence + self.fill_color = r else: - self.fill_color = drawing.DeviceRGB(r / 255, g / 255, b / 255) + if isinstance(r, Sequence): + r, g, b = r + if (r, g, b) == (0, 0, 0) or g == -1: + self.fill_color = drawing.DeviceGray(r / 255) + else: + self.fill_color = drawing.DeviceRGB(r / 255, g / 255, b / 255) if self.page > 0: self._out(self.fill_color.serialize().lower()) @@ -1001,15 +1013,21 @@ def set_text_color(self, r, g=-1, b=-1): The method can be called before the first page is created and the value is retained from page to page. Args: - r (int): if `g` and `b` are given, this indicates the red component. + r (int, tuple, fpdf.drawing.DeviceGray, fpdf.drawing.DeviceRGB): if `g` and `b` are given, this indicates the red component. Else, this indicates the grey level. The value must be between 0 and 255. g (int): green component (between 0 and 255) b (int): blue component (between 0 and 255) """ - if (r == 0 and g == 0 and b == 0) or g == -1: - self.text_color = drawing.DeviceGray(r / 255) + if isinstance(r, (drawing.DeviceGray, drawing.DeviceRGB)): + # Note: in this case, r is also a Sequence + self.text_color = r else: - self.text_color = drawing.DeviceRGB(r / 255, g / 255, b / 255) + if isinstance(r, Sequence): + r, g, b = r + if (r, g, b) == (0, 0, 0) or g == -1: + self.text_color = drawing.DeviceGray(r / 255) + else: + self.text_color = drawing.DeviceRGB(r / 255, g / 255, b / 255) def get_string_width(self, s, normalized=False, markdown=False): """ @@ -2665,20 +2683,11 @@ def local_context( if line_width is not None: self.set_line_width(line_width) if draw_color is not None: - if isinstance(draw_color, Sequence): - self.set_draw_color(*draw_color) - else: - self.set_draw_color(draw_color) + self.set_draw_color(draw_color) if fill_color is not None: - if isinstance(fill_color, Sequence): - self.set_fill_color(*fill_color) - else: - self.set_fill_color(fill_color) + self.set_fill_color(fill_color) if text_color is not None: - if isinstance(text_color, Sequence): - self.set_text_color(*text_color) - else: - self.set_text_color(text_color) + self.set_text_color(text_color) if dash_pattern is not None: self.set_dash_pattern(**dash_pattern) yield @@ -4682,21 +4691,19 @@ def use_font_style(self, font_style: FontStyle): ) prev_text_color = self.text_color if font_style.color is not None and font_style.color != self.text_color: - if isinstance(font_style.color, Sequence): - self.set_text_color(*font_style.color) - else: - self.set_text_color(font_style.color) + self.set_text_color(font_style.color) prev_fill_color = self.fill_color if ( font_style.fill_color is not None and font_style.fill_color != self.fill_color ): - if isinstance(font_style.fill_color, Sequence): - self.set_fill_color(*font_style.fill_color) - else: - self.set_fill_color(font_style.fill_color) + self.set_fill_color(font_style.fill_color) yield - self.fill_color = prev_fill_color + if ( + font_style.fill_color is not None + and font_style.fill_color != prev_fill_color + ): + self.set_fill_color(prev_fill_color) self.text_color = prev_text_color self.set_font(*prev_font) diff --git a/fpdf/table.py b/fpdf/table.py index 3b1d196ab..73034c697 100644 --- a/fpdf/table.py +++ b/fpdf/table.py @@ -11,6 +11,8 @@ class Table: def __init__(self, fpdf): self._fpdf = fpdf self._rows = [] + self.cell_fill_color = None + self.cell_fill_logic = lambda i, j: True self.col_widths = None self.first_row_as_headings = True self.headings_style = DEFAULT_HEADINGS_STYLE @@ -32,7 +34,16 @@ def render(self): self._fpdf._perform_page_break() if self.first_row_as_headings: # repeat headings on top: self._render_table_row_styled(0) + if self.cell_fill_color: + print(self.cell_fill_color) + prev_fill_color = self._fpdf.fill_color + self._fpdf.set_fill_color(self.cell_fill_color) + print(self._fpdf.fill_color) + else: + prev_fill_color = None self._render_table_row_styled(i) + if prev_fill_color: + self._fpdf.set_fill_color(prev_fill_color) def _render_table_row_styled(self, i): if i == 0 and self.first_row_as_headings: @@ -41,14 +52,23 @@ def _render_table_row_styled(self, i): else: self._render_table_row(i) - def _render_table_row(self, i, **kwargs): + def _render_table_row(self, i, fill=False, **kwargs): row = self._rows[i] lines_count_per_cell = self._get_lines_count_per_cell(i) row_height = max(lines_count_per_cell) * self.line_height for j in range(len(row.cells)): cell_line_height = row_height / lines_count_per_cell[j] + if fill: + cell_fill = True + else: + cell_fill = self.cell_fill_color and self.cell_fill_logic(i, j) self._render_table_cell( - i, j, h=row_height, max_line_height=cell_line_height, **kwargs + i, + j, + h=row_height, + max_line_height=cell_line_height, + fill=cell_fill, + **kwargs, ) self._fpdf.ln(row_height) diff --git a/test/table/table_with_headings_styled.pdf b/test/table/table_with_headings_styled.pdf index 9c45c728ee39b28e786eea1cc4e85b7c103c0312..f8a53c0d7944305ba076fba5de99784554a09758 100644 GIT binary patch delta 845 zcmbQuJCApRBV)ZOmz^C~aY<2XVlG$3oZhLY^KLuvxPJe~r8nDkxzt(bOGcctS|={b zcq}g%@dwx)HY0pH_m$OfMf98ofR20Y&eDMC!yIlKhJSK#Ru&#-F z`1;i)t;yFk^t^89{BwxpPF*m~OM*8jGm*C@>}jOcnun%;_Y|jw)}Jok*{uF+=a!`z zQt|UyGu1U_v}XHoc760ew4t$3ShaP{!Yr@A%!s`QmbbqxuyDFx_F6jPuiW%z`NvT& zuXOJHv~k6v9IZstINi4_tlv3y7qZ^-jZ)5PonD=zUgmw=@2<}5Zmlmr?xz-Q+afG- zNBPY$(UW((oL+FfFWc?8&5OO>FK4R1i|DbaiyC`EZ*g+H6WsQQYtPg$w-ZA7rTcC7 z9pBpZvDbHxhtnSI(&De(3u1oGij0v8Zu&7T=iy;}|J`2?E{%VZ{^aGdo*%QSe=LY; zlymd>btSidf6b*oQ*2g$dAIMGoSkO4!kOftrL|}NblB8ns%!0N?>{Np5&flgn{B<0 zf3Ez#%TwgTPrb_8_ad?Otd3rzA6 zE&r4YKQ$|NfmGYp1g&#uIkx0hfYWpLCojFM0}tBP_<)3F+;5M)z5fm8f`?lFy`yKZ zez~Z;)O2$J&~Sz;W@djFwj6%9;k{=4;?KdKYA){HHLJR1MU0@NYvlV||9TCr>{ZW; z+pb-`)7|5g=)}M&A!bu9{uHd-cgZiHpkH9Jw$fsaXOI6eZ2z0qTj$2Uia_X{|RpM45}jIi}@En6Y01#<4fJ`qu-~@pQPR+cm4XE!z(OV z7b%#ig-#0ib+E%G5gagq#au3#J(X%D9NYi12QK(~W%Etuw~V%C3I-sckf*=}W*8V6 z8kk~;8DSAKHZYpZ%w`>HX6$6@Mw2XG2g$ bEF`NW7L`;KrKWKi8k-q&sj9mAyKw;kC4qVl delta 842 zcmbQoJDYcdBV)Z0mz^C~aY<2XVlG$3oZhLYi*7jxxPGs3)qm`&CUw^N(xtMa+^1HC zB-J^jCOh@GxH>HT^Ib4e&i3x4_N1$4pMJ~z#o-m9$Caq{WA~2egVWhLFLf7uZToyW_PwwJuQa(2_s6;A#0^(Jp#I(NYX zxkU4I9`C|LoWd)%-}c=UYE@95w7N!VmBF(#Si8l@X?I&5yHxM__OgoQE$8}ATy|amD*N5T;v!Zh6SluM%YHMfmehI8 z(*vq5=AS=BTVSE#O0y{!ehOCZy5tv9z%M@;B=qci;`ML()l3;XPW``h?OE2Y7qPKt zbz*>qGi>eUwg2~agY}#0Q!oBZske#$vTofoIYq5-7q`G`ySLRR_nh-T`PtR~b=Et< zNky(HBC1n)Q%mYx=B?i%EOJNr$dj%U8eKnk*dNH4*F zOblM_eC2Yn_y5=SGbXC{#9h07=kN+k)}RPTuhwoYzV4|h2)dOqLPZD S)HE(bV>1ITRaIAiH!c8q>1{Ir diff --git a/test/table/test_table.py b/test/table/test_table.py index 517151a16..89b59e2fd 100644 --- a/test/table/test_table.py +++ b/test/table/test_table.py @@ -190,3 +190,31 @@ def test_table_with_multiline_cells_and_split_over_3_pages(tmp_path): assert_pdf_equal( pdf, HERE / "table_with_multiline_cells_and_split_over_3_pages.pdf", tmp_path ) + + +def test_table_with_cell_fill(tmp_path): + pdf = FPDF() + pdf.add_page() + pdf.set_font("Times", size=16) + with pdf.table() as table: + table.cell_fill_color = 200 # grey + table.cell_fill_logic = lambda i, j: i % 2 + for data_row in TABLE_DATA: + with table.row() as row: + for datum in data_row: + row.cell(datum) + assert_pdf_equal(pdf, HERE / "table_with_cell_fill.pdf", tmp_path) + + +def test_table_with_cell_fill2(tmp_path): + pdf = FPDF() + pdf.add_page() + pdf.set_font("Times", size=16) + with pdf.table() as table: + table.cell_fill_color = (173, 216, 230) # light blue + table.cell_fill_logic = lambda i, j: j % 2 + for data_row in TABLE_DATA: + with table.row() as row: + for datum in data_row: + row.cell(datum) + assert_pdf_equal(pdf, HERE / "table_with_cell_fill2.pdf", tmp_path) From e5d537c0fce5a64b06cb3ea8a39425801238a1a2 Mon Sep 17 00:00:00 2001 From: Lucas Cimon <925560+Lucas-C@users.noreply.github.com> Date: Wed, 22 Feb 2023 13:56:13 +0100 Subject: [PATCH 05/17] Implementing borders layout --- docs/Tables.md | 21 ++++++++++++++ docs/table-simple.jpg | Bin docs/table-with-cells-filled.jpg | Bin docs/table-with-cells-filled2.jpg | Bin docs/table-with-fixed-column-widths.jpg | Bin docs/table_with_internal_layout.jpg | Bin 0 -> 18568 bytes docs/table_with_minimal_layout.jpg | Bin 0 -> 14832 bytes fpdf/enums.py | 13 +++++++++ fpdf/table.py | 33 ++++++++++++++++++++-- test/conftest.py | 1 - test/table/table_with_cell_fill.pdf | Bin 0 -> 1707 bytes test/table/table_with_cell_fill2.pdf | Bin 0 -> 1730 bytes test/table/table_with_internal_layout.pdf | Bin 0 -> 1569 bytes test/table/table_with_minimal_layout.pdf | Bin 0 -> 1481 bytes test/table/test_table.py | 26 +++++++++++++++++ 15 files changed, 90 insertions(+), 4 deletions(-) mode change 100755 => 100644 docs/table-simple.jpg mode change 100755 => 100644 docs/table-with-cells-filled.jpg mode change 100755 => 100644 docs/table-with-cells-filled2.jpg mode change 100755 => 100644 docs/table-with-fixed-column-widths.jpg create mode 100755 docs/table_with_internal_layout.jpg create mode 100755 docs/table_with_minimal_layout.jpg create mode 100644 test/table/table_with_cell_fill.pdf create mode 100644 test/table/table_with_cell_fill2.pdf create mode 100644 test/table/table_with_internal_layout.pdf create mode 100644 test/table/table_with_minimal_layout.pdf diff --git a/docs/Tables.md b/docs/Tables.md index 36163699e..a0b8efa5c 100644 --- a/docs/Tables.md +++ b/docs/Tables.md @@ -99,6 +99,27 @@ Result: ![](table-with-cells-filled2.jpg) +## Set borders layout +```python +... +with pdf.table() as table: + table.borders_layout = "INTERNAL" + ... +``` +Result: + +![](table_with_internal__layout.jpg) + +```python +... +with pdf.table() as table: + table.borders_layout = "MINIMAL" + ... +``` +Result: + +![](table_with_minimal_layout.jpg) + ## Using write_html Tables can also be defined in HTML using [`FPDF.write_html`](HTML.md). diff --git a/docs/table-simple.jpg b/docs/table-simple.jpg old mode 100755 new mode 100644 diff --git a/docs/table-with-cells-filled.jpg b/docs/table-with-cells-filled.jpg old mode 100755 new mode 100644 diff --git a/docs/table-with-cells-filled2.jpg b/docs/table-with-cells-filled2.jpg old mode 100755 new mode 100644 diff --git a/docs/table-with-fixed-column-widths.jpg b/docs/table-with-fixed-column-widths.jpg old mode 100755 new mode 100644 diff --git a/docs/table_with_internal_layout.jpg b/docs/table_with_internal_layout.jpg new file mode 100755 index 0000000000000000000000000000000000000000..8937cdd83ceb11fa2f03f0657109a4e15e648e75 GIT binary patch literal 18568 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 PcC8ov>+l9(jcI8mw+fz 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 literal 0 HcmV?d00001 diff --git a/fpdf/enums.py b/fpdf/enums.py index 1f5c0caf0..bcd6ee135 100644 --- a/fpdf/enums.py +++ b/fpdf/enums.py @@ -240,6 +240,19 @@ def coerce(cls, value): return cls.U +class TableBordersLayout(CoerciveEnum): + "Defines how to render table borders" + + ALL = intern("ALL") + "Draw all table cells borders" + + INTERNAL = intern("INTERNAL") + "Draw only internal horizontal & vertical borders" + + MINIMAL = intern("MINIMAL") + "Draw only the top horizontal border, below the headings, and internal vertical borders" + + class RenderStyle(CoerciveEnum): "Defines how to render shapes" diff --git a/fpdf/table.py b/fpdf/table.py index 73034c697..58ffda491 100644 --- a/fpdf/table.py +++ b/fpdf/table.py @@ -1,6 +1,7 @@ from contextlib import contextmanager from numbers import Number +from .enums import TableBordersLayout from .fonts import FontStyle @@ -17,6 +18,7 @@ def __init__(self, fpdf): self.first_row_as_headings = True self.headings_style = DEFAULT_HEADINGS_STYLE self.line_height = 2 * fpdf.font_size + self.borders_layout = TableBordersLayout.ALL self.width = fpdf.epw @contextmanager @@ -35,16 +37,41 @@ def render(self): if self.first_row_as_headings: # repeat headings on top: self._render_table_row_styled(0) if self.cell_fill_color: - print(self.cell_fill_color) prev_fill_color = self._fpdf.fill_color self._fpdf.set_fill_color(self.cell_fill_color) - print(self._fpdf.fill_color) else: prev_fill_color = None self._render_table_row_styled(i) if prev_fill_color: self._fpdf.set_fill_color(prev_fill_color) + def get_cell_border(self, i, j): + "Can be overriden to customize this logic" + if self.borders_layout == TableBordersLayout.ALL.value: + return 1 + columns_count = max(len(row.cells) for row in self._rows) + rows_count = len(self._rows) + border = list("LRTB") + if self.borders_layout == TableBordersLayout.INTERNAL.value: + if i == 0 and "T" in border: + border.remove("T") + if i == rows_count - 1 and "B" in border: + border.remove("B") + if j == 0 and "L" in border: + border.remove("L") + if j == columns_count - 1 and "R" in border: + border.remove("R") + if self.borders_layout == TableBordersLayout.MINIMAL.value: + if i != 0 and "B" in border: + border.remove("B") + if rows_count > 1 and i != 1 and "T" in border: + border.remove("T") + if j == 0 and "L" in border: + border.remove("L") + if j == columns_count - 1 and "R" in border: + border.remove("R") + return "".join(border) + def _render_table_row_styled(self, i): if i == 0 and self.first_row_as_headings: with self._fpdf.use_font_style(self.headings_style): @@ -79,7 +106,7 @@ def _render_table_cell(self, i, j, h, **kwargs): w=col_width, h=h, txt=row.cells[j], - border=1, + border=self.get_cell_border(i, j), new_x="RIGHT", new_y="TOP", **kwargs, diff --git a/test/conftest.py b/test/conftest.py index 7166bbcc7..deaf6ab72 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -21,7 +21,6 @@ from fpdf.util import get_process_rss_as_mib, print_mem_usage from fpdf.template import Template - QPDF_AVAILABLE = bool(shutil.which("qpdf")) if not QPDF_AVAILABLE: warnings.warn( diff --git a/test/table/table_with_cell_fill.pdf b/test/table/table_with_cell_fill.pdf new file mode 100644 index 0000000000000000000000000000000000000000..2f4b5ee29e2fa2a787087a9173bf196172e7df21 GIT binary patch literal 1707 zcmbtVe^8TU98c5JUNx|*6V$^e6=j&bd){qqvq^4aZ!$)VO+{OD_qx5Tm$vuCy)VB~ z(CEeyEr~QM@CRo~5mI6jBx(JIw=SD5Y3DgilNz<0BcDKzmTHE=r&iX*=hjG2BG6PT>s@uat^eyx^fJHZ8ZcclYi2va$H~oqfKYNAzo^(AC?F5z|^~_hl8t zHTC&+CELns*45Jw$)PuwO)kPCpC4ouTmJatquZ5weZHU@D z=hi*!b-34BTU94H(bin)i~hTvjye($p|j$;n@Y5`Sr|dHHc; zN6SzBd2_*xxYEYfbL9oRVn^4i-PqRZ{U3I|`$YF(*O9&(r7vo=&gQ}|#z(ty4em+r zS^eJn&WeGim$n@^RGD|WyzXRaL&Y;~6_MAr3~}xU6-Lwjn5fLtC3QEZUjI1O42rvU z^{^Y4Pn^4PW=HJN!t`^IXW&Y3=^eYmv0%E zGkIgco!fYMJkpB)s!jAo6#&l_zK2N^NTHe^YtC9BsCiNO$Sg(-K;#G! zQvAP^&~Yxu|F0m*_;0C-186ij34u5pG7ORcVha`|Qrzs}>{eO;HXNBAnv>2)()cXfy_H;Wz<^u8x+Q#Ab3pT#xuU5!f_xgH8qYI#Q|Bl2Aq{ n3Yz*+k3~ltQc3JDs`6*& literal 0 HcmV?d00001 diff --git a/test/table/table_with_cell_fill2.pdf b/test/table/table_with_cell_fill2.pdf new file mode 100644 index 0000000000000000000000000000000000000000..12de9722183b03dbd6e41d70ef29d1f18bd83714 GIT binary patch literal 1730 zcmbtVeNYr-9M-ag)exK;zebKX41o-H_r5oQyiX-yIPVY;#M*;BIJw(}+dVu{VI&JZ z`Bc+vv{EWjQE?Pygwe@EMHDMCbRuC86h%qQY8cGwT|V;CnfjympLh3p_xJoh=6#+G z(ra{K_xl}LCvf~pw@%>f)iqb=zyND;#$Ln?yCQt1{_#W+C<1`#PCoi9=V zg#@3kAmC~I>TC+2dNPAzk;q7dqSJXgkq2#DHbpDbI159MaspIm;T8khVYNa6J~W10 z%{VxK#?h3Tu{vz@2+RV$Ji}NLHOY}yCc`5QU*gm1X^x^f7Dz^7^rRiWjxiW0mT}nA zC>F>)Df#3ce0=B_pUz_CC_AjxN^+EjN@LO~1dXBS3@#JM2r(bUa(0TeAcZ0*&X0Jb&(_M(nf1#Q)lAgLElwT#)z5q!pRvm;+p8B z8-kdn1HHHDS3V6;WVg6pXge}MMdVi=Ojdoha@oU&m7#CXIOV?9tSz5(@pxg}-iEqavVl_z{dC)6&mG@YkH~$L#I7(GcA_q!dK&vqnXNJ5 z4{dRIWv{4CTbJY2+!b%!5TRRwEo)iYnY+GY;84@dpG}y`(lQH|3+UN}c7<9%PLA3$ z1MU6br<40uJqT%=bH|XH=iV=?v`*V6oY-__gDJUj9GSzByANHdZ^2t#YvHWty5O@S$e*|ncZD;eWyNV^9*qRf|oqu^a=NxYTzeHHm(0k+xG78rdFeiW#WXfW+J{knJsI1&`lpWW@Z z%{{coD}Ks@-u9ZT$2;7A*1A)NI;*m36+bBEndb`3elJew|E47O%;x@@1;U{u<(JnE z3tkHg4xnex6&rneHwB(8yc~0*_Q``xW$Te!?viekxw%VV)FhSfG<7s0TN)Owh>rZR z>-?)BMUT{eq|%%(oU*8{zdm;0TDmgo_u73+Hl6dnu==QYk3R4vujsvBuxvh^R&exk z%3arTzpZ8R(yg$esi6}NY&^-GxlwfJ>oeQSZ$GN_NT)O?I9Ja z&s@&8cH~X2@-G-a=Sor`uhh}|JE~c!$K_X%ETvHj|iukODU%r_7oj_Pp0_Xd4L zCjxv42B=+BZ)ehs6bDjJ=!LLP$_cxTvOz;ojqd8vJu20s1%*cfHIzT^YZ~YfAVl*f zPRIycB*t+9gDV*)f-x*O)Faqwr_2Zj2!uZ$SwJS0ilx8|o?-+TJ_7VpjDThH%LBuS z=f4xlpTlrW0$uH&u{bV)&iM=`l0dV41`~^6yJHwrGgjy*hG&-$Tsg>a3$p8Lgc=9Yq+PUG; O;bMY7f`YVhI^-|XVPt^- literal 0 HcmV?d00001 diff --git a/test/table/table_with_internal_layout.pdf b/test/table/table_with_internal_layout.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f47e1eb2f7bf2408f76ec1fc6e42d014acdb9331 GIT binary patch literal 1569 zcmbtUYfKzf6t;vEn6)h`psBUof-A^lXJ?-?u%i2#$g3>7s}z=o4$H7?v&_KGY`fc# zB8Y8DnJ|Gzh9^Jq!;p1Wk7qalj^rCi7+l&7_N*l#cZRn-n5S zLMf5q09RlVoPbuVuZ#w$iE_{!l9GbZOp!n*^P|lwqZzH8ce2bPCqPLj|2AMeE*B&a zTr(&i>)`>K#n5`zv7v@4ygSph2VaCg6k3=>2&e58|Lbwc-lbQ*&-T2Gib)amjI<)CU|kYo2E(;@3F&& zhc^Bu4gKK0=DP&SK0X^W_ zfBksN$?EC7mm}ID@v@=XfJ^Ew_Qx#xUcYCse&trlkpm-D4WHG2bTd(-&y_d*L8X;l ziNkLwt(k*yA-Cf5Q(U{s*Yr$X$Qju=cRbsICHC|VS4GVgr#EwLjZ`{7+ zC+l<9CJrL0C3)>XjD}U-2+t0lNW|-=D37$~t4;e?=ZS{9quy(XJQ29Q{rLHtv-Vw) zXD@ae8&_Ql8J=2w?r2=V*A*i%qqj(irZ=w2TL;mMdI2?m8e4ET!nb3b?T$jKDjtMZ z?rxnb*dF+WPgN4X?Luem?Ne(k0lVv%jz_u5zHL`#4z>I0G_Q1oCx4Qhf8KgMM09Gb zelC84YfPLK)H)1#>lE*Jd#jtfn`(w^6A$)$Q(lYLh!cWucfEZ5L}fuxr771?BFE!D z)HSzoN!>3!jOl8RDtPmaAHEpzIOp`( zxb^pI%$&%ZVRH#WSR9W!iJ~+SF30H{If`U%XQ{`;~zE1<*rv32Vau1qfmdNf@CbFqs^~ z2q`>y7!f0t#=P$5>~+({h!hZrU|%>urBuq5pcpJ;1eiAgW*H-3+QRX}FyiTVGWF9K zj>9GNgfD@^{r67{lj3lDK7nCs*v}=5cT-Lm?VjJn7UvEcmVugCmIuNvh0RT6idi7E zNBA}Xn}$>wbUK5UAk=D7A;**?sZ%NpQaNcPjasc%o$}u=<~z^vl$)P#9c(U+h{eV% G68Q_mmKg#7 literal 0 HcmV?d00001 diff --git a/test/table/table_with_minimal_layout.pdf b/test/table/table_with_minimal_layout.pdf new file mode 100644 index 0000000000000000000000000000000000000000..9fe839c34a5170c99c4d9aba762310b4cd1cc46f GIT binary patch literal 1481 zcmY!laBHDUpWF|W0 zS13dq07XnKP4$c{6f8^(^(-ubvLTfPsS5f5iRr1uTy}O`sd*_NmCPSDKRpGytU4C$TcWv_wJQKQGleKc_S|4Y$V8XB=bO8VdlAI=9Hus z0o|IDSd!|Jnw+1K%BAmXg%YhYUnqzSkU$-6m~b zrxwYi#qAQh@(KGIr_5V6OISiaerJ8SU9s`$);BYErZcfjo6Pc2&-o9GxY&$&(W5l>b?@vMiRV-8Arv}s&tzpghYMAOZp*+g9B3vz z9B(rVJ&tW_`TFMQh1}aRuXo+4XZPjL==mOpUKCiv8?aFs<(-^-fa7Lzqu-NVu4h#=ot=KyQj=Tc8uOfj4y_)J-ug5 zZuw&=I~MMv@vebe^+ec1+F4CPwF}g4NlN_>TeK}7lwhIJ2u-@CNNK<+u{hN&ADD{t zLo#zyi*{gdkuN)(zND87fw*x8A^M`B6-0A$pU9!E&ye37hpzF&~ULbv^29cG%_|cv@`&MC__ti z0|RwUB+V5?scBpW3YJ_Tc?eK2Gc`3fRY+4nh*>Itr4;fIVwON>g8-74p(Um|BXdkK zb4#G-(ezqa0y8|Cn58AK>_QbYG_XK2ucRn3GbgnOTw(@iR;2>Hp&yi=U!nji^MHZt znU|KY016%u+eIPT#>COk*xA&`&CSW#(a6cv#Te*hS0@)kBUfV=M;9|=JHjf!AzxgQ USX2TIIzvNK11?onSARDy02Wv2)&Kwi literal 0 HcmV?d00001 diff --git a/test/table/test_table.py b/test/table/test_table.py index 89b59e2fd..e8023accd 100644 --- a/test/table/test_table.py +++ b/test/table/test_table.py @@ -218,3 +218,29 @@ def test_table_with_cell_fill2(tmp_path): for datum in data_row: row.cell(datum) assert_pdf_equal(pdf, HERE / "table_with_cell_fill2.pdf", tmp_path) + + +def test_table_with_internal_layout(tmp_path): + pdf = FPDF() + pdf.add_page() + pdf.set_font("Times", size=16) + with pdf.table() as table: + table.borders_layout = "INTERNAL" + for data_row in TABLE_DATA: + with table.row() as row: + for datum in data_row: + row.cell(datum) + assert_pdf_equal(pdf, HERE / "table_with_internal_layout.pdf", tmp_path) + + +def test_table_with_minimal_layout(tmp_path): + pdf = FPDF() + pdf.add_page() + pdf.set_font("Times", size=16) + with pdf.table() as table: + table.borders_layout = "MINIMAL" + for data_row in TABLE_DATA: + with table.row() as row: + for datum in data_row: + row.cell(datum) + assert_pdf_equal(pdf, HERE / "table_with_minimal_layout.pdf", tmp_path) From cffc3986c91f3c6285eee9f845c33596c1983019 Mon Sep 17 00:00:00 2001 From: Lucas Cimon <925560+Lucas-C@users.noreply.github.com> Date: Thu, 23 Feb 2023 09:29:51 +0100 Subject: [PATCH 06/17] Implementing images in tables --- docs/Tables.md | 39 ++++++- docs/table_with_images.jpg | Bin 0 -> 31466 bytes docs/table_with_images_and_img_fill_width.jpg | Bin 0 -> 46561 bytes docs/table_with_internal_layout.jpg | Bin docs/table_with_minimal_layout.jpg | Bin fpdf/fpdf.py | 17 +-- fpdf/table.py | 102 +++++++++++++----- test/table/table_with_an_image.pdf | Bin 0 -> 78789 bytes ...table_with_an_image_and_img_fill_width.pdf | Bin 0 -> 78790 bytes test/table/table_with_minimal_layout.pdf | Bin 1481 -> 1493 bytes test/table/table_with_multiline_cells.pdf | Bin 3071 -> 3044 bytes ...h_multiline_cells_and_fixed_row_height.pdf | Bin 2995 -> 2969 bytes ...multiline_cells_and_split_over_3_pages.pdf | Bin 5292 -> 5242 bytes ...h_multiline_cells_and_without_headings.pdf | Bin 4966 -> 4919 bytes test/table/test_table.py | 3 +- test/table/test_table_with_image.py | 74 +++++++++++++ 16 files changed, 196 insertions(+), 39 deletions(-) create mode 100644 docs/table_with_images.jpg create mode 100644 docs/table_with_images_and_img_fill_width.jpg mode change 100755 => 100644 docs/table_with_internal_layout.jpg mode change 100755 => 100644 docs/table_with_minimal_layout.jpg create mode 100644 test/table/table_with_an_image.pdf create mode 100644 test/table/table_with_an_image_and_img_fill_width.pdf create mode 100644 test/table/test_table_with_image.py diff --git a/docs/Tables.md b/docs/Tables.md index a0b8efa5c..1fda13f8a 100644 --- a/docs/Tables.md +++ b/docs/Tables.md @@ -108,10 +108,11 @@ with pdf.table() as table: ``` Result: -![](table_with_internal__layout.jpg) +![](table_with_internal_layout.jpg) ```python ... +pdf.set_draw_color(100) # dark grey with pdf.table() as table: table.borders_layout = "MINIMAL" ... @@ -120,6 +121,42 @@ Result: ![](table_with_minimal_layout.jpg) +## Insert images +```python +TABLE_DATA = ( + ("First name", "Last name", "Image", "City"), + ("Jules", "Smith", "shirt.png", "San Juan"), + ("Mary", "Ramos", "shirt.png", "Orlando"), + ("Carlson", "Banks", "shirt.png", "Los Angeles"), + ("Lucas", "Cimon", "shirt.png", "Angers"), +) +pdf = FPDF() +pdf.add_page() +pdf.set_font("Times", size=16) +with pdf.table() as table: + for i, data_row in enumerate(TABLE_DATA): + with table.row() as row: + for j, datum in enumerate(data_row): + if j == 2 and i > 0: + row.cell(img=datum) + else: + row.cell(datum) +pdf.output('table_with_images.pdf') +``` +Result: + +![](table_with_images.jpg) + +By default, images height & width are constrained by the row height (based on text content) +and the column width. To render bigger images, you can set the `table.line_height` parameter to increase the row height, or pass `img_fill_width=True` to `.cell()`: + +```python + row.cell(img=datum, img_fill_width=True) +``` +Result: + +![](table_with_images_and_img_fill_width.jpg) + ## Using write_html Tables can also be defined in HTML using [`FPDF.write_html`](HTML.md). diff --git a/docs/table_with_images.jpg b/docs/table_with_images.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b277876396b224861021262e830bd5307ebbc4e7 GIT binary patch literal 31466 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 AB>(^b literal 0 HcmV?d00001 diff --git a/docs/table_with_images_and_img_fill_width.jpg b/docs/table_with_images_and_img_fill_width.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dda23c59fc54bc870a4b9dab4eab08975ab0bd5f GIT binary patch literal 46561 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 DR>xtd literal 0 HcmV?d00001 diff --git a/docs/table_with_internal_layout.jpg b/docs/table_with_internal_layout.jpg old mode 100755 new mode 100644 diff --git a/docs/table_with_minimal_layout.jpg b/docs/table_with_minimal_layout.jpg old mode 100755 new mode 100644 diff --git a/fpdf/fpdf.py b/fpdf/fpdf.py index c1af656aa..ee93e106f 100644 --- a/fpdf/fpdf.py +++ b/fpdf/fpdf.py @@ -3789,6 +3789,14 @@ def image( if self.oversized_images and info["usages"] == 1 and not dims: info = self._downscale_image(name, img, info, w, h) + # Flowing mode + if y is None: + self._perform_page_break_if_need_be(h) + y = self.y + self.y += h + if x is None: + x = self.x + if keep_aspect_ratio: ratio = info.width / info.height if h * ratio < w: @@ -3798,14 +3806,7 @@ def image( y += (h - w / ratio) / 2 h = w / ratio - # Flowing mode - if y is None: - self._perform_page_break_if_need_be(h) - y = self.y - self.y += h - if x is None: - x = self.x - elif not isinstance(x, Number): + if not isinstance(x, Number): if keep_aspect_ratio: raise ValueError( "FPDF.image(): 'keep_aspect_ratio' cannot be used with an enum value provided to `x`" diff --git a/fpdf/table.py b/fpdf/table.py index 58ffda491..41af099f9 100644 --- a/fpdf/table.py +++ b/fpdf/table.py @@ -1,5 +1,6 @@ from contextlib import contextmanager from numbers import Number +from typing import List from .enums import TableBordersLayout from .fonts import FontStyle @@ -12,13 +13,13 @@ class Table: def __init__(self, fpdf): self._fpdf = fpdf self._rows = [] + self.borders_layout = TableBordersLayout.ALL self.cell_fill_color = None self.cell_fill_logic = lambda i, j: True self.col_widths = None self.first_row_as_headings = True self.headings_style = DEFAULT_HEADINGS_STYLE self.line_height = 2 * fpdf.font_size - self.borders_layout = TableBordersLayout.ALL self.width = fpdf.epw @contextmanager @@ -81,36 +82,74 @@ def _render_table_row_styled(self, i): def _render_table_row(self, i, fill=False, **kwargs): row = self._rows[i] - lines_count_per_cell = self._get_lines_count_per_cell(i) - row_height = max(lines_count_per_cell) * self.line_height + lines_heights_per_cell = self._get_lines_heights_per_cell(i) + row_height = max(sum(lines_heights) for lines_heights in lines_heights_per_cell) for j in range(len(row.cells)): - cell_line_height = row_height / lines_count_per_cell[j] - if fill: - cell_fill = True - else: - cell_fill = self.cell_fill_color and self.cell_fill_logic(i, j) + cell_line_height = row_height / len(lines_heights_per_cell[j]) self._render_table_cell( i, j, - h=row_height, - max_line_height=cell_line_height, - fill=cell_fill, + cell_line_height=cell_line_height, + row_height=row_height, + fill=fill, **kwargs, ) self._fpdf.ln(row_height) - def _render_table_cell(self, i, j, h, **kwargs): + # pylint: disable=inconsistent-return-statements + def _render_table_cell( + self, + i, + j, + cell_line_height, + row_height, + fill=False, + lines_heights_only=False, + **kwargs, + ): + """ + If `lines_heights_only` is True, returns a list of lines (subcells) heights. + """ row = self._rows[i] col_width = self._get_col_width(i, j) - return self._fpdf.multi_cell( + cell = row.cells[j] + lines_heights = [] + if cell.img: + if lines_heights_only: + info = self._fpdf.preload_image(cell.img)[2] + img_ratio = info.width / info.height + if cell.img_fill_width or row_height * img_ratio > col_width: + img_height = col_width / img_ratio + else: + img_height = row_height + lines_heights += [img_height] + else: + x, y = self._fpdf.x, self._fpdf.y + self._fpdf.image( + cell.img, + w=col_width, + h=0 if cell.img_fill_width else row_height, + keep_aspect_ratio=True, + ) + self._fpdf.set_xy(x, y) + if not fill: + fill = self.cell_fill_color and self.cell_fill_logic(i, j) + lines = self._fpdf.multi_cell( w=col_width, - h=h, - txt=row.cells[j], + h=row_height, + txt=cell.text or "", + max_line_height=cell_line_height, border=self.get_cell_border(i, j), new_x="RIGHT", new_y="TOP", + fill=fill, + split_only=lines_heights_only, **kwargs, ) + if lines_heights_only and cell.text: + lines_heights += len(lines) * [self.line_height] + if lines_heights_only: + return lines_heights def _get_col_width(self, i, j): if not self.col_widths: @@ -126,27 +165,32 @@ def _get_col_width(self, i, j): col_ratio = self.col_widths[j] / sum(self.col_widths) return col_ratio * self.width - def _get_lines_count_per_cell(self, i): + def _get_lines_heights_per_cell(self, i) -> List[List[int]]: row = self._rows[i] - lines_count = [] + lines_heights = [] for j in range(len(row.cells)): - lines_count.append( - len( - self._render_table_cell( - i, - j, - h=self.line_height, - max_line_height=self.line_height, - split_only=True, - ) + lines_heights.append( + self._render_table_cell( + i, + j, + cell_line_height=self.line_height, + row_height=self.line_height, + lines_heights_only=True, ) ) - return lines_count + return lines_heights class Row: def __init__(self): self.cells = [] - def cell(self, text): - self.cells.append(text) + def cell(self, text=None, img=None, img_fill_width=False): + self.cells.append(Cell(text, img, img_fill_width)) + + +class Cell: + def __init__(self, text, img, img_fill_width): + self.text = text + self.img = img + self.img_fill_width = img_fill_width diff --git a/test/table/table_with_an_image.pdf b/test/table/table_with_an_image.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ef92320ae88903028ce14ea459c5711d32420f24 GIT binary patch literal 78789 zcmbrlbx>SE)IEqpAZU;PgS$Hn?!i5{TW}cMJ;5b-u)*Ek-GaNj2X_g&lh1zN)^6=T zOBGdbURU?MuV3HuZl8OaN?GCy6B{!pG8-u?se_3%vVZ_Gi@1ZUy$dNDGK-v*nKP*_ z2c$_=ADKnL+|0^Y%)x_Hmlbk{iz~b|JRtLEMKf#q)F{vZEYa~{Oc-j?CId@Ldv3KZ!Yd&>uP8J zpSPV!|GB67-$ulZU5srVEdH07e=hzX@9ka8?OmKnIsdbdl#_!ih*Ut}zdZcUpDb#m zEMJ|B?VUl!PUiNeo}?_|kUJ9QZdRt|s#0Q*2Y~nkX@N|`e~zMR?(E>|WNHp^<-f-L zKM(xB9QoJw-;R8-vUM?cf;^7mgcE}zX z(aGcXtE?E`FT5fI8}YupB)QnmAcV!`TJGYJV)3}z3>Tke|6Wb09q7^@<#bBBGXn1T z)i4^V%**p!R<-K)jte5%Yw7o0)A(qEzmOA#C(EERrN}e<*``cSj&*`n3J^N{QeAoD z#krTTMT$AQmC-XFpK*norda)@=NevUt;+ow_G6==@Av(S8mqsgrx^NuQL>{430v9t zIZUq2jcb+*BlYKbl6Ips#-Z^+;iuL&GN7rbsbs#vwhEiVwE8n~2Sf4MYr3VJXyZ)z z^#ANh=h|E-Ydt8ra%=DF@gO+~6+M-fe_Z(my=v74%aI_1L&8hp%!XxyyG#(~p%>r$ z&t+~$A$}*VE9KT;q0;Nq2^O|`fDFRklY^W3XFcpOy+XY7M z>920x-4j`=A*d|&Gn^D(3u2ILXYLlz{8f$C%Ye^*uKc#W@PNQ1-fD=QYRr$+3LL#^ zm{RH!w0+4+LBZd?6VG7=D%d|bwuLJ7ozQ!(lIK#F?9caaOL{Ai*F)ydG8$QZ6U_7` z1KN&axA$;0nEl9f2>4K2bF|(X`>uz!95c)(t`XaXS(r#sOD}#emPc+62UleklFSiP znxQhtlqG>UKIJqKM@s16-tUSh@`xheB6eE(~0{#PJ#{jY^BX6$VK#Q_ojgq7NjhiR`#Oy&Q||@1DQq5)x_mL@Zn$3K!D{xW9Q!(|0{O5 z|36HKIoO*0|F^*Nzb#m~I4hewi96VV9PIxEI`ALx**Z9>fs9QdNcKNifDF0(7rPKV zuyg*0Bg#$?AT)Jxa3W>ng5bu#KF*{Z|8WIDEN4=7HXtdB*#Berf0*+B3JKEYRu+~n zr0m>W{{s)~oIE_-kZDsecD5k}LcE4x-~Y^^j2#3i|9cL#luWG6OW z7B0g{bMc;4MIY>=jt>O=3=IAV0RHY)OADQK**GDLu znVFfFm*+vXk#tJ7***b^ML<)(}~W^kOAFRWaI}5-j_gu!utC9>j-2db0f@ljo?NS)Eu}~h9tF%;(id`MfZ%^0OYrM1E`vxT=ai!ep1U?RL zq<<~yf&uuy-Yq(Gz2ZIw_aeTe7JFgRQBdSH*VmUctT%Nu6i+T?x^^T04ecg3l60R8 z?_FX2cj*7D>{?nzJyD1Z?Bl#}^z#sd%`Oa&XR;7tl-r?t+T1T-f|i$;r^!qe{Dgp6 zO*Tb!7OXbTS>FW`8uIfN*XxSvbJ-)%T^rras&odr#C}NM8x%4ZZ~}7Rg*>m#zJ2@l ze1E2LNh58y`qN<>bm#G2*384r?2wpw3fw(FZbRRyfC<|nO(RyQElzh%9@(6sPp zr6mG@y|{l5(jA~g0a5BNf!B*Ttvq&C$3%K7D|hkUy1k^dmAU88C?ElLtE|T&hb^f0 z{h0zendQIOMU>r`?W_z8qgZd*4mc^vUVLo;{`>anP7b=qNcfnfqHj<`0|^&QI)F=U z6U4Xsh!eUT(05CFd;7-kVj>uNm(i$#GDBJQ0)pPyU6MLFPeI`i&{B-mGH=h22>8_U z*B@Dy7En}FL_xf9oQw5PDZ1I&^ha|t+0M(*h@R1PeR`E&L@R&5Ui#07vJO_udx=tb zFh%1Ar9sNQSIFVk)k|lSf&KK@cIoTTW0y5Sx?wsAA@A{>&Z^=sWqK_*8$BUUsqcBF zr|j<+c!oZ4)vxbr$~#++w?}G6#iuM?jBhK|u4v8^utNjy^o-0h`SSoruCqUyJ>5Dnl$OrKt$V}jImz1J3naNku8 z3?_tE-w*viqCX~S8k8)7<%zXBO_kY9EnPPVxQp+~uID~>IeB;hjf;NnBm#k69R?p_ zQV)e?bepC3EhS+Hta%)ikZ~hh5tkf4$LUEG^%}=%SgE6SJznh&ec%uKTG-#CBAbB# zXb>5Aq$&eZIz6sn0b(I*=4*YSs0}i*ycPx1MPS~`Q+auLm*jnov!0 zs#r~3|20A(T$!o|n+P>J`Fvc$W=|dHsOA$nd-Sr3nhFHU(x*5Z{ZgbloUv%Z;c6_V zWnvnyDR`z@T=*-pEiABV-RhRK2rQ>|6R{cl)lP^Rqh*x4L%6!Ka=zL14uQ&d9X)Ea zn4Qj5L%(IuUFa-i4DBr!I%2n*#>}!vv17P}6wO4}i*O=;mgm+*`_6!ZeQ5<{~+pg1yOpYWNhc97VwHg-ul z=iT$Zv0OPJOVjgHadf^A=?^nmIOx1vhiwq_))$2BJnPt~%sf}nJ=O=mxc<-qm#-2L z!KKd3%%J*4hm6j4$Q?1Po?+}KBqWF&cD=t|bg}Y%f*Z1!1YaElVKM`KCoetHD*an6 z&CSqn((cUVn$Qj&I@I^=W^>3;xe#B6CFkY~e z_0`%#)fX3ALLl;RGVA@k?c!~&9Wv3_6yF(`{YDN|SpUZ4EEqcP-b9Td@y6j)5LLNb z?rU}zoQ#{I82GC1O9cMfnNejGo}5@W@{R`~0?0T3*zeh5*Ap&<<48Yaa%(o;D zo{-Dl;fLOqNV!U1Vik}kC#Ri|XW`KlT?%GZJSh^c)+$AjqV<8?BJmdbnu~&8XU^2E zJ;#(3>h==QYY+>N&h60GR;yVNbVp%;7%)4EYJft$!IIg0fG_kx4oRc^jT?gT@A>Pc zSa3r*IXT_aU;!FCd()w0&~xY0NN};Q$jAP|1-D`^jQ#-q`3X_dne{rvTwGlFy2TxYOa)fI=;Pl;hJ=`LW@_6f8KY z7>r{(>tY3+5V>C+69VraK9`a|;xZX(x3!FN0Z&)`Y5D#2`xiNI@tAb#zn!g&5Fl3c z?wEutc(v{4+WJ0KI6VBMVl+|lG;Ya5<0sWeT{SsU^}wQR!o2<653mQ&iGsf8p1HN< zIBJgh(4U!B6b-zPa!mN_of5JmYK)%0;&{h`j_r*VGKV9fxdJASoSymG2pZ4y_BS3? zQ`K}F=Dc-U-D;^ieFl(aM&}qn)adG3g9jE?Nq4BqI{9VWUF8O-Vc4(7M$qBBYd}@< zEhJrs%0e}o3BAnqQO$B}igvHA^`O~@wNM&)3=4u7#=x7h5;CbEvu7 zM-IJFLfzVAmLdib?Y-E5sgz1X9d%P2L9NFf50(;!_!SIzz*$bXST>3O3mfzyp_D8f zpzHn3dnGd}>crKNe_wGbu{0*1k z0HDJJnX#Ztg!?`Fi0iN-kP`|YDr^KH#~S9W5S}-jJQZy_%?PwTz|zX`Azs41V;V)E z{n)Wy#g)DW-G5ZolX5E3jpz>(3)oNuegBPHB}0fs5j-|B^5on?_6d5Zu~Fm{j=yrV z^XU_wt)DL%F1djSAASJgge+6X8*2va@7XS;kyY0QyD*}dQ39Q?=p;=|!j(C2=Bvuq zxA{FLuQrFR0OFYBT>hQj&hW**_p1({K>b&_o}s(5MM~O^oO>}MWUmf>DmBfqA(Be< zM)oNU?gZqjdn5w!@*cIF1u4{Yn+kc1zibE-0+1!9JQBh+Lm_u;~ zcrib*(L#fpLbS4>$zKtu!>y>LyJy0yhce#oLni`_aU^i-?PG{yqIFyUSbH(<&_(>R zvT4>T9mII*aBET6x7MAZg9aAxpdgPxMz+CL^Y7kQ^VY+0@^ zNox7Murg-0@AA6HUIYdOq;;vqu#DpY{GZR7z+mFOo7tQ8_;792!vdPs!fY|F4G$v& zkeZerfFDq^kdk!5!rW4v8%)8K7{9eNcRKPrtfW9_HtTmM7!T+NN!F=Rt>wzBZ>4^N zL3B$EMm;dj2;u6iH=v3er<3&;eR?)NL(oe1#%?ae8|Cv{*GT zdISfc>-n6+30IQTYrLk_V;{4)+p8fiKyc>ys`2*d7}6xVuNpKoPV9fKQi!8X~( z>nkx%!oXSH$8D|krH?YGCvBh|>PO3Fc=_EkjEAZA8vX5B)^|pHoU6dyi>`M+$aW$O zowG>gh(m*&`eJ698SJAZQPH>G6R9q%gqzWMNZ4goEPH@g9*G&rI(ZWO<4Jz{ue*n5 zkUlys9BB`xY@>{7>@duiJ5Mr0-#c|ZG_OuN4dA~l8Km5R<>#xwWd67uwbp)WnV;zU zf-)$Ank>DnsjW@a-D(i8XLnC=Z_4C|Q7 z4gCTOFA?zKJK7oinDUWmJiV~4^^NfyOuLPA;D55fL`y|ai(T@kA7=qgpGGWUToGQ2 zw4g~j0~QNF&`}TuI{2$}E0n!+cf!O=YUtd&uIv7F0oW^OrP5Z?*P~)fY@b9vk?YKt zc{MOD5N8e)@_ll#w4^=eWjH5#t(J%16->W% zkpPLnRGskH-r21i7^s_1TwHyZppjA7qFn|hOPh16^`T{1E`}YM_b$V7KDNH<%9a0xr2n(dg-Z}{*C~EV=+^D(B3o}NOH(OojFDGT zut*YOlXqDZhWjOiBH;0E(J&?X3yUmeZzD_)4i~hUg8*BFFug5XOunx*LVU^=((|Bo zB^T4;of1XzdVOPq<|4mfrvApcP=LdJ^3Tezki1ILr@J*`Ws#Pd`xGgLTzJsGMU1Ja zwI(tmWgK`DXN>#`d5tia*c6fhyLA?mJAa@|OEbKRwr-hfv+-CAR6RDbCvXZs4g_fz zmym?lJ2Cretk!9^BC-k-bYaxQ(Ls$|1pSH`X!&%V0S7Gw!oC>i0YM!!GW{Xoh`LK> zoE(#S5`0%P+YR|a@iqGG?M>_3RjRUzB+f@XH#Y8u#*@FOXyN7f2jppl>>;~DWNhi! zHZ>H?j`zAZY_JBz`~cqA@4q>Guwrw^vtV%s@DPLNP`*QQqe8#SmCrGgS;Dcs*0^-! zF@#czrn}YCw`InIB2ROOKpKtGUUQ>jmTH;O_Tk^ZwKfH_g9e^9co!@i?A0-2JQJE~ zrK-ZxVTmx)WDaW0H-dFy7hZBrmYg3`5Q2&s`(EN9fhN>*Su2YGg2NpEUr$-3LDC2W z9QjUhQ5YnJ&8e`uj=uaYp4_k@?-ZqtKwnur=($@fow6!RU!Q&@D}E5?7mNUBkJzl5 zt`{dAowPcKEM8ngyY;xtgg$g}1KXHE5U9WMfJlhJKF0L4HZwjBJ*564f(Xuyk1q4t z^u^x}?+2_{RyoQ(%on}A$nK1mI=s*GL0{L~tOc1od?H5~NOcPoK1xZdb73q)@x8V- z8fESY23pyo<5D1QsOsS2(Kc84t1d3(OOm#^rPbeE*{9dhPYJ`Tj_xZG}62#$~e@RKjAY38?Ig zYnH9_t=v3=>_hScZT4t{r?|Q|T1D%N_8iH04OI7Z%QLB=+uw+! zTNvN_B8RGP+4b@a@Wt#mAD`q3{=-^T*W1d0X6mlf(voE#H9M9{4x5GMpBvwHU+8s`XhmKC2-AOi|k^(P1ap|2-ML5)hO{}-rpX&ZfxIhu?ya9a{m6LCrs;5M7;AWhC>s3g@IM=dE37I!g zCoZARrGss!{XUi55Csnh2vg-Zuxcob3B%7vOdF>#&6gu~ese2m9cQ>_J?+HB z>~C~rpQ8e$YEvn+mk9qXJab&R(G(!vWgSK`LU_n`C(hIpEc!gzn}$u?9VaArN(!*& zW%0N4Sbcqc4IfG+9|pY~6=nS?#H$z!6sYy;X8pRV1Wr;8GlXoJOmy#KOcPED505{M z91{+lB#6VMWfb}QpMoeILtqhbb40(C$IX9|_tVl>&GKEuQ5OtF_Pi4R@e{ey6;9|z z1%Aox5}v!O#qI{rSi^4qm_rbGzFvLtqri4Hm0WVZ?ImA%9^zi-eGOlFkK>HuHm~1) zlIA4~T-n1GZ9e^HV%%YE9D1Oeii__q`HSdRdUWb-K@jI4oK}&rJ@hi7B^iesBua?vo7HIIPfiyccg0{;+oNAW{1%@oB}9 z7crrU0kO|bA-q{b?SpVJ70vS=v1mx;bA-tXk&~c+W~XI#$A%7>g45BuE*;1 z?XltZh>MG>>DA?YjrR#95l%!jf;3XXD}Vh0b| z*P?#fF`|<=ecj`-qHkN8{6Jnhc$cN?rME7h>e?V_Ug|g3=k*n&rfj1it8hVbVf-87 z>ajGt4uh=N%$ROm56XM}0XF*^Z}Mdo+fVGDi+z#(EP>eOKcLLp0;0FUj%80H;z7G@ z7oDp!Sjw!l1B3Q_zrqT*D`mVQ-AbCqgLD&Z$a__62`IQfKA;ijf0YZO2)mXeFXu@P zX%@Hu_cyl-jIZxgQL(}|Z`{qP zK;iz$ElR2VjT|rlBUz(HvGv(962xW1vKuM!Qp><#)3l7o(kY@rYT38jEW#2Q?65)xoAeh6c8hBIL zFvlYue(61Yp(A3x-mZ|7+4AOkqrp*@V1C>&f&TF_r4K5%d!MX+Z1*&3F&%E8`e3gA zM)Fn$tOgIXaq9=ehFHCZqhJBl1-AD)o?YGXvj4pW4=Bt}z))jEY5?(l5F^fbcIR8T zOU6k=r0;GD-0eep%Cl!fq2mL`Q(NV)i_O z5GPI~-rn2w=1nbvFBtlTAq%LZG#Bk)%wLoA2hV$YPvx?r-=>3v5QAO*wqjMgF(zqe z)L>v72{=cxnHgT92h<*A`v2&@3Q4A9=#8_ZHehw{mvB*hgxZXLOd4juj!~UjH%<8R zOn|k81RZ@rokl0&0rG7Nm6wkQ^8#B6g;G3hUkwI3|D9oV7}!<$PB8#Q_>Ge**u0o5 zkW5roOg}g*AI5tLppf2FLWv!j2nHJn`~48=I6wBK{cwb`iIJ5RQI@qrn^(lcsyb0E z)kOfvrEm*Vb2rGqEjwT=P*i9m4t#>D@WEQK6xc{41JDFZ$WQ;;^24~yeGkIOYN znh8QsU2DY`AWjQ0wx;)`Bc)hN=~Xj!O}XsQYO}nK^@So|Z+h?Qu5*!8`+VApKt~<9 zz2ssv_mYH}#Ww}XtK*})F=n=a?75tadiexRRku;9GP)4@0y7fa?OGqlAxeeSbv*mK z2eU4AlGPg3J2|auGkjsuPonG!%xz`%xQV4o5&GZ(?(_B7e;wg;5V~x187pAeQ~PSI>Ea)hm%JK*)bwREKc~qGU8*$i zx`$J~qYdVVFxyO|Uvz|(R_p{GI*CPpV^75z%p}fflaap2i@FmeHOVHbc0j?f*;wx@ zc#;E}e$wXZnATV+4#K4VQMl2Jzc>Q z3g)oSngg|b?*~Q$3BSVPQ8WADas$e}UcZ8YuQ{4APFy>(I?u-uT`E~RPoe-*sn7$v zKt=HlKx|wC;hh%y4VBJ9G?DJ-Afum8s(f}c`?o~Q*Q!SonVxS6^Eh04O+4GU5$1E) zQZ;{HXQJ~g@*_n~qCYoUE%VE#SPK#V5g;>IzyeTcGzZoF+Kgfv;EO}p`n^9N7}HmKd|551i`hZSoFFCuR5KwhN4!(5VUXvy0|LLt3Ds3HpBGYpHfl z-F-{}A6MXl;jp<;kl@}eN~g;Wu)2Hsbg?@e>S}w_7Z*(#)A?N&Lg(_iXG()Xm~GT> zc1$g_X2{)F!wEDl7U`AniWAk0?8$HX+oigk03-lBF6WR@x9vw~s-EQLNTfO7r%!}Z z8`U<#H9pS61(gv$H^BtZVM&5JZ%_@&hzd?AMjxS@n`>(C72A|~@@C*OS#l?v;um%< z>0-&(TU{Cc!x-iP4pp^fs_C1(_bowI-=*y+Q&@7UcMj69 zn=&WQBTZtVa>Khi^eagiR(2wSq7CSf@+}Ah*o??F+Ech|=b;Ey1$s4Jz{XCLA9MOb z=PQ-8>`=b^JRwnO$bm?%a$N71A=g#l$vV1-g9yH85+2jbq*-^L6HkW4AQ6NtV2mLI zBx{Q!VVz%>#5qgYFEe>%f&(>7Lf9T1+oW1L>4jC8Hs3`{HH9x-mwHOT8PMEH4mkl} zOF#T4aQ3#yK5NvUtyo*J=}eI|sdi|$uLCGC+5af)a9Xpp;N3klkr&5|JaaFNR;!9; zjz$=ZiB%50Jq@^EI0hX3*lK;sxM=080(tXtRMacf&WO_1WU=E{stztyA&cZ29 zbtc6!A~itf#0RFI5T8$35m=^KphR$ZU)ukHf;*SG)%(F7OXW8w;*eA<@pPtZJ0Y+) zLoVyc)SZnRL-(9y_w%{Gr!2K1JPD-}wl68%H;<=BZ?oAsPC`zYbuWI>Lb@t>e}t*C zeixljIV?;tY>wvR5BPA}5=VhUgY6%JkOA5iMLM=ORBofyKOA7w$@h_+K`&=bn@B!{ zisN)5cl;014;6mjwsAS7IZ__KFG&0#SpO1*Y4aC#2<9A%?oy5GnMFYHwk~HgVsoH1 z^Qrjru|-fiWeELgp)nJZ-6mXSMaI{%`zA~03mjq~9PLE`Su_WhqDq3V01lc@( zznv~IG7RmGYmZ&ZE02WkgbAjmu=(LJ>*yGgp2hc;LLRu4xD|Jx|2G@^dM*FpRq79N zbWs&Y$~7^%qeh>`r_61Syg%a_BoiX%!~}A`XdX+O-+zttHub3uWvDtb!luM5$;$~^ z)#S?bKa@BmCLsswi*G%iE_1ZjplqzXNf&79!lW4xlS zzt%4*AjW8d)2xJvFW+U#F@@EP6vlF)#CMc`dJUOhZ#Zjn)_>{Do)>Ci?PzE(qDY9~ z647x}{YgIbp@~2V#}M=c7CIC@db`8`zFiHG+}_q_rOx)<#>RQQziHuy+d46(V*??( zDw`!vIS$yLL2Ui#QTbd!RZFgupC9q1h@e>pLQy}HC(D27SX!k^CR?OO;bZgH=!aqM zQ@Pk{gz-7F68<9(9uG1)AWvq9Dq7%UO%Ip z7v=`}bGjKf1FBNtjWO3y%BpsiqXkBI#U&}63!<9&O^oX&=9gFnT#RI>o2&=@YFFEG z2|v<$bTer|7Yf>MXs!67ZR}xG{2}ghk;WK$gjY=!4LP8o4n-i9-);6?6_zJ1UU!nJ zFD`fy_2P}izo1o{*XVPVs3j)e*kpaZ%Mzl)(tB`l&_%d*6z%nY65KkKvJf9Ru*Ohiq}Ar7Is0ZdGfp4{Hv zQjXXJyX9qO>L6-`1^;xQy2R48WHNL?AuyKFPK|b=*5NJ(pr3@#`FOiMKglo&jl#0f zmKN?m!zDHL#$)jjT0W75IDc*l#|ss?zXW(Z8RCE&UrQzDXOLjd;%TB~lJj*Z^ z|0=RIH<%zq|EfdWTsgTf#m+T37LMZkO$_U~;PWJ9{wmfTmWW!Z7Hid@s-6yhErw); z&1RyI{bj#RmU)v}e~@3}hmt@D)4?W>-A!^wpV!=P@o^HC1}0dcv`9_a9uZ$;r=DET z%;3ysK;1NPpRO?O1op|J`u!&Bosu|`rB}hW05es!PkuOfA3_T=KdXEGsSo=d@e~r} z2wQJR&S)6Dsb6JuNolE%z=IS{3bgz#yeJ*BF4w*!U?z&PRAq-55^F3N5TtU!@ky zDSG>HE0B5scYiNpCA?qG*3tC=h!ztbR&HyVJ502bJ3$t0!I_5`HFUsZq-}vg#WE*V zV4sl#j=3g4q+yBYQMo!8ZY}!i3C4Fou`^FEH`ijWI~9}8*Ol`{7Sy)2Ro!b~19uOWCiHlf|!ORxmIZZhSSFA!CXVk@$)~pzigW%K%%Nem|Q zRLInAR$Ro5^}MWMVao-&o3^HKoePn697M8oN;6_}v4>EE>Fmf3h*qSCXJ{Sc7VpGw zZE%v}#VAV`nracQw7RfE5#5h=7Y>h&y6fOi!QHbovfJ=-&tuq97ghqCiAdp1`>#Qt zd4_-F`MEH-5WkMzB6#TP>XHXaW8=n{n(B0+SszTuU8n6tmgr_jlsU?!{MOeX`Y`;M zJLvqlR(rEj_0=GF_t5BL(ON0Xd0IJHo3H8k70PWLm5Q8@oXPxJ%osPi_;Q{$${QJ2 z$IY#g%$n*#LUqqo3#eKVB-F#vR4&_Ybq6OpFz^i-(*-!K-wSQyCa$V)$SBS+V61y| zbW}FsFTYg#Rg?Jh@HYBj*sJQ!PIk1T%!h4=5Nz-nv{%oR*a?vcNtj&y_yB0p5Ixpv zvN|sH7^(@i$p0}kx7;eqNNfE3HKWc1g<8=@J&YM0WW+W4Q*&D$Y1BOvI5cf>CyxYn zf>Qe;TO=(n1RjpxVU|l~WP3xddxsRmmX}kd89P}6cO#7|f;itQ|E{z2^T#~TDz%tR zLHE~wpC4-Y1iyRbdHJaI6f_c`*HkQU3)DvNJ4-{d1X$v z=+IT&_9Ov>d!D2!X20{g{SA~K2pZ4v#hlrEQ!agCy9ob0K#oYUMRAF+}o9ejGpUrtPJQQkDY4PR>D@0CI?W+ z{|#V~r$iVxg0hPPo@S}>RhoEIIAVd87|hT$TinN=BjO*u(>u;h{#Tn287;<`p(DRX z0z+Ebj8FB@*^L1#7`z)mFUP&u}O=tZ&Cp+Po*Jj09y5pr~P75e57GeaSw zlOkzH-7uZ|&@w`qwDsMGbk$YTnrst;I&X63hg5gl9J85CL&M{{StVgAxCjEt01B$m zzI*Hot(n)uyCcN6FqInX;;KC-hYf;f#PEYdLe`4l0@h?=?ggss?yzgG&N}Zg&Ax(` z1=_@DBj8?$#wcnFkq!C2D;#j<7kUW;pV`CCl=WhBn|J;`A3I$s+|x2ijdywh<=f0| z%2KkbrVL$E-@yYy*g75KQMRL@$)k&x&Md8bNC2adyP=Z^wW@*CKc851QYlJeJH<_R zh=$hJO*?M~7Bfyi-NpA}Rd)KWk!tJn7M^1_X1C+ck|g{&$E>3*t}6HRlR2>r3j#|& z^T7ZN;RttSdu*&8MRua4UOCgW0D^9rxUmlX%O=~s98iE}_C%fHkUdsBUUJGW>l-bJ z?fr>{1kAomX{*!(l_r_&ZWkLJa7I@@kO6eOddLQvoi|jPJ?23ka(xV>*-(q_99{{t8;I&pr8|zWs)ra$YK@Awjpnwxc&G$F$VMDNmS&8E z7(Zsy|Gh)u7p3h(8*$E~-0=3z;W;MWsh-BCo{W4?5=fXGtox6paI)L=^_XTbeW{D| zgw70!{!N;;WbyX&e72R)@Z>B$Iwv2@ zulJ#xS}2G@JMX9`G*MDvHDNYPlXBG>YO0Q$Dp=cV(9r%kJ3HIivxzH3Q{cQszp8R{ zjQi4*?{g6b8WVUA?^phmKvD@OC5v{b_YOjx`m}p$2XtMYo$u>Pjx|gm82vI{boY1Q z$KeI0H*DGN8kLG&MR9Sn@ALiX=_!2=;Rv(Ki!wW#=I5mTQ{uz77P2vJ|839yro_`F zhE6KByG2=0{vPNaZEKqCd!Co~+2<5@@7P}l6b*rJ!n)q zo>b^IZQRe!&FK;FYBsBSS0wR5=a=$8MF<0w^pnvTc66;R#1wfM7#N`c4gK=>Fw1d} zO#Ct`ZFtafwX~|egnyhyyfl}x4go1(19u>)#g$ye`T5JldEqfWU0HEszQ_W2Mj+ZC6&psh#+r9c_pnlm=J?2g-=)d1&A(MOo4~66e9nq<=M(q-;&`l3U zQ~7w=VltjME_;^LoUfs(yvs@W)x#-rL zEi^NK_^O|9$B^XSLL-i_9u3hpFyI;%_r(obI&F0Qf}v1dtMi`2E7!M*ksFAs(_kTQ zD6IZFOVXlkFvO3(u>NRR(N&=mYWHj2mLE3J%+%_vL2(0ImSShCIC5ZS__0FJU!yYmCG~-jWaK_()9YTn@ z2T_xFksh3GS;%1UIIN4l!#iGBqDXK#df%+H4cWd@L|G%eg|BZKgOJ*9C&3X!WtaRhrPMX3 z9Z&@K(V&^OuW=T&^=ML7&Q~#z>cUu=uN`!Zp-)Z{RalD*0q3R`JrQ_miJ1-sIYUba zS#YxS3&R3^z>3?&p*7<`4^n*^AKwvz(ZQmJ&JpskEZT#D-Zqv&$$Io(r*==hwP=VA zuK*4(yiOsgWu?801^Dy{99|vVGe$sOjFH^RBZC?x14}mBAJ3%9g9ZAcL6lZ33@noD z2h!8G!n=w?pwv1F;kG-2HBJ{5F?wg2aYB|m+OOXrT*vNA)!nN4h zMM$n{nQbO71o-kJXk6_nTL=yp$}M^1n7jjg^BM*tZvETu(e1AOf<( z50Nb8y>VU;LIf8_@Y$9x!k1n16eSk!FUlcCiC#fzEUp(KdM!gu>4n1GYIXqGhd*ft z0jlYVd!Q%P&MUd`1(J}b;h%rHAu8{5EKt4ylt~E#Czc?nq!ui9hgM;v*|{!5xK*NgwwSJ;P*M zxP#x@sf`T?uA#nO1m1X`!eP)zv3~sGS%D81)&iqcg4=}w9{o;R?&qQ&7XqQ=D}qjw z4UY&B9KAKnC;Isz$3aKWD!(Pmf~@3b0X#8+)`oShe&w4?^rY46lcAl%2V|+tS%gQ4)g|z!Qu^+dFLJ*{C2{d zL$k*je9nwD@UCIJ==qs}Zs9G}-xQW99o~)@ z<8)q8FlSFs*S~tjap;*J1Er$pnzMWzOCqc&1o;diPMV=0q%GAX470iM9`VyMm+4JhaQqk#K6RE`($iv&jGDU&u%1Mfiw658sreGar*Em8CdLZ=TRDCn?2mvZ*lJG1 zx)Sw-#fDj(kPX5}nEh|ZyJD(l;d%9TH>6d0ffU8HwODQ%D_^s@2I6nB%ovB~C}uF+ zx-CsgjZifqd^J5|MslY&sXTu2;<(1C&2?Zx=kIlrJUMNpo%lW1wL@pg4^q}t>h7-g zS|N!Ive=c*i$0T!(E(9gAPsV7BFz!+qWIpRYuWTo!uFkV>&p}o`R$(LILpBw`Mo~VHNl5(=P~(NreEi@#NOI=e|e(x$UIfRw8tFX&3%k^<%Wnpc3r3P&QpoyM2s4rMZU zsZ$qL_Sf^=T3601_nJPxp`cgvo~yQR-cxA&jLb1bf!K;_wtC&L4(Q2XIeHROJ9b#& z$(^jDKK}DZS_mLIKAsjh9L;d2%_vn)(BJxqrju%Auh05`uTUg2U@G+mor*EH~79WSM^HnuBltL0^Krv92;#W5t zO_j4||2!urPc^E@2b$WuqgaT3|KMd?^xx2zG<9f`@7ff*(%B^3i7YySVoDK9bguN7f_XP(cE$d) zz$ZG0E?Q*D*8>nFmR`W_rfsvEZoGyO`5|^6qOeHw0ivPX5F)Q8bhd2&G1D!sOIg7w zLIc!9D0VTNH|N;sI2ht7u9^8a7aT}HIC`YpDxyrXIEX;o;OaGsg9O@N`A?3KhZ2|p z)GGf-@(Ij*>8+3o_Q+BWQAP zJE=ytCXPJx%<#P-`L^Fhe|8*;_dOE?eKn1EbH}M-N9I4P?nu3Ojnexi_)OcT7F}~Pk#zq0 zIYo74E$&8ki{KRB^#}~?#olD*5D#;6^XqNt>E5*n0`P53d-2!z@s1AI9Sy!!e#V-F z?-fDQqo;(6X``X{4{;D+BgIvRqoyxQL1Y5^I85&h?13zKF+P7@nrhmdsnD6nw)2Za zW`M)^zEhK*$AkQGr0FV7Vfg;{=1?Ytf)l|@2q>T?C{VeHB;$LFMl7%8pjuXT@R*@Z zL1ioFyLwp*Nhr#^9uN&|3%m)NDR4ePRGX3xhWgbLGrk1Lv_~HvZ|qMHP#BMiJu2)h z^hiI$NEutM709K;f0X(;d(>ZH%STxJ0@CZK+QgReoqK|z#T{VaYb~YuSa#*ss62cygK1GPMv)KrovNFC}r-B=P&@7Qdq=M798iqz0kb@D; zFr7m6c$@bIpH$wgPte?+`Zu!4(LniT9F^d}q}P!X1ZD=d*vPbTssf&{9Vaw+Gg^s8 zOIMk{+Y<|@j})JEw+2Rzc#jfvCPD0mjqNyphRx`NX){tZ+a?ATrjLTO_W2RC0}sM6 zHY$mz9UL9Ngrk?Q51TajF_U1yJYBjL+@FhF-XVA1l%=tWur|Z`DUbU=;1{oak3&^I zAS0N{LfGDiffZ|VhE)J6^Ry+RF3@M=8Uf{%seh_qfs*OhJ~%Vs6BjPo6fYJM<3_vZ z?C#ZL*SC;iE;;v!mTnVUWlY5XAio2TcR8R}t0$xlBDZ$0L}eThtU9d=9ri1=gZmD` zgQ}PEm35z&wI|SjzhOI90LMlWw{2=Vi` zx!QCm)s@c5pI6;HKim3w63O-00Je~&le|N}IM)Jci?i_hnZiqsNy4Rri znJ*pFK)(uuw|GI%)oqt}soVx0)|w5~I&2jKQ#rbF#7q`G#-Ml65xf)v;1`htYubF? zu4{;tLyjF_WlvUo8j{-n?Sg`b9!+y2X++L?OA*r|#!&az4F)5jRhzJUtLEun7&SSt zH2sO54zKI<&aNrosvmtqc7``POKvfys##jR3Zy8DWvm*V_+IZqw&R0;j_@u0U3=-K zrkI5ff{V$EB1K-^A4u)*4p+8Q^HDubr%mK0X)IKd_>ZrHg#H$8^k{8Kqnu)JbN!-P zvg_!DM?pq8QZ%tr#v}p0y**!;{n$1xu#-)1wea32!2(F$#hnzz^V^cOQr+=Tc#hAq z&J%uR%xbUe%#HW6M@nYUO7rP>8i5^ICZkq3WA0vsXsze>musVW_8^q<@OO%TCsZIw zCr8ip54%;{9LP%1GvccnPhcOs=++4mLlD{{1VYIm{}GYUSm5Eb+X%_JV)Y173hL0_ zk|d^u3O?Q8m~7(hdzJV zNhU;l5h~mowAkE(xx&DI#r0#bOYNz-l=e4}UykuZz!W3zd*I1wMRLMnV|3Okw_Bn4 zyYadpT-u|amR=Bl(Hbvdfg!D7 zX>q;neB$7*vKY9H4R)Wk8Pnl%0!XeHMJl+9Cc1RmAQ)W1@1{P#kb0WWwDQlJE6M6Q ze54EtQYn|rzJU=N;!1=vjORau1XdvL-e~&R7}B@PtsvB{?GtOx90QhfT*Eg zP!4p?Y`?a2s^`hldr+mI^1sh9c#)-Djs5IIf{pBqEO0?iUhGd=me*Ttpy5Npy;xhU zv9J_BTre+W1VJRDI`mf)e!qfuY}s=mXIZH~#e6-Ml~C}Xg;1gNY&Czgj4s7q7`XJJ zf+9v4^j5w9FXrAcNV2b8`z)i&wr!hTwr$(CU0t@-W!rXDmu(weHYWck=6&ZmbIyk+ z&P+_qhm4GjjLf}r=U#iSb=}wfy9(|D=d6-=rgtj+wJXc+T>cLDM@~&dFf%ht(NOoZ zH#oyuo%gNM_A63*6yFKu&X|r5>MJQ~da2Tkg;2}bx2}&w95u63u&xs9G@52{|4_F( zv)`WUt*`7f*y0}C8ewaO`+FIds>;k%>0aBAD~Kv8WXHP)HSq&o{!a?Vd4+jX!E^ns z&~DZ5hK`o%!FEp^M%^Qu5Tq$xd(wI8ICfjhYrOaY9o!Y89176#;G(Jw+3zXS>z!ymh>7 zT^}@xwVs!*!){Ypz9H7HG&x!u=nd{yQTamBx!6 z1^uZ!p!m^tmwBAvkn`j4UMq)hFbL{S+&Y@TWIj16I((tETU}Y{v#`9aE&UqNt-IEo zBe^%K(cM5=^Yd-qh%XQ@2OCrBW1M#Qt+di-xBY>!RfxJrHc--+m@-=e?jwsugl|zg z8g5&Ch4qVmNmD1FcB=Mk<`t$|{U$9qQ!Z<;|AioJVzwUrreG z_kW8eX79y|8iZ1JhK?ECXm0cwHCT+CikdvI#{zdw7twI}l)RCBoi3Q%2=2ZIdEfQF z8QRk?B!irCyWi%VzTe$xrqF2Zbf1$=_ zfa%Z4?}4~@t?y-d##OED+_oHt9B3*8@;=99B|Ko!$FP zedoGhWR9guRLoaFGi0xA`d1XCc=_iuY^Q9y#`c?l( zh0Hn1!9K!hp5I&K-y%y^{hwx#oHY2d+;;B~0EeGX7?Rv`4~v&_uQ4ZjZ83-o7q6KDJoWj-_Wa6QR$-o2 zBwMXU$Mb5v8PL9;kbuOk^2pB&5ada-dV%?#Yt{dL4@rLn1+Y!=R{cG1K7;z!R#zYG z=b(y#;tu9u71*@$YB<#_f`U8Zwp~q{Wi@y6L8fxs%);Q@Z+zumI;v`WTn9Kt{}HU`_8u@okabc?;U`pOZZa@9qqfC&h6Bu1cPiFe>8h5x zDp-cxRTUH*?vG^+97kgXO=dRmIIbnmi(;~4m*3g$?qc-!agI|Nbm|3xvjAo+fE25& z)bYGq#t$VTCysr*?r_fB-3sV_l6D^eXVv0$+xKOB?_;qstunuyY<#BMMjVdyz6TLk zaC2kd8hxAI?!ymVP79czrjaEiepE+;hVbx7`YZiuE6EDSoIcoTvgqVtHnkL9_*3{6 zQ~ZWVrB>s{V@r`In@!G_Guo$N&;{^r@BVnT3G9LkJU^ z2kpFmkwt+aO5CNbp{bqXv!L%^!ZrhCYaUVc{=op8GA~DWu_#-<2x_-pv|-?gSK?&E zuaQ+AHNH%MU3M*hyUjaqia?~^i-I3N58h} zTqtn8^85E~^m*cPBuR0zMox%XUz7kO4rixb%8IzG8VI`@qXjptSZIcRA7fzz8w~du ze87MLGEaFvxcOz(PwF;z=6-?8Ys3{H2Y)^6tcfef4`0C+#05 zw~R(^Uhi!gQrzNSQGhe`u*SG2lx~alGqk}w$@31x!9V(c71PU%#{-Sx9J5>Qtv<_)y#@|_wEvRINAd~r*KX0WsM_$*uJo?w*8hf zB~Up__l+x|(sV_qzjAPoQT`@FoYU!ujUo%HB95HjR{xoP#|`F_FF+U0r}HT@7{SZe z)Hk@)8)Fw_8PJ}e1fM%N@i?Ug>m}P6`r6lJFna^(_ytDMP6>af$L$w=#AX+_ZM}pu zaffYnu|NJi7PGX@k#4|g7N>_K-`^#C%{!o|LJ(bRJ#H4(e-X5w=x`In+x!|_ZT3-H zRO`8G@E+SP!=GT`r3nxyIAK@QIkl3&wAB{1p!lA?3y@(dE2S);q+g6Bnqw+Dv??+; zd4b4!B_?H?tn{NZg&$W{rKqGPNFATt0!vCulR!rS}ZR=r&u92=6QMv_-9>^M1TnQnu64fNmpY77p z(z1t-fZtoywe3ROhxSlhgB?suZB)r+eos%CEL(l`60Ks8l8_MC8xgp>!ooa(qbu9F zLyN_Qk~U6g3u?dLpb0n;3IeXshDGx;ZkiNQS5$(kxAToscHHU4tt+3{)SZN+fYvmw z(!MRrkBR85J?rw&6C%5E#W{NrscW63K%7a7?f%Lv!Nt@zUk6+zUYy9Y`|r2z(e$%W z0-LYR(af6!uc}+t-Ddu^AS6%H6P5jSfiYV%AnNNlYGPmzF8Qdhu#jd zHl^ZT?{XJgjNW~#1z(U*4%n3bKPQjHuqd4eob4Y(6KXI*kkETPk7DGcj$mWyR0}ka zO{cMWWD-`LJVDtF_P^Ve9!M*@jH0iX{cX;uPtAXo^3!t?;IjCl67wT~PLnqd74fCs2y zDkvyIYV|7lMsN_c@j3eEAf?v7Veuoq?~3yOWAYQI`F6$GuP z>S4FMMe{NaEsZSIU~q&jdF38n+zuzV*=Ts6QL8%0@Bkkv7FTm$#KMj~1+y~#u=!%l zWaGL|r1}&V+wTTbm=%S^ero-p96_Zzznr1t@SSU- zJM8sft2`CGq6X~XT+iwfCQNwQkN9`;ej5pS`4x)8X&%7*qW|KUFqd0yA_mB&0J`Gn z0QiiTL!Yuf@-f+e*6-YBqeoE6`6|ZZkWIa&Za<6vOHWIy!^^*MqTIbno?zuE5XG4_ zuQFxBz*AOk6wsUMq7I$9V)V*&3ZMu{29UJEowWa$FLNTU9xZYZO75ez+=Py%R4^=P z>;`?K+0wg&fU6vcWuNL&&OU`BrPJ#gT38e9Rr=tFnq|4Qq#iPCm0q;1E7JR2iRkL) zMh+ai$-aqx`F`qi0>g)E3)taBNExX@xkE(k^n1?6;Uss-g$8J0B3e4TAANTn`-i65 zWllytH!}2k4Ixi~Eo4zIY?Ia#u!Uksk?w*Wq5N2H@a>TSBnWgS39W}86lb-)HQ^*| zJ}07|5~9BbTI$v*NY9V>JpBM3=vmE;ZSJ3~E6mmB45%2nf)gQVuKW&EkC9?M3oL)e z`&!P-oa8kdYXB3<)+%Ws!o&Ne$8b?ACvkbIYk zUG&rXw|3!rjYv&1xbv24x1K%n?pXgtm@jbP5jMXeWi1K+gO+bk<}%v*d=-trcbOXm zFY4yf%KSdP`6gr6;Rj?}gBQE7Y?Aan=UbkPkxk~6{VltMo->|1;ATaZL!>v^>Mg*b z_NMt#evQkSRAPWoC(Vlca~ApZfT~%XMjdLwlO-fk&Qw3V#5P!rdwKYvKEV*%C2l9`$dn5KCro4+g}#!^!{6rwQ@ z77aan8IdDB$3jx6D`1Yp5T%bNf7d^@h(X~c{71Q^=Ifh4o?K^xrS+D;CNHAK?1``1p7suYDhW zfED0N?q>n8dHa7*6_Dx1mc+ASTPY+c0O~)GZ^Ui(RwI^IF?A&7$f=f<4Q0w4v50q> z+D^?fqJzDLDZO_SH0(r;Iq6A8H%af63Y4LDxrGYN<<6uu(5#%q=qY&A~ z+$eCP3_VaG6|Fn7E(|wg4h}LtPGzqZc1sh3jy9xiwtkRSE>z}=DaoNEY}pQWt5tV; z(-A}|33t3zu}V#ldBF7F`6sf<2}KoR1N@6mmt>KpJ*0n)y}aH4_!7YWI+3ZL)C-nW zU-|1nhf6TwtoYQMGWtiqO{*_+L}X#=PGGU!7Ko8Oq-C1Lb^MSp_Gk;_5>=~uLZHxy z2DaW;)mn}al||LCS>@QT=bT-@rzORZWN|}*1}xL1Y9_+SJ4(rhGp+2?ai?eOhL%?A zO}FVB{dYWnEI3NjrVIW0=#3>)1J=*eUP%g9C99hVc#L{ODH zXlnabULO#h<06#Qb9PEotF&reaifGo-20G@szQv59Oxm(J(x2hmxV5AF)+UO)O|ts zs=WuOErokyDLU2e-*GKe=5|6S8jf?E1`-9Tj)n`?UDfjhL|(}8sY3G30Emf3|F#DS z_51oxQIPMPn|~`0;h>+Aq$`O$QMk#ePW3g=5=zjG%bfmL50MiA{^-iDzrwK;rH&7< z9*|@ur*YaB>DdOHUjS(dxM260w6^`N?r{C2<{~f3c_QQC8lSqNLF)}a4g54-GbZ>% z4s34Rx~A9!w)xdl^|mZiU{in~1jZu5R@>GUq-5+}#tPJ1HKS_!bkQH|m-|j%Kev1I zstYSF8E|Y}ZrMrtb6W{@=;Q^_e5ZHW30@i1z<_N$^%4vOlR2(-2E{58i-fB+Dhd@$n z>p^YU1~3;O(3{Sk#PQxuZ$Y|X{fAgcxLP4wsC$cq6Vwb3Pp{Rh^ zoIVmubXL1avuW_$_;H>gso^#4;|BoafD|}3TY9g%iVdP**IsV!&B2|@l5x}9c`1RE z)rssKo0Cu+8Y#Dul72X6ld|3SO0#;G(O$P;!kY^(9mJP6PHC7R_H$92j{3n%Y~;N8 z)$}o@8K3CgZXqoV4f#NeaB!RlIri??!T;^%> z>y=m5fuWAZv8k4*`j6((`Gz_lGk9Q++o2A?`I;19yB$IvVYy#OI#n=(nx<|cEPxOT zQsOljq5IadD^qjWmjF?l$R<4Ler(nTVE3&oI?kZun&j>-UFO|HQDoT{4Rta_T{w6` z@O)^ySwZJV%_&A50Rc~bI>VnS1!RKZRbSg&QoF#8+Yt_+{8LcjtcW>FQAbZ+;>KzH zTd~#Ld%GLiv8N0dKGMwf5F8G~Kj!7*TfsE;=g)8HJ;!-7I(*Iw^X#zbyuzv~+Dyi5 zTuwg#WHRsyW+ZKZ%@RJ_y)1InD{E=5!%=fnE@q3*BvrFJHvOm2T5aGt7Mnc*LJt_H zNGI5C80%1w$a0e;Nda{5;0BL^r&SoY1TaS%uJHfNH{RWU08zSrXcF8C8|T~ z>tHb0FTlcnMc=>pz3hjT?q0_wlH;ME3GA-CG)o#CrnHE(j%7lgs7sdUN@8+@qwUWO zX+2fCcCo1~VIy^A6XB%h0i-Y0DIxdf`3nSVJD(aOyT&(( z$D~DzJ~P&CM0D1+hM_>%qgo=g6xB9_UlojufP<~+$QvcH`f6Ha)-UV>Q`Xxw;7j~9 zjsBcOA&-eB84Pgq?o(w-|9G02!yx|x<|{Wm!9QTYRdov9H!2QazgqhUwp`Kih1v>6 zf|%kg1j7(FND@L$w?M53+3kI~xd8h^E#F;IJ?h5?ea>+z2`cILotCrLx@Uro+qzPQOHYJDpLgHdtSg}4lDZb zT(ZC-tqypc=Z~EuncZ9Gtq1R&koWk86Kh={r=(g@_wVlJFD7zX{)hiG67Md*`GeXs zs#ZiTNsU*$v`~6Awr%yy0<#RL6l_JEssw40h4S>zIv>_p{M?^_CFtFV^k2alOV(qT{N=dm313U!(ZKZBQc|3 z1oJ2ort%ZUykCQ(aPlg(*XI8y1O$gNn-CxtVe$|m5PV}#?*V=6H3;JC*_>`hN_ep6 zlL~SM`~?|3pP)g)R4_Fq3wQx|!?A>jGXSi}6%f14g{l&7_o2TR09g(&KT`TZCw`z!3d z4-VWp#>U3_ey>M>cH^;j3!(9lgRM?2JRWyoC=Pou(#rCCwH0cC@4nLAj|hP?eUfQ$ zB*%;vhXk@Mpg&pj14Sefs+-V6nB+lF;sJsOL4y?IGHSQv^A_6b<{YT~0Oi}`5U6J$ zGAnklv>+pZ(lo_qF2h){+O5Z(>|ROGM|VNK9-)i(ai20=HH^ zW(p|8W44Bi&rAla+n8#mj2M8%Tqt1r;dlE-&AQ}WUDw$HRe~ZKq{dfEO8%3rdRGxCFQ1-gTJ`ljg zwC3}H>kuYR$*>3xrS{_!!CUs!@~fr>hS2C+}v*f&eQkZB*T4pIO$+Q7`1|xd=X>HX2?)% z&KzAfibz%g@4T3j+LECA;)V>ToFeN+NIIKh3jGu;CD>$~C}kGPDofTjvO7j;VO3_w z0z0eGQZfLCN{)s|9-)fHXe9;kTvlVTdSL<|8(Jq6+9}lE%!;b-@Rw^MAx)!=7;_Gz z`lt1YUu7Qq`M#REQKP+i5+NkUk_0LTkpwXaX(;!gyVs;~lCAjw8BNCWCq?8*z+lja z)MaL8gTegc1V@4RnE*IK8egQp`Xto!758J=NnnISNz|GqQllooVaRs^y$}?X3z05b(42C;rT64RRl!cUS>sY` zQ>6h?mf$(q7uzp8?`}OuE9rCPyS*3U)#a+Qx6<=mF1Mk+J`)S2#O~#{KX&027zu1v zYUllmR#p)(fT9opgyv`%j+LRwXbreh0`bHS9~chSW}gY?cnNJEF(9kj3(ow+=u^BS z-zQc;RPN`l7oh?cuf~DEKT0~OXnCT{<>;>mVCfjcNkYnkh^UT@&T_gv$Z%L+u*gB= zbYbK!FIU#dv}jS7eghnCfA_sZSrCSQ=b~W`;`K>nEJ{`<=Xs!|P1}hV2dS{?vfDN#a5(u91Mo`@s5S|5`vWk{KPmKOWt!`?P8zWn=~WP`K;h`QW1lzE0Hd=7I} z83Q#nxBr*VInFc^V4E-Re|s0u7k2s43MUwdF(DPW0X|Yl{~$96&GNM1dc+zAGhUzv zfB-t{B8p1Sd0X?ox&h{1<}zym7%y}2?z?53))cU)!VHPamXyoD?q&TM-|?QVD$EC`zEwp56#JmNI=rYl zASUTjaJ)DW3iJN{E-ogPzr+iekpoO_{@ggC2}D=(Eb;$Hkg~tcDVv%e{rLmy(%(z{@{mmJu$Wn1 zj>JZ^>@7))B;x^K*%eVihY9-P|ztq#eE%CBhO9l1d8#8iCn$ z*v9p<0Q>O$I^&NDj+;zp5zhLllF*dvF4Q&3XIXv3mVW!DtiJKot*WMra!X#|8c>|^ zqM1(_7aL2DM1Hz&Ub+DNdIMl7M=X*0+e)Ev_9&uL8Ds)#OV=u~qRg=*VSo{fV4{|3XtC<7;+*|0ke2>1T)rhY_Q;Dy0>Mqw0@%Rb= zBwpdN=lkpZ8~>g-Az8@b10W<5g9t^3g+dZ@7M`3g0>pWC0R|TW?qd6`WG2rQN3WKP zQ>x(`)@0FDbPtuUFar?E(A^h6k4eNXqf8e#kBk0$TUB?GUNAu)-tZU7T2d=cY+mU# z%sFB<09US!PLZwz^$&TELp&1T{hf#=Z&^54}X`KL9@g z3@b=1%lbDBODHWp)Ul&&*Czvj08=uxq2kor*wFCy{tn!aN~QLeB_c(~d3<~@_XNdxWI@)v$C@K zK@6))4Z1gX00Pc+gBDKBhpvv6Hm`?Mm)p(Gg%XD54J9+8Y3i=5eRv+)gsB6c=ZZ-`iPfeLWN5 z%*CV7SJ3xoOz$`HoB!zeb>V-FqxdHi;eX|<{MV?3|1QZv+{w`M--~i!`hPXbfr$$c z_3}RqZ^&VA+mt{I4~3xBG^m4w(x{sizd`Z=BQOXww1|x-!Mp^9#h_)>Ktwb^{O3{E zXCm0wwf1X-r6@s5>9gWOeW{v*U~KZfk?m2oS?g0@_F&M;_4|F&ZS=l+L0n05>)JL< zM7-q0j<3+=kce9(eQA`d6!hX$0oZPYEphnH*rkuyuDG0=g!`Op2)vHI6}K9XV-CbJ z7rEd|-FKazG$_0JGAa4t#!mt37s}OrSo3nMYSSWo&`PWYU8V-G)n5y%Jv-h;vP#iT zI(6BVx9WkITM-^df^spoXjvRhy7`!D^iwhQXdH@y%H}TZ8m-AkrzN+pP0?~&AF#Zd zkEOQknA+K?8gk>;2~^X{;xNx_5Aw?4jJbtWY^O_R)moDkE}iDh({tr}Pbdch;Eet= zh}1a7DQ4lx&~kL^7P6L(ps5JU&N%j>az3%>x$`lL>eS&Vrp3aTSWNGu=|1!OqX+$k zbAf5f$P9IZXB#jQrb>sA)J01N#CN}!nF}9I0ViMX*Ncy+mc(i(PSa%X&F>~Mx$v(*E@c88Gml#ruN zWYI)59i@(45=j&NV5^;dxP+nZ3S{840#m8Ztj}wMh=g8XW8;0sVQ(irI*hL1gA{`c zsxVC+W4P}%8sc}pfoj+GdEK=FZ~iF#xr8b`WKIs`sgIW1V%1jmxRif1yD%f96)A$y zkMlr|1)R8r-kX%^A^(&^3p^Dv|WqCjBh1Y%Gg_QEdd` zjtZ%#SK6!@K#45la5X}7adx-Xg3PHA&G(*MIgw!;nl3XF=O9a5N`*!19;hs(`O^O@Rzy$Y3bBrgtU^-H zk+v)V@ZP>&&2jTJ%f5(pWgPC_%JJvM_b-uup(Nye9gwL zwFnM7Z_9cuqN0SpHqgu#$&pd75|*L0DLMhcyAy_QVd%i0Svn%J+Hsg>;8~f1As033=kPPrkTaS!gBQVaNm#8n-{m{11F=K+#!hEq z^zqDZxvuySwTQ=c7T0&!7?R#$8e;v>Dl{+6X_`gv8W9fhG}(>VMhXx%MWU9@h0E0R z9g}Ot4sa{Q=@RBeN&jF<2*XBbvEej7ODqvX*fS$#IzA6Okwg5pTFkoApHPifIH=QM ztH*N3!YjH?sYFX`5g8=v{*A~;BO?39X$g^~m#q?A=cg50F&yt@J8|=H4=e_{btdG* z!RSLKK$uMV4aXx}Dbu_sjN=z>g=NKZwA5EI?DoSM@!`$!BTZTO&n{Ed0%jButoMs2 z2f89$C8~GtXV4{-tGaS<&%tkaw#!SoZ2h1X7Rq%DMj|74Jy^D%G5f}5r7c_^EGNgL z$6Y7ZleN4ZFPU6Xa7(eas;)bS8>`DO4zPVXF<{(4yEQFmA2f%7tGnrY*iJm9D|24> zGG8H@S7)Lma^tU`4=w)t1-P|ho{c%rQrzmDTi+oI>EepzIY4q?juiF3CABD}m#yYZ zVSFK7pg`ijK5Sh8R#6vEm*y&svgO!l@66V_7R_O?5j8Ggl zscH>>3tV$A{J~sY2P;W}Aw1LJm5SC_BiP^-dhN{_0Nd=9HpLjFu9w)s%t#+4yxgLx zWf~VPg$PmDxDjHmO?0=01h(GXt%A5U>#3}sY_6u(AVilue~nhp2N1+mQ|Od?uGk4( zTXt(>V59r`H?=ux0?PCBa?$epTpg^LU0n4Y#)BdHVXJ7A;Tq9!q58ChjgXp zg$hk;>R!$7&GQ>--$|GumE5`tx`C(zP9kkId1MgC#-Z<1lHnzdjjs16Ocwb(KAfA) z)r*Pywh^l;gpUFWR`fxPz-Bv;pQQQFLQ3Go(1!*<%3#m8k-L}atfJmF;-?(e)E4Y< zp|-=V9(c#U9QTX!({v}of?kG@yFy4Em$uw!?=}zG!c5ESzpbNd^mVVSAV|8%tq>LV zU(BBGM*8wx80hG*5+yA=?L3`)EiK*Lyu7^lcyjPmcmu?k;|maT1?xm=2~kDf(`xlU zOzqS3@3W|%TQa8P)F-K3AM$H#kmj@FI<-a#@k6bp@)L6P7~!daJ3u$-h(nLn^& zUB@>!zA#VPQ7S4=vuZ9f8J8BnCA_Ip;PH5qC^Ci!i0ebJByoPj215q=F<9U$85{q- zsZ<2agTAgWjAFKL5Vbu})=RmDP-Z4iC`mK!WV_&GEHla1PCc7_w)cqx3Mf=MeHA@7 zJC~ae*2il7PWDBWJ(B4__5?Kqiv)^rMH)g>_&GSAlbKJnnOgy@H|1EO4&I-FMnzl!V^(ZlexZme)vA|oa zUqGG$g%#%tSYz4>PUJKZh_O&AOgm*Pc(Fi5S|BqKF-C5zLop`%{%Dk&$W)sC`u#(- zUfW8e6>-^;Scp?&8vUTegt*gBqcq4O2?Z(bI*4Hy4CXEB_&*Y=#`&7W(r%d={zhsdk=d?5Uz!fT1x^O8sMJM%B4p z_!08p00H6Sush4UM!@&1dm)GdeWECg);9Zp^j0* zqV=K{_vK8yR4&K+`S^-Y-oD2b14|o5AtL^+r1LA9NKPX{m8vMD&cGIT2!HPR7nmk! z>O3sW6(j6Lw?3c7``JsmyZpA#)8(;uHx#m7W4_O!Urt-(F7{UQn^;~ad`m&9Va8t+W_d#mb<)O``rUBib}{=e*>~OdqbLABV9LQ@mR2Z zJ?%VyWEqO$pbY|AM`zj-pQiSP_t#DHt`R;rt)^_ zi<LPZ@6_a5Z1f9Z29VVg;m#%=UJ^JzyMjq8vihnN(w+tAsaELK9xlfWX{M_wspQx-D^8O-%N!0(KO;W5KegW6JXD(R)h-}DHvsELD zxJZ^@=!;185|wq&yN&Jb!3UVqT9Ma**~gJF$r#Pz6IY&7vm+#GL~r73Y7N-KsRs%A zgB0&SLcgAN!x0GhHF(=@;Gn$DepUskV^?Zf8`9Sng(VuPS{Bg-0oPat(E#<&Ty8zz z<2)8LgM+Q6gfBU!vQvTt$6#;+J_M<8uj1TC2GU${7@5%|LONKdlE1F2@$xzlEzNPw zuc@*5^|F+Mus|;J=BZNDYJ}z`IYBf}V_CqdoZQdHgq_X0)o%w~`XI2~<7){u_wDep zSXrwk5ZpT^@#8po1tD(OCr22Ee+lWQfP@sO>o0PgNipDoqx;8E=V%z1ysJ#F24BOK zn)x1hwThKnm`+V>eH9I?{oE0J9H}CL3OQ+z!V5Lm;;$R~lj9Z!+Dqz1chSA%%KBfZ zl}*Lnvac5B+(>ge#_Q~56X^wIWL=^CGy@J*>%s>xX#(B=QB1$fUb8bzW2}9aC z)|WK;Z)3V>0;xpA(Fm*RWY_PpF?AT#=SE-Uy}WNfzvslt-_?)|PQR1g=}p*Dt6?zD ziY*)nH%w3$G%SsG1&@hK*T*Op=r*ZULIK#xrcT3^UHls-7n$@?28B&$gN&A6h|f5d z@QSZO)0`7yj1-nwn^7kC43LK3y1CO(9zWC zdNP>L`4PsBi*<^|s58}bb2)$iqQ-2wS$eG2=uGLDS8m@pv&~jqp7x*vjCTfee8xJJO7vrKQh{n0*;HHfM&U@v3Cqq4UHI`1_$s zybkshUzZd*Jrzm3#w{U2agW=qCkFj zofk-MK~W{$oM6BQ(A3#+;C$qisNHzJ|Hf5ydD;K#9Ov9+T-pm8ta{Ed3`jSw8loQ z-fgnTxeGd{QzJu$6BjY?(7LDX-Suj^)yx3d$yh3)eCM!W14ugT#v#wBDMx=V)JteJt5%zfa`FU^7 zMp;;fZC$SIpFWI?zK?EZVIFeaHb|>N=1yAE>vuxl@G(&@&dN7e3|L}d^rsQFU(V6) zj63zM^s1Cylxau&V9vQX-{(Z!N*bVl^Te4+q3FxWZ22Al*AOhfD^rTW&E$uVyzy6~ zgV!vqzp*$!9Msf^XR6N}4yE~qqSW#-{?A`q`Ru*Oz$ak^A}LB<~$S#eEUQFOgHua}~X!GWyyjeORklJWu{D zY%JMN7R%B#;hGL+DXY<&(OSoPFU|l2e*J9*6%JV$R(W z9ulk!6YWvE_x(V~YrhMlqb3CnI?zD!^o{4D+9NWDK99V>>p%4df)O!!|h8OYZS9f|ctC zEcRr3=;p!`%atQug&?VyIcS*JJ4+5+w&tk-HX1IBLvUICm_AC8s{cX$T92a0>q<`e zvw}SNFI6m!p{10~#%W;y2x{qbpY{%GK7&|hS|WJPDxTiM;J9S&PmcVK*)!yBcVobM zN=S~@t=LX-D=Ex1q~Puw7!d8@^JJkf5D+YA z{u{?urbYuKSp0V6z`cKPm zU?9-%4`5huBs&gs2W44NRv2CZBv&U`ZZwOG7-~`e7-wT%J8lXADsF#g^K>IhVgh(o zF?dZ{ZU-$0a$@c@f00(KDhc~+|jP()hQUf zsMy95IO;Ue43vl_Vi-tpc+xc1!6wFra#rE?2_a5!l0OA><;g?c4YkGNGXv?9WBJs$ zU>R_@0>TJzu>EP~4-ey}iuA|p}Si_^)l#ni2nHI{K9j*CGt9qo_FVQK$TwTCiC!``>R^ca4Nj3#D zscMV`Zm=tly+mx7HH;K7aga@Bh^uX~J(8JDao2coNdZ$jrbt7Tq}7QPRD|TjLKwwg`YpYrD+rd#RHsWEeza#JJ7}j=qUEX7|GxWu?iZCiRPv9i?E5gnPRb!V)GHAS}^c%``Tc6>M|P9rlokO1Ui>zgqoPEB>ZwU_b~v& zLSb-{%>CtsZqMzI5tmaEizmY&V5%e*V4Yo;C+@F-XvQk)ASo7Qm(x)W1O(I{ij?@@ zj49@S8B_mWPWGyh*&95V;gzgaj0Z0$dd|ErwtI5Kgx z;m`2P@U<VaFObH={zG23$Y}rLBZg!AGOyS3f??;i#ygE1 zrYR&dceVz5=O=|qW*7j!~LF!k*hf1h@(0ccPudwTnhKlHw7%jH_YdC(kHAS`~_FIU=( z*I51v1%R#HJ2f35Ll>dmD*XymI;RDuhHQpM7tf|zsY-Rw67I)SM;+{x2Q^L4gp(TH z?uL1;oB-`9$vDTwtOV6*#2$n`02Sq-v}z);InEJGG@~k>4RcJ2vDtE7P(Z80%4WnM z3IR2_0rBAe2`d=emC>||3ob<^J?})Hc@_`bRIt|wmyM0>ScJ9M#sj|x*0<1FN8uwK zUv*)|$0#R(qKQpOmpEukgSG|XVD%?y^uWSg))^BxtwNM+ZVHg?Co+j&Qn8nj#FA3x zmihiS%+92^PR&W!7uxM{H*n>E1Ny0hu0>UYdG36_N!=>~>qq zox&0)mtC=;#B%LC=)$gxZ`X+{ zZ2;@iS+tZ&4%_00$gZ2ye1d6BVazC<03$8p#^xmnq(_@OR99Nv*r4N zqn;X>x%A*vVhQG*P8cO`%l!#0nrk+OIu+`^HcLiuNe8`}bum%LXefTq9YkS;W5W*p zJNm*$#v=Z6j_F&I|Gi8xxFLF})QlQm1@?(dK{&}p1`$GeUL}kCS}fn#uNEhH9+g;U zOzFMi?4c>;)DV;=TyWs&k5|}+Dx9>G&M5z!3Ow_cX7Oybqg-tY%v38eYD{QM%Akx& z-c>a7$Idl&2YBPf!3JE+-In$LgST%A?k(uIjBV${c5-4TC$??dwr$%^{;_TQ#MX&z zYx3QxnyRUqhpGE;A9wAC?%liV*S%J+UMnRt`^tZd);Y)>#2$IW#tPX{GuaTc*#}c^ zU;i-VW!(Y9-$s*ypKiHHe-*1Gz7pmZ*ME)RV8-AOZ&c$t#i7xsbq1+bH(Q&Tv@@U= zT$4+EnCh<8U2PFs|7ap}_+S&(h~RiOgerlbvN_O}TUN#CWV+#*QfED0=B9aUhz`nmBv}iF&| z`UdJITdVx)026c$sb{OP>YC{*U>3Q;VCI;xS2JVG^Rj#A78vnVRy0&VU&i!P!$Ffx z{O4_kOfDLz8J@otlwnm?4(#O20#!SppPpubGhH*fy!gO9wsVX5^K`jQt(^(gPvou5 zI4bH?s7SjpcPX!V7q?U(d8r{;ds%(KdAs{ikm#B6rnSw}uHw7j^`>FDSF?rBP|5+p zl$h+Xdqy4Gg9&6HN9LR(TG^(MxVC%}U$6afxkwCA&-d`FnL&WPmfxz`=~DyO+x~K7 zZz+o>&!|}SUN67Gy3-!PG>MQqOk{Ew>`~e<=pA-v@>H7s+NA)=BfIO9o^Y$@D|n|H znF8So=TfKB!Ojq_iQ{f`&adh$3$qfFq6FJ?lcTd0oR`S$y9Jtf#;v&dX!{>eyW@GY zowpQ}pUdM2WYS?uFac+qXHv_1%5kpWk65DItk@cqBD>&8dmlEnqmBsb_%9eIKqLG5 z`=E@QL_B@#_VpW31WlbA#7q!qGa506(4){9t$yqga64|RE0|qJ{WeuJncy#Qp3#@? z*>L)P^w8wcKs1}$xTP*GG-Qz`J+89$eQ+DrME%j3+KD&`Ar;e!736T(Z7~G?6VsdK zZJybm;p+(!3q)5|wesHi=i#iP_did73kE@^Ihey^5xVM0TTKT6xTax6E zyoGV@ZCS|Q)k+Sz5o!33RO+Ksg*GgnW7u)uZ+tLK_sbmInH(}Kf#u)iUQINr3Rg8GV4#pG+J7JE5}QGZL)HTB<_&I%V-^v zwCtQC>e-7}65_YBXT5RPQ6;Z3?&@dw_v$`QlIkk0L)GVs^cnqQdpM_6Z;=kno64ts z{zl<;>LWM3cP?m^4P7k~S(wra@Q1T$G^tm)e+S|oeh=M~PKk%Yjd=v>jetQ3i+yM$ z84ZM_l`U-eWU;G5fS?qMobz5ydrG-tcF>xiKD)s<0?JLJ1eE%}@LzgTG0mIt#5xYD z#OwUAE;b;OZaW^Mhd7Y!2#HBlBJ~;*2Dari2{d?aUe2mD00+Sx?< zNx80mnuktp{)fLc%Pxid`{^EPq6fm0a0u)^_-NIZIKrp`Q?$#(BT5X(N{e4ou@3|b z;o(zdoA-_95K1$a7xo<89BJcZ)Q9Xb^}5`iH(*H!LmTjpF=+zlT8%SeizF3O5-ow2 z`ATgMDcN;*v0h(s>=JEhB1|heo@=&{c$%9!59S-tj`oo$W{v5yP!7LzH1D<~akBu} z+1WX!pE|LNIZpfroYK`Tck{#m)V4Hv8UkDd0clEK1qbuAD+h0md{6_4H<}{7jYDpZNxQ@_s{bRH) zy^$%t-#3p-r_((UjkT5?M(PWeD98E$7+e`QIXCF`HZ>g0#vBgX%Y+vgWXE zZSnthFMe^&=>LCWgExLJy~3vd2XVb;E%QoI5>Es^z~`?vosUgf}Wq<-Of7%(ZxWo zK2g5+J6u4Hgz2{Tap!T1Q^Z%d)vU&;v!;p)S+#g1B~>CV%?rPXBDzS5h)POuQ)X)G z^MS9*rJAycD%qt+VU;+_S6j6&-$zuq9;rw_0RuH{mg(LeAQ~~{_VrZfPWSsH3hM&1 z&h2tY^0^FI0tlsDPw~w|1U;oGTu+6sx=&36coneWOP{YPsy->%OWm*L-jsonQ%2mQj8r+K;+Psg!6 z-Q8Bl%RkMl!n#(4i^um(RBS*@`tbqh2=7MOO8|gIpw&w#!~am3BwX5_zCLrs?koE9 zFwT8m4UD+$9IbCq*S4=qG9f4)^PI$=bzV!_(C)6a(H2o9BZph}CGU7#2Mw=GTj(}4 zUGA6Ax$WpUZY_P0<%!aU#C|@_t|VNt&s6(46?_+o$RKVXb6Ym#EPg(ll)ydBy`$lA zjCkCQ_Y?FYc5Z3&K=p!q>*TjKP=`nM1zAz|SIS1AaMf*iMS-r=dJX!SSursARf4lg z#!?L5aj6^>U%vQ)V(uy`aMFR1fDRgKX}w9(%-5};XTXL`Fmx=MjWx>T%yV3iG)&Uh z!(m@$@~koK+2agzI5%bGZ;|flrxQ49ZlgvIwU0rJ>U z(BMEdL`I8ZaWoJDKoE23+X}Qb_ZBuxyM89w{{Q}fVurcxr4&0AQdtEzundbEVB;|o6 zg8aVnhXhTx=#B}!wm>XsL=Da<#bwzS?wN4Eft=qEE`{Hd(SXiD_0wqyVsVFBm;5CI z(eYXUiCU3NI^MOS;4(<3(5fZhcVvg-ZcpMLU%AfNjG6uYy&g5CQ~$dZ=D>9!q+N`W zE($P3quABTt)PGYewH=!3Y)z@nh6XF1`YvZyv^PoDYp#(rIrCgs!p@2Qa+W|MfT5rk}n#YQuk4BR$t zu@@A-|Jveb_-fQOt;Hs<2Qd|p69o&KlH=Y{OZavIP%rw>U4Zxp1Wz}Mw`G~gZ=U;Os-$J7v$Y0FdfeTzaL+B=FEqX<5UZ5p>Tw;#Z`=K-xxa*;EzBHn*e2Xz z#;FNvdkkul=309nGpp=3gh~OW;6o&vj2iN!7#}YBFZSmxT7tLl+COuU1|xpW_?Iir zjiy9&n5Le`HluYDja#tSiMsO>C3#*!UyL(qbW}cG-KoWAevxe$JrB1ygTW0}=!R$v z6|oC_WIa=K7$F{oq6LaHyzPvIU$??s3k2s}f@3mVQq;zPwjf}^t%XLD;L z7WP!l<#4MKgK{gj0g75jH1#ewsruPX1@XkzaEE>7s3sxL16Vx8z+Lh<@MUl|{Puza zwyB9#`FBjKlDjRDa9^!;y!=WEucRBF!)e{$UqdW!`8PklJ}L)&j?{j%z0Neewrw zrYj4FhQVI|Peyxlt^fqT+W+d}L?09Ca~N~3*n9b1of`+A!iDwMxlL|D(G-h?Xr|;V zR8AUD`EP#-$ZD~MH!H#gkrV4M+~xP$!<@-9$TS9-gW7A|*3$DJ5$NN$jt$$}T#jzT zua86$#MV=I3`Mg-=MZ)AKbjT;g(P%SGs9kU+lj@XW7Hx60^8#&5l<}-7Ym;|K7(Ya z>3>j^MWl_uMKV$Ac?j$d{k@`8WYr01OElVM75N=eRG6#%ikmSr_|0rY$*qZrFyO1y z*M96p;h%RdbJ(^DCh7AT*G}^LtFZCX`^#j2#ADb&INYLnuf~Sa^n8J5A0tra%{9){ zjF7LXj@zEMW;56)ygrf(B}P}K-<*DEIZ>VMzrAX$vwm%RHJuY*&a!h~kQ`K7EvvLe zI@o54?_z>pSmS7lZ*TmwmcF0UN00=xyoQQLw__l#yWQy$zh**?DvwG9bH?u`p2(z7 zL}rAAM9wK_5@TeTeydGe+P1fb%V1y8xPz_Z>?c|1x2jvSgy+4~=y@f)epd&y)a$93 zh=}(a(9;xBJM|foX`Ec1vf9yRu&s&4pFgb8OX}sDZKA2@=U01nXUublUTL|`c(|}n zRc3nVj@~o4R%`C@oaEyP0zskVRoAC5vj07DS5(@<+eLVaD5?oi z%+VQNw(Mz6sIGLt^J>a6t@|5B+)b(z&%Vg$>-`DO-qd>|I9rxipM&@K%sYR7q2%)# z^5wQ|?(6J(-)@%W7`iIajRVKMypw1f>AE25jwvf$GEh4*1qdmQocTcAn8Q~yVcSH0 zJF7G{Q5if`TYn5zwJ;7|IW5L!H)@*O9b&@ZD)VPr#h#ZsWkd^3LE(~fja4Z_hIA)s z>KC4maoZVoViW<=q=5!d>pKdg)vLh^weChnid&fIH~Q;&*jc+?uXjN#CjkGczmQfI z0dK3M9gu~7e)9SDnWlSAZ@Aa??4UFgAAU#z(6@ITCX9l}@m}Ka0rpS9=lFV)rO7Wu z3d?Umj=wLQYHi29P2<2`95q6?c=HD$=GLnO$<06ovZ&Ule$xjPoL7={Q8xA51{f`# zL^?pOJ34B64Dxb%v<#BB^xjojTwo>5$h$11I2wrnIxE}`nO2hbFQWUMZVYUBbNETi z_Q#JyYGxv>>}-9W4&9p@o#wJ)sYX*iPB-tgY#nhK=Oh>Kqm=_HNT>9_p@9EA+@$E+%Js!_ za|(X*N+qgGh3m0qNuN^B^4Hed`@G+oP!m{cv?`pO4d~jJ=%u2`{!@XrW!99gCLydQ za>bODNVcT*_v)L@j{1)YKa+DUs-D-T|)=f<6uc=AVd!W@j z%(i!5*q0lxFQ&c&PHR6J=}pCDUSo7l7J2UV;eiC!gO^p*6Ts^8?Vy~OL6Mcl4|Fi{ zMpNS3?^5>ixs@1Q7mcavxsUBz*$MUgs6WZR@5JcQ{hrtId3_DATM4fqgx_^~Cz2j5znHRc!0M{F0hIx3aB%}Nx1ecIeR%6|EE&I$5f-%=2 zFF#)v6w`l@=9&;<29KWMG&VoXI2LBBLEf+&b{E7z;^;!M^7+EPk0+9e+umq4Fk?bem*y>b)T0tld%>8P)0@Aj@UOpNVXaj4EQlTAQctd#d`axxUN9&h1Mg zWTabLqW$gxfe1@ehyp{0anCs1gY`$+j;w0pza0wQ8>BJS`Bhmp1mpatjN0G{(ug?{ z<^0j_p~vRT0mp*l7iChe^WUbRd^&aU{80`JA*~0E-3f@^FBspdNFQ4ZJ`jr?_>+!Zf?(!CMoQj2YzM-4F%I~Bd02(GPOBA)n@+^;9>F8JQNZa z00R+`Xw`O2F*xu1mj`|B(eV2jp6@;T+}qw%idv{I##9^1J6zx6+ad(_F)m+j{E{jw zl&b+$lfRBpNvSk6w(l+$$jYWExt;}ED5@$zEv9Ms=`Pli{eMNO8#CDZ>{MTBznH!| z)ecz#T0H#X1syBOhqrG}%l3w^Hz@Fc?H%P={%SHycu>54yaP zB}>U0N64|R+}p(5Y$WE`JjU@)y0m~TfB$`2ujHk{fJ~)5_dKiUpsBf$$<@|pad+{A z6=-*cc*ZWHxFn~-mvVBPP5c>voz2JXFmET5bE(=?ZD%SiwLk&-E@gMU2?C%JuY`;l z;Y+e+J(PD7xRoHp43wa~zat-SYb%`3*eX1yb-VM=!P~N{D+aY?1~XlKg{|I3BV5rP z^Y^nbzO9=2?cye6nAZZ63DKk zmz8SGy*G+oQ%m({QbZ^}1fMd-fJ@0^+y{y6^h%_~JXY*KC2gL}10^c|5W)e2zyP#9 zqCQ9cLII^)NvTt?-`a3Z#hibrUhFq)9hW~Wl`kZV4AY87CZ)QWWnD}Wn-kaAAjYb< zC4X6Sb(2h*XV}LlF`?x+knb!}Q;xGRltfNOn(hodx<<-eRyAsmHN_j@K^%!QwM$3D ztnAop1t54WWGBxBjc{(b%pGdi35Ac6vX$PT;96Vc<24KbEEH7UMPz!#qb4pBd70AB z<6@_ztATL)Ppocz1eww;FD<>VmP)w^DBEAWQ3Wy^??3WtjQ7eRRL3fKUw1O$Lj`mC zJ^O%t*cvG#KwSS&;iiGCuX!I2M*Pk)x7qddGMemt!gXrWs&zU#T6N2}C0B~PQEEwY zook9A_J))ePgM&r0b@XFuMZy$OGjz@iQzq#TEBWXJDq}+5tD6-!#d?QH*{XZBz_wJ zB2#Al8<_xc1ig?$(@US>=JWh7uFW1xYH04l(BEX^8Ip!_*Qclrge?^444ukgeK*$= z_oWYC@wkK%QKFsd;Mk!2=@U++?{ix~Y%Ce%|zHuydQJSvuq7bR>oe4x}r zRieZsLB*t{e$H)mPZz~|g%(GI3wxr9IW>n@>EsHm2k%l2)IvZ`LlG#+`&Szbq;#kf zqfAp}%Xoe@KRwesWV#FjE~{Ue*LpOd-O0#Ag(wO-T2g=7ayELQtwlBBxL*&%8iI%I z7&uG|t^@FiSj~5hB5;9979i#z!T9en<-+Zc{nDLrTjyD(R`E!OuuO%~cfG8nodK5e z`6@YKKhIY(^P(pqYnB94Zo%NW*-TZ}$9hdk-rlw9L3w-r-A@!pu4k9am(dcYp85Q7 zrsI8=QmN{6?n0xb$n`{u&UJ4d005~bquSn7S__G$gRQTX{N)U&FF77|E3#Ut+nnJk}KsVrz->?jfBlN426JDccEz@t(lM6*!i5NG%U!qo;Jw9xq4yD zi$YHC1{9)yayW&m%yjEQg(-g8|G5Dot?@*xFqHKZ}k4ZLvpV3_ZHNWgTq$v4vFj4nE z6V9%Fl$X16dVuz-62_37JHp7m^_#xyYNgHl5_SK_8OPi zyuWIOplCNhh5}WdFMRA3%yOJvCsU2y(z1uA%#vo=JtVFuuFM$CC`}=y+N3(H&z>zE z2~oqser}V26hQ>u*%wzw9hy=zSr!YH4z#2hwMBT*^)CJV{r<+ZJ#cJ#ib{@!uO+P? z-*1)_*P!`r1WKqc3&JUoIBBwg3_;vBu)4we`T0nVl@dV#;3f0hdPhwV$E};0cQU2Y z^%zdo5uo7ZfY|bcm%9^Uq&(ct_yx7mSnkPW}lSNrcHogP~DG@qV z<(?7mq2Fs%NU=7HMNv#h^i1`F&0-PchW$NVU~ig=h<((%!f0?5M`Rnok~VZ_($sHM zYM7dFHQc+ai&p(cNH0O?hMi@~FXPf$2-!H}+V`}*=6U-dB-n4~5VnH=zkGV3nGZMxSN`Pupb+ULdXLdNeR}josPrj*-GKFjIEG3(kdngS(jj&(1gj zW`?F+Dk(LS+D1Pc+tQXJ#rvQp6?UpHV+Dv%3fI@8$bKMrLT#@@G%ts3%diPrq|%`; zJyJBLR*o3K*5l2-wvNpqxSvBb_VwRW80Tb}GN-?yhzUjp4b$B61Xd)Es?!EeMh0i` zkwO&BT_1|~R<)fCch+!hHe8Nksyf~lORt#gp%-QZ9dSkv=1D}bHx>kp9shbdhkH0e z6X&Ex?8$n#oLSs#R|*rcLfwJ0Q8v~$-}WdX026JE;#cP)e*mi!aJZav`_~>vTRp7j zL(1AT|J0h%NFc)e0Wbx*Gb_3-GMuW+xxt`L1?}|GVP{h;m-vZVp0_3u`kj>dNYD*N zJkoum=n7D}3W||vy7xIw59){^RXuOXN~i^FH!}U><$jg{*L^}s^kRULlE=AGD*{gz zQ&%##KWY|odVWC0rSGkDdoTzo`Sx>vmSkGn&kZx6)3Fxa%a|A?o~697AO-{3n{bh9cG`1^#d`i?B6=EZ(6!OTM6t#ysxA+ixd@w z#CMV$#KI(!4Gf2mA-&qut<9ht$;}B6nshi%3PjDrwrQ7OTCJ_hi=J_dtWDjY3T>M) z9H3!!&DB18qnCO$Kmddqa(Ok?IZG7aJ`{H!b%cD&^+rIdN#fr%)k9+*^&6vC5zGy^ zc1BeD!1{HXw`q^4zcT*e_sX16$pv>>HSfi2R3WZH=BMEp8ENKmiJ zSZXq$I)Gw0MFryLViPC}ltC-S6}^#xU1VSTp5X!$gZZA!X7wNK6d6u+jdvPc>{FQ> zmBc6FTL&m6>{;Xs)zIgx5ery#8Gi$Gw3emt5)h19lYS?`kjnRa6BqWK<&BUHqRK=gTRZPJf%5*RZE8f(bMj&bGNw%KmznN)}wv8F4*2(qp zhTbeT1WbjOw-jrRdMgcb?cz|eDZu;$pfb2Gn3pmtD^v8ju7ZH>OvoaMqYxP2d?Qu;nn>HeBHr`u8{=?0^BQfosI z{}==$sHP@bZ<2qMvIF?&CPb@OS&o84GOv_E`#FB7=(-re#l2EhcIdw;AVrg;jPg~* zC%S&Y-zKiV+(P0|jfngPhr1*!4;Y(LF0`>6D{hz~#ZsIC>mbM1a(eFG8d_t;RziVLpG&8_fno6{Iuc%u|5R5gPFb->;VIQicwbQT`_=4} zjHX_1PTF-fIyT}xXKLYffBDvVecg8b<1vbVqESz*p%HqV7^=b+bGW}M0mH9&DEy~- zk>Jil6W^om>Z`YvL5CLNBd}rkX<*~(#o1#i+iKJAO=-o8;KBE`#OI?w7FtY%hrWv8 zOfA{>qd$`E6>2i3O?fcOE=%+(=ond~U4AQ$(FpO^ArU-l>t^Xq6;oe})Th03A9iwR zYdr1!x>%g+Awp#)Z|mDf)P$)HwJ_J3a-r8+Z%3X-gdG5>ke4dJM1}M2n!pHLRs%)R z!e$ZWEcnw`{fYo2qwe}e-s~sAd^E>3U#M%Ip^xC!e2dqQ`8c*b@7q{grqly?M)#XL z>ddZ#NL6w3?jh@zkN-Ej2#F)@N55D~4_`$QGw?&)Wo7&R@|oYvahvids}m0?HAH&- zX~On|DN4CM&{&iHJ&QszbJfK~23{0DnvuiJEXrYtw_6-3bp6Qu--fue<1OT`ubr>w zo&6*QVE-WOabJaDUf69ceW>Pxmt?=`mFhU&rTe+CfF(UQ{%7rJ8@I(BZ>jT3H|NdI z=g8yh>HjG78v>P%6w+ZFn^AA0rNH_t!7i=49$&nRQD9+NHizVb;1a&MSWL)Dg zJSCP#%Ff)0m4qY4cQ3>&{5Mydo6e=}@g%F`>1wYhs+k?wG8Ijd=b*Yl->k=X;UjX! z6=zfT)L(1z@_a_2Qg+U=98G4YVm8-)nK$gpIxf{DG_yHLm><4A_DgC7kLQec&xetr zX?aQR68=R5Q9Je^AQL^{LMduG`&?gbKN&ZYx9S^{wU9mUv2mnpEfCkhV)^DkBAn*y zf=S;x_K;(=+t>az$9gi0DuyC>Z4G}Q$?A{yO$6d7G~?~?nF_i_sNEB2pE(& zNNqH+Y1|F#LPTsP0g7^NpM!B+(VViGRDbp~d02uF3F*N}D1<2M6qNPo~PH zt(p|d<<9@2#MwsHAHq@b-8Z$2=7n=i0s0J0Kr%Tq(7~+>1e(=V&f}EX$vBvcfRTF| z2&HiIqLtI6#*@pJ4hdo5#T57WyroOMU`L^dWktNR6c>$ebG;+eOz$k*Rn~0Xr;VPj zbz8LmtpVp@j$|~gA%{O6^scOm#)2`ywJw%2ulIYEJ;=J>7WaJIX?Qas#f4_#`!RKy zsx)v&Nw~pqjg)dVqVP9oZ*p@Cmt2SJ9xVES>B~8Wy&y$U0c_Xg(fw3J%mp z7Gl9I@x0@9{v2&a0J8HfGhB3GE6e*@8MzZ8J+`J1d5j6zXF6E#{GLoee=ih=FksC)Udds9ln z5wGvb?*>+WnXH*bgX#ieU71Or{1n$PMC~^0tS63-_UoVAcCLL7;R{-ER(-pg>-W~P zJk@Fy4!eDiuDY9|!XZpQJguPRa)_#qb7SwRSg;Sw$#Sl#>#2=TS>troPJv z?=lO)uQ-t@qydHG$dixvK$Nlx!Qy&@LC>i(U1Qvz(QRvRx!Bon!z5x^aK+2@k4n!N zuGR)9vr)K;$9U{LUs;EBo&C%)&rhPh>S{jsyxMYD7s^~HW)6}i7>x<6OQJT*@%bSx zyXr{&v*+iBAD54qvrG%dd@}0wWN#}Aa~o*2h1PKUzmNJ~8ytrC(9N=Sc+bxOr)J4h z9n|{YJ;y=MG&4DC&6Xm9+XL1Lbi$SIg8`!Y;^3+KiH=Oj&m1o^3a>bDLsujqrF)ivpNV zAMhu3Nq;lmpZB52p>~G=*My%zszR6`ZT@ky=-a_;M_jJ%T$rHrHL-GgSJfn3yg-S>ZdS;ds(IF_%Ka zGh!W<+r%6UO=kHhySu@qGkMYOh@|bNVMT`AoC&SWie$o5+}4Ej{DKlYa8_yhb4Gr| zfW+pbdfSc(mg-$IgaWh8S~amWkvPxIv}Pfv;f2q%z+Y0&R7B;Mx%Z+ZdR}I?U><(3 zouaoE&3XCl-B8;?+wsH=49cZB$F8WtN>s5r4)p$Kjw@QY=d^j{A`BNp^PZOh7&R5O z#01{2xAQdgTv9gM)*$_#17u3Jt0kbTp?39{drug%q*eZ4IZ{RX6uYb>lE+%8$bYG6 zukS1-G5#N@fOBU&g;gh1SdKmia|{W@Z*Pz%;=P~}SQ35+0#tBg~E%Q<+@Zbh{ zt&G1G#B<3pZ!W76#Y4O`9*M5(euINW}EAE(gVugkurabLkTJKgAH4HZ%c=Y zv_*@{>W>Hzo$0>0LINZe{;lpF>w)vV2p_4dfJ2nQG+^0Tpatqw&vvV`-3v~R`Fv3n z(vk)pHiMbW0c;$~@u%IPY&!6(8NhTWew%h9xYweaT^pqSJAN+&CGDyj>3R#p-=&^t zQy27KiJ{WLhts_7U0!VnwL*=d90h8YoxM>=u=}1aaM_ZK!t3grIh5Lh7!>_f{pIa{ z_GE^y5S$$T35-(fBWw{ch?sVaGCaIh*;~Qu5eg3*jkOa#ClCj!ZHP}If3r$QiB<eAV*w$N0%ACEG%#1L5BBL(n7mVvxfT zcN#;Dmv=y4gJC4>`bBjd!|yoGeDi+>%S1xbaF-jvXa=VsGFe#UdbO>J8syX~fHDWl z)vvH7-e>jGx&%}5*2gD579RUrtJQMBoS8eC3fX;JMm(i>R@yellE3rne&2)5?4P_J z*LK5-Y3IdM^#1f`=r$f*R%Z?of7s*jNqST0@i(93-KLkE=-v!!s?Q=Hk1qBuXL$+e zX!ePH8m7c(LrUWKa}Q9~SG_pKgXgtu9TXvOWY!xUC2M;X&MrXEg1FZi;OpWt<&#vc z)3+C-te(Y?rE7Jc6Cq@m#+iHzeR=ATC5F zcR*N5EDPTlOXrX4_n<|{x$u3dZ!I;V_AlQt)Bnb9;HlH;t6jjMX5i@kx18loA>DZ1 zc*!+UWt2UXT0>7W-qxpy@2dV9y`Y83v)E}}p{zi5RO(;y0r7V%;Yp|!aov9zj5wv{w@v^wCUNosGWkC z8C6HjFYhv{e-v?BdcceUw?*%@c?BBJ#+ni#oAqH$QYyCJnk6*Vm&nGji<-hH1L~iK zGO>$Hb!{&dSt86RgevX1`*ruf{W!Y6X53*hz?$YJP>|5B5iCJ#0x8sZ7;W<%Al8^8 zo4XiZiOfxpd5APymtAAGxT9o-<4>w|coR{Y41U^sMX#m*m}gz#@C-#wB+&r0WD$bO z=VK0oafRZTLT1i~7vH?x#+6a^hG47e`ePMcM+}z)-pS@w!(W&s{Hhl&7rl9DrqYAY zpn5fTM>yU^i1r_n))dbVpui~q{_GwTsf%F)EOnMeQ@vj4^4t_#ao? z-xGdPJRG?}ZH#`0&BsKjGrJrV;StK4DpV01F`-JpV3B`Se-_~4bT)O$LW7A27eB5A zrx_1xtLDY^#=~)abMW@sqISn+ZTd|d`r5s9tsf!5Ku=O9w#!c6G^qX8sdIwaTIx*V zU}?=Pn`_S}{l?n*$NYkdnV!1y5b_l$f}gEOjC7=g zx+26)DOrW2M|j5{@2u1CCBr!d{R!)$XT%ki2Bz79bS`UPgFdJJ|Csn`Xz;q}x-YSp zB$aiDU7gS4R8P&w0vk@joz9(h?~@m=uO}uhzPv@5D9MW3ywslzo#Kn8$({QIvmHaW z5mY-NYk<1a5hmRlUK6*aVR7AA4Ex|bDickspGpU#cuLr60z z_Rrr9R)!OLKmygC)Fc!Zo{K3*I5lMgB5V_mLBh@%-y`@jeo*V`HS7Ff!4spK?nWU5 zaz_EFP5o7+(WYsedAEI6xb37Wl>6GiLl*^|wcjbH+Ob?|2&^tq`M_Kx!EVSLlWp@< z{#J)ZmIWvJab=sF)y+;d9(#!Ht+I+2E+a#ktjt`3!5+We{LrOQ$hLI|X8L(kt$YPD z!Lzep-FY4Ra6wMS-3KJKf?BIV>t@qf@6iKu;5hOPh^r_=0GOlF_Si5T;oJ5m5)LYL*ZPwEB+mgJE6WPb0;)|7b{a}$u5w@eDpAwX z_FQBvQJX&0{6$mSG0#V+7}9^-RRGUE3*UA7i{p|wRZ`LdnstLSWFJfgd1(Focs)Xz zCB0tBv#w)Ch@6~u$IW(ZcC7Y7e@dadCAEsqY=ofwT-g)o zNCx)0fPyY9%+gw8!^dQ*eIl*JuY=u0i3;&^vFlgUZ0q^sHsp+6W5{!y+TIAMks)JJ zT|JW=KKQO7!Th3h_)$won|+W;rhG1%fkfA6JU!1z6Q(UxtodN6&Ac=Q~kuRhZP8p|ay;R_5OJj{in_ zbifVAw!85sY=nlPcZ%Iab1h;a(sat)=OUqSFt+8)$r_7sS&P#8x-S0(y`%Of)rRFq z+Po=&g=gMmVU4{tN0qrQA%MjmSQf@Vp>M+EBpHn%DOG7Jz<}kqF5o{s)IpX{s*2~H zD9QlM05Mh3a}aD%kx5OzN&=<0YFiIaU|J@DCPcV*E8426WPr!ax29fWfp0xOvsLAS z)tK(>!RZ=Gtq<3er^_jSa)wGg!0%nO?F`77uUWqg?;FV?py9MR=2 zXKODp5luA;=xM0*{krv3{6}nf5)KmS9L@i`&RK` zM>t*m-#iBmETKpAMoF_-hZycv>#^pfH4)0n0+S6t!BY6qu|Qx_gGo(z&OJnoJCq$W zwiSLB{x)}qm9%dR#XuluoRVx4;HTX9(--mj!qxZvH+6vktOv*mNkQ@?Bxv!%3HBew z*{9~lV4O?syXqgNxL-UVrblEib;aWK{h25S2_o3A*vb<#;`#4C7?Z5)l765^0hDUb#0lD+~ z5M&XrS1_wxau$(7Dw&u2WYnzG%bSC@srx6F(~LYMFB&QZ2N?L+Z!E2eek{Pz%swbD zwRfN9^NT5wA`z~09`^!tTydi{smYwT?B(ym9Fiv)We$~qwBqiukIS@WBPu82W4%X< zM?AM-z=S7;A95ufrf@`c4QkTd(L2En5*M5uNZkBkbI&&$2a{t1q>Jxvgd$IiafHn( zWs|->qqC>|>P4^qKozKxeO+S(u^{3_WjqL`f}Xz)`J$<@CN$l$q{47UoK`uYy!}aXrP%1BmhTX!-Hu2o?WB=MlR|m2 z+KrNF=YC0TxvPLa@uByn%O749W*|jwqN3PudgO^Bm!A9m0^oHmVRd(N8;fy0Ue-=! z>4VWRM9;zc@HXP1mX_<>6~feUN=pG;oC$WOC2VbY#|TH=U{LLJ_mF%zYFw;^G-R%Vx1kA1kdKA% zus2VZOWHgHjzvCs#Q}8dempn_$IHuTA319xL+-+_YA!iQS6dU~g z0UP;JFtXn4&^?xG-R*Qqv5$Xs;|a5x7a}9Q{9kbm0h=Uk9$e^|T|4jg_OF)*r}rBL zm9jh&9A5G~gNtZ{?2(Sw?_>?OheON~F zK2f_Lv9y4vhUN~TA}e>IkRdY@-71|#hWUhq$>OC=}yIK42uq-gOh5_z%?v{t#1J z-s1~AC+bHE-IASV+~YO3q0;)rdNZSCf|+B-{HxNoGs6TpBe1-5t>JFMZ*zz3Sv8No z%z0adHLe#47CgkAU}G7L!S%hSL$edQIOYx7F)O}(EnxGZ+vglOYnMnZ+etO92*||# z(D<3Xax+X8%oriNB&Gwt+)lVHT8KN>yX$l>%y7p}oH`O0>W(L>Io`VAr4SaEb8Q$B z*AmYuoXkp`$Yf}aie+ZJWiB|X7{)m|Yu>{=Cu@%N`x96fjct}zh76_KuG?UOscp}g zlns3Rfdrh?}~yuFr0QGQpy zPI5s6+gf^=;mBHR})eAwGJPSWHesQy5|a5IU?9)S##y5YVYVV4_Ul7D?vMF=%JEG%|H!?*yoY1l z$UT4Ip&~dkHMwjemtbmN2zqeC1*iL!=*HwZ5be)fqqP;;MrZ!U4=Qk9g<_YnnVNKp z<6|)#7qh|rp(@w!bEzo$j+`z!dwu>TT+Z^XJx<_k&p~s?9GfC z#<2FqD$rmbLe(9sCl9lXR553Iu7i*;zKtB3$nK-a!q?HC z#5Nq({Y~o?NEe%+8%aAxJ*mU6UFL`6(=<=xZA!m)j^BM zBV9xaB|8NQd{40p;5jXR14q<+6kSnB+6u#OnZ^OXSe!bM)_0_W&vQRw;v0yUJFkWS z_#O>gZ!(Nozf`L9D9JXO!f)m8++`Hn$>BtrH|!O{qK=2tQYRGNU5OBY8ex#CT6y;; z&h&5Wa@V^u8$a0vkhKJgW9=EF7~8KYj`9uOHNv+j6!EqX_Kk5oB-`~efpV4ae>+F7cvA`!sbm{J! zpAWV;87p)^t^D#d0swxwA%j{wo~|D5^!|F;!HLfq-tFiMt8vV*#XyUorx>t z>Y~q=UxuuEP;&n-0FFR$zW{ezkV2LM=XqzjM~}tIBpnUzw2Rbxu{D(0j7*^Jz`cK@ z4eJ@wvd@0DBaZI*{Bv0qctzkPkq@*~{plQaAK$B zwqxT?xJ9G^fbAxYZbD}vr~-<%Fo;+eW!yMyAODKa6ipT-24_x5Y3b-KGrTdI#pq4o z(fs9FJ{ebHsZ?hjFnr%Bm!{f#MJyjv`;|Q-GPIi^Gt=Rv5hXqnOL)uKc%bfvyK5i0 zKV-2cJ8IOvC~&-vf35UQJ15dqtwj11PKb2%`d6+fJMX-TBTn#4nObrAC8ejHVa4W2 zBkXB6_R$-yS=m++o8osRAZ?qAV41Aa>8G~7@ND3_A5xKk$|t$bhEzuj)_BU`cqtjy zC1@pV;Jk4t$*OR&D0OuCzxvvH31MvsHV=G`uT(MiXHv*G#mx{80T%Rw++nkm%j zijF@i@a-33EUd|HVNWoJN4~&f*RO)vARKumO5hgpteVls!U;Pfi&B?1Fhfzht!JYd z{YrV;F$`36R5bVn{LODIO4T<={US=${(_K))_cw-s;issdCdRYUEQmBM@75(jqUb5-WDU`l2&$s6!8Q)Ziivm!+Vcf)rE5_7|TCZ?vSFlLWr!gD(@Fl0;K0 zAB(WyCdLziakdTjypIZ&kn)qp8zIl}M;V*Z=c%ao{F{OChGU5}b}s=cFmF@#8$X zL!1MqLVy!!Ic8GFf@k{jH;O#!bhR(}xa)-%y~iBiaQhuxB2atL1tuN%ex#EEB5Lpw z|GNhjd{LVYNpI8q$K-HV`}~J(I-sePdB6-(@V&ut1+Z6P|H5`QM!x%@{@G_#S>U2vDxS!+ zN-LSRbwLzGspo_DFszTg8g$_fOpo1_mz87+^|V>fcn?0jZr+W(ue=>zy)If-B&T?- zhg)V*L9!o%`teAjy;YL6`3|y@X$aR6McRl1jNfSgC}Ns@oA(WNn}|VeUPS<>GtJ>B z#{LUb9)UQck z_$aVpZOKVz*%-Z-(phtdlw5j&dCa&SxOI$)(PK5Nen{;zPsKbA$G&60*gB~#{-h0K zw%ADrhSauIcQ~U}XzB~b9MJmu%Wbc|8T$5nDG~6$voKn02Y((_`u4Kf9bK9_K_>8n zi8jpA@p4}uY=@S6A1OI{V#%Lpl~13}#-mtjr|>)uyuw;oK}ri;%ya3*TGcpV+d)l$ z-@rC%;!#;%6oZCc1xGct(U|AiZ;W^9@m*hkA#yC3K}j1LEei_22g+b3u93q#-hR35xfgco z-n#NeB%B+=E52=*b-5)g%LPQ51V(MJY-a)@)?E=)fq^oQ8r$cy3#t$(G_^kSgm=Vf zcTR5DW5ro%$ym`D=eFH{Pl9E4=M2i=BNOZ-iY{v+-S7>MwV*)sgs%7Aw+zd2=Z&`N zXy34*jd$IJGY_<#jgpG0Bt`n_9=OM`|9A(MO_NS?aFD5i6DVuej|Qsz#2G!GE^fQ& zuGo63l8TFL0_T>42dGuxDz}jqvyrvx?gxR?6Np#o>wt`V!Wv#p{jBqED1>- zrDt~E&tf+~CU#m#INlf~&%j%WCxiZ;k3Tf!?bH6sOUd@u%D-G;A2P;$%2_KkPN-ZXrGf-0sG#WihD zJmxs?(B6gb1itvxnLFG~GWitnnw^XV02^X-ov*)>0xF+~l%H{4zK-+}I`eiq-EE{E z{7f8wq9fb{U^vS$;gHII+#UJmM@|fsopff$r=N0b*S0QrN=-#Y2?N@LeQUS7b^~Pg zYm)gXHqz0daLLkB&T=t11$jf0>sBi&POOBZH{RWzjD_KEsrF`3WKsNAQ2I)I4$N3; zhbX4J2FqYFwte;sezwHFbX6)E4>|2MH~ckfvEnEYtS*$LNH}IO``>&&;;_gnw}-en zTdnkfB_p+gj|KG#!ShIzS8kW)hV(y6@EzdW)3gh9n~Vi`WHSW}Q+x51 zTr9|oqR`UQyM9gaF~>ALxahC7rR$16(t#Vw}0V#-ke{NY>whl>k_?B~%Gx~v%~v+Z=Q;co;og%wDQlc0-EJvUZU z+Gk!LU9%=uTi*QAYn{u!koNkS|IY%OnZ%HeBDFVFTy=f>>#rvJdcZeB4Hzsbz@qGA zONaZQLu+rIm$F$C<>hQ+lVj=>ED9f_ObMR%H0h=ZE0~3SMi=cnHn?h8^E30^W5!g> zx>DrhYAVQMfD#iO*jNapNzy8qaA@W3%b6>KmcIH3@G zz8TGt*)B4%ivT-U3@(B$z3A-XGcT+;|FVXEKHT=iYiz7j6%*oaJPCKVKqh9im9*Fu zh?N&&}k2DSX+1ZtyX5}PDd1eHDrPhlWW~? zZ2LAqwkpLJD96kqhRujclu~QK1%B6Hhj(X3_n(WAeJuWMX zHmVPsuiyZZMIiKS{on5bY~Xlbf*Ob-R6H7zXTcg;J!U&7+C)+|I@d9f@#5IbP3o0) zQs42yW8r_VXGJ0O*=MFKBXD2`c4ltJqd{E-O(hf_1AYf(wCKp9Gfs(lU5YGXNC~Ur z_abxamF`b-2s?};NGf*cV-hpiD@5XWv(UDvd}frf$^q9EH1$fHlgx7+%Rlqzv*Ba@ z?_>Bky?_*98#KY7D!ImyYVW!`QRJ$fHJ9z_lhb&R^zVVW%HMj49c`{dj==_6iZcCz z%$Av=tLI#u=xz^{HS~P&zQtg)VYeDE)g9tEwx7Dd3v=@tue%}D+JvS2d@}J}p%@BE zTA+5YZ`D?7kdT>%jSR*FOV7ZH0P~TBWc?*qcfS4-M&%`~z)Wj~fFqbggM;H3#bmgA z-t}I?5bG}x3i55L85&C**&Gpw~%P56y){Y%Go$(OYzS=3hiK09cCZ+rhvHTxA zmtJ5q>Uu;rEQST8`Q;oH3T8Nu%4n1vVvNJq(r?eP<`2}YI9JlbfmYq8@ z-rcMXc}%PEkR))DHuo=6V>meXb2nb7O`)U(f$O;CF554#nP~cGgPk^-NzzSFE=>S! z2icRR<%c3Kg?fGYv6Cw=xUA=!m3%lX$XZvqB1B3`MK&_nw`!|3ST?gi>a^FMdsaf` z6n+c82R@-Giz>3h2EP5VcSAmx3Rj$Xs{iYMrTpEsciwKLGgDay;lfcrjG^ebW1Am& zBvxF~v1FMnz@ego@gJ0XxTh?wHeVIhe$n4qe&sa|gWk%Zw0yy@H9va?F4W+os2}zl z$(lEyJc=L&-d_^-+IQ#b_CaH_iN5HE3*B z;$ksdeq_UsYa_U|Kf-~{BD*qrM>{r6 zZKBN-=_VP6!Ps)w9bBO2f4_l2TDuOJU|KNit_qq|h^*CFW@fsl2R;VatPqPfy!cjd zh?d{DK6a~M5d^;D+y9r=8(un2i`FH54$6a~JAS;Or($O%s;vp<&aygwq#* zSCxv(yIIC-mm*WehH?=IppZ_Xs+6q!$3Qhy8Z6i&nl7Gsde`bNg;+%3SV0z8O%Emgdm5qo8!vQCR4jqwRV9vRvi6s7U*%2n z+>8OUi;QtscJRT0>m=wx9DZSR9({~+$OtQKsJrTBiTk5wO#pu)5GtgVIJIoP*qt2Jm5 zpk!xPaK$Pf`z|qvqDq=Z8&30363J-!3De#G$KH2<*HIm9Z@*V^!C-8IZNM~B63P#J zU)UPl@T;%u)9f6biDuE9 zNzv%)k2`L?GZhRP?1-DtT(NSRP5WMdIb1v^D2XAl2s|fn3r!_&u;Lf^Ql78>#jnhC z3Z{c7JAi=|8zYCPlX(i4@=y1W*;Lp4)T^qEFlf3H7$?Cw0&H(o8ykr3xU)ac+R2kw z1Qh(S&aMsTg3X|os+_*B_r z07_HMo?w>&CV#ae5%tU}nL=cSVG2np6QuGZk5vb{C+IW~=nfR}$**ke&0>S40NCNB zSkEV9u|1DWOhHg8Rr+z@Yx_Z*DNSj|WsH{sAU7sQc|JOC!Pxt6>g_!mw#KWgJ05sE zNpz?lxYX(Hn$KkUTPj*M`0i^M89@7w^xn5W82jX7q#KRDzbnQ81NYP+lZRSm^ZoZ2 zDl`#*%mK8g!=;Za&u2?A20@smhM8N7W$D&u=FG0bBmnz8)iU~Cektmi7ZZfQ6n2sT zm$WE`fH@lO{{ym8zSq|}ufBTZ?U(9*boS6&Z7zi#!EjQFAuLh`WU$K$^Y323YMZ0g^>lZ`JA&fq5?(CG^=ZE zQD*0eqbH?Xn%dYj^xUg$cir1@+aJ1azty+PE-}zG5*=xyDLj$aFVL=6e4-MNzM@3-S4@!<+*d{0}6}Z`dQyjpT%;N)H4=>;aF9F5WKNs+)PDE7YD+x}WL0pRkP{ogQ-z%Ag(+3| z+x*CM?p+CRRUu&CpviF+rESfTbcLUGf~XR8KKX3*_r7CTIx*pF!fLkSup=r(9$$)Q5_p33(7Tpx830iGFfU9kmLv_ zM)ufu?4x%H)|ub5O&eGM9RV?WYW1q~f=qU{I33Ievb2u-AL+R7UX!I4ZA~Pr0y?4J z2X+4GuC;sYX~fG}D9QfOyW7LtE(+zj|HEMq5*?-{IV5?ze)oF|vtvXfg%0&8H|KtZ zZ3W%v>M<}Vz?p-+ZMWYN-eIvT$P9~8P~d|yNY=-9Tb}*!6RIJD0uiza!jKU7P30_Z zKBC#2MWFH9%4Ry>`@}HJOjkWMN&l+V`p6ilor5REO;=qP6}kA=568wh1M5H{nBbJ? zMwDbWA2Q_-@OHCwU##C}UoYBEPBY%Lt-)B*!}bDFv%MdFY^u-(S9#V2>;7l| z_(2D_f=rg?#5pm}d;Fpj^b|K<`b%|mh@BfFkN-)AANUhi0u=#)Xf_*uI zwjh#CjS)55^w2{ASqcd}OKsdzk@Cylh7(V0zvBV`@VAUQu53^WNz3-!{`}s3x>Ej`*W`MxDyq zW*(54vq8GUfL<)N{`1#>v^2`}5B5L(Scdt}|Mzw1V3b6Eo;$Nb4wp|z^n~`>cci{< zv;XV``;rD+7O-C!K+`o9(H(XH{&nb~b*F;T_>H5JfiM~EW0|la!8UU{kqUm*w z7BUTtEC;N>n+!v66d7j6g%^btXj%Mp<+;in;^hF#GexQX%Igc9chkp+odcl^m`sPk zu==wuV0mT`bTy|AnL)v6KH)^4tn~c)YGj~fS!6U8rdZe5H;3Vp)}F$NuzVxa*7Q`_ z$v^4%+h0tCn*MNmrnM0{%v{V+@4zaSQOIIg_-y4_57W`Tl>FYJf#+Ys(^#QxYcsa< zvldEKM9FZ!Nl4ePZwLs2Uy?}3wPWnmH?{6^(YP#gA5=ktB5v?iAGlfreKBJN+APatpPYC?L^M6ae`47{~ z06{rS?QSVP6NU?@Vf2p$7cODhe00}6Ok>1CK;eL?o$6RuRy5CHH1vG7@?ABN6TDo$ z*VnVjep=8VnLY;Ih>pJXQef9*qoo0}qdva-t^v^#m@-&?rWY0xKrSUJcw(ZbM3L)% zamm{6oN9~@5lS%JQO)GL*~tc^5-guI&4GV@*z?F=Dv$e?ZJ1e5%|w_Wy{2-N>`e$P zXi=g(&?Wiu>_0(5+*{QBx2FlRFerFIg@;;Hha3mk!{Fc4(y2{N%aMyNXqHTg5vqa0 z0&2PSx78<}k}mzYZ1=r_qBNCkmrzjyom^0w3v4qd=$RYbes=2>S9ITgSMAy7CtKD5 z{l=D*XHuYlh7kjb(Rle9k~Ii1GLF!@p3d~Y^jh0Zzx$+kc0hEv%<}9rL7jHtLSt>E zY1xM55LALhGRZLvQfh)qrwwyy=^-6>ae-nj?uQ?WD6>mE#SuaA z@tdStyV>>zCq_X18ag*SFT8NBTOLtN0YniLe!F&&U z*2J(8wDr=QZsJT+o8H_IS#e~tyd3!C3p_wmVr-k(C}$FayW1Ksx;Umt0ZHFC`nzap?NVMaPw@k$L30wh9*)z$z&je*J<{ydK^X5N$?z%@) z)w(mz^$BvBN2)pb`$kv4I?^55ZMOjCG&IwJJ$D~;6 z?N6_5P>1_^pMTD`c$e7HMdjOUn~nu6P`WPUqElg*9h1~#PdkgTnI5h=;#+=Ei3?)D zB}K+4FP5-aTHwkKIW#hF$G%6OKnSWPGkXebvH>oUPOzOOB-`0M6bfKM4WxBmf1_Uz zOBO9mz53kR!@e2dxtPSB2ux<>1DSpin0_LnQuEEDhhKhCW19d`Gn=lxer3}I7niO0 zMtGaqvF*28#d2LUVf=4!53A1ZU1%0pVITxGg}BU zSz@nI%0fo~15AX2<8erjU|iaO;)G@n_E!AQA!S^#pCL03(Th{0k^-^_QZqa3+;Pnn zjlaLX=7jH7pM6pN_fHFnVo-#ku;8bPLqddsQ&a+?lHmE$Z5Na;+HthxBVd}C!fxiR z+HA`pmYy7}*kiAJ_k?ZAiVE^-g|9#Jbk#@$GtQO~&2C_}(;R6#1rrM0!s)6CGc|&f z1LY?iTh4jIqT~~%Qqy8%OA7L$Pm;@7f+~rTg$wn{O4Z7_M54b{80dw8j);v+w)0IO z7tLf62d)Sza8iRno1jc3cl(CO6r;SS?(Eap_hrDax6|WpL8&dT&tz(uprK$0HGLLJ zX2Oxg?t4WREiK!A$B&d^hRgt50!@RApOgHu5(D~EDdbUN`ybH#+N+qF1xAwmnGG!- zgdzl2a})^NH48PJdtN|*8l$`W0k}3jO7*eFkVHArlBNlgNsiuRezTh?MW$1#g{w~F zbRHPg9Dn1(fZ~k-53k5V%9u;H zaeu_n(?BNa=#i^!)fG#Z2R|!my5%!Nyi_iFO1EDW66MeV2UHz!XwQ>>K|S3@o)gWf zRJH}S%khqGTSt!g7w~c!ZB3Db_6rF@kQbn=JcT_UU+^X(yb$#kHC%DImK`^NZj2CM z{WGTQS#5PjbJ^kH!Dn7EwWJMXUF?Zlx@C5){B2C~hVra9{>3ZGE8zu;lBMre9C?)9 zR@d>TJ43tfmI{^Rn>%Vs)!}(KZ7pBAb3_n*f+yw@J_C{%oV_5`)L@t_(uUC~+f;$$AkPyKQ+fl$Qs>cU zo^870K9dk+vBZt)$+4|o~mvc&70|*af3I(OF>yk?DIcrYh!`C-Ce`B-S^zn z39q+Q;^UM1fq;m_(WJ`%wU8gm-C|GxLD$&9hZ|jOwWpue|NP_m){M)050Hf^u}wmA zh~<@p7|E=eF%ZTkfj*q9mM%Z~FoywX;<>wgMIQe228eI_)y1l1&_b{5)EEW!aL^F} zjTu56F+XepX}GDUYL7X(R8XRVm=MK)#789ACwn8J6j8(wUzBeq)F3ZbF=Wb8DKE9& z_xthYI@Q!LNSw@MpUHsP^wcwGRjJCJH3OqXJKua)O;l26Mp;8@@{Kox^6Y7aOwc0| zrSNXc(`_vU7O$x>(AuDgWHVzQyxDs7)ugKh5B8b5feB4^w1;+H7M6;Gyx`~gxTu7- zTbNn>R_7n?4tTc%x-a7>oZTaaD5rrR ziQh|=B?clfeQ*@?;>Sm;_ukLXUWz1zM7cy1qT;NwV^383`vx9*H0br_dr~aM2_c^I zZ!_QT-KK2L_RYV!F^g2@(`lajsPjK-Vq3^Yj<^h_PG_EJAYfI|^s#r}@kw$(DxO}* zkPb`8d!WJ=&bmfW_e!&}ufu!OR=-1;y zg3$Z-*Lq)iD_Z0U=ee2^U;*vYz4X=wb)eT68#aikvWU;b%+KfbndAkT&cL)oTnTzl zg!xML(3!)`8l>;3$NK*CK3FrIT}(4?TCuuP`;7Z(vj z!-aaLt7c_80a@}3V$4bW)|_yx+1Jze@~bgVQNCHc;=DJ+dm?-7QGL{k zif?|q?GJb9YsyVx*m*v+^My?4ePp35LIW?po?IOTd2N%LnCK$|22$i)Rge@V4gAi{<0_6l@cX*mfrPQDWP9K1C_x#kc^I zAAVVGI_=bC`C4tTC$eN&X`VG#L+m&ZM9|gbq&1uvQUw2k1r6W%5zdb0^=HqIdctQu z6X;#EVVW6F0h6w!TL=-uv~`2phC$S-SfF_RD(|#FW&{Wg#IUIN1yAU(Z)AGAZNo-| zXx3F@8>shzhe{PC4zEU9EsD%-mh;So^3gfl)tz@{c>aP!zPY1-YJ-o85`$<7c#*l4 zl2Wo{XPh3+>(8DqWKw6gR8v(mnIVqYJ#lCvjn?L_Ki+AW$kg<@*Ga(9?G!oUdQP7hFkMY9~YN){4=QliKauTp))5o?b7CLS8f>yMrnl|IYDh|-Krk)^XF zo{$^@CLKdZmW{DV^>lw%+YP@XwbH97~F^Wm1QEVY5G< zf^E9lcFySPDqpfQbCvnvh}x9p7nB%R6c#+pSI0STn3McsQBazVTUzt_v*!hwQ0l=B zK$BymAH8krV=!ETsb;Bz&%ZwO)U$(6KVc?Qqo2GVm*w*5;4=j&sED0+-3iow#OV9r z9krttxHxHn`^QZKy5fQUvYnO%+(V|LyTg_9T#3l7VVRdCfatAvw$a^`*PlH<$Yjpa zvQ3++1AXeflYLXwc{xC|$O!RCXVkVNQ+-QssBPi(%5o zLb_=ZlYPUez+>RHp@F`{&N~N0CEs<+jV)-V7o^n-7Iof!bLELAwV!!zUo?iA)=@O$ z^2|*zkT4}66`D*`b^YnC-j%n6=gbR;e8jEWAYhsi$__n@YFWerSx~UBp>@+P%$iKK zQK*4Clq1fSAwp*D>1UQfBaTa5D8K_GlrGp|^rH_m7BQI1QPq*44{MpcJ_py3sUzI; z+*7G&>DtS$?704l;H+6uapG3mji=8`6}<4t+}Sn1_@zGB%F;|sF#<`VLY_J0215`O zQ41)zX$}!OaLX-zUd+3)#zt0%mwkdz&dY079NG2Y-Q5p9I{xlI0?LAs*Ivo%V{iwV zEaWw_TK%_9ZaM$ln!}F>2})G*LaE9nu9qM$trCT}z(tk@u zXJ!c=tBPm4d&m9ZFwci1IGn;RF?6vgnq@L^PKh0`U$(ue<&Hm_U2O*N(G-w5)n?_O z=04dSzdi)>i^#NR=zQk-P9SJwhok{C zdq4kO=avYhLM?kJ6pgbaTjCR3amb};Hpt5*q8yisTOPU(6WA9Rbe}A~_ghx}zT?+dn}$B{mq#NWc6z#VYWq1cEP8^xHzayt7WD9g&ExQ*9GGxzP=J_b8O{G5eB{!T3%)`8-0DQ=%>*Gr~zM%Z++w^*;V648;-{ zkO4N7LY_J0MssG*Z*Fb6=C+isnP$?k=#X!9#jJU&r&1Yy@{$xk$FWd0B#Lp7<(z!? z?`}?JlJ?ByXa{5xqBYc^!G4P%GIpsL?Bbo)*N|EslY`!Dde8QOsOEoC8gn_ z3k@TwSy*SF#3bJlOTqr#Eao-MEJf@kP)w19EWNukw)39BJa?{dba7HxmMU4kv&-_X z-`(tAv~=ykN8^!^d~0duJ(>k>SsRqrX>L+9Yr_};)w6n6H&V6oLyj)zgg7Ua@b0K5 zggD4@{h|<)i|a19WPJ6i;SWkOmT99xG&|MCg2XIgCppmkB6f0HFtOBf^U6SxJ9%c1 zSJ>WId&)^;6+aD0>(eQtGN!K{f8WSPwDS?%}SWm1HkJ|zQz%<@Q?xd+Zx?O|eh#OGSfE{#CE59S!;P_Bs{B?QBcO8QXT0 zSn`teB5Vxjo%yQ4Wbx?a$6OBEbRQho-86L)WwEU=*1uWSn`pr*)~*AeY0=8?YSV zK8$hm`4>e6F6dG0X;c9lujd@GvFI5&>A-(3flU&*l zpRWL~gakgu%cb+Ttt^s#a~9~GZ3K}S$BTzVDkDk=sc%xf929sBUEAoqcVBvz~N3S;>eq7Vf&#}}bCO~DC*XQ6? zM>`8*Su#O0ANgvpxt!Qo%VyUde57ld(=5*fb{Re>iV0pSTX9rsU9~=%#D&S}DK`ov zQow=Ud-uJ8X~1_8;S`_DSMR=Wvb)#R4V2AjglH_^*k(hi)@q(rj-} zWas4(M?fYh$iAuV)MKy=Gq)+qoyQ(SC>pn%`RPK@WXcWaprzWhXy09TMqHXbn!JL7 zQYs2ziBBxurR}`4TON5xM`>Hv^F8h0+I%Kdl1)R`hSG^3(RGIs3%CFB7Xe-jiAsQZ zPI2lcWkc)*aAMR+IDI?pm~Ly!!I%%iIo+M-vo#xq%00^?>V9@^AkR8qo3hH;#t@~7 zz4q;i`X~ZPX0^7i>bO&B=S<@P+7x4f0Ad+5v_!Ia7J3jdWj-`re#DB3B|DUe5Lm{i zaEdzQcpXr5fhsRU!*9L1|lgV|H+m zC0z#Fs)m{!=rWD`>XEyaX9Cj;WYNeR?$O4_v1w)5k3Be`4fMqp>=>6lZn0g41W((w z*9@)xAUQN>7H)v1+$<|+V~nU}rm{mXKVNh3!EsLZ$)ew-2|=eX%@gL7btj#uHdJPT zxQ%&q<~z5{XclgOEO48o@!@ByfAB-SyUlRKPmredzWZX!mA?q{?sT`afHtvYX=K;k zd+&YNE^r!5m95vpF>^UbE6yUOzV?hWOGIy+^Ogug#4Y~`5u5~k@El)v&czne(^e)~ z`mt75pVtTCT0PTbF*{}1rj_aKj_tHGwR#mhCN)Y%+8e44KRm=2MMRe-!gwht@-ac| zyX!7g=mDB4TR%1k1A`c)2p(Ts7TbP@m~#aHe6ucbL8F}zA1C#NpHL>mH zYYp|3rmQ^2Q?B_;L}AbeV+&+V3DIokFKv+V!+7X{zl0oe2Up$%+XVh?=Z}S>6zM?H zWr2IQF|rGtdU-R*Y=FUl#Zl_$n{Rae@sE9f{$HQu4NilqNr)wxyX}EGn+-=cD>Ig4 zDVI$l@XqTqam{BM$QpCrhi>7ax8Cc$??KB#fCOS|!@d5Uc8cdv0&N>Bg?}&L6KX3oqR(AiFfH$x9JI3dytl z`|Ld)39++$Z1o2{4?M1;LIovX22u&c(k)7|spdaF(0TU7;f0H%5?4A6qS>$@$9W~D z$W7;*%d#($;U; zm-;_KFvc!N1+n%=KSTsMBT3NVn-8v+f=w7WA!?^>s;!Cm7c7BS&q*wljS8MpP6_ee zfC!@CF6{>~DtQxg=T-morzDfrv6=1eBgrh;B9X~n1tP>omSO3JBS)>-6h6_7@lZ&w zuT8!6rjO@bc@sfS3dlvP1+H@8!c@2fa(&A#ATzH9OqS5co}<~!@T;%aU35|7q2CC| zN^Y^ zC<|+tWVP|3cit>N?R1~l8xgp;AeIX58mV%=wmx@Y-D1J0=9%^aAgzDHZ znSDAvqwdaw)YNNx|haT$Ao0zm>+b_zj ztzc=UZW}bu%)eWkv2%`XZ$wQ@brwF^aO;UEHrMkNvQ3hyh&P>gQRmHfcCNfOJZqL) z$b{;;#7CFytqu($lR6}`G~Zn)?o~~IXose92qUfUmDkL{5n$G}Fixj+g!R_uSW%Jd z$PDpv*&#=ekui$wLZ`vzHQSMofikgWYfd5$Y>Kvpa-Sm;#=)>f5N*Bvwy;Z8G(QVy zId7TZ>A3Yq18WpzFlEOyM)pkRXy2GY)r8tM2yW%zT8<#ZP9bU`8yhy#y1J8fRf$6m zaUGeUKt6ZQP`H#uvia7r*y_x(3_xBE!dG22Z5^}Sfb8}8{Aa*q{uH;}d}FCwtd_hG z;H7{d#g^=l_{Mie-+13L5T)!q*)oyoxJReQ2}EVojF}z-ULY1XrZUM_Ury|QaP{J4 zZo^Uz3Q|B4J8t;3b8r`;+0AMes1C3luBHZJmtCdxbeX_s3CH!s?}Nl6+aWrkrn%+^ zrJS|$8u{BhfqTZ|qr6`MKm^wT1lBO68_A9hJo98=+wIFwII;Wj$F=6h-lw0c|LK{-&pxACTHpKc zlrLKjs?RQQ8bo<9vGYF7M;sLwrOq2}rpUlfQ+sYpt(xG8;xa=f!S%nnt>x!uHC=lp zh;V5p^HJ?jJrQxK(_q6T1w~=aUi*%>wjf-HW;dt7Eg(iZ#VWDXhU&o5-QuF+7x{2e zu}|X5L?OIjLETS&Tz<$wF-Z)_Ubm(Kqf*ge+^=@juQ~0sBZ^F=Ab;&fnzqx%RWvF@ZK2j2^7s9E)QaZB3-km@P6KXWWwb* zC0ct|=ktF{c6DN`6GU_qw_kpl>u)H`Ng<98vArUAE5CUh8W}`DlEO}Vx1ZV;V0Mlj zb9z@>^Oe`uoqvvhR&hiU{9;kqHPxxlmyZ`>ybu-mki^G%e)yH=ZH!IkCZ~|&VtOF+ zQ~DP|a8AY4G_t*ayxTXc*!4FA$mDsSqWC#3EJ>B$`=K$?1HDRx!1gN}&apRc8`P22 z>gy`sXa92MGlin4OZ~BvSA>^Bk`R;lz?}J2Kl-WG)@0_WnS=Ce%AU`3KxPhv`fM8p zt|)Vunf4p5^GT9hdWn-4DBkiygyUHDALC^fZ#Q3dosK~{+wI3TMr6DGE-EI86cTH?UVu`IBq?TJ3GFhI<+@+08LJ%5y?uk-K z4oQ5Nn+85}(h3NYUy-8AmSxu^V1kWeVj)U&ObU8oU&dIdMBprDhq5D~N-;%ts<*v- z_kCP{*M8Ac!3nbwD?76rN#SK@81FnOx2=m;DZycvLtwZcQapG{d zAK}b23*Nh78@h!l+%&MrmX4OL3e4Tc{dX-00l`zY{o;XF{zgsHmB%wJkV!$rS2I%T zngb33aa&1_e{HYIgQi1A`=qzU%Mro2d>4TI#FyI^BB4Un130WNK78>s%0%hs+q zQV+#4)m4LuSYnUm34!-X#jY{uZ)62|sZoeJ=0W$3zOVwanlh9N}#2DfTk3SOSynaCr zNpoCBDSc2myx(rL?P+WX3HF!$p*s7^X0( z8V$#eIV_@uePvW!O|x!-LvV+LFgSrhW^i{1PH+i6xH|+VxO;F79^BmtE`bCF4el<3 zbLai;chiHaadipep6@TPP!5Si$Iz}Uq`W>YDRt5cbCT`-6cIQ31jwrAb9$>ZQEUHvB-1v z>&FO2g6h%**ekL^xWR3SlJE%W1S5}S$P;}jwvfDji34G86;Xf?d zbuJqHr6ozo;j;Zla6W4L^G1hJ42(L%#Gpj&>#u5|!k$wDj`L`}EN93|HH?#X$chpG zZ*-C$bDSFW^%VW06_qg9P1qw)$J7tMel97y7yccyc9tX`GjPb!<}75_G)!=5yOcsp-V?bA)P9 zpxXYuTSkKUv?O3Vn>+@!E*;ZHY429%RAz@QwuMs$>@|oy!zN!L)e3v|jxW=bpgD@C zL-9`0J6t(}nC{v)b$cA`lN_Hran4zMA9_3aTx3YdR03T&+8PwkBi+?uxu}32?TLPV zw^S`~j9FiXw|Hfz*q9*krIQG$0qHP#kLz$0=RS9m;o0^tWWY(Br$i^Z>c_Z1!e1CWU>k)h{|&!N4JGAs3m zwvDbdwmA20flbsHZ#M9LcFHQ2LagD14d+jecWil?(j^*-mqfUkSfFw}i!UVad2f>$ zwlLA%&l0s2DG=0~Y_x>bS4Kt&t(p&O3gB4~r!N|o zoKw&k7{k^EwH(+no{KkU8{>Hwc#iZfcg-6r9(fymG(t^xnc%>BgnWF3&mAgD`H)IW zCFn8ZDLV{cT=PNBG?~Rr=L3k08jppBvg{qtFD>HBd&IR5PCXH6Mkn=2NoiO-w;U?N zV!L61=@c}g$H7ejSuR50^xW^HRElP}-v{=dc;l^38_{O8hpadt_$hVaf#vDy^DD5> z-EkZ_AMrD3UJ!7s*NR^(}vhD-C?FEB+&Mq1izV4OdEz4AB_3Lt|p>^b0H z;G8^*Y(~!v{X+g0@{FQy2Wgj&@B3cxVNzHg3A(>j`b%X7(D|4{p}kc@BFj;({j_K? z*f+}$7M;!MK`6k2U|Ja&{%6?9MfGWJ{8lM7-PT5)cJg0AI?Pm7tIj6@UK%C2#09&T zqiM9WC0$E?%LN4v2!9Ra89!Nx5!q4q`{s=v!mkox4o)n|a2~SsBSB*E0*<5RiKAx* zN)TQkuf&(eLZet!-$iOeJ)y8Un2`VN5 zGh`;Yh;w~VGaz1YvgigNNm4OIQhoE3>86%@a@lRFesr5EoWkYWW=GM@_0AzPJ9;?r z+W&oXST#RG`aN#tY3M9%-4e<7nTuT}$c^~tpSdCBXM?s%uZ}O-{M?H^&usesBuQE- zxKH?$>nY_=*waac*muNEoMbEhY_p{4lk1o|k(Cu#jS+>h(dRk1-pR8qL3K`$pk2&2 zpIxVfGOM*CaCLLbTc6TiZ0hs-S?$Ex!lf|vl;f^Nu5TTwgBYatMU7%3PL_Y-bJ*bv z-VS9R^HfHU&8}m+gTX=?k3Z^sZzedou2Fn>Q=I9g*M)lq83c{tmPI%0dn?=R(#tb= zeWaq*NWt%L{zF_ivx@E0T*wseLXhwG7&Ylb^;N_){jQ zbZzw|DxU5tZR|JK5FdnskI#Sgw4M4i9|)BE(5V%#jJ1ItZE2Dv(iAIVDMtBU22U%= ze;usX>7pPoS8lcvb~j0#%FX>zDk@p1UcycjNud~r0OsjkkOmD6nFz43BzzCwicm!C zOscLMB|a6rI;fB~6bYesXpu2SDc1%L&;|Q3#c|*LoD$pXDd?ZOy}3V5>wjNK-DrBRz@mTWKDW%j}CdUs1#=>I4V6zVTT&+*HwlK>$U7`A@)rX z$?j(~*}g>wf99uWy^+W?>2!b7w|a;lToxJcb3N@ef|3Unbaad7m9RgnYC$|)8fn}G2pLNBkOTE!3U&Yl+VnMh@RIddGJ?$PFycn-L2Ep zyk15QQ?;bV@6E$Mco3iGLm-p%;$GM(cE?#;QD)MMPf&ufHSy4}yI{FgeV*ST2$;gylR1=NgqGKT&l@%Aa9}TLN{x)VfFmy*^iC9J-=vzAg?`T5hVkz zFiKPN#GdyGXRew2X@7=4J526;A4wewWXL_#^)mfPh?q#|EZbz~azZ-wBXBo|{2KME z09zD#;u=T$PNs~T;0x!a^#C52^KY@^5Bm{1hQ%N5ROuPKP*|oUEMxEU#rR0>j6ZeEixsg=oEK_|fibeRElS zOFTf5hz~fN;EOXUE$*lzk>)ZmyeNoCKW?_D9p)r~5tDEDjN{x^k9KQS5QCjc0juPl zdZ5LLG850jPaJfHwtqR_U}p=3umZ!;C!Z$cuZJPb^o;#%f|Y#9lJV~aU|X5n=ne*% zWW%oFtcbyzPq@KlcFC_sH6c75bVi>b=2*0x_`m32MhtAks9~d# z5WZd>EN!OwuSvf6Nfxl~8w{yAfa6C+W$hhv3~=C~k$AIX!BAdB%x;$2$cW!JQe2)T z_tz(6#^R<7XpyGQ(WVilxEUG^JDESR{crQ_%7MAdz^V9Fl-bao`sf&K*1O!?OAF`z zo06AxLT-^K_D`0L`Q{R`<;^9BC++<%BuG;6ug))5;~58dSx03n=;%hr&?gBt;km>d zY%Ya8V|Q_Ac;4L0Uv&u$=xc`sCV@SM<68KU)#-ubBi#A4B9DDh6_OvoSgwT^4Wmd< z!!4_>9dKtEHba=q+FgmxyyfCFuGtPdLUiwN)`U2kB^%0b`j+~lx8r{~IH?`u|Lz7n z{SIn3+?0IvepmxwNg^D>RWsC_plyqmId_K`QfWUku#w9~k98 zu@+PXhR`aLd9w<_k>*|dr#PYbDhGPt3nx(KYiKb`4VzJ@+Wgw56xRd!CsJ@4snj<$8)wOihK4UT$RJ zhiVE4gIQY8o==Ggw`%&nojY57I^WZ)E*Z0_snT6=jUsVSv)!R`p>CLH;zrtKkyA(_ z>z?T1{V1&Up^qs62ctuo*fjQ)QW{LM*>K^uKDTN0qFq4;@}miRU-IiK z7frHChnNU%JWQ8X#t}PwON?d7d6*hla?xuPEk^k3nJ`N!4B?8NtjSnAG+`p~NV~~c zf9mw5<0jx`_ZzZd0zR=anmQMiFKVObWU1 zBpTeBvnr8_7~%dYZWJUykap`V>*kXL(nrI1b23qZNI;8+6N7*4gdhYg)1wL?9xSV^ zGn)DF%2soPucKKs-2Q+S$#J$>y}TySp;x%KhmelxtUi8aAL-OP~~u#v$-t z)^U^pYy=*Ua1uj5YOx(Y<-tOmSXu4OgmB=bI~rOdWFBe*@v}MDp2_Gf6d);KM9y+- zASDw#^XRA1AJ7Uj2gtrsm)FwIkOJo%LzWBUUV^QGh_^<&P9JQ?z%acb^iMf3uc(4S zm!L#K0;Hxm32Mr8luiLdvpeJvA&l1~lt8Cu7o<^gNSn>8WSU)A8#f ztja6rKd)QV1S4cT==H7;{WZ(&L6u^iq*jP!GZm{wlFTf^H>AE4lLhW>0R%c;bvhFQ zn2?b`fCxX?3v`3L^l!-Bv_q1706D*aldEHomE>&#qFg}oxwy%cuZ(yRietDo{6CpP zGQtyuntI|0~i7%A(}uWa3xq6s6d6#X}@ho9Hd;K5hoCSJgPzI>Wa9Q2EL8F*ehd9!Sg%} zOXbbB?IGJx8iF(~#v$6JY2LHFq-_QY%EVg@mq>CyPhFT=+$Kbma(`;Bx>g!x-tVyG zcO7nS`jJ7%H8S(?2Nm3nR_B~3;HpMtMN>_sfKa%-!&Ef{4lvIS({eTG3`zw7AFw6QTu7VjR^wJj}@4OIACCUU?D!DP}7*mC#EpS>Kv%%k}P6 z=OBbm`?RF*=&sbI$0%4bN}%yhVU=UUDup(IFG^AH7n%twc zPVD7s9Rj$yg=kB%yXPB)ufms(xBS=?_l_1d=H_!OJmzq0nv+!ThI$Mn!V{jh2xvG` zW5TEfSY;VZtj6jR%G}(CZnO{LtOo;FE48k9bL6Y@3a4Qilyf? zHOFbOg=y0^fPlXILnEH1U1UXnii>%i&_&jyGd5tLq-^fv*zb8x19v}Yhn?Jx=iA9P z$Kxt*Fx$bm+dM|8;@45?#=hr~P5@bQ`~gO`AE~XXA#o8VlDJT+x4LyeJ-wKK`#;C} zEqAu^;^x>OM+9gLSJR^5ePeaV?j*(ILlp6t5PX-4^abT9^(<+H-u%-%!|#NI$j#U& zH1TMX{w!S9+i|OIabT``-h8tvW8{UiD{PxW>obwS^VUq*$%*edvajbjURM?rR-0ru zCQct8FR>J+R0B#qdip6cG|xqyYJBQ9ZCws~% zxBJt)1&p)51j*k#zyxZJrV(i_Nl+vwr!K_|(BwJ{x2Oe462DJh89|n8|_z02Qc!88AF;xBN0!58p$P)K?yp&erJm zRvll*(WX2dLLK;vhMrwvHag+JZ*TQrGp?e2^>0le}V&)}w3RQj)v0PDW* zI+-{o(p47U#?|fk=am!1S{B0er07n*-wH9^5AQXwW{vauQhO1oRwm1kVuWEPrvy_p za_@xXmU@P?&5F3enr@3YrU>e4^rXQI!fjn@&7njAZQ-Q2f>bkamrR>?Dym8S9_%>T zKaPxN);=;dX#faJ1v2X!^J`~#40zJVX!BUC2zIz+Q#0n+p|V+%ki=Y{g_ol@G%r_W zjWH7bFBbiAei>;37C}LF2w7F9i9uGc6YF#-VQbOOCw`xSa^w@29Lk!V_XO=Rhtft_slye=`?GeQPps6uVnrLyPiJNo2wiX}H6ICD)2ZkrWgV5)Y6vNCqO7tEfQ*nFr*> z3>?3t8K>BBIQ(7dR?Eu%G1C{T9rVGSajPWT>Ai#8d*k=H6iWMH=YL__1JfOT4kDy|;YK+~t#NzvG#mp@J15dKcFITc04 zQ_5fW-ss}|b6U0t+30yl;lOe{`Q{%piE#R_CYB{D2Ddz|B6l#kvMrCuBr{Rgk(MB4 zE>+krw`xoM(%Zawa*IF_4iC0po@COL+s~4eV zZb(BNoEIYbxVB?Ec5S2g{lV};ZH=Y{TlO|rur@t+sTKBB47?y`bw>DpZg%3^XYw?T zlE>1o;sU_Ph}DJVR=?Li<{h}Re%nMFDX%OaoD(`>`+m>+2{7SNh{n41U;cPp+7IJ5d+~V}c1beIUiAN@>RO334 z9)LN&j{gj@O_TnfEmsSfvv>Pc8c~RsJQd(9Kv~SbeTzhvqtJAmnD%K)?OtGPuEBF+ zn!%W>FoPJhSCZ{z?@-jSq#3F(9p*ZqC)TnEuBps)=l`qM{&T*6%tM}A5-aL}Sn2og zjLs(%*CU-Yb2}5&gLfOmBkS+F}7hb zoew0zHG9{mzM@TjmD|((U|ZE-%tX_vrl(Z_o9a&Mt*;&l=~4hnG#C=`^f2*>c{4E6 z@@uGE#PMFao}>h@a)6Ob(_?**MN2;nE4x)q<)eqVPO2k*w3svANlYHmdtu{AXP+PN z+P?n5oVq8RlgHT=UytPztw`zuTxQ1}hYO6eJOScVK`br(1p9KXpE4lEB?5vZS3R4H zI}4^MUYE1&Z)H{W1o*E>#rQJ4)G(}}aO`fR!`dZD8YM55E9VSYei!I73FcyPEE%rc zh~*3o>1A978Wh=FJgnhnWA5|1OYz3$2iAYGZ!2s5#yI7m?Ya#YVt6#YbODIsFz_vz z`+C|`m?q!*+>9)4Dp_@I)9cUI+Z}iMx2^D0FgDCinm#M<5%aG%e$W)9Pc!Sk4H90| z_1Fcl8hY{*Wp^~eS~~+dJJQr*5Kgmx7`2Hd5ho8h$IAt#4htN z?2sWZQz3a!)2HyhlqR#fyXszVEf)Pz<~<*MxSwn+$%JgUxB@V?9#`o~TG9b3eUM8P zPmc1qL3^n3WCe^B6@1%{5x(hm znS2$ng^r-o%giq{B-h|+FUb^nkrP?i&3Dm9P&p-Rh8>fqkOATFM6uRYDk6%%t43)S zqb-5*$pP(3E#UOdsg#c~2_9>jAoK3Y)X5rw2&aV{2&aV&(1I)9POM&*Kf$v5nWxa- zzw_Fo+vX11O5-4C*fyK^sx+AyBpZI-hdSyHKYqNM-)fsE9dET?)kH;>0J27l^(zk$ zCh66nvUytrmnIK7;}(3L@Ej7toYULJgG04aS$cxbzXwP+p8uqJ6Q9-_0VHSmsyo1QK$e)NAaA`O($~RENuBaH0I3W7u(6#9K z%cH{oqFw=BHAxhLn(dCclspX68x^OQ$N&mL9eIHhLfXO*;ZBF0n~pEQD}X|diQ7l&6v^zhnQtm7I} zI4w%xMnM4epHqLMr!tX~*2}4Vn22Tfc~f1IAN$$(L0 zK@-eb8cO~4%Y^fSbZDww+jdjNtWuf4VMm+c6VsjSzGW$Gmus~$L%oQ+j708^8?Llp z+wJ2G5%PAyP893Om;Jl8+$_8_E`i6^Z<-lw?WM;fVeM?4KhA$$9w^_fGD$_BtyX0^ z{FX-j^wKlEwr2ZuxY?G$y&zFn)(iLuOrka^jClY422Cs_3U^$PR;7QD6fCoMu3~&+ ze>g$KGl(&~tZw>=Nr`^R&s!b}T08JR0@YU}+3_L7e864myY70@iJBn+%k*;L_lhbB z397iAQGpB$8YdoyIQ+ERAhKmZ6gp(q_#VB{*U*vk@6;BhA^GB%;m(9cH@1ClqnPvZ=Urx6nfp=o-TO_k10fj7cH3rTPB8SNh7D zzPneJ=N)je6IN)^ap+r_)i0e++gR7T*-KxB;t-eYv|v$D2mX(<_oun3$EQj-I1Q_A zIOOt5=XwiYegupwaxwlevIUI&sIYIn4LZwtxE8vd|4~$b1b??uPnZzg-^DC_D^Ywr ztg%n%(Rt>)pSY4S$v;*aL6gxq^i!2hsM&mEW8m>+Z8asBn<#i4c9EgZ?5WZ#FVqsq zEbc%}t*$at5cIeAYtY`{@kUwDdr3SoB%!@tWG68xu}@c!j3IN7yR5#hT4SSPp}vAu z;y0MN|9NhNd{mH$N<~+k=&Etrcsy(Z_QLVu|{FxgxHclDxgO!CRFfCaCo6QOZr?^ZmIKCDY8+Fn-wA;`QkCPxRp!D~7)^(?* ztW|80H4!wp#D49d(<=#@W|~-uGh_q9G7wyI+jF$siT=`$s7s#3&1KLDWH)x!n}{UI z~{)Pi*YGI#q2b@W3tIJ6y-=`=}*ScTm1|u9P>ZT zJ)`V3+lfO!vltW7Lj8(7#?Bt$gbGsHW~E8e09~556(-?&{XYLmJs69jLi%(gXG&b! zlTR5`7M)!3dG$q>w>a8}J)w2n2Z0DNv?mF(j?yPnyB*X7v4X|wPu(01AfA47=nhe| zM1R(!KdR2;Hyg;Y)=}pvaM^LCScO@`R$h(Gvqd)dch~^1b#=Ij=Z* zKB$JrCNV#2tOM7aH*29u$n7E+dWRzKr!y`_?3m6^w|dAJxxQTJrcJ0Vyqd`GyAEx` z!WkQV+p#I0k}~mzSc=I)L`Od>DrbY{s)ENj@lXrPyA z6^@@w_s*DE8C^PdxS>%mV%L!WlUT^|>sE$gvBA~nb@E+*fzRft7@ljbD)aG|2n&H1 zX~7&C2{?sakVQ%#?@gr}CwcTI|4czqj`1xrV*|p{9}GX$)9|&r*m*nIaZzK=5GjZ% z)&J%Svkr0pGZIk>!;>Uan!;g9n8!P2L%ii*8)X=HB9sv~>FI_#^>xk|PU@eq(>E%q z$%8wn)Ke6DjXw29g4%@C>>yMrQ~IqLeBA5c*^sDOv~TIGpQELGUWxrAZpJXPhq$;p zn;F~v({nJf#sF~w*a81^1O+kJq#f*C0fK^T(jWjAT&xP0fC1e9^n`^m*i@VyOx4U> z0eWmIlF|S+bu&*_0Gq6xv4xrVzpoPizRK!juxTrsSeu#tYdBdDfam`XCkqDf{kz8j z0D=GAFb4?4#}040AU+0m zc7_ia|9!Wovza*tI{?Iu@sGm)Z2)dAE)Fh$IpDu#a4`Qgfc<~V_~7&XUosHif9i2? z{D&Thog0q%f8GlMal;+_zhq!;_{{%@3@-T(yI@{UKHmSO#{uTx1^tJNoBMy`HQ-7gu9v V*MCKlhnEAyi9tsvr7Vr{e*ow5jRPVPa$EL}DXlC3Q5lK@t>1Vv%rkb8sbPLt>G)Hg_S_;{Z3Q z86dGJT9{j#h&y_c>al|FaPe_5v-6VjaQ-A z{=d3a23k0XnYmg!I{a6kq%2>oU1dle-0bYY9sGM#!Nkka&6Siz*}+1>(az1@;XiM? zkp6Q|?Z1skn7EqQIa>ZNGyh!tKi)gIS~$46kaGU#Gt$nEZa`8&!T<8`KmTM=CuRBS zY~tVoG;y|YF!Lg1kpSP3v~agJvrv;32M+-354Z(94gcATnuUv_o3oh(*p>h4_x}v| ze>w86?Y|xQVr}PY;S3(6or$Z3q=lKIxdjr7f`x;ns}(6X7w^BPTwI+kOze?7GhSq0nTfp6`^XDbiRkt}|Pml+AL%Qt(zgg#6%n8Cm zuJ(cx#&t12istmaf*}%w_5lvT06n|hkjvHAcOJx}XK59!rK+m>V$PRsakk-I;3yXe zc-GFQZfrXOD7u*e@u4wQ4Ao6>{-EYMrE^YaDoq4#u%nYA*_rNbwf|1%bc z{~pVCJ78DbI;3zzb;cG?Dl3;yT@* zJ8z9mjF7Wqm3wxGA+)i}%Tjg%Ul&uXZHf*NAkhOJ?c@MJho1sPUr-EwvYYtdf3ICY zoD!=(qBinuBK(Wr|5}{?70F!xYh{a@xLAB~1P2GpS8IC<7bZ1FdlPV|N;!bnxV3{N zDT|i1gP4Ph^?%<$Vo`T9b^Q;3_!l)`WcknF`Paw)3LftN4-?{!cIN;8E%5wr3)ZeK zDi+QXj`l!DhkudI`w#i-9G%sHCT3tL`yVhs0$=_MUN9ioyZi$Z6=yIKnz=eUld^Gv zf#csZE~Fg)aRr7f7gBaMUQ!nE|3~-#K;{1x6J#u`Ev;Nh*}1v?2Oroud3dW>~Hnp)Zb43Erxj7hEz_$Nyz;f0hukv+qg=ZuAnCA)x zBN|r{78bVUPZnId{AM#PeIzXc61{3(NeP0?rN7vKWDFl$ge)h`#Yc8EeTc6HJ}>ZR zP{=0$@1Jhbup+H&dT0 z9=fSXk&oBcr<*ytgQU}d{3&4GbjecO-EC)J5>g(&TBasj+jM3XU)<$P$X9rNB{(gKhmwZOKz>ZA)>b_#adSMsJzZO`^~v_=8=pn8o7Ny0J91yFRU@t&g$JCB?PX69PZHQJGXE zLIwDE+>I+%&h9;c=%S;ik5oFVd*U;4>qz7^vY*^Y)_XR(cY_Ytq5r$GYh@MvOd&e3 zkNwKg&qE9{zc4zU$%cznX@}@(^SFQtUS3|FCNop?7v{}wvMsK&WVLn4{w|o

{d4 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 D;>X%$ literal 0 HcmV?d00001 diff --git a/test/table/table_with_minimal_layout.pdf b/test/table/table_with_minimal_layout.pdf index 9fe839c34a5170c99c4d9aba762310b4cd1cc46f..51b2610c049b6db5a6e2e74e0c9e663f3e0f9d30 100644 GIT binary patch delta 647 zcmX@feU*EI17p3Z8JC?MS8+*EYGN)|#hj^A&gL~ah_rsUI~u!fw&rK<%^|_FC1$JX z>Km-Qc8N=6L1xYGq&bQIL`o_@p0iBf$1D`#Cv+tE$Lupj6;TNXm{d8R#DADmzCXZ| zV~-EVsTGlm_qfDZJUJzobr@?np3iLa|IBCCkkV1~`N1Wpgw;t1posA2=)K~ delta 635 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 X1Y$gy7#0pPvqW2g^z?9^E}*{w!!^n< diff --git a/test/table/table_with_multiline_cells_and_fixed_row_height.pdf b/test/table/table_with_multiline_cells_and_fixed_row_height.pdf index 742501cc2a86b40e99a7bbfe3d69ede4958ffa25..af0f014118fa323aa3c3c162c74a2dae0d6ec824 100644 GIT binary patch delta 1988 zcmai!dpy$%AIHx^*1EVHq1={jrs!<;8`~JQlPyyta!H}33@4YSX-uqx%Kc z^U9eW&d(ccK>e8+U}I6Zl)C||+YTXu`eijr`UXp+~X&eFuGgWv{=g>(QJ6 zSY^{`*u$V>gXjPXO!Mj84{OBo^+5I*Ve=&=iIWf4oZ6S9Bn`5{FjB*R)dFS^ups& zD8gLgUMf`j&0!`bg~AQBS_dl>BW^j)<{3iA0k%qVNYn8Foi?W0YtrMgA_7rp^2grl z`yUXf6QnYi%iP8kLC)9f9|Sk{~?AdgLV z`72dXi$m?IZu+2;O`Nw;VznH<0hXsa8D{E^@pjhbI&~3u`#3uD-<>x_j@5z*8DCnU zqwZdH1z}^>Vs9LD~YL?*_6?FFihoWPL1TDk>b^0 z&u#9Lt=RHM6N~N8%~6*52WmlC6J-K_+>a;0yq8;tQ^J~xSw%^*(mS~?lIF#m++K)A z$3Kjgtw&nO@@Xo(Gxed#WMxI*mXNL@%8rd1Q z@x(+gXy^LErupjh`PsvpKscs_%d9oF0(3U>~$bSvMIUGcwR3PQF_kf7YUrsouJ- z_GSsM$R1Kn<6?3D)x`{cU*tbsj7zn@rI#A7xjYiWnXNuL1M)cH9)%u;B4Sn{Al~9> zoE`(N%yVs8seUj&b=1ehx;gF(CkgdZ3+k1FFf5iYG=|IRn{jHDC8V+n^Fq4ckl1f& ze)Hr@ji|QS)&@{pW}4G_z$mv1<`jLBn!W{uYNrtOimR| z?ysRrjP$bBuO6VmbO-A!gX8)*I!Xw~s<~pHU4+@^>u{|(-bJFD)yr11d=Ht?W5Z8J zF!DvKjCbiXfa#BP$Q*`uUJ*-KT ziu$3UJ%W#_7q21nUX}PZy!Pcc=;4Kqn%_jXD`2H#RZ03WQ-sS5Q!-1L{j6m20Pumz z6+m48pauP&G7{JFeMNWYF>B-3N2(FA+Y_hFjD$eMzMjk*HX8_4tjAx-@9zw%qS%&j zMx`*kCScc|NZ^6w-UaTktWJ|W09!H({PT2tPxMyAJ~GtHtz3O%_p7OIL8-BU9?B2 zJPOw|3xGFdU%LS+dd_aT`SxLE6z;<_?GIgtHGp$8cUZ&}!)3P;ulKGoxtAJoFghY` z-*huV@CSZr$)zSBIV=Ns!MoFR*U~$p8a&dq5?0yRw-8xAdh6T=+rJMP-b?$D&7A(J zzcDRe*>lf_X7wp|hj~M<;dB{I9u#(1q%jjfTXJX@wBSX02bU((TZTP13lhTX6nK@; zmgO^-#ontMbS)ANoOKJ>n^{F(C`a9n*ogO--iJ&SHQ5EsE&o!yE-`PNn0!a|QDS4h zy+QVM|6(5)1zGBbU19fg#T}~|^&MaZh=D~z(f8)WI!<11ZxNaL3X7;{srx{nfm|$ delta 2033 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 delta 3491 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 0: + row.cell(img=datum) + else: + row.cell(datum) + assert_pdf_equal(pdf, HERE / "table_with_an_image.pdf", tmp_path) + + +def test_table_with_an_image_and_img_fill_width(tmp_path): + pdf = FPDF() + pdf.add_page() + pdf.set_font("Times", size=16) + with pdf.table() as table: + for i, data_row in enumerate(TABLE_DATA): + with table.row() as row: + for j, datum in enumerate(data_row): + if j == 2 and i > 0: + row.cell(img=datum, img_fill_width=True) + else: + row.cell(datum) + assert_pdf_equal( + pdf, + HERE / "table_with_an_image_and_img_fill_width.pdf", + tmp_path, + ) From caddaa82d73d71262555d340a52873936d858976 Mon Sep 17 00:00:00 2001 From: Lucas Cimon <925560+Lucas-C@users.noreply.github.com> Date: Fri, 24 Feb 2023 12:39:49 +0100 Subject: [PATCH 07/17] Adding SINGLE_TOP_LINE layout --- docs/Tables.md | 19 ++++++++++++++---- docs/table_with_internal_layout.jpg | Bin 18568 -> 18536 bytes docs/table_with_minimal_layout.jpg | Bin 14832 -> 14822 bytes docs/table_with_single_top_line_layout.jpg | Bin 0 -> 13287 bytes fpdf/enums.py | 3 +++ fpdf/table.py | 6 ++++++ .../table_with_single_top_line_layout.pdf | Bin 0 -> 1350 bytes test/table/test_table.py | 15 ++++++++++++++ 8 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 docs/table_with_single_top_line_layout.jpg create mode 100644 test/table/table_with_single_top_line_layout.pdf diff --git a/docs/Tables.md b/docs/Tables.md index 1fda13f8a..34028fcdb 100644 --- a/docs/Tables.md +++ b/docs/Tables.md @@ -112,7 +112,6 @@ Result: ```python ... -pdf.set_draw_color(100) # dark grey with pdf.table() as table: table.borders_layout = "MINIMAL" ... @@ -121,14 +120,26 @@ Result: ![](table_with_minimal_layout.jpg) +```python +... +pdf.set_draw_color(50) # very dark grey +pdf.set_line_width(.5) +with pdf.table() as table: + table.borders_layout = "SINGLE_TOP_LINE" + ... +``` +Result: + +![](table_with_single_top_line_layout.jpg) + ## Insert images ```python TABLE_DATA = ( ("First name", "Last name", "Image", "City"), ("Jules", "Smith", "shirt.png", "San Juan"), - ("Mary", "Ramos", "shirt.png", "Orlando"), - ("Carlson", "Banks", "shirt.png", "Los Angeles"), - ("Lucas", "Cimon", "shirt.png", "Angers"), + ("Mary", "Ramos", "joker.png", "Orlando"), + ("Carlson", "Banks", "socialist.png", "Los Angeles"), + ("Lucas", "Cimon", "circle.bmp", "Angers"), ) pdf = FPDF() pdf.add_page() diff --git a/docs/table_with_internal_layout.jpg b/docs/table_with_internal_layout.jpg index 8937cdd83ceb11fa2f03f0657109a4e15e648e75..70c9513ce7896f44722cd24e1af54532f5c3eee2 100644 GIT binary patch literal 18536 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 literal 14832 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 diff --git a/docs/table_with_single_top_line_layout.jpg b/docs/table_with_single_top_line_layout.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c43454886ae92747c9b229f4b9783a1ad9af692a GIT binary patch literal 13287 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 F{{>JIV)p<5 literal 0 HcmV?d00001 diff --git a/fpdf/enums.py b/fpdf/enums.py index bcd6ee135..47b21bf2f 100644 --- a/fpdf/enums.py +++ b/fpdf/enums.py @@ -252,6 +252,9 @@ class TableBordersLayout(CoerciveEnum): MINIMAL = intern("MINIMAL") "Draw only the top horizontal border, below the headings, and internal vertical borders" + SINGLE_TOP_LINE = intern("SINGLE_TOP_LINE") + "Draw only the top horizontal border, below the headings" + class RenderStyle(CoerciveEnum): "Defines how to render shapes" diff --git a/fpdf/table.py b/fpdf/table.py index 41af099f9..a585944e0 100644 --- a/fpdf/table.py +++ b/fpdf/table.py @@ -71,6 +71,12 @@ def get_cell_border(self, i, j): border.remove("L") if j == columns_count - 1 and "R" in border: border.remove("R") + if self.borders_layout == TableBordersLayout.SINGLE_TOP_LINE.value: + border = list("TB") + if i != 0 and "B" in border: + border.remove("B") + if rows_count > 1 and i != 1 and "T" in border: + border.remove("T") return "".join(border) def _render_table_row_styled(self, i): diff --git a/test/table/table_with_single_top_line_layout.pdf b/test/table/table_with_single_top_line_layout.pdf new file mode 100644 index 0000000000000000000000000000000000000000..5d7c6f3302a8224f1ba505d1f8be42bb3538efd8 GIT binary patch literal 1350 zcmbtUe`pg|9A~gU>Ip^KF?3A#)TXVS?cL>imz-qjl3dT#RZ^3xbEVtP~0VAqvE>ZlW?LU{xKz22k2C z2my8N)CSBn25cC?kZGh-Xc4vnO)pXj64J0{m+!VrPB znYLok1|BCR4esEht`$C2H!!qFu7-x80%K+zGHfSA3H&Y)c!7G^*n(P$$sGUU)9dIE zx2pY*_pffAntZNp;(A@O=|uNuFMRkza^13i@?uCe2uYeV7mP;p1@RN>jWO@WCCym4^bxV>WQ!+om*!@(~b z>tB3S>zf<8IDYWv%wJW1-dZc%5nkPy9S(aHrgKl#mWL}6-zN?TgLtO)$HKAv+41V! z!jWgzyPBl+{q^}`{=1jax*`wh(MzGTL{)s~N=u3B-XMg>;jeTRb zhN`99!?JEf#{~p68>%L`Lbh8^LAyC(rZggqc0{g1M+w00)=>c2dIezEXnHR$$&reZ z=y*|^l*4hy(!YcVnnwKpN1zIOq9R&=&&R4fptTV#t8PG3h!Fj-U6vV(LJWFXGLNKA zm?716q=+bk Date: Fri, 24 Feb 2023 12:57:30 +0100 Subject: [PATCH 08/17] Adding docstrings --- fpdf/fpdf.py | 3 ++ fpdf/table.py | 32 +++++++++++++++++- .../table_with_multiline_cells_and_images.pdf | Bin 0 -> 79961 bytes test/table/test_table_with_image.py | 27 +++++++++++---- 4 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 test/table/table_with_multiline_cells_and_images.pdf diff --git a/fpdf/fpdf.py b/fpdf/fpdf.py index ee93e106f..77d88e1d6 100644 --- a/fpdf/fpdf.py +++ b/fpdf/fpdf.py @@ -4711,6 +4711,9 @@ def use_font_style(self, font_style: FontStyle): @check_page @contextmanager def table(self): + """ + Inserts a table, that can be built using the `fpdf.table.Table` object yield. + """ table = Table(self) yield table table.render() diff --git a/fpdf/table.py b/fpdf/table.py index a585944e0..100934274 100644 --- a/fpdf/table.py +++ b/fpdf/table.py @@ -10,25 +10,37 @@ class Table: + "Object that `FPDF.table()` yields, used to build a table in the document" + def __init__(self, fpdf): self._fpdf = fpdf self._rows = [] self.borders_layout = TableBordersLayout.ALL + "Control what cell borders are drawn" self.cell_fill_color = None + "Defines the cells background color" self.cell_fill_logic = lambda i, j: True + "Defines which cells are filled with color in the background" self.col_widths = None + "Sets column width. Can be a single number or a sequence of numbers." self.first_row_as_headings = True + "If False, the first row of the table is not styled differently from the others" self.headings_style = DEFAULT_HEADINGS_STYLE + "Defines the visual style of the top headings row: size, color, emphasis..." self.line_height = 2 * fpdf.font_size + "Defines how much vertical space a line of text will occupy" self.width = fpdf.epw + "Sets the table width" @contextmanager def row(self): + "Adds a row to the table. Yields a `Row` object." row = Row() self._rows.append(row) yield row def render(self): + "This is an internal method called by `FPDF.table()` once the table is finished" for i in range(len(self._rows)): with self._fpdf.offset_rendering() as test: self._render_table_row_styled(i) @@ -47,7 +59,12 @@ def render(self): self._fpdf.set_fill_color(prev_fill_color) def get_cell_border(self, i, j): - "Can be overriden to customize this logic" + """ + Defines which cell borders should be drawn. + Returns a string containing some or all of the letters L/R/T/B, + to be passed to `FPDF.multi_cell()`. + Can be overriden to customize this logic + """ if self.borders_layout == TableBordersLayout.ALL.value: return 1 columns_count = max(len(row.cells) for row in self._rows) @@ -188,14 +205,27 @@ def _get_lines_heights_per_cell(self, i) -> List[List[int]]: class Row: + "Object that FPDF.row() yields, used to build a row in a table" + def __init__(self): self.cells = [] def cell(self, text=None, img=None, img_fill_width=False): + """ + Args: + text (str): optional. String content, can contain several lines. + In that case, the row height will grow proportionally. + img: optional. Either a string representing a file path to an image, + an URL to an image, an io.BytesIO, or a instance of `PIL.Image.Image`. + img_fill_width (bool): optional, defaults to False. Indicates to render the image + using the full width of the current table column. + """ self.cells.append(Cell(text, img, img_fill_width)) class Cell: + "Internal representation of a table cell" + def __init__(self, text, img, img_fill_width): self.text = text self.img = img diff --git a/test/table/table_with_multiline_cells_and_images.pdf b/test/table/table_with_multiline_cells_and_images.pdf new file mode 100644 index 0000000000000000000000000000000000000000..270e735278db6e7768417cf51c0c160d95a22121 GIT binary patch literal 79961 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

gh8QNqg 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

^0FtfJfh(ieT`q_KGZRIkvUY-<6m;uP ziOy#!nek}y7is#UKZQ1C`r`zs-?fRFDkk+1K?TW| z6sjuO!QlyS*OBR(>YrKntC=M1(GXEm}M^91dl^Y7$1E+-< zU(`Gf>q7sAKL@Fln^nv}hP;&bf%OSX4xJCm0t=}}nq6^YHxK#FMt8W2 zGGxzj=5}y4z{KcKwZwihv+VuH01yC}4St=y@1$9GR;6BvVR>LN9f<~^E3!0ZDNT?Y z>FyNUo=io;+E#>Yl!|ixTr1L5BN!>Uo)Vq*lKl`2sf_a7r<2s3ZSY5@Z}<`}>n${( zW&|y1i4xkOr(A>K7`64d8Su3qdv7;U9=syxz0|46RjjwV4_K|+~Uj%L3lsXRWLL<;--x^34PDhz-rCIIfrKR zwV(pvL`VW-(svES+4MCO!PK#3+t|w6Y z=uu8ov87xsq<2z~wySFcsTJjgxXP}JCbvp?pkOy!W0_2wHbN+gVW#(g<5%BG|wSaJP;jp#w}2 z5;wm3g#c()7dh5!v^*|xAFK{B&-*nvyVN2=Pi^$_J-yZ#>8paZS|}qb(2!%~x5kzn z{D@ly_u!QIog6&K5kmEwOreyVAZRFVn^882p5+~}_5)lDTUttyqVHf1*oiPK4`hF@ zcv@rXJN2mXX0#JLO!=jDHw2Mi_Wep+TG!=~f z`d6C}9w|bbrXjnB2Z5io8Y1Nb8G`DE)0E&$1JA74xI5s#hRCwyM=gl93=XjH=NhEX z3zMO;D$_Ovn;Hlbo)k(s=!9zDhm;aXr>^Zhq^YcsRA(9M*LsmLKBTzWWSdTJ7#JMi z%_s^{LWko^_>)tH^xk7$XimQ!+#SKahbmWF6;Hv8FKFitB)Wz6Izq)xj=JI|3NLL<28NQp0rwMYW2$7<7K5O zfqq^huJ%gHr+A;pbt>v#XJ=>I zyVkKKDDv#Ls8^K^4zb@F^Sm!YfusB%VSP$p;)yGuC1p?!bU%Q|lV5gDZMj{RX6AZ3 zlVS|w@khRm72ZAd|2nup_xe=2vr4IKTV7Pu~d z-b^~m>9^(4*O+j+NY_EhaSwN^NRViPhKAYEu`bcI^2{$ z>uc9LC2jX@;uq7l%}KdV)8E?%`RlhPA}ia&kK(6 zXiAH+vivvy#w$@n^zw+znP_C_wZA??<9Y{|ZuRJu0{dh}bQwD+A)kK8fG7C^1_Is@ zGQ2~5^{aD`d>1VUMfvk(v+-EMn9NyXQ=Ynt(iU4G)Y#XdlzMNK^XIwANr<~xQSR}3 zlx@G&*q)U}u8S_+nF3R@hwpmvcXWwv%~WErYf)fs10A+OQE%*kh2whXA1HE_)mpDv zoH9MjXxaYQT6HF}`hu#b8RBLw{Xss|`L#!b^3HPQ5ZgaJ`>OrOCE7 z3d8%R2A|6X+>a;|-NJ5AZQny~!1P*01a1{32z6p)FM>tmk>O~cL!8gWdDI0bgLVFP z>oAvFMC;Y=Q2dj4E-S#`anPdXCE+BMl9JV^{l1665^C%@Rof?^>?zLiJ&9pNCiB_< zvBH&OD{&GnHAde0NGN0Nx#?cl_pw_Ug#KfunfXhDy2kvqK-rDmcW;fcU%!XggMxx? zLi%x%Hl@yqDxyl7t~?Z^o4@a?is(#h4hp1 z_sG7_bLGW!4wkWNwL{?FM**i>zsH)_)S*aPI$cGBs|%y0KDLn22Hx3;l%dVi`0N{+ zw1l9=MMfGV#B@z!cx2Uhg`-SBm(yu3%ShWiWd+DC{(GAIx7x?33f z#cNSdj%^;gt5IMcUOqHnXpLMz(^6{*1MuYwD6A@|dla9n2ra3FOBy*+`V;9)UmSx9 z7Y6W~I$>&&5O<+OA2%&+3ye#qgjOG@d7HKaz-sPfV?$55`Pj38Buwiv=e7Z7s+#ST zycjY6gM}>TB21H&MHZ*8(d+GJ2`AKEoGJV5h{R6g(r8VIP@h?O^K0?E3Ex|NxuOQCq%HZ1YT@-!+lsaPLX1upO6mFigoi#Vz52oP;2O_ zOD^Q^Ru=F{`oBsXx+i0LcaW>K!jJq(dnw6@>lIbViMi@AK!h%OYyRC<~NpAV?XY5@z2a( z^Y6%=je9wdXz3(DpUlxp#5tYmU{LS0 zWPdN{a=;QuyuoTWT5|~#LepA7eW9HjbQo~(sPtX5$j?k_;>QuiZyAplT4eVMDDK zA1GQ!nse&5#%m+ENw5cpP?!vugXnem@{HB&G>+>rkY(DTtmfsKR|8>xqsH=2iPAFn zX37k~n9kbN2!x|BdZwnET1w@pc80&5mRb0uo3s_0=Kn0E+Gl~+@RAXu?^R8I(fvCe z)!a+6uQ4=3Dy$7I+VQ+Rf7Xtcrf=nn?Z6{18bVpuC41>QhFC~J5WEe-O_(CVrY=^; z53#uN9Pv>z7W3**YH1=)aO)C*>gtWmGoK~nr=`C(J6Q`SXIu>FIv6aoTV_LhIXkmc zZn}ST>=)Pz^5JMtHp15ZV(L&(mq8NLuqlGN5i)ibKZX$|@|7vmZ2}tYC(yoxWcf=; z%gTmi>p9<+x!30fjZR~5LGz(Kc-LBNN==D6&};0-fAS!#SkT`qPRSD=I(<)JH#U;* z+syWLXMF@TeyU=Jt1VWGU#Oqa4qhjSfZF?Uyd$b&8kSpUdqYy08$e!EQ-k5EzWhCl zqd)E@)0BQ_mV6q`wadb|#1L5noUf*(PfzObB9X&OS{PG5wZ0CB@A$h$oGYuPxE;6a zvU=bofgou`spjTlrx~13FN0a(wBS9l5al1a2~;O@BGef6Dvaw1yp~DZAZXhzv${+c zmfPw+j882e=sUIBy_{AeqWW-{SQdZZ4Q^U&gLej6~Q*2k~bL_u1OQUXAqM zlkoST+uHmCM41Dq$-Wn)LP398X$>V}oVZ&x$FrNHBP|-seQ>!N{DQ9JEXa|ruX*^% zEwRM&+NgYp?~o>f7CUr4$^3blUG2<%<6PC_GZ65M+I7+L$$buqo0dK%&lg=*$x^Ew z(gr^3FGWp&YsdDBTsaf9UylzDr33*YV`HfSLs4{hTFm0o^!uy^O)MnUOw`j)- z4dYCeA|r+0%S{lE>z?KYTekcK5)hBFw>`ncFJ!g{oq`IEhtGLT-o1OQ)Oc7l9d9Z* zA>0aiI zpv5tqKT=0`A)u6)EcE$1WJ@Y)({uk-yT&o%t)HGdXDdi6NQi%uV(7)2x4ARvJh@fq zic89!-lY3HMC3g0&>L)zrKsHwR=-nL3G_~8nkp>6!o;Vj1}G!Ivu8sde@D3=QqMnvIzO0rP0A^P|Y+0w$3M8B&MH{IA5WvyAJ{CX&5eR;O@O!( z-_g8vXsT0Go4kxwhyth%SLmcWZ_2jTwl~00ST*%)%HJ0U=jh>YD+x15W5EP%{j0Y~ zHeyIWrNeAPcSR5#utn~X_zQ^f(n~%C2TMyM2LxZVkM}tZ14?4B zqj5eJ5cSHo-x8)sa#V?ENf>_Up5}dr_i4L}!gUyp^End$em4n!cf+b+Qv0Akq}7#! z7g5wG1=Q<~2doX;T(mxd>|a&D2VTfDBDVI^&^jz<_HDss0Wke#vPO)zHLZ=|Ik|j% z%*p<|?1E6YIsb!F5vM%4U2i-}=aJ*;n3(7b0L)2~OzY$$X!ZJ>u@!d(Z_9cV?{{13 zu(Aq)B<4mFt^2Cdw`rZWc3bMn=Vi4h2hsp3>C}t3wBaztR1nr981-gjSnzayJJbF1 z7YJECG~s5ux_gZGcdaFjw8$Vu3o?;c|E<>~kh}(0 zN!;x1XxGrvae%U0{}W>3QksGKLdZmR&CpQhMw2fTr6qOloG|$1Gvnck8+;E=gVbIz z9>bQ2dFQNj1dX3wc42L4vzwvq0w~#MEgTJVp(lwk*xk&`?0QRTs%JGEA9P#YR`mU2 ztiAoywmR<$AANQF&+@>jkyC<&)RB<;hgh&! zPBv~#mut^q+WN*K(m|vB+^){c68$led%3N-E(tD_q>;sHzHD;bXUX3)M}6fsyaYwBK;8Dr4NPgD*=HyU4t%4I zR1`%tvV5hnZKnrH&@89#RlQh1M`O|{n+1~#!KeL^=WyXR7Hj@fX8Jd)6j1#yszov| zRd5Ph-M}y%d@!O3szb02XX9S~i}JhG35x4;-+C4q3NX)rv?T7+nN-f@C;UfLCH9n90NRF$s**|>5a}=*V0c163Xu~=jGNlosPEXco9UqXN zIttX>d-V}|6btm3cmBAD2Yk{mnDa{XoT+n;t}IE@bCT$BZ#C&CCyxaoQYS8{oZu4U6=~&^MVsPr>kK50nxA zg#(*(k_Q8xe!b0OX6Nd$^GEOyhpgLpbCY@CBQ|%gM5OIu zEjz3V?Ds0Pf_nGE0;?ADlyqK}w8l{zDJrWGY+u%MGKU_0_7Y)|Qu9NdQrta5bF*2j zB&zf+qL$Xz1^M_|U97tjYfEP2&MR+TUTl0l2xYsi0h{nv*4DKWaSJ&$f7@j!BKTky zwvW6j)2K{*+`i@d?{NYiD_hQSk~#HU%+>2EwV2BKCbBeTa2ZUz^no8D z!#K(K+~0)vt*G;OIdy0j|*}xS`>}-#9>*hO$BuGXak*NS17dj z7A=CZ&FbfWX4GiU)Oh%RF!z?RjePC4XOa$fn3slQPELn3xe)L9U|&I+WqoO`+|`#cas#i6smp?;UVSh`b`QsEyBWXW zJ&k9Lq-QA26;pW5ZiDz=O1Annb|hdgkk|p~T*1-KGF|rsx=O*G?s|jQs7> z3KD|kKfvV#k^FulD5AE+!DhP^mUqMC5hfqht+^+u6;&GFmeOn#`mvz9oY3b1E)7q# zjE07mH`_)%X%lnDq#%=kdE>_{73DzlCVC_r4c8Y|->Xup z%yvt;Hm8e-XimbF+`&U++*}dy)CP<0Gy$aT^DTe{VvAmjCU#xC`)jPdvw@cUd}=^Q z{lS-!nk<(+NU_`Z#l^dr-ZX8upd12NUpzj_WJ%{GvKF>9{2(Z=Kz(#PrMX?@s>|6oNe=|JqXLXmfLCxi9I$ zp9sl2ufj6*wy)yY{3z+nXB`clAfD0f%zy#V`7`fA;1^w5|~w8c6;ScgYzXp0FmUfviM&JHf@V zbnqUCp^1wn`n=u=f^U8L`;To~Ma__;r~0T&x_#taZd!2Xmbl!S=y@-vblNh`$N?vD z@eEj>l9`X?m%A*CghHrY5IjEo{kyT4mz7r9bGLF#_1$6*Mx4eKf~y58b4nGcMsqph zgp2!Y?od9|;#|F9rd8EiIsx3Dn(?x%xP7~UZs>Q|BdtptmG&OhA}JaV@-%p!uLW8! z;>?@h@jcMrqI;r?UB0I-52dWi=&UzWazkVM-B_+Sw-7#FGA*HV09r=1Xl|zc(u4PG zSPFr?tQ4rRDrZt6vi|cxDU^n}{w2@gTIih?pz|{*YLZrG-Mio}aMmh`XL`HRU%RsG z*5&Vjf8^9e1Pcp`6fI3ZdxJBa)mh&PUB4oYNAayt?u_a9puUo#rk5)1SO|@bee2pt z#9=c#CEE(&cB5$)_jh%>Q~Ryi-ulW;gH7(i%@IH|{NIbPR8m!1%e{I7k^ z7O`yaB`vvr$_M-#S~lK0-HC3L3uvDTasbcxaCaef5=l)yMgxuRS?pEVbK$!Lq5{nI zhIbt(^cO=c(s@Qz)Eduvlnf{Gz{QWY+svZ`hn(*RcUn1ogF(=@;?~iGCUePA(c$y0 z-RjCpABE*@ZRuA?Zr!!!9Lc>=jqV20njf!oMtp(58f;9dk7?TBm(p^d-PSwiW+B=x z`9MiuV#=Qq2p?H&VgifO(Qw=9OYENvi<&wCwNtg9GcT~!>emsPdPGd^4|;YG3qx%AGa+gn(zC;SS6PHw_|@U{$^Szr@U z667dmzmmGboe9w+jj6)=yH3nIkwl=*}|%=5slt zrGvRF-1>Hx}>PmaV2B9Wy}?JOkZ8)XkPbGhdI49`)K>8XR3~@#$gwpgk>L zx}i=EUfygO&N(!<_@#tFfB)B5682vFs6l9TXPB7L_2x#OQG!Dr!LUO1n*P8_aTDy@=Us`8H1v|@i~t{s z$;)f`NtFvT=69@%nNG5A<$Y2h@nT`ixiv@M=pNrMiK1g}BQ?s0sBU<1L3KF!R` zT=(m6J;!)*H*qF-6xTFW1<~+(TdOeFa|wM76H7l|N8vdN$7#L^E0g~jEr6#Fy)|0F z7pOz+i%ubkRR7#n4x}zcq0iwu`c1cq8K3JC^o4q9uF^dw?JVNqA;8hp-c<&aUY*6j z1nj>)oCo~lAC(40EC<6UDZJ=<{Ps3jUBcsNklF(+Pw$qKt`A(KU8sna;OjTn+Zj9C zzkL_#;Q9!__;YsYEvqm`Cz7pJqvLtG)(mXlPe?%KR(arO0SfYDS-qfqPqpfQzlNmW zg8~3kyj6eCnops>wAIx|`#Gp%pt*xN*aSALyc$k4i=g2TxouaH{;-+5`Jhm{ZDe6` z?lr#fJ26;xv=_`CpAmkCLatB8TUcHeXF-q&{RFEUfsH-50!=Gipwn)e2NU&AJ|oZRT)*r3a;32>;%x-HnO%aOJdr{IwQ`yPc(QQZuy^++v z{Vt)XJ%)|N>w^5z-V$!PxUteIkIY=xe>_NzkOb}KRa~UjQSa(!-?B*F!bw|QUM!%* zQYE`uDtqZzuK&HX^6=+ooeL$NSAPGVjXqCYjwBgg*2pml+p`jo#Nq6;Lsb!%RRd{P zV>IuE9Sg(Q?_(^CXoKlKLjW95z(&u9a=Vr0v$Hdb)^MnR3P#zk@7Ujv zj=!+cSKgVJx37LH;-ve{?3U5U&Fj4-LxxxUGYWX79`xOW?)X++!ZcObXLL~H@Ez1f zVn7E|j6lN&%b(Y;F3_c5Mj|b|M!pneWMoJRsN_VK=r%p$OX}@Qq?%dL?A%`94M%$* zArF$RGKd9^j8kK%V=;?s9O(v}W^sDR^8H=HSG)s?DumIs*5hVj z{pUe@i4NC6yv;Ac)n@OtMYWzg25+(LGW-b^UYbCGf)j2fol`3bTw85H3!3los{jSI zvQo+dTKd^oqB*9bL#rZlgBOInS7K7O$x1&uQ}|&;Rf<|_g3R&JEwH4tH0j$Yko<8g z>#~i|RKf(Or+x)z7{7(@i`4Mkk9@&%dEXLn8A;MsBF@@j7!(13$(T%46*@iN-gfaQ zJQ+&)={TuovX$Aqw%cq^ff)K!an@$#7)iZ{=c1`!q$zzyU#2Tw+O`&U;2Pat2u^;W)7 z%CJ6E^R+66{z{@EbW|0@QS)+-A(3S3nF55XFKg)gwmf(pL4;0g&O5F zG)ASip5#LS#71F+9!5LZ>XeFmy~}NEF-G@|7D7QnIdD_@|C~G)!=m&a@V38^OlZJ~ zz(VivJ&IA1I)aU*Q!UWJHk`)hP)ONy@&skq+5c`;dLS?FFp0ig^tU;qJvRSU%1_Tp zfY0KKO3cSflTJrAn{%}H+oe*|6D}&`LFIEM=|?Je_U4jD=!6VB#OmaI!rUzDd(m*Y z1~&h)KUhId6{c|U?oH3_C9~R5|Ip=FP{wXz)9cL1AB15^T?1VSjrGuWQXEUON8ad-Thg55AP*>5=Ks`e{Y zQ=#y$gSf9vo>Gdx^^T$-qV9LfTQo1?(9_6M4F*R5$;)>L;&!;X%|^omjat<~hWiA_ zv3Qz$A{KTGDOi>92hHbWChJ#yBGo5wIDXey!fdFl_ET&3<%lXZg8JERVPL*QR_-M| zZAO7!MwZ?urH7HSr5X-K=4Z<2=L2mB)ix3=dQ5SoOYjImZ&cUtGq@cg(78s zk0f-3kxb%fyFkWp7DuCR1Do-(&^6n+?PaC?iB@D^&J=%!7k(G6nI!J@+8dQgS)74q z+UW81M%khABIH7E{bg8#k}R1$aD_V;g#@(A)-55zvm~smD>UT#uqF3{+)XNpYr#OV z_lxgymZiA3UhtK9Kx|(T-{PzVTjiOezQ?~&^xH_t%P&(NO!ENi zi~jQ?qFipdi5L)@0+@=!eb7^04t=Wn$cJSAKYnLE>pg-}&X+M32LSb&y1gv^PdzQI z4ln=4iE{TQdBWw#KvZY8yvmey15a7GQDASXi#kl|ve66I36LTr89>?!f873kuFQ#~ zdbG$vD7lZ$aswusO2M$8vHROA?WW!ZBz)ySEc;ZKa`p*48NFWD(EO@suhKh5)F0Lx zOPV3WR_O)Xx+1+_l}N5`ZWN%g8|)hx7jGv%$FO{Ow!j@;fRd3alsiDeNx$Q498PkV zoNs^;CZ?me``&lkv3FpqUFKxeb1lQ5*AVg;*g_ul44AZ@fGZS3j&v972<69qMQD!< zAVs7%NoYNIr#!9gtqCUu_#BIVNQnL%XsKJHBs)9g^YjCHp#NyDZ*l)ey-q&(!<|MD#SOY95$0cG&Py|Latt7pGUI~%G8&QX&X1792 zFnz!7R$WAKUqxsYd+M2)x#VUI40M$zb5*ngUuABPyl5MX%X51S<{M012k%gA4PNZRvPsf+oUeH@MmCw3_BZSj zdd~Rnz?&6$4zb>3tG5KNV|@Sx5Z3}E6r474HHTXVk}I8F6NsiooGcx|Oo2VX>ClCb#8_%dhf*{K(xRbfHzRVS=SWB@bs5}o7_#)?`0v{LCdoGh3I9=Usk!DR6O;PpbbKt*k0Nmy z2!Mh{1odrU2Zxv&rBabV)0OV@)G~o#x7}Le$idAZY$^&Ki%0HG>PAIAn8{l7fydaM(?IHVX z?B(?e#Fqf~*NI&HxL&ZN`qEzyCR~CUciE@jl*vE(by|IiBO(h+cLE!5Qy@lupO$GB z*YRD#*rP3wOH{4u5s^|O8q|7ERck3iR2EIcW`$#~p7YN<0Ua5pB&!=L3~-t*RWlJr z(NRi1oM~mBjyFAHH?+7?Z@NYA=)djxecn-;A-zmdCyJG*9h07XaS2b=%5@Yq|Azbu^r}?y8<6 zB=$myPZg4P20~0U`nNntY2Mbhi-LS--TYg5hz9+XBwb16iNj4!bgHjF7Eyz)U1s&i zdWf9}2}YNH{uPd;EOoqx^ME2RIf>IgPtP{s`~*r%panZmWVP+Dbq8z5HRpLz&J!8; zR|GT_4O*`RX%HvznlZu0a^SP$)-}Z@aLq5CsyAhs0viH^A+Qz^w%WF?U?pR3GFIQb zRWqulPZs>af4Xn?^>e#Nueh+`k%Pw8<(3_%Ked(6gif9l&vkm29pk6bQ+lX2TRb)& z1;DA*3G0c^7J=Cpgy`_wFaI8WZg$j;n^?D|sDXMMC8Q(bA3agg-%~rMWa)p5BVolv zv;`K^+daZsS4!~^si`UZRQ;Ha4oECWUIw%t8Ep6f7@#quxp_6{8{6hGKYL(NK_?Wq zDO&aVe!~*sJPKwXsi^0s%f~zw1BCSg1)1@;eA>oF^@9T{A*t-LzR0Fj8jb+mq@325 z2gPwy&|>I~>CNV(d`M))wjQ*GEg*9N5~JzNNgV&p^aiX8&VPuNl>6nz_vXDXq|l@L zIZ{i>W^b31@6w+B>2{Lyn-mi>c7C}#kW8e=lK3a}yvqWrK&$?KH^fLfx|+idq`iDb zz*bULPk9xR^5~DQ=B=^vt%wNNPLrQw&gPm3g)WCW-!4~wH1WqU7NQ67XHajrbSAOa z{fQ#*##G*h&cPpk1zmrb@j|she`Xy`rKG-iAom^b)UZ#tUVyg)Y)&7kB?g;aq}en?Zu~gUkks(1_R&3%aX9rl-005*s;deldNBX~u17dmV4g(WwVQnMLHIZl1&xNprxr>2n!&_f|Ym;M(Dn_?8wv{^d&&nCIW;f-H*)Lfb72I1;-f-Jd@m= z#f!Y_D9SARqM=UasB;HTNS=3XH!GO@s9D9RLlDr(4`+l^rGQLu{OT*43mO-=aXX>` z)PELKI4fdKQ`9k%7rAj;|5j`^_ulM8cI+y{hmSOK-3Nz*@Q-=<_*O8F{r>$+de?Ez zjGlnA!aO@HIALgdIs609YbqyO%|ddSxx{b~tKo$i-~(nWSoV z$EN=fTCEK{!v@$BBKClDigbeSgs}|;i7Yiqk`}-O53chlcv^*VOMr5;f!dCUr#mG$ zgoJ}a-i9SOZU~~iSfV+!z6=I~{{&9#m-YRN-^#vQ>F#!1AUhrin!xSIOS7iYV@Zoh z>sTh_iMnKoE+-~8INJWmkk(VBZx@@|6gE;r#xHwfuR+5eIphFSFM-CzMp_fV? zXB~@-8a_ugwdSn{6yU4~>Iadifx|H8QiPkcXOn8x6?QgDBiZ#FIjJ@i@u;vFRJ>I(v>1?T(OJ&M{e9vmljH|#I~)RT40rdl!7m-Q03nD0OZb-3CDdJ)4t_NC^-2d@@1KfWKg)XA`u@SPG`5Z#cFPNd}M=xeR8vF<({U z?LPFk=!7J9x%hB4MA5n0t?5{fINM(DD;pkNw6pTsB0!*#I_)gm7*4Wyv z2o*Ens1Q}1D8C<5WpA0i_uhd!$Jp3d-|yuR*ls-5ZXq-tvcK7>h0o&-3e90JMpjvV zr?yNZ@YPqk^By5^s!uvCj_jDx;*dbT3GzE@ZlH)%LUjX%7>gnZT0B5-KWLD0Tt@AN zV$MQa-JAohAE&wf}0IkEh{JvKF-CFX%<(n9n z&=S$PDN+;L(4rS>g}}|__n87p@tDow;!~3W>o(?^DI-RZF&DczJcwOquGgSEpbvx1 zM}+K}Y2vqOP(WA$F7(F3T)32;Vf<=; zd!@`2gw9hg70O<-*aHE&m{xt>@f^a$sTda^pw+&AAQ~)|T+ug~p#?`pMFsRiArb&# zuaQ9CMdr9@Ip2oxdiEX$7O!jTS>Jd{r8B$$gvJ8y?E=S7$;uQA!Hb?p$F>=obWdo& ztV3!m4DkN^;|x1Wf-2g;o?@cdPpKXQknZQcf8~2586E~~RY$tDDIf0g;kjy^XzO!i^)J7Dg`%&-caDjRyVIlNd2EmNZZ~h%|^%NJF^?!@VYr zlYG?&#Aq^>KPe(l0v3}Yq%Jc%8yxl@CpaqPj|AWm()c9%*(afP6{g=N~+d0 zks37t0ZXwR=!KNfY;trMj4VX0(^IqZo}!5K(*ldOO;V~a0i!#N)!|z&@DGo{n{C(7 z(&A=e0iz{Lp!*Y&2nVciRdlGHcNn5Zjcq*!$~$A;#AJftjf60t?Z$_yQsupNEPzU7 zmDz5_tQL#5`{u9&(r6oY(x=%T2>4CRZU8hg90n&3&)dl?sbz^Yjl%7&$IYH-+-Rfa zYbIaQ!d%Eg_^oM7ueOe+tsej@9f;X$D=~DyfK!#GzQk9keTl%_b%tLpXycq$w0SJ0 z%y;ne!l7eYEyWK^L>#RJ5+X5v!+FcSb)YG?h5R#p+Pz(pY-2+h$j96Ljk$r^a21mTGt-Zvbq%{~>* z@eB7ogTr97VYtf-H{{lMP{_c5)vLX)u%0c0m41I5L4K@E(7m922Gl7Q3(ncSgz?wb%dcA4V72 zH#m752mhQC_{j^mKOWN{q7bof&AO7 zWP`K;n7Z5+w0VXnLJmt+86yo1xBsWl8SXSPaGTF>e|zUK=6Cqf3nv&!u%HyUfj&|w z{~$9+&GNM1dZZdgGhUE;paA;EMHG#J^QPu)WgXnT%;k>-aJ?o;#QN^qp5W-5xtH}ve8*e5 zsxTkC`eqd+NbJ4t%J72ffS9C9!O_A%DD2zYo4A-*{vt21A_tn>{JC*O6OVy2^ii-fadSW-P2qi&I!XW|k6e3R#Ln{(*i?PfwqoS`z%0AY*@>RW>y} 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 N?QGAKlk0Do?LGUf@@X?#7Cftp-2Z+vyKoJX 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 0: + row.cell(img=datum, img_fill_width=True) + else: + row.cell(datum) + assert_pdf_equal(pdf, HERE / "table_with_multiline_cells_and_images.pdf", tmp_path) From e20b8b59efce2fef61864e4b8296fd4859bc8fb2 Mon Sep 17 00:00:00 2001 From: Lucas Cimon <925560+Lucas-C@users.noreply.github.com> Date: Fri, 24 Feb 2023 13:06:04 +0100 Subject: [PATCH 09/17] Implementing text alignment --- docs/Tables.md | 16 ++++++++++++++++ docs/table_align.jpg | Bin 0 -> 39270 bytes fpdf/table.py | 6 +++++- test/table/table_align.pdf | Bin 0 -> 2112 bytes test/table/test_table.py | 20 ++++++++++++++++++++ 5 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 docs/table_align.jpg create mode 100644 test/table/table_align.pdf diff --git a/docs/Tables.md b/docs/Tables.md index 34028fcdb..616aad6d3 100644 --- a/docs/Tables.md +++ b/docs/Tables.md @@ -47,6 +47,22 @@ Result: ![](table-with-fixed-column-widths.jpg) +## Setting text alignment +This can be set globally, or on a per-column basis: +```python +... +with pdf.table() as table: + table.align = "CENTER" + ... +pdf.ln() +with pdf.table() as table: + table.align = ("CENTER", "CENTER", "RIGHT", "LEFT") + ... +``` +Result: + +![](table_align.jpg) + ## Setting row height ```python ... diff --git a/docs/table_align.jpg b/docs/table_align.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4d4e7dae2cfec9c012dba467d1324bfab4a12d42 GIT binary patch literal 39270 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 n0S= z>?1(fJ}8K)S1rR~P6U>Q8=-&z2q#i#I-V7+Vi`^ZCR19H80CaHGA*?jCQLdVAfQu2 zu~nprf;kET7n3@Zo*03RFfC6xRz!?Zn2t=dDnmz30RE0KC~+fc zG9=?h*xQ>8c-p(iL(ymI3o@jrVh9(D9Q&&W*9UjBA?r~b{2{m%l`bFvF}c}>~1 z;_P_;)v@YOZPV2*R_-fq(aC3WbsMW0f3mcrFs3Y9k(bLn+J4&u(jH4(ePw9!;j0%1 z0-I1vtaWoPGtFGP`s(s4=EvsjN%iab<34AbF<}OEvu0vmNV1&U^k5?4z9Q^S(yhk+ zJqjE1`Fvjk)lws~bDZv=ieTClhm{U4Z(Q>#Y>Q{;p*u3i$LWL1sN&jxTU#Gguz`!diFDnKG2z-M9xtm>`lwN0=-Zk+?ltC3@=m zfU4YGw#d%$V}~@6Lrn98*K4~Ava4doAG~#`PH-+E%(3TT+(vq?OBPj;5v`X$8&n{Og@%vj(Yz+zo#EdMBmcO{eW{APRwDAdrKe$UB&wNh;(tJt4ZmVY|Yo(l$cl&$;cwm9CRlb>{gTa2w1B{#8*-%y-@TLe;aiIOJ`exq5$pm3rI^W3v1=a(;)P z(|nkl!|G0VTO+T81_!i}_C)nOqVE(dv>d9%!w(UI+y zpk8I+C-EnN_LXRs6!Y!S%wl8#v^-qXWeW|0T>G4Y*}b>*4%ZCK%7hlj_#@Rnh#r)F ze=9n6=Xrh9%*d)dqO-Gijwzhh+DjKvR^_q5kZ8!>sc7WTe0ms*cdI0uzA6E_Z(OR= zefZtC?E33<6Z7g$%pIuRPINt?bMNK#nQGcD1WBc*kCq<^0WAja=G1r9$?Wz{cd)OR z!|aaEvNtt=PpmBa>&>}2ZBzMQXtG-3f?cDg?4_Z31ta1{p47~5R5rmCCHM8uW?#Hl@jLC4qvkQ{m_jS-5n)DLMgsHVsI_|B z=&2<27_dYs0Zd3sq`{mREfGiC#)D}IN?@Fv2m_g{!YNq80h Date: Fri, 24 Feb 2023 13:47:25 +0100 Subject: [PATCH 10/17] Implementing table centering --- docs/Tables.md | 14 ++++-- docs/table-with-fixed-column-widths.jpg | Bin 23447 -> 18152 bytes fpdf/table.py | 40 ++++++++++++++++-- test/table/table_with_fixed_width.pdf | Bin 1636 -> 1636 bytes ...ith_an_image.pdf => table_with_images.pdf} | Bin ... table_with_images_and_img_fill_width.pdf} | Bin test/table/test_table.py | 17 +++++++- test/table/test_table_with_image.py | 26 +++++++++--- 8 files changed, 82 insertions(+), 15 deletions(-) rename test/table/{table_with_an_image.pdf => table_with_images.pdf} (100%) rename test/table/{table_with_an_image_and_img_fill_width.pdf => table_with_images_and_img_fill_width.pdf} (100%) diff --git a/docs/Tables.md b/docs/Tables.md index 616aad6d3..9ad8c2a83 100644 --- a/docs/Tables.md +++ b/docs/Tables.md @@ -28,11 +28,14 @@ Result: ![](table-simple.jpg) ## Features +* support cells with content wrapping over several lines * control over column & row sizes (automatically computed by default) -* allow to style table headings, or disable them +* allow to style table headings (top row), or disable them +* control over borders: color, width & where they are drawn * handle splitting a table over page breaks, with headings repeated * control over cell background color - +* control table width & position +* control over text alignment in cells, globally or per row * allow to embed images in cells ## Setting table & column widths @@ -47,16 +50,19 @@ Result: ![](table-with-fixed-column-widths.jpg) +`table.align` can be used to set the table horizontal position relative to the page, +when it's not using the full page width. It's centered by default. + ## Setting text alignment This can be set globally, or on a per-column basis: ```python ... with pdf.table() as table: - table.align = "CENTER" + table.text_align = "CENTER" ... pdf.ln() with pdf.table() as table: - table.align = ("CENTER", "CENTER", "RIGHT", "LEFT") + table.text_align = ("CENTER", "CENTER", "RIGHT", "LEFT") ... ``` Result: diff --git a/docs/table-with-fixed-column-widths.jpg b/docs/table-with-fixed-column-widths.jpg index 240261a96b5b3c4558cdbbe4563b9f16b6db25ea..6634b26fe82fce339d09e93f80f80782a3bed617 100644 GIT binary patch literal 18152 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 DdD;i* literal 23447 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 diff --git a/fpdf/table.py b/fpdf/table.py index 4c5444c47..a164f30fa 100644 --- a/fpdf/table.py +++ b/fpdf/table.py @@ -15,8 +15,11 @@ class Table: def __init__(self, fpdf): self._fpdf = fpdf self._rows = [] - self.align = "LEFT" - "Control text alignment inside cells" + self.align = "CENTER" + """ + Sets the table horizontal position relative to the page, + when it's not using the full page width + """ self.borders_layout = TableBordersLayout.ALL "Control what cell borders are drawn" self.cell_fill_color = None @@ -31,6 +34,8 @@ def __init__(self, fpdf): "Defines the visual style of the top headings row: size, color, emphasis..." self.line_height = 2 * fpdf.font_size "Defines how much vertical space a line of text will occupy" + self.text_align = "JUSTIFY" + "Control text alignment inside cells. Justify by default" self.width = fpdf.epw "Sets the table width" @@ -43,6 +48,22 @@ def row(self): def render(self): "This is an internal method called by `FPDF.table()` once the table is finished" + if self.width > self._fpdf.epw: + raise ValueError( + f"Invalid value provided .width={self.width}: effective page width is {self._fpdf.epw}" + ) + table_align = Align.coerce(self.align) + if table_align == Align.J: + raise ValueError("JUSTIFY is an invalid value for table .align") + prev_l_margin = self._fpdf.l_margin + if table_align == Align.C: + self._fpdf.l_margin = (self._fpdf.w - self.width) / 2 + self._fpdf.x = self._fpdf.l_margin + elif table_align == Align.R: + self._fpdf.l_margin = self._fpdf.w - self.width + self._fpdf.x = self._fpdf.l_margin + elif self._fpdf.x != self._fpdf.l_margin: + self._fpdf.l_margin = self._fpdf.x for i in range(len(self._rows)): with self._fpdf.offset_rendering() as test: self._render_table_row_styled(i) @@ -59,6 +80,8 @@ def render(self): self._render_table_row_styled(i) if prev_fill_color: self._fpdf.set_fill_color(prev_fill_color) + self._fpdf.l_margin = prev_l_margin + self._fpdf.x = self._fpdf.l_margin def get_cell_border(self, i, j): """ @@ -159,14 +182,18 @@ def _render_table_cell( self._fpdf.set_xy(x, y) if not fill: fill = self.cell_fill_color and self.cell_fill_logic(i, j) - align = self.align if isinstance(self.align, (Align, str)) else self.align[j] + text_align = ( + self.text_align + if isinstance(self.text_align, (Align, str)) + else self.text_align[j] + ) lines = self._fpdf.multi_cell( w=col_width, h=row_height, txt=cell.text or "", max_line_height=cell_line_height, border=self.get_cell_border(i, j), - align=align, + align=text_align, new_x="RIGHT", new_y="TOP", fill=fill, @@ -224,6 +251,11 @@ def cell(self, text=None, img=None, img_fill_width=False): img_fill_width (bool): optional, defaults to False. Indicates to render the image using the full width of the current table column. """ + if text and img: + raise NotImplementedError( + "fpdf2 currently does not support inserting text with an image in the same table cell." + "Pull Requests are welcome to implement this 😊" + ) self.cells.append(Cell(text, img, img_fill_width)) diff --git a/test/table/table_with_fixed_width.pdf b/test/table/table_with_fixed_width.pdf index 37d74b0394069663887a4a020405bf4818d635dd..f66f13526e470e2c43d63eeaea3ad76e5ae23300 100644 GIT binary patch delta 683 zcmaFD^Mq$ZAY=XMyxRr>uHS!h>CNW#?ph*uTE#=mt&6F*t|8;jm9?tOlX{iv<0UVB zFjVe}V>RBnqc~yS5!TyxIrFr>y??hcH9lTtvZ{E~*8Mk%t=D&Dgi7m~tX}%aZFAq* zGV2(l(E0{&-B)N(Z71nlX|c--rKfzRDrSa_{a z(`&6IwLc2x{FJsxT=Ky6h-7|DQ<;U|tQi(tH7Z35?PSl*XV|sKSSVYvw0LvHkBy0H zqMws=AKcYtO?a<&{BOsWyF2P9hV$7QpV`9fkg0Ux+T?wu?Vt0Pyg4>?Pu`D(iOXai zyo4J!%?rs)d2_6DPwvNK>KW__ms}EZJ~ZB%_f~Hkd&HCTMyFn-?f-E2kdM~0qfrO6 zqplqId6sYfjSF8o_r(4P1)6cdQ@C-V+?V#Ze#&MhwW|5zbrCZ%*(U&vS)qQlo=tj| z-NfzM_kOUvW$>BB!Si*-{r1Ig@B4cMXv{ob^s8`n?2p*#GedN`w>AiG$?^KW{yyLF zk5`i2FNc4sdsrTucI#n4<{@jT4R*Kw=@$Zxe=lBlD|MM{-xReyiy2quY*_qKxN`p^ zP?)uQ3g5fP@cFCBruKiy@-@9mozpI^2%oKbIG@{irGb{{hk4U(EsU#+`V+gqP&r?s zE^qp_Q_v4y3Hv7x!6skyn6xq*wZtBIWrAr+H7*`xus C!#&mj delta 683 zcmaFD^Mq$ZAY=X6yxRr>E$=J2LW%6&ZN<8pJ2E2fPTLcI| z{pHO21AI&O+p*X_=CsIQ`?92OCS&XerB^>USl8`Z#BHIxVNJ-}s}CL~Tl*^MHLEtK zZ`X=>dp2|bT!C%c_12$GJT$iUHI4~<#j)Y5@BH6)Kk7S`rFzSm*JLcuY|HkNW!$uH zWk|=3siKv)9(9&q;0d2>#gx>{p2fD!awg-v%rpH{7wwy+UlXz1^GNE3ln)*A)^2<5 zZ(Nt;bXogT$-~uFK(qZ{ad3Qft)KnRAkpb^G*I*~NHiEITL0B|>amt(;ZI(6so!%n zj`0PlG_CKgHr^vAu%KY7ex&KItX&^s*QyDYZAf8oSiP-jf1UBW<%b(2ee+L#ZhfC+ zdbVNJm4}kNyY9_?*laNC-lXT;^RH#iV)R{k*jUO$R5#6JuhRK&aG=cssmrpHRVy>! zliPeF#GiHXHz%s|#9zyt1r!wwcs1MZP1XPE zQ~4)_+xlOdoV{T5ltbgI?^1^;>(-nQ7W3cJoR%@Oh-J#JS;h;M@BFjh{qvIY<|WL@ vOit#e#%`9*hQ^j=MyBRYW=@W7MwUi~Ce8*HW+uj#u10n?gj7uSWRnH}mP0sp diff --git a/test/table/table_with_an_image.pdf b/test/table/table_with_images.pdf similarity index 100% rename from test/table/table_with_an_image.pdf rename to test/table/table_with_images.pdf diff --git a/test/table/table_with_an_image_and_img_fill_width.pdf b/test/table/table_with_images_and_img_fill_width.pdf similarity index 100% rename from test/table/table_with_an_image_and_img_fill_width.pdf rename to test/table/table_with_images_and_img_fill_width.pdf diff --git a/test/table/test_table.py b/test/table/test_table.py index 8b8db4bdf..80dabc388 100644 --- a/test/table/test_table.py +++ b/test/table/test_table.py @@ -132,6 +132,19 @@ def test_table_with_fixed_width(tmp_path): assert_pdf_equal(pdf, HERE / "table_with_fixed_width.pdf", tmp_path) +def test_table_with_invalid_width(): + pdf = FPDF() + pdf.add_page() + pdf.set_font("Times", size=16) + with pytest.raises(ValueError): + with pdf.table() as table: + table.width = 200 + for data_row in TABLE_DATA: + with table.row() as row: + for datum in data_row: + row.cell(datum) + + def test_table_without_headings(tmp_path): pdf = FPDF() pdf.add_page() @@ -267,14 +280,14 @@ def test_table_align(tmp_path): pdf.add_page() pdf.set_font("Times", size=16) with pdf.table() as table: - table.align = "CENTER" + table.text_align = "CENTER" for data_row in TABLE_DATA: with table.row() as row: for datum in data_row: row.cell(datum) pdf.ln() with pdf.table() as table: - table.align = ("CENTER", "CENTER", "RIGHT", "LEFT") + table.text_align = ("CENTER", "CENTER", "RIGHT", "LEFT") for data_row in TABLE_DATA: with table.row() as row: for datum in data_row: diff --git a/test/table/test_table_with_image.py b/test/table/test_table_with_image.py index 9c461dcc1..cba902e32 100644 --- a/test/table/test_table_with_image.py +++ b/test/table/test_table_with_image.py @@ -1,9 +1,10 @@ from pathlib import Path +import pytest + from fpdf import FPDF from test.conftest import assert_pdf_equal, LOREM_IPSUM - HERE = Path(__file__).resolve().parent IMG_DIR = HERE.parent / "image" @@ -38,7 +39,7 @@ ) -def test_table_with_an_image(tmp_path): +def test_table_with_images(tmp_path): pdf = FPDF() pdf.add_page() pdf.set_font("Times", size=16) @@ -50,10 +51,10 @@ def test_table_with_an_image(tmp_path): row.cell(img=datum) else: row.cell(datum) - assert_pdf_equal(pdf, HERE / "table_with_an_image.pdf", tmp_path) + assert_pdf_equal(pdf, HERE / "table_with_images.pdf", tmp_path) -def test_table_with_an_image_and_img_fill_width(tmp_path): +def test_table_with_images_and_img_fill_width(tmp_path): pdf = FPDF() pdf.add_page() pdf.set_font("Times", size=16) @@ -67,7 +68,7 @@ def test_table_with_an_image_and_img_fill_width(tmp_path): row.cell(datum) assert_pdf_equal( pdf, - HERE / "table_with_an_image_and_img_fill_width.pdf", + HERE / "table_with_images_and_img_fill_width.pdf", tmp_path, ) @@ -85,3 +86,18 @@ def test_table_with_multiline_cells_and_images(tmp_path): else: row.cell(datum) assert_pdf_equal(pdf, HERE / "table_with_multiline_cells_and_images.pdf", tmp_path) + + +def test_table_with_images_and_text(): + pdf = FPDF() + pdf.add_page() + pdf.set_font("Times", size=16) + with pytest.raises(NotImplementedError): + with pdf.table() as table: + for i, data_row in enumerate(TABLE_DATA): + with table.row() as row: + for j, datum in enumerate(data_row): + if j == 2 and i > 0: + row.cell(datum.name, img=datum) + else: + row.cell(datum) From fd8451d21eaf2f1ebc34939c992edd21ab79a1e0 Mon Sep 17 00:00:00 2001 From: Lucas Cimon <925560+Lucas-C@users.noreply.github.com> Date: Fri, 24 Feb 2023 13:56:40 +0100 Subject: [PATCH 11/17] Improving docstrings --- docs/Maths.md | 28 +++++++++++-------------- docs/Tables.md | 4 ++++ docs/table-pandas.png | Bin 12279 -> 23645 bytes fpdf/enums.py | 7 +++---- fpdf/fpdf.py | 47 ++++++++++++++---------------------------- fpdf/image_parsing.py | 2 +- fpdf/table.py | 21 ++++++++++++------- 7 files changed, 50 insertions(+), 59 deletions(-) mode change 100644 => 100755 docs/table-pandas.png diff --git a/docs/Maths.md b/docs/Maths.md index 831a65527..2c6a67eb0 100644 --- a/docs/Maths.md +++ b/docs/Maths.md @@ -128,25 +128,21 @@ columns = [list(df)] # Get list of dataframe columns rows = df.values.tolist() # Get list of dataframe rows data = columns + rows # Combine columns and rows in one list -# Start pdf creating pdf = FPDF() pdf.add_page() pdf.set_font("Times", size=10) -line_height = pdf.font_size * 2.5 -col_width = pdf.epw / 4 # distribute content evenly - -for row in data: - for datum in row: - pdf.multi_cell( - col_width, - line_height, - datum, - border=1, - new_y="TOP", - max_line_height=pdf.font_size, - ) - pdf.ln(line_height) -pdf.output("table_with_cells.pdf") +with pdf.table() as table: + table.borders_layout = "MINIMAL" + table.cell_fill_color = 200 # grey + table.cell_fill_logic = lambda i, j: i % 2 + table.line_height = pdf.font_size * 2.5 + table.text_align = "CENTER" + table.width= 160 + for data_row in data: + with table.row() as row: + for datum in data_row: + row.cell(datum) +pdf.output("table_from_pandas.pdf") ``` Result: diff --git a/docs/Tables.md b/docs/Tables.md index 9ad8c2a83..f60cad82e 100644 --- a/docs/Tables.md +++ b/docs/Tables.md @@ -190,6 +190,10 @@ Result: ![](table_with_images_and_img_fill_width.jpg) +## Table from pandas DataFrame + +_cf._ https://pyfpdf.github.io/fpdf2/Maths.html#using-pandas + ## Using write_html Tables can also be defined in HTML using [`FPDF.write_html`](HTML.md). diff --git a/docs/table-pandas.png b/docs/table-pandas.png old mode 100644 new mode 100755 index ee350d41ee365ffca045ec23a41130c2750ac555..d0da1d064a17eef97bbe862179a7af4e56314483 GIT binary patch literal 23645 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 literal 12279 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 diff --git a/fpdf/enums.py b/fpdf/enums.py index 47b21bf2f..fde29ce4a 100644 --- a/fpdf/enums.py +++ b/fpdf/enums.py @@ -246,6 +246,9 @@ class TableBordersLayout(CoerciveEnum): ALL = intern("ALL") "Draw all table cells borders" + NONE = intern("NONE") + "Draw zero cells border" + INTERNAL = intern("INTERNAL") "Draw only internal horizontal & vertical borders" @@ -794,7 +797,3 @@ class EncryptionMethod(Enum): NO_ENCRYPTION = 0 RC4 = 1 AES_128 = 2 - - -# This enum is only used internally: -__pdoc__ = {"DocumentState": False} diff --git a/fpdf/fpdf.py b/fpdf/fpdf.py index 77d88e1d6..e8bb1953c 100644 --- a/fpdf/fpdf.py +++ b/fpdf/fpdf.py @@ -946,7 +946,7 @@ def footer(self): """ Footer to be implemented in your own inherited class. - This is automatically called by `FPDF.add_page()` and `FPDF.close()` + This is automatically called by `FPDF.add_page()` and `FPDF.output()` and should not be called directly by the user application. The default implementation performs nothing: you have to override this method in a subclass to implement your own rendering logic. @@ -968,16 +968,7 @@ def set_draw_color(self, r, g=-1, b=-1): g (int): green component (between 0 and 255) b (int): blue component (between 0 and 255) """ - if isinstance(r, (drawing.DeviceGray, drawing.DeviceRGB)): - # Note: in this case, r is also a Sequence - self.draw_color = r - else: - if isinstance(r, Sequence): - r, g, b = r - if (r, g, b) == (0, 0, 0) or g == -1: - self.draw_color = drawing.DeviceGray(r / 255) - else: - self.draw_color = drawing.DeviceRGB(r / 255, g / 255, b / 255) + self.draw_color = _convert_to_drawing_color(r, g, b) if self.page > 0: self._out(self.draw_color.serialize().upper()) @@ -993,16 +984,7 @@ def set_fill_color(self, r, g=-1, b=-1): g (int): green component (between 0 and 255) b (int): blue component (between 0 and 255) """ - if isinstance(r, (drawing.DeviceGray, drawing.DeviceRGB)): - # Note: in this case, r is also a Sequence - self.fill_color = r - else: - if isinstance(r, Sequence): - r, g, b = r - if (r, g, b) == (0, 0, 0) or g == -1: - self.fill_color = drawing.DeviceGray(r / 255) - else: - self.fill_color = drawing.DeviceRGB(r / 255, g / 255, b / 255) + self.fill_color = _convert_to_drawing_color(r, g, b) if self.page > 0: self._out(self.fill_color.serialize().lower()) @@ -1018,16 +1000,7 @@ def set_text_color(self, r, g=-1, b=-1): g (int): green component (between 0 and 255) b (int): blue component (between 0 and 255) """ - if isinstance(r, (drawing.DeviceGray, drawing.DeviceRGB)): - # Note: in this case, r is also a Sequence - self.text_color = r - else: - if isinstance(r, Sequence): - r, g, b = r - if (r, g, b) == (0, 0, 0) or g == -1: - self.text_color = drawing.DeviceGray(r / 255) - else: - self.text_color = drawing.DeviceRGB(r / 255, g / 255, b / 255) + self.text_color = _convert_to_drawing_color(r, g, b) def get_string_width(self, s, normalized=False, markdown=False): """ @@ -4713,6 +4686,7 @@ def use_font_style(self, font_style: FontStyle): def table(self): """ Inserts a table, that can be built using the `fpdf.table.Table` object yield. + Detailed usage documentation: https://pyfpdf.github.io/fpdf2/Tables.html """ table = Table(self) yield table @@ -4768,6 +4742,17 @@ def output( return self.buffer +def _convert_to_drawing_color(r, g, b): + if isinstance(r, (drawing.DeviceGray, drawing.DeviceRGB)): + # Note: in this case, r is also a Sequence + return r + if isinstance(r, Sequence): + r, g, b = r + if (r, g, b) == (0, 0, 0) or g == -1: + return drawing.DeviceGray(r / 255) + return drawing.DeviceRGB(r / 255, g / 255, b / 255) + + def _is_svg(bytes): return bytes.startswith(b" self._fpdf.epw: raise ValueError( f"Invalid value provided .width={self.width}: effective page width is {self._fpdf.epw}" @@ -87,11 +90,13 @@ def get_cell_border(self, i, j): """ Defines which cell borders should be drawn. Returns a string containing some or all of the letters L/R/T/B, - to be passed to `FPDF.multi_cell()`. + to be passed to `fpdf.FPDF.multi_cell()`. Can be overriden to customize this logic """ if self.borders_layout == TableBordersLayout.ALL.value: return 1 + if self.borders_layout == TableBordersLayout.NONE.value: + return 0 columns_count = max(len(row.cells) for row in self._rows) rows_count = len(self._rows) border = list("LRTB") @@ -190,7 +195,7 @@ def _render_table_cell( lines = self._fpdf.multi_cell( w=col_width, h=row_height, - txt=cell.text or "", + txt=cell.text, max_line_height=cell_line_height, border=self.get_cell_border(i, j), align=text_align, @@ -236,15 +241,17 @@ def _get_lines_heights_per_cell(self, i) -> List[List[int]]: class Row: - "Object that FPDF.row() yields, used to build a row in a table" + "Object that `Table.row()` yields, used to build a row in a table" def __init__(self): self.cells = [] - def cell(self, text=None, img=None, img_fill_width=False): + def cell(self, text="", img=None, img_fill_width=False): """ + Adds a cell to the row. + Args: - text (str): optional. String content, can contain several lines. + text (str): string content, can contain several lines. In that case, the row height will grow proportionally. img: optional. Either a string representing a file path to an image, an URL to an image, an io.BytesIO, or a instance of `PIL.Image.Image`. From 8c8aba20ec226c60d4b56fee55f3b4bb2e7d788c Mon Sep 17 00:00:00 2001 From: Lucas Cimon <925560+Lucas-C@users.noreply.github.com> Date: Fri, 24 Feb 2023 14:57:50 +0100 Subject: [PATCH 12/17] Tutorial update --- .../continuous-integration-workflow.yml | 3 +- docs/Tables.md | 2 + docs/Tutorial-de.md | 18 +- docs/Tutorial-es.md | 30 +- docs/Tutorial-fr.md | 17 +- docs/Tutorial-gr.md | 13 +- docs/Tutorial-he.md | 16 +- docs/Tutorial-it.md | 13 +- docs/Tutorial-pt.md | 16 +- docs/Tutorial-ru.md | 14 +- docs/Tutorial-zh.md | 23 +- ...77\340\244\202\340\244\246\340\245\200.md" | 20 +- docs/Tutorial.md | 36 +- docs/table-pandas.png | Bin fpdf/enums.py | 3 + fpdf/table.py | 5 + tutorial/tuto1.htm | 91 ----- tutorial/tuto2.htm | 50 --- tutorial/tuto3.htm | 43 --- tutorial/tuto4.htm | 34 -- tutorial/tuto5.htm | 43 --- tutorial/tuto5.pdf | Bin 8069 -> 7482 bytes tutorial/tuto5.py | 95 ++---- tutorial/tuto6.htm | 68 ---- tutorial/tuto7.htm | 315 ------------------ 25 files changed, 99 insertions(+), 869 deletions(-) mode change 100755 => 100644 docs/table-pandas.png delete mode 100644 tutorial/tuto1.htm delete mode 100644 tutorial/tuto2.htm delete mode 100644 tutorial/tuto3.htm delete mode 100644 tutorial/tuto4.htm delete mode 100644 tutorial/tuto5.htm delete mode 100644 tutorial/tuto6.htm delete mode 100644 tutorial/tuto7.htm diff --git a/.github/workflows/continuous-integration-workflow.yml b/.github/workflows/continuous-integration-workflow.yml index c4e6c53fb..f56ddfd61 100644 --- a/.github/workflows/continuous-integration-workflow.yml +++ b/.github/workflows/continuous-integration-workflow.yml @@ -75,7 +75,8 @@ jobs: sed -i "s/author:.*/author: v$(python setup.py -V 2>/dev/null)/" mkdocs.yml cp tutorial/notebook.ipynb docs/ mkdocs build - pdoc --html -o public/ fpdf + pdoc --html -o public/ fpdf --config "git_link_template='https://github +.com/PyFPDF/fpdf2/blob/{commit}/{path}#L{start_line}-L{end_line}'" cd contributors/ && PYTHONUNBUFFERED=1 ./build_contributors_html_page.py PyFPDF/fpdf2 cp -t ../public/ contributors.html contributors-map-small.png - name: Deploy documentation 🚀 diff --git a/docs/Tables.md b/docs/Tables.md index f60cad82e..929fb7320 100644 --- a/docs/Tables.md +++ b/docs/Tables.md @@ -154,6 +154,8 @@ Result: ![](table_with_single_top_line_layout.jpg) +All the possible layout values are described there: [`TableBordersLayout`](https://pyfpdf.github.io/fpdf2/fpdf/enums.html#fpdf.enums.TableBordersLayout). + ## Insert images ```python TABLE_DATA = ( diff --git a/docs/Tutorial-de.md b/docs/Tutorial-de.md index 56d4d3c32..0d0e0388a 100644 --- a/docs/Tutorial-de.md +++ b/docs/Tutorial-de.md @@ -144,10 +144,6 @@ Sobald det Text der dritten den oben beschriebenen Abstand zum Seitenende erreic ## Lektion 5 - Tabellen erstellen ## -In dieser Lektion zeigen wir, wie man auf einfache Weise Tabellen erstellen kann. - -Der Code wird drei verschiedene Tabellen erstellen, um zu zeigen, welche Effekte wir mit einigen einfachen Anpassungen erzielen können. - ```python {% include "../tutorial/tuto5.py" %} ``` @@ -155,18 +151,12 @@ Der Code wird drei verschiedene Tabellen erstellen, um zu zeigen, welche Effekte [Erzeugtes PDF](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/tuto5.pdf) - [Länder](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/countries.txt) -Da eine Tabelle lediglich eine Sammlung von Zellen darstellt, ist es naheliegend, eine Tabelle aus den bereits bekannten Zellen aufzubauen. - -Das erste Beispiel wird auf die einfachste Art und Weise realisiert. Einfach gerahmte Zellen, die alle die gleiche Größe haben und linksbündig ausgerichtet sind. Das Ergebnis ist rudimentär, aber sehr schnell zu erzielen. +This section has changed a lot and requires a new translation: https://github.com/PyFPDF/fpdf2/issues/267 -Die zweite Tabelle bringt einige Verbesserungen: Jede Spalte hat ihre eigene Breite, - die Überschriften sind zentriert und die Zahlen rechtsbündig ausgerichtet. Außerdem wurden die horizontalen Linien - entfernt. Dies geschieht mit Hilfe des Randparameters der Methode `cell()`, der angibt, welche Seiten der Zelle gezeichnet werden müssen. - Im Beispiel wählen wir die linke (L) und die rechte (R) Seite. Jetzt muss nur noch das Problem der horizontalen Linie - zum Abschluss der Tabelle gelöst werden. Es gibt zwei Möglichkeiten, es zu lösen: In der Schleife prüfen, ob wir uns in der letzten Zeile befinden und dann "LRB" als Rahmenparameter übergeben oder, wie hier geschehen, eine abschließende Zelle separat nach dem Durchlaufen der Schleife einfügen. +English versions: -Die dritte Tabelle der zweiten sehr ähnlich, verwendet aber zusätzlich Farben. Füllung, Text und - Linienfarben werden einfach mit den entsprechenden Methoden gesetzt. Eine wechselnde Färbung der Zeilen wird durch die abwechselnde Verwendung transparenter und gefüllter Zellen erreicht. +* [Tuto 5 - Creating Tables](https://pyfpdf.github.io/fpdf2/Tutorial.html#tuto-5-creating-tables) +* [Documentation on tables](https://pyfpdf.github.io/fpdf2/Tables.html) ## Lektion 6 - Links erstellen und Textstile mischen ## diff --git a/docs/Tutorial-es.md b/docs/Tutorial-es.md index 7a17f1efc..20fc0c460 100644 --- a/docs/Tutorial-es.md +++ b/docs/Tutorial-es.md @@ -169,11 +169,6 @@ volverá a la primera columna, desencadenando un salto de página. ## Tutorial 5 - Creando tablas ## -Este tutorial explicará cómo crear tablas fácilmente. - -El código creará tres tablas diferentes para explicar lo que -puede lograrse con algunos cambios sencillos. - ```python {% include "../tutorial/tuto5.py" %} ``` @@ -181,25 +176,12 @@ puede lograrse con algunos cambios sencillos. [PDF resultante](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/tuto5.pdf) - [Archivo de texto con países](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/countries.txt) -Dado que una tabla es solo una colección de celdas, es natural construir una -a partir de ellas. - -El primer ejemplo se logra de la forma más básica posible: simples celdas -enmarcadas, todas del mismo tamaño y alineadas a la izquierda. El resultado es rudimentario pero -muy rápido de obtener. - -La segunda tabla incluye algunas mejoras: cada columna tiene su propio ancho, -los títulos están centrados y las figuras alineadas a la derecha. Es más, las líneas horizontales han -sido removidas. Esto es hecho por medio del parámetro `border` del método -`Cell()`, el cual especifica qué lados de la celda deben dibujarse. Aquí queremos -el izquierdo (`L`) y el derecho (`R`). Ahora solo queda el problema de la línea horizontal -para terminar la tabla. Hay dos posibilidades para resolverlo: encontrar -la última línea en el ciclo, en cuyo caso usamos LRB para el parámetro -`border`; o, como se hizo aquí, agregar la línea una vez el ciclo ha terminado. - -La tercera tabla es similar a la segunda, pero usa colores. Los colores de relleno, -texto y línea son especificados de manera simple. Un coloreado alternante para las filas es obtenido -usando de forma alternada celdas transparentes y rellenas. +This section has changed a lot and requires a new translation: https://github.com/PyFPDF/fpdf2/issues/267 + +English versions: + +* [Tuto 5 - Creating Tables](https://pyfpdf.github.io/fpdf2/Tutorial.html#tuto-5-creating-tables) +* [Documentation on tables](https://pyfpdf.github.io/fpdf2/Tables.html) ## Tutorial 6 - Creando enlaces y combinando estilos de texto ## diff --git a/docs/Tutorial-fr.md b/docs/Tutorial-fr.md index c6687a679..f400d46f9 100644 --- a/docs/Tutorial-fr.md +++ b/docs/Tutorial-fr.md @@ -110,24 +110,21 @@ En utilisant la méthode [accept_page_break](fpdf/fpdf.html#fpdf.fpdf.FPDF.accep Une fois que la limite inférieure de la troisième colonne est atteinte, la méthode [accept_page_break](fpdf/fpdf.html#fpdf.fpdf.FPDF.accept_page_break) sera réinitialisée et retournera à la première colonne. Cela déclenchera un saut de page. ## Tuto 5 - Créer des tables ## -Ce tutoriel explique comment créer facilement des tableaux. - -Le code créera trois tableaux différents pour expliquer ce qui peut être réalisé avec quelques modifications. +Ce tutoriel explique comment créer facilement des tableaux. Deux tableaux différents sont générés, pour illustrer ce qui peut être produit avec de très simples changements. ```python {% include "../tutorial/tuto5.py" %} ``` [PDF généré](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/tuto5.pdf) - -[Liste de pays](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/countries.txt) - -Comme un tableau n'est qu'une collection de cellules, il est naturel d'en construire un à partir de celles-ci. - -Le premier exemple est réalisé de la manière la plus basique qui soit : de simples cellules encadrées, toutes de même taille et alignées à gauche. Le résultat est rudimentaire mais très rapide à obtenir. +[Données CSV des pays](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/countries.txt) -Le deuxième tableau apporte quelques améliorations : chaque colonne possède sa propre largeur, les titres sont centrés et les chiffres alignés à droite. De plus, les lignes horizontales ont été supprimées. C'est fait grâce au paramètre `border` de la méthode [`.cell()`](fpdf/fpdf.html#fpdf.fpdf.FPDF.cell) qui spécifie quels côtés de la cellule doivent être dessinés. Ici, nous voulons les côtés gauche (`L`) et droit (`R`). Il ne reste plus que le problème de la ligne horizontale pour terminer le tableau. Il y a deux possibilités pour le résoudre : vérifier la dernière ligne dans la boucle (dans ce cas nous utilisons `LRB` pour le paramètre de bordure) ou, comme fait ici, ajouter la ligne une fois la boucle terminée. +Le premier exemple est généré de la façon la plus simple possible, en fournissant des données à [`FPDF.table()`](https://pyfpdf.github.io/fpdf2/Tables.html). Le résultat est rudimentaire, mais très rapide à obtenir. -Le troisième tableau est similaire au deuxième mais utilise des couleurs. Les couleurs de remplissage, de texte et de ligne sont simplement spécifiées. Une coloration alternative pour les lignes est obtenue en utilisant des cellules alternativement transparentes et remplies. +Le second tableau introduit quelques améliorations : couleurs, largeur réduite de la table, moindre hauteur des lignes de texte, titres centrés, colonnes avec des largeurs propres, nombres alignés à droite... +De plus, les lignes horizontales ont été supprimées. +Cela grâce à la sélection d'un `table.borders_layout` parmi les valeurs disponibles : + [`TableBordersLayout`](https://pyfpdf.github.io/fpdf2/fpdf/enums.html#fpdf.enums.TableBordersLayout). ## Tuto 6 - Créer des liens et mélanger différents styles de textes ## Ce tutoriel explique plusieurs façons d'insérer des liens à l'intérieur d'un document pdf, ainsi que l'ajout de liens vers des sources externes. diff --git a/docs/Tutorial-gr.md b/docs/Tutorial-gr.md index c80460a09..f25e80198 100644 --- a/docs/Tutorial-gr.md +++ b/docs/Tutorial-gr.md @@ -109,10 +109,6 @@ pdf.cell(60, 10, 'Powered by FPDF.', new_x="LMARGIN", new_y="NEXT", align='C') ## Μάθημα 5 - Δημιουργία Πινάκων ## -Σε αυτό το μάθημα θα εξηγήσουμε πως να δημιουργούμε εύκολα πίνακες. - -Ο κώδικας θα δημιουργήσει τρεις διαφορετικούς πίνακες έτσι ώστε να παρουσιάσουμε τι μπορεί να επιτευχθεί με μερικές απλές προσαρμογές. - ```python {% include "../tutorial/tuto5.py" %} ``` @@ -120,13 +116,12 @@ pdf.cell(60, 10, 'Powered by FPDF.', new_x="LMARGIN", new_y="NEXT", align='C') [Παραγόμενο PDF](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/tuto5.pdf) - [Κείμενο Χωρών](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/countries.txt) -Εφόσον ένας πίνακας αποτελεί μία συλλογή από κελιά, είναι φυσικό να τον κατασκευάσουμε από αυτά. - -Το πρώτο παράδειγμα επιτυγχάνεται με τον πιο απλό τρόπο: πλαισιωμένα κελιά, ίδιου μεγέθους και αριστερά στοιχισμένα. Το αποτέλεσμα είναι υποτυπώδες αλλά αποκτάται αρκετά εύκολα. +This section has changed a lot and requires a new translation: https://github.com/PyFPDF/fpdf2/issues/267 -Ο δεύτερος πίνακας παρουσιάζει ορισμένες βελτιώσεις: κάθε στήλη έχει το δικό της πλάτος, οι τίτλοι είναι κεντραρισμένοι και οι αριθμοί δεξιά στοιχισμένοι. Επιπλέον, οριζόντιες γραμμές έχουν αφαιρεθεί. Αυτό επιτυγχάνεται με την παράμετρο border της μεθόδου Cell(), η οποία ορίζει ποιες πλευρές του κελιού χρειάζεται να σχεδιαστούν. Στη συγκεκριμένη περίπτωση θέλουμε τις αριστερές (L) και τις δεξιές (R). Τώρα απομένει μόνο το πρόβλημα των οριζόντιων γραμμών. Μπορούμε να το λύσουμε με δύο τρόπους: να ελέγξουμε την τελευταία γραμμή στο βρόχο επαναλήψεων, οπότε θα χρησιμοποιήσουμε LRB για την παράμετρο border ή, όπως πράξαμε εδώ, να προσθέσουμε την γραμμή όταν τελειώσει ο βρόχος επαναλήψεων. +English versions: -Ο τρίτος πίνακας είναι παρόμοιος με τον δεύτερο αλλά χρησιμοποιεί χρώματα. Τα χρώματα του γεμίσματος, του κειμένου και των γραμμών ορίζονται ξεχωριστά. Ο εναλλασσόμενος χρωματισμός των γραμμών του πίνακα επιτυγχάνεται με τη χρήση διαφανών και γεμισμένων κελιών. +* [Tuto 5 - Creating Tables](https://pyfpdf.github.io/fpdf2/Tutorial.html#tuto-5-creating-tables) +* [Documentation on tables](https://pyfpdf.github.io/fpdf2/Tables.html) ## Μάθημα 6 - Δημιουργία συνδέσμων και μίξη στυλ κειμένου ## diff --git a/docs/Tutorial-he.md b/docs/Tutorial-he.md index 59d6e7308..f0476ec94 100644 --- a/docs/Tutorial-he.md +++ b/docs/Tutorial-he.md @@ -114,24 +114,16 @@ pdf.cell(60, 10, 'Powered by FPDF.', new_x="LMARGIN", new_y="NEXT", align='C') ## 5 - יצירת טבלאות ## -דוגמא זו מסבירה איך ליצור טבלאות בקלות. - -הקוד ייצור שלוש טבלאות שונות על מנת להראות מה ניתן להשיג עם שינוים קלים. - ```python {% include "../tutorial/tuto5.py" %} ``` -[תוצר](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/tuto5.pdf) - -[טקסט מתמשך](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/countries.txt) - -מאחר וטבלה היא בסה"כ אוסף של תאים, טבעי שכך נבנה טבלאות. - -הדוגמא הראשונה נוצרת באופן הבסיסי ביותר שאפשר:תאים ממוסגרים, מיושרים לשמאל ובגדלים שווים. התוצאה היא בסיסית אבל קלה מאוד להשגה. +This section has changed a lot and requires a new translation: https://github.com/PyFPDF/fpdf2/issues/267 -הטבלה השניה מציגה כמה שיפורים: לכל עמודה יש רוחב משלה, כותרות ממורכזות ותמונות מיושרות לימין. הוסרו קווים אופקיים. זה נעשה על ידי תכונות הגבול של המתודה Cell(), שמציינת איזה גבולות של התא להדפיס. כאן אנחנו רוצים את הגבול השמאלי (L) והימני (R). כעת נותרה הבעיה של הקווים האופקיים. ישנן שתי אפשרויות לפתור בעיה זו: לבדוק את הקו האחרון בלולאה, במקרה זה נשתמש בLRB עבור פרמטר הגבול; או לחלופין, כמו שעשינו כאן, להוסיף את הקו בסוף הלולאה. +English versions: -הטבלה השלישית דומה לשניה אבל עושה שימוש בצבעים. צבעי המילוי, טקסט והקווים מצויינים במפורש. שינוי הצבעים נעשה על ידי שימוש בתאים שקופים ומלאים לסירוגין. +* [Tuto 5 - Creating Tables](https://pyfpdf.github.io/fpdf2/Tutorial.html#tuto-5-creating-tables) +* [Documentation on tables](https://pyfpdf.github.io/fpdf2/Tables.html) ## 6 - יצירת קישורים וערבוב סגנונות טקסט ## diff --git a/docs/Tutorial-it.md b/docs/Tutorial-it.md index f19d0f6f9..bde3bfb9c 100644 --- a/docs/Tutorial-it.md +++ b/docs/Tutorial-it.md @@ -130,10 +130,6 @@ Una volta che il limite inferiore della terza colonna sarà raggiunto, [accept_p ## Tuto 5 - Creare tabelle ## -Questo tutoria spiegherà come creare facilmente tabelle. - -Creeremo tre diverse tabelle per spiegare cosa si può ottenere con piccolo cambiamenti. - ```python {% include "../tutorial/tuto5.py" %} ``` @@ -141,13 +137,12 @@ Creeremo tre diverse tabelle per spiegare cosa si può ottenere con piccolo camb [Risultato PDF](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/tuto5.pdf) - [Testo delle nazioni](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/countries.txt) -Dato che una tabella è un insieme di celle, viene natura crearne una partendo da loro. - -Il primo esempio è la via più elementare: semplici celle con cornice, tutte della stessa dimensione e allineate a sinistra. Il risultato è rudimentale ma molto veloce da ottenere. +This section has changed a lot and requires a new translation: https://github.com/PyFPDF/fpdf2/issues/267 -La seconda tabella contiene dei miglioramenti: ogni colonna ha la propria larghezza, i titoli sono centrati e i numeri allineati a destra. Inoltre, le linee orizzontale sono state rimosse. Questo è stato possibile grazie al parametro border del metodo Cell(), che specifica quali lati della cella saranno disegnati. In questo caso vogliamo il sinistro (L) e il destro (R). Rimane il problema delle linee orizzontali. Ci sono due possibilità per risolverlo: controllare di essere nell'ultimo giro del ciclo, nel qual caso utilizziamo LRB per il parametro border; oppure, come fatto in questo esempio, aggiungiamo una linea dopo il completamento del ciclo. +English versions: -La terza tabella è molto simile alla seconda, ma utilizza i colori. Il colore di sfondo, testo e linee sono semplicemente specificati. L'alternanza dei colori delle righe è ottenuta utilizzando celle con sfondo colorato e trasparente alternativamente. +* [Tuto 5 - Creating Tables](https://pyfpdf.github.io/fpdf2/Tutorial.html#tuto-5-creating-tables) +* [Documentation on tables](https://pyfpdf.github.io/fpdf2/Tables.html) ## Tuto 6 - Creare link e mescolare stili di testo ## diff --git a/docs/Tutorial-pt.md b/docs/Tutorial-pt.md index 6064beb42..6e66b2b0c 100644 --- a/docs/Tutorial-pt.md +++ b/docs/Tutorial-pt.md @@ -125,10 +125,6 @@ Quando o limite inferior da terceira coluna é alcançado, o método [accept_pag ## Tuto 5 - Criar Tabelas ## -Este tutorial irá explicar como criar tabelas facilmente. - -O código seguinte cria três tabelas diferentes para explicar o que pode ser alcançado com alguns ajustes simples. - ```python {% include "../tutorial/tuto5.py"%} ``` @@ -136,16 +132,12 @@ O código seguinte cria três tabelas diferentes para explicar o que pode ser al [PDF resultante](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/tuto5.pdf) - [Texto dos países](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/countries.txt) -Uma vez que uma tabela é apenas uma coleção de células, é natural construir uma -a partir delas. - -O primeiro exemplo é obtido da maneira mais básica possível: moldura simples - células, todas do mesmo tamanho e alinhadas à esquerda. O resultado é rudimentar, mas - muito rápido de obter. +This section has changed a lot and requires a new translation: https://github.com/PyFPDF/fpdf2/issues/267 -A segunda tabela traz algumas melhorias: cada coluna tem sua largura própria, os títulos estão centrados e as figuras alinhadas à direita. Além disso, as linhas horizontais foram removidas. Isto é feito por meio do parâmetro border do método Cell(), que especifica quais lados da célula devem ser desenhados. Aqui nós queremos os esquerdo (L) e direito (R). Agora apenas o problema da linha horizontal para terminar a mesa permanece. Existem duas possibilidades para resolvê-lo: verificar para a última linha do loop, caso este em que usamos LRB para o parâmetro da borda; ou, como foi feito aqui, adicione a linha assim que o loop terminar. +English versions: -A terceira tabela é semelhante à segunda, mas usa cores. Preenchimento, texto e as cores das linhas são simplesmente especificadas. Coloração alternativa para linhas é obtida usando células alternativamente transparentes e preenchidas. +* [Tuto 5 - Creating Tables](https://pyfpdf.github.io/fpdf2/Tutorial.html#tuto-5-creating-tables) +* [Documentation on tables](https://pyfpdf.github.io/fpdf2/Tables.html) ## Tuto 6 - Criar links e misturar estilos de texto ## diff --git a/docs/Tutorial-ru.md b/docs/Tutorial-ru.md index 1712f0f6c..0601a56d2 100644 --- a/docs/Tutorial-ru.md +++ b/docs/Tutorial-ru.md @@ -105,24 +105,18 @@ pdf.cell(60, 10, 'Powered by FPDF.', new_x="LMARGIN", new_y="NEXT", align='C') ## Руковдство 5 - Создание таблиц ## -В этом уроке мы расскажем, как можно с легкостью создавать таблицы. - -Код создаст три различные таблицы, чтобы объяснить, чего можно достичь с помощью нескольких простых настроек. - ```python {% include "../tutorial/tuto5.py" %} ``` [Итоговый PDF](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/tuto5.pdf) - [Список стран](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/countries.txt) +This section has changed a lot and requires a new translation: https://github.com/PyFPDF/fpdf2/issues/267 -Поскольку таблица - это просто набор ячеек, естественно построить таблицу из них. - -Первый пример достигается самым простым способом: простые ячейки в рамке, все одинакового размера и выровненные по левому краю. Результат элементарен, но достигается очень быстро. - -Вторая таблица имеет некоторые улучшения: каждый столбец имеет свою ширину, заголовки выровнены по центру, а цифры - по правому краю. Более того, горизонтальные линии были удалены. Это сделано с помощью параметра border метода Cell(), который указывает, какие стороны ячейки должны быть нарисованы. Здесь нам нужны левая (L) и правая (R). Теперь остается только проблема горизонтальной линии для завершения таблицы. Есть две возможности решить ее: проверить наличие последней строки в цикле, в этом случае мы используем LRB для параметра границы; или, как сделано здесь, добавить линию после завершения цикла. +English versions: -Третья таблица похожа на вторую, но в ней используются цвета. Цвета заливки, текста и линий просто задаются. Альтернативная окраска строк достигается путем использования поочередно прозрачных и заполненных ячеек. +* [Tuto 5 - Creating Tables](https://pyfpdf.github.io/fpdf2/Tutorial.html#tuto-5-creating-tables) +* [Documentation on tables](https://pyfpdf.github.io/fpdf2/Tables.html) ## Руководство 6 - Создание ссылок и смешивание стилей текста ## diff --git a/docs/Tutorial-zh.md b/docs/Tutorial-zh.md index 55985fad1..fd85d992f 100644 --- a/docs/Tutorial-zh.md +++ b/docs/Tutorial-zh.md @@ -177,10 +177,6 @@ pdf.cell(60, 10, 'Powered by FPDF.', new_x="LMARGIN", new_y="NEXT", align='C') ## 教程五 - 创建表 ## -本教程将演示如何创建表。 - -该代码创建了三个不同的表,演示了几个简单的表格配置。 - ```python {% include "../tutorial/tuto5.py" %} ``` @@ -188,23 +184,12 @@ pdf.cell(60, 10, 'Powered by FPDF.', new_x="LMARGIN", new_y="NEXT", align='C') [生成的 PDF](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/tuto5.pdf) - [源文本](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/countries.txt) -表格只是单元格的集合,因此由单元格便可构建一个表格。 - -第一张表以最基本的方式实现:带框的单元格,大小相同且左对齐。 -虽然简陋,但操作便捷。 +This section has changed a lot and requires a new translation: https://github.com/PyFPDF/fpdf2/issues/267 -第二张表进行了一些改进:每列都设定了宽度,标题居中,数字右对齐。 -此外,水平线也被删除。 -上述设定由`Cell()` 的边界参数完成,在参数中指定需要绘制的 -单元格边框。 -在示例中,需要绘制左侧 (`L`) 和右侧 (`R`) 的边框。 -水平的边框可使用两种方法设置: -对于循环中的最后一行,使用 `LRB` 作为边界参数; -或者,如示例中,在循环结束后添加一行。 +English versions: -第三张表与第二张表类似,但设置了颜色。 -填充、文本和线条的颜色直接指定即可。行间的间隔着色可以 -通过交替使用透明和填充的单元格实现。 +* [Tuto 5 - Creating Tables](https://pyfpdf.github.io/fpdf2/Tutorial.html#tuto-5-creating-tables) +* [Documentation on tables](https://pyfpdf.github.io/fpdf2/Tables.html) ## 教程六 - 创建链接和混合文本样式 ## diff --git "a/docs/Tutorial-\340\244\271\340\244\277\340\244\202\340\244\246\340\245\200.md" "b/docs/Tutorial-\340\244\271\340\244\277\340\244\202\340\244\246\340\245\200.md" index f64e976bd..e481ccc0e 100644 --- "a/docs/Tutorial-\340\244\271\340\244\277\340\244\202\340\244\246\340\245\200.md" +++ "b/docs/Tutorial-\340\244\271\340\244\277\340\244\202\340\244\246\340\245\200.md" @@ -154,10 +154,6 @@ Logo को निर्दिष्ट करके [image](fpdf/fpdf.html#fpdf ## Tuto 5 - टेबल बनाना ## -यह ट्यूटोरियल समझाएगा कि टेबल को आसानी से कैसे बनाया जाए। - -कुछ सरल समायोजनों के साथ क्या हासिल किया जा सकता है, यह समझाने के लिए कोड तीन अलग-अलग टेबल बनाएगा। - ```python {% include "../tutorial/tuto5.py" %} ``` @@ -165,20 +161,12 @@ Logo को निर्दिष्ट करके [image](fpdf/fpdf.html#fpdf [Resulting PDF](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/tuto5.pdf) - [Countries text](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/countries.txt) -चूंकि तालिका (Table) केवल कोशिकाओं (Cells) का एक संग्रह (Collection) है, इसलिए उनमें से एक का निर्माण करना स्वाभाविक है। +This section has changed a lot and requires a new translation: https://github.com/PyFPDF/fpdf2/issues/267 -पहला उदाहरण सबसे बुनियादी संभव तरीके से हासिल किया गया है: सरल फ़्रेमयुक्त कोशिकाएं (simple framed cells, सभी समान आकार कोशिकाएं (same sized cells) और बाएं संरेखित कोशिकाएं (left aligned cells)। -परिणाम अल्पविकसित है लेकिन प्राप्त करने के लिए बहुत जल्दी है। - -दूसरी तालिका कुछ सुधार लाती है: प्रत्येक कॉलम की अपनी चौड़ाई होती है, शीर्षक केंद्रित होते हैं और आंकड़े सही संरेखित होते हैं। इसके अलावा, क्षैतिज रेखाओं को हटा दिया गया है। -यह Cell() विधि के बॉर्डर पैरामीटर के माध्यम से किया जाता है, जो निर्दिष्ट करता है कि सेल के किन पक्षों को खींचा जाना चाहिए। -यहां हम बाएं (L) और दाएं (R) वाले चाहते हैं। -अब केवल क्षैतिज रेखा की तालिका (Table) को Finish करने की समस्या बनी हुई है। - - इसे हल करने की दो संभावनाएं हैं: लूप में अंतिम पंक्ति की जाँच करें, जिस स्थिति में हम सीमा पैरामीटर के लिए LRB का उपयोग करते हैं; या जैसा कि यहां किया गया है, लूप खत्म होने के बाद लाइन जोड़ें। +English versions: -तीसरी तालिका दूसरे के समान है लेकिन रंगों का उपयोग करती है। Fill, टेक्स्ट और लाइन रंग बस निर्दिष्ट हैं। -वैकल्पिक(Alternate) रूप से पारदर्शी और भरी हुई कोशिकाओं का उपयोग करके पंक्तियों के लिए वैकल्पिक रंग प्राप्त किया जाता है। +* [Tuto 5 - Creating Tables](https://pyfpdf.github.io/fpdf2/Tutorial.html#tuto-5-creating-tables) +* [Documentation on tables](https://pyfpdf.github.io/fpdf2/Tables.html) ## Tuto 6 - लिंक बनाना और टेक्स्ट शैलियों को मिलाना ## diff --git a/docs/Tutorial.md b/docs/Tutorial.md index 8142de057..03b326026 100644 --- a/docs/Tutorial.md +++ b/docs/Tutorial.md @@ -169,37 +169,23 @@ back to the first column and trigger a page break. ## Tuto 5 - Creating Tables ## -This tutorial will explain how to create tables easily. - -The code will create three different tables to explain what - can be achieved with some simple adjustments. +This tutorial will explain how to create two different tables, + to demonstrate what can be achieved with some simple adjustments. ```python {% include "../tutorial/tuto5.py" %} ``` [Resulting PDF](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/tuto5.pdf) - -[Countries text](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/countries.txt) - -Since a table is just a collection of cells, it is natural to build one - from them. - -The first example is achieved in the most basic way possible: simple framed - cells, all of the same size and left aligned. The result is rudimentary but - very quick to obtain. - -The second table brings some improvements: each column has its own width, - titles are centered and figures right aligned. Moreover, horizontal lines have - been removed. This is done by means of the border parameter of the `Cell()` - method, which specifies which sides of the cell must be drawn. Here we want - the left (`L`) and right (`R`) ones. Now only the problem of the horizontal line - to finish the table remains. There are two possibilities to solve it: check - for the last line in the loop, in which case we use LRB for the border - parameter; or, as done here, add the line once the loop is over. - -The third table is similar to the second one but uses colors. Fill, text and - line colors are simply specified. Alternate coloring for rows is obtained by - using alternatively transparent and filled cells. +[Countries CSV data](https://github.com/PyFPDF/fpdf2/raw/master/tutorial/countries.txt) + +The first example is achieved in the most basic way possible, feeding data to [`FPDF.table()`](https://pyfpdf.github.io/fpdf2/Tables.html). The result is rudimentary but very quick to obtain. + +The second table brings some improvements: colors, limited table width, reduced line height, + centered titles, columns with custom widths, figures right aligned... + Moreover, horizontal lines have been removed. + This was done by picking a `table.borders_layout` among the available values: + [`TableBordersLayout`](https://pyfpdf.github.io/fpdf2/fpdf/enums.html#fpdf.enums.TableBordersLayout). ## Tuto 6 - Creating links and mixing text styles ## diff --git a/docs/table-pandas.png b/docs/table-pandas.png old mode 100755 new mode 100644 diff --git a/fpdf/enums.py b/fpdf/enums.py index fde29ce4a..21261891e 100644 --- a/fpdf/enums.py +++ b/fpdf/enums.py @@ -255,6 +255,9 @@ class TableBordersLayout(CoerciveEnum): MINIMAL = intern("MINIMAL") "Draw only the top horizontal border, below the headings, and internal vertical borders" + NO_HORIZONTAL_LINES = intern("NO_HORIZONTAL_LINES") + "Draw all cells border except horizontal lines, after the headings" + SINGLE_TOP_LINE = intern("SINGLE_TOP_LINE") "Draw only the top horizontal border, below the headings" diff --git a/fpdf/table.py b/fpdf/table.py index 961bbe496..8676b7315 100644 --- a/fpdf/table.py +++ b/fpdf/table.py @@ -118,6 +118,11 @@ def get_cell_border(self, i, j): border.remove("L") if j == columns_count - 1 and "R" in border: border.remove("R") + if self.borders_layout == TableBordersLayout.NO_HORIZONTAL_LINES.value: + if i not in (0, rows_count - 1) and "B" in border: + border.remove("B") + if rows_count > 1 and i not in (0, 1) and "T" in border: + border.remove("T") if self.borders_layout == TableBordersLayout.SINGLE_TOP_LINE.value: border = list("TB") if i != 0 and "B" in border: diff --git a/tutorial/tuto1.htm b/tutorial/tuto1.htm deleted file mode 100644 index ed8014135..000000000 --- a/tutorial/tuto1.htm +++ /dev/null @@ -1,91 +0,0 @@ - - - -Esempio minimo - - - -

Esempio minimo

-Let's start with the classic example: -
-
-
- -<?php
require('fpdf.php');

$pdf=new FPDF();
$pdf->AddPage();
$pdf->SetFont('Arial','B',16);
$pdf->Cell(40,10,'Hello World!');
$pdf->Output();
?> -
-

- -After including the library file, we create an FPDF object. -The
FPDF() constructor is used here with the default values: pages are in A4 portrait and -the measure unit is millimeter. It could have been specified explicitly with: -
-
-
- -$pdf=new FPDF('P','mm','A4');
-
-

-It is possible to use landscape (L), other page formats (such as Letter and -Legal) and measure units (pt, cm, in). -
-
-There is no page for the moment, so we have to add one with AddPage(). The origin -is at the upper-left corner and the current position is by default placed at 1 cm from the -borders; the margins can be changed with SetMargins(). -
-
-Before we can print text, it is mandatory to select a font with SetFont(), otherwise the -document would be invalid. We choose Arial bold 16: -
-
-
- -$pdf->SetFont('Arial','B',16);
-
-

-We could have specified italics with I, underlined with U or a regular font with an empty string -(or any combination). Note that the font size is given in points, not millimeters (or another -user unit); it is the only exception. The other standard fonts are Times, Courier, Symbol and -ZapfDingbats. -
-
-We can now print a cell with Cell(). A cell is a rectangular area, possibly framed, -which contains some text. It is output at the current position. We specify its dimensions, -its text (centered or aligned), if borders should be drawn, and where the current position -moves after it (to the right, below or to the beginning of the next line). To add a frame, we would do this: -
-
-
- -$pdf->Cell(40,10,'Hello World !',1);
-
-

-To add a new cell next to it with centered text and go to the next line, we would do: -
-
-
- -$pdf->Cell(60,10,'Powered by FPDF.',0,1,'C');
-
-

-Remark : the line break can also be done with Ln(). This method allows to specify -in addition the height of the break. -
-
-Finally, the document is closed and sent to the browser with Output(). We could have saved -it in a file by passing the desired file name. -
-
-Caution: in case when the PDF is sent to the browser, nothing else must be output, not before -nor after (the least space or carriage return matters). If you send some data before, you will -get the error message: "Some data has already been output to browser, can't send PDF file". If -you send after, your browser may display a blank page. - - diff --git a/tutorial/tuto2.htm b/tutorial/tuto2.htm deleted file mode 100644 index 0a2fe9620..000000000 --- a/tutorial/tuto2.htm +++ /dev/null @@ -1,50 +0,0 @@ - - - -Intestazione, pi di pagina, cambio pagina e immagini - - - -

Intestazione, pi di pagina, cambio pagina e immagini

-Here is a two page example with header, footer and logo: -
-
-
- -<?php
require('fpdf.php');

class
PDF extends FPDF
{
//Page header
function Header()
{
    
//Logo
    
$this->Image('logo_pb.png',10,8,33);
    
//Arial bold 15
    
$this->SetFont('Arial','B',15);
    
//Move to the right
    
$this->Cell(80);
    
//Title
    
$this->Cell(30,10,'Title',1,0,'C');
    
//Line break
    
$this->Ln(20);
}

//Page footer
function Footer()
{
    
//Position at 1.5 cm from bottom
    
$this->SetY(-15);
    
//Arial italic 8
    
$this->SetFont('Arial','I',8);
    
//Page number
    
$this->Cell(0,10,'Page '.$this->PageNo().'/{nb}',0,0,'C');
}
}

//Instanciation of inherited class
$pdf=new PDF();
$pdf->AliasNbPages();
$pdf->AddPage();
$pdf->SetFont('Times','',12);
for(
$i=1;$i<=40;$i++)
    
$pdf->Cell(0,10,'Printing line number '.$i,0,1);
$pdf->Output();
?> -
-

- -This example makes use of the Header() and Footer() methods to process page headers and -footers. They are called automatically. They already exist in the FPDF class but do nothing, -therefore we have to extend the class and override them. -
-
-The logo is printed with the Image() method by specifying its upper-left corner and -its width. The height is calculated automatically to respect the image proportions. -
-
-To print the page number, a null value is passed as the cell width. It means that the cell -should extend up to the right margin of the page; it is handy to center text. The current page -number is returned by the PageNo() method; as for the total number of pages, it is obtained -by means of the special value {nb} which will be substituted on document closure -(provided you first called AliasNbPages()). -
-Note the use of the SetY() method which allows to set position at an absolute location in -the page, starting from the top or the bottom. -
-
-Another interesting feature is used here: the automatic page breaking. As soon as a cell would -cross a limit in the page (at 2 centimeters from the bottom by default), a break is performed -and the font restored. Although the header and footer select their own font (Arial), the body -continues with Times. This mechanism of automatic restoration also applies to colors and line -width. The limit which triggers page breaks can be set with SetAutoPageBreak(). - - diff --git a/tutorial/tuto3.htm b/tutorial/tuto3.htm deleted file mode 100644 index 3c784517f..000000000 --- a/tutorial/tuto3.htm +++ /dev/null @@ -1,43 +0,0 @@ - - - -Ritorno a capo e colori - - - -

Ritorno a capo e colori

-Let's continue with an example which prints justified paragraphs. It also illustrates the use -of colors. -
-
-
- -<?php
require('fpdf.php');

class
PDF extends FPDF
{
function
Header()
{
    global
$title;

    
//Arial bold 15
    
$this->SetFont('Arial','B',15);
    
//Calculate width of title and position
    
$w=$this->GetStringWidth($title)+6;
    
$this->SetX((210-$w)/2);
    
//Colors of frame, background and text
    
$this->SetDrawColor(0,80,180);
    
$this->SetFillColor(230,230,0);
    
$this->SetTextColor(220,50,50);
    
//Thickness of frame (1 mm)
    
$this->SetLineWidth(1);
    
//Title
    
$this->Cell($w,9,$title,1,1,'C',1);
    
//Line break
    
$this->Ln(10);
}

function
Footer()
{
    
//Position at 1.5 cm from bottom
    
$this->SetY(-15);
    
//Arial italic 8
    
$this->SetFont('Arial','I',8);
    
//Text color in gray
    
$this->SetTextColor(128);
    
//Page number
    
$this->Cell(0,10,'Page '.$this->PageNo(),0,0,'C');
}

function
ChapterTitle($num,$label)
{
    
//Arial 12
    
$this->SetFont('Arial','',12);
    
//Background color
    
$this->SetFillColor(200,220,255);
    
//Title
    
$this->Cell(0,6,"Chapter $num : $label",0,1,'L',1);
    
//Line break
    
$this->Ln(4);
}

function
ChapterBody($file)
{
    
//Read text file
    
$f=fopen($file,'r');
    
$txt=fread($f,filesize($file));
    
fclose($f);
    
//Times 12
    
$this->SetFont('Times','',12);
    
//Output justified text
    
$this->MultiCell(0,5,$txt);
    
//Line break
    
$this->Ln();
    
//Mention in italics
    
$this->SetFont('','I');
    
$this->Cell(0,5,'(end of excerpt)');
}

function
PrintChapter($num,$title,$file)
{
    
$this->AddPage();
    
$this->ChapterTitle($num,$title);
    
$this->ChapterBody($file);
}
}

$pdf=new PDF();
$title='20000 Leagues Under the Seas';
$pdf->SetTitle($title);
$pdf->SetAuthor('Jules Verne');
$pdf->PrintChapter(1,'A RUNAWAY REEF','20k_c1.txt');
$pdf->PrintChapter(2,'THE PROS AND CONS','20k_c2.txt');
$pdf->Output();
?> -
-

- -The GetStringWidth() method allows to determine the length of a string in the current font, -which is used here to calculate the position and the width of the frame surrounding the title. -Then colors are set (via SetDrawColor(), SetFillColor() and SetTextColor()) and the -thickness of the line is set to 1 mm (against 0.2 by default) with SetLineWidth(). Finally, -we output the cell (the last parameter to 1 indicates that the background must be filled). -
-
-The method used to print the paragraphs is MultiCell(). Each time a line reaches the -right extremity of the cell or a carriage-return character is met, a line break is issued -and a new cell automatically created under the current one. Text is justified by default. -
-
-Two document properties are defined: title (SetTitle()) and author (SetAuthor()). -Properties can be viewed by two means. First is open the document directly with Acrobat Reader, -go to the File menu, Document info, General. Second, also available from the plug-in, is click -on the triangle just above the right scrollbar and choose Document info. - - diff --git a/tutorial/tuto4.htm b/tutorial/tuto4.htm deleted file mode 100644 index e357d9619..000000000 --- a/tutorial/tuto4.htm +++ /dev/null @@ -1,34 +0,0 @@ - - - -Multi-colunne - - - -

Multi-colunne

-This example is a variant of the previous one showing how to lay the text across multiple -columns. -
-
-
- -<?php
require('fpdf.php');

class
PDF extends FPDF
{
//Current column
var $col=0;
//Ordinate of column start
var $y0;

function
Header()
{
    
//Page header
    
global $title;

    
$this->SetFont('Arial','B',15);
    
$w=$this->GetStringWidth($title)+6;
    
$this->SetX((210-$w)/2);
    
$this->SetDrawColor(0,80,180);
    
$this->SetFillColor(230,230,0);
    
$this->SetTextColor(220,50,50);
    
$this->SetLineWidth(1);
    
$this->Cell($w,9,$title,1,1,'C',1);
    
$this->Ln(10);
    
//Save ordinate
    
$this->y0=$this->GetY();
}

function
Footer()
{
    
//Page footer
    
$this->SetY(-15);
    
$this->SetFont('Arial','I',8);
    
$this->SetTextColor(128);
    
$this->Cell(0,10,'Page '.$this->PageNo(),0,0,'C');
}

function
SetCol($col)
{
    
//Set position at a given column
    
$this->col=$col;
    
$x=10+$col*65;
    
$this->SetLeftMargin($x);
    
$this->SetX($x);
}

function
AcceptPageBreak()
{
    
//Method accepting or not automatic page break
    
if($this->col<2)
    {
        
//Go to next column
        
$this->SetCol($this->col+1);
        
//Set ordinate to top
        
$this->SetY($this->y0);
        
//Keep on page
        
return false;
    }
    else
    {
        
//Go back to first column
        
$this->SetCol(0);
        
//Page break
        
return true;
    }
}

function
ChapterTitle($num,$label)
{
    
//Title
    
$this->SetFont('Arial','',12);
    
$this->SetFillColor(200,220,255);
    
$this->Cell(0,6,"Chapter $num : $label",0,1,'L',1);
    
$this->Ln(4);
    
//Save ordinate
    
$this->y0=$this->GetY();
}

function
ChapterBody($fichier)
{
    
//Read text file
    
$f=fopen($fichier,'r');
    
$txt=fread($f,filesize($fichier));
    
fclose($f);
    
//Font
    
$this->SetFont('Times','',12);
    
//Output text in a 6 cm width column
    
$this->MultiCell(60,5,$txt);
    
$this->Ln();
    
//Mention
    
$this->SetFont('','I');
    
$this->Cell(0,5,'(end of excerpt)');
    
//Go back to first column
    
$this->SetCol(0);
}

function
PrintChapter($num,$title,$file)
{
    
//Add chapter
    
$this->AddPage();
    
$this->ChapterTitle($num,$title);
    
$this->ChapterBody($file);
}
}

$pdf=new PDF();
$title='20000 Leagues Under the Seas';
$pdf->SetTitle($title);
$pdf->SetAuthor('Jules Verne');
$pdf->PrintChapter(1,'A RUNAWAY REEF','20k_c1.txt');
$pdf->PrintChapter(2,'THE PROS AND CONS','20k_c2.txt');
$pdf->Output();
?> -
-

- -The key method used is AcceptPageBreak(). It allows to accept or not an automatic page -break. By refusing it and altering the margin and current position, the desired column layout -is achieved. -
-For the rest, not much change; two properties have been added to the class to save the current -column number and the position where columns begin, and the MultiCell() call specifies a -6 centimeter width. - - diff --git a/tutorial/tuto5.htm b/tutorial/tuto5.htm deleted file mode 100644 index 166bdb3c2..000000000 --- a/tutorial/tuto5.htm +++ /dev/null @@ -1,43 +0,0 @@ - - - -Tabelle - - - -

Tabelle

-This tutorial shows how to make tables easily. -
-
-
- -<?php
require('fpdf.php');

class
PDF extends FPDF
{
//Load data
function LoadData($file)
{
    
//Read file lines
    
$lines=file($file);
    
$data=array();
    foreach(
$lines as $line)
        
$data[]=explode(';',chop($line));
    return
$data;
}

//Simple table
function BasicTable($header,$data)
{
    
//Header
    
foreach($header as $col)
        
$this->Cell(40,7,$col,1);
    
$this->Ln();
    
//Data
    
foreach($data as $row)
    {
        foreach(
$row as $col)
            
$this->Cell(40,6,$col,1);
        
$this->Ln();
    }
}

//Better table
function ImprovedTable($header,$data)
{
    
//Column widths
    
$w=array(40,35,40,45);
    
//Header
    
for($i=0;$i<count($header);$i++)
        
$this->Cell($w[$i],7,$header[$i],1,0,'C');
    
$this->Ln();
    
//Data
    
foreach($data as $row)
    {
        
$this->Cell($w[0],6,$row[0],'LR');
        
$this->Cell($w[1],6,$row[1],'LR');
        
$this->Cell($w[2],6,number_format($row[2]),'LR',0,'R');
        
$this->Cell($w[3],6,number_format($row[3]),'LR',0,'R');
        
$this->Ln();
    }
    
//Closure line
    
$this->Cell(array_sum($w),0,'','T');
}

//Colored table
function FancyTable($header,$data)
{
    
//Colors, line width and bold font
    
$this->SetFillColor(255,0,0);
    
$this->SetTextColor(255);
    
$this->SetDrawColor(128,0,0);
    
$this->SetLineWidth(.3);
    
$this->SetFont('','B');
    
//Header
    
$w=array(40,35,40,45);
    for(
$i=0;$i<count($header);$i++)
        
$this->Cell($w[$i],7,$header[$i],1,0,'C',1);
    
$this->Ln();
    
//Color and font restoration
    
$this->SetFillColor(224,235,255);
    
$this->SetTextColor(0);
    
$this->SetFont('');
    
//Data
    
$fill=0;
    foreach(
$data as $row)
    {
        
$this->Cell($w[0],6,$row[0],'LR',0,'L',$fill);
        
$this->Cell($w[1],6,$row[1],'LR',0,'L',$fill);
        
$this->Cell($w[2],6,number_format($row[2]),'LR',0,'R',$fill);
        
$this->Cell($w[3],6,number_format($row[3]),'LR',0,'R',$fill);
        
$this->Ln();
        
$fill=!$fill;
    }
    
$this->Cell(array_sum($w),0,'','T');
}
}

$pdf=new PDF();
//Column titles
$header=array('Country','Capital','Area (sq km)','Pop. (thousands)');
//Data loading
$data=$pdf->LoadData('countries.txt');
$pdf->SetFont('Arial','',14);
$pdf->AddPage();
$pdf->BasicTable($header,$data);
$pdf->AddPage();
$pdf->ImprovedTable($header,$data);
$pdf->AddPage();
$pdf->FancyTable($header,$data);
$pdf->Output();
?> -
-

- -A table being just a collection of cells, it is natural to build one from them. The first -example is achieved in the most basic way possible: simple framed cells, all of the same size -and left aligned. The result is rudimentary but very quick to obtain. -
-
-The second table brings some improvements: each column has its own width, titles are centered -and figures right aligned. Moreover, horizontal lines have been removed. This is done by means -of the border parameter of the Cell() method, which specifies which sides of the -cell must be drawn. Here we want the left (L) and right (R) ones. It remains -the problem of the horizontal line to finish the table. There are two possibilities: either -check for the last line in the loop, in which case we use LRB for the border -parameter; or, as done here, add the line once the loop is over. -
-
-The third table is similar to the second one but uses colors. Fill, text and line colors are -simply specified. Alternate coloring for rows is obtained by using alternatively transparent -and filled cells. - - diff --git a/tutorial/tuto5.pdf b/tutorial/tuto5.pdf index ad61ea3c23caabbe6adc472494246d628cb19d22..2fceac7108950d8ba7af4610e4b77373e765bd13 100644 GIT binary patch literal 7482 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 D5ZX$0 diff --git a/tutorial/tuto5.py b/tutorial/tuto5.py index 735ee4533..468e623b8 100644 --- a/tutorial/tuto5.py +++ b/tutorial/tuto5.py @@ -1,73 +1,40 @@ import csv from fpdf import FPDF +from fpdf.fonts import FontStyle -class PDF(FPDF): - def basic_table(self, headings, rows): - for heading in headings: - self.cell(40, 7, heading, 1) - self.ln() - for row in rows: - for col in row: - self.cell(40, 6, col, 1) - self.ln() +with open("countries.txt", encoding="utf8") as csv_file: + data = list(csv.reader(csv_file, delimiter=",")) - def improved_table(self, headings, rows, col_widths=(42, 39, 35, 40)): - for col_width, heading in zip(col_widths, headings): - self.cell(col_width, 7, heading, border=1, align="C") - self.ln() - for row in rows: - self.cell(col_widths[0], 6, row[0], border="LR") - self.cell(col_widths[1], 6, row[1], border="LR") - self.cell(col_widths[2], 6, row[2], border="LR", align="R") - self.cell(col_widths[3], 6, row[3], border="LR", align="R") - self.ln() - # Closure line: - self.cell(sum(col_widths), 0, "", border="T") - - def colored_table(self, headings, rows, col_widths=(42, 39, 35, 42)): - # Colors, line width and bold font: - self.set_fill_color(255, 100, 0) - self.set_text_color(255) - self.set_draw_color(255, 0, 0) - self.set_line_width(0.3) - self.set_font(style="B") - for col_width, heading in zip(col_widths, headings): - self.cell(col_width, 7, heading, border=1, align="C", fill=True) - self.ln() - # Color and font restoration: - self.set_fill_color(224, 235, 255) - self.set_text_color(0) - self.set_font() - fill = False - for row in rows: - self.cell(col_widths[0], 6, row[0], border="LR", align="L", fill=fill) - self.cell(col_widths[1], 6, row[1], border="LR", align="L", fill=fill) - self.cell(col_widths[2], 6, row[2], border="LR", align="R", fill=fill) - self.cell(col_widths[3], 6, row[3], border="LR", align="R", fill=fill) - self.ln() - fill = not fill - self.cell(sum(col_widths), 0, "", "T") - - -def load_data_from_csv(csv_filepath): - headings, rows = [], [] - with open(csv_filepath, encoding="utf8") as csv_file: - for row in csv.reader(csv_file, delimiter=","): - if not headings: # extracting column names from first row: - headings = row - else: - rows.append(row) - return headings, rows - - -col_names, data = load_data_from_csv("countries.txt") -pdf = PDF() +pdf = FPDF() pdf.set_font("helvetica", size=14) + +# Basic table: pdf.add_page() -pdf.basic_table(col_names, data) -pdf.add_page() -pdf.improved_table(col_names, data) +with pdf.table() as table: + for data_row in data: + with table.row() as row: + for datum in data_row: + row.cell(datum) + +# Styled table: pdf.add_page() -pdf.colored_table(col_names, data) +pdf.set_draw_color(255, 0, 0) +pdf.set_line_width(0.3) +with pdf.table() as table: + table.borders_layout = "NO_HORIZONTAL_LINES" + table.cell_fill_color = (224, 235, 255) + table.cell_fill_logic = lambda i, j: i % 2 + table.col_widths = (42, 39, 35, 42) + table.headings_style = FontStyle( + emphasis="BOLD", color=255, fill_color=(255, 100, 0) + ) + table.line_height = 6 + table.text_align = ("LEFT", "CENTER", "RIGHT", "RIGHT") + table.width = 160 + for data_row in data: + with table.row() as row: + for datum in data_row: + row.cell(datum) + pdf.output("tuto5.pdf") diff --git a/tutorial/tuto6.htm b/tutorial/tuto6.htm deleted file mode 100644 index 32c4c5899..000000000 --- a/tutorial/tuto6.htm +++ /dev/null @@ -1,68 +0,0 @@ - - - -Links e testo scorrevole - - - -

Links e testo scorrevole

-This tutorial explains how to insert links (internal and external) and shows a new text writing -mode. It also contains a rudimentary HTML parser. -
-
-
- -<?php
require('fpdf.php');

class
PDF extends FPDF
{
var
$B;
var
$I;
var
$U;
var
$HREF;

function
PDF($orientation='P',$unit='mm',$format='A4')
{
    
//Call parent constructor
    
$this->FPDF($orientation,$unit,$format);
    
//Initialization
    
$this->B=0;
    
$this->I=0;
    
$this->U=0;
    
$this->HREF='';
}

function
WriteHTML($html)
{
    
//HTML parser
    
$html=str_replace("\n",' ',$html);
    
$a=preg_split('/<(.*)>/U',$html,-1,PREG_SPLIT_DELIM_CAPTURE);
    foreach(
$a as $i=>$e)
    {
        if(
$i%2==0)
        {
            
//Text
            
if($this->HREF)
                
$this->PutLink($this->HREF,$e);
            else
                
$this->Write(5,$e);
        }
        else
        {
            
//Tag
            
if($e{0}=='/')
                
$this->CloseTag(strtoupper(substr($e,1)));
            else
            {
                
//Extract attributes
                
$a2=explode(' ',$e);
                
$tag=strtoupper(array_shift($a2));
                
$attr=array();
                foreach(
$a2 as $v)
                    if(
ereg('^([^=]*)=["\']?([^"\']*)["\']?$',$v,$a3))
                        
$attr[strtoupper($a3[1])]=$a3[2];
                
$this->OpenTag($tag,$attr);
            }
        }
    }
}

function
OpenTag($tag,$attr)
{
    
//Opening tag
    
if($tag=='B' or $tag=='I' or $tag=='U')
        
$this->SetStyle($tag,true);
    if(
$tag=='A')
        
$this->HREF=$attr['HREF'];
    if(
$tag=='BR')
        
$this->Ln(5);
}

function
CloseTag($tag)
{
    
//Closing tag
    
if($tag=='B' or $tag=='I' or $tag=='U')
        
$this->SetStyle($tag,false);
    if(
$tag=='A')
        
$this->HREF='';
}

function
SetStyle($tag,$enable)
{
    
//Modify style and select corresponding font
    
$this->$tag+=($enable ? 1 : -1);
    
$style='';
    foreach(array(
'B','I','U') as $s)
        if(
$this->$s>0)
            
$style.=$s;
    
$this->SetFont('',$style);
}

function
PutLink($URL,$txt)
{
    
//Put a hyperlink
    
$this->SetTextColor(0,0,255);
    
$this->SetStyle('U',true);
    
$this->Write(5,$txt,$URL);
    
$this->SetStyle('U',false);
    
$this->SetTextColor(0);
}
}

$html='You can now easily print text mixing different
styles : <B>bold</B>, <I>italic</I>, <U>underlined</U>, or
<B><I><U>all at once</U></I></B>!<BR>You can also insert links
on text, such as <A HREF="http://www.fpdf.org">www.fpdf.org</A>,
or on an image: click on the logo.'
;

$pdf=new PDF();
//First page
$pdf->AddPage();
$pdf->SetFont('Arial','',20);
$pdf->Write(5,'To find out what\'s new in this tutorial, click ');
$pdf->SetFont('','U');
$link=$pdf->AddLink();
$pdf->Write(5,'here',$link);
$pdf->SetFont('');
//Second page
$pdf->AddPage();
$pdf->SetLink($link);
$pdf->Image('logo.png',10,10,30,0,'','http://www.fpdf.org');
$pdf->SetLeftMargin(45);
$pdf->SetFontSize(14);
$pdf->WriteHTML($html);
$pdf->Output();
?> -
-

- -The new method to print text is Write(). It is very close to MultiCell(); the differences -are: -
    -
  • The end of line is at the right margin and the next line begins at the left one -
  • The current position moves at the end of the text -
-So it allows to write a chunk of text, alter the font style, then continue from the exact -place we left it. On the other hand, you cannot full justify it. -
-
-The method is used on the first page to put a link pointing to the second one. The beginning of -the sentence is written in regular style, then we switch to underline and finish it. The link -is created with AddLink(), which returns a link identifier. The identifier is -passed as third parameter of Write(). Once the second page is created, we use SetLink() to -make the link point to the beginning of the current page. -
-
-Then we put an image with a link on it. An external link points to an URL (HTTP, mailto...). -The URL is simply passed as last parameter of Image(). -Note that external links do not work when the PDF is displayed inside Netscape's plug-in. -
-
-Finally, the left margin is moved after the image with SetLeftMargin() and some text in -HTML format is output. An HTML parser is used for this, based on the regular expression splitting -function preg_split() and the option PREG_SPLIT_DELIM_CAPTURE (introduced in PHP 4.0.5) which -allows to fetch the separators as well (in this case the tags). If you use an older version of -PHP, replace the line with this one: -
-
-
- -$a=preg_split('/[<>]/',$html);
-
-

-which is less strict but gives the same results with valid HTML. -
-Recognized tags are <B>, <I>, <U>, <A> and <BR>; the others are -ignored. The parser also makes use of the Write() method. An external link is put the same way as -an internal one (third parameter of Write()). -
-Note that Cell() also allows to put links. - - diff --git a/tutorial/tuto7.htm b/tutorial/tuto7.htm deleted file mode 100644 index 2bf1bc737..000000000 --- a/tutorial/tuto7.htm +++ /dev/null @@ -1,315 +0,0 @@ - - - -Aggiunta di nuovi fonts e supporto codifica - - - -

Aggiunta di nuovi fonts e supporto codifica

-This tutorial explains how to use TrueType or Type1 fonts so that you are not limited to the standard -fonts any more. The other interest is that you can choose the font encoding, which allows you to -use other languages than the Western ones (the standard fonts having too few available characters). -
-
-There are two ways to use a new font: embedding it in the PDF or not. When a font is not -embedded, it is sought in the system. The advantage is that the PDF file is lighter; on the other -hand, if it is not available, a substitution font is used. So it is preferable to ensure that the -needed font is installed on the client systems. If the file is to be viewed by a large audience, -it is better to embed. -
-
-Adding a new font requires three steps for TrueTypes: -
    -
  • Generation of the metric file (.afm) -
  • Generation of the font definition file (.php) -
  • Declaration of the font in the script -
-For Type1, the first one is theoretically not necessary because the AFM file is usually shipped -with the font. In case you have only a metric file in PFM format, use the convertor available -here. -

Generation of the metric file

-The first step for a TrueType consists in generating the AFM file. A utility exists to do this -task: ttf2pt1. The Windows binary -is available here. The command line to use is -the following: -
-
-ttf2pt1 -a font.ttf font -
-
-For example, for Comic Sans MS Regular: -
-
-ttf2pt1 -a c:\windows\fonts\comic.ttf comic -
-
-Two files are created; the one we are interested in is comic.afm. -

Generation of the font definition file

-The second step consists in generating a PHP file containing all the information needed by FPDF; -in addition, the font file is compressed. To do this, a helper script is provided in the font/makefont/ -directory of the package: makefont.php. It contains the following function: -
-
-MakeFont(string fontfile, string afmfile [, string enc [, array patch [, string type]]]) -
-
-fontfile -
-Path to the .ttf or .pfb file. -
-afmfile -
-Path to the .afm file. -
-enc -
-Name of the encoding to use. Default value: cp1252. -
-patch -
-Optional modification of the encoding. Empty by default. -
-type -
-Type of the font (TrueType or Type1). Default value: TrueType. -
-
-The first parameter is the name of the font file. The extension must be either .ttf or .pfb and -determines the font type. If you own a Type1 font in ASCII format (.pfa), you can convert it to -binary format with t1utils. -
-If you don't want to embed the font, pass an empty string. In this case, type is given by the -type parameter. -
-Note: in the case of a font with the same name as a standard one, for instance arial.ttf, it is -mandatory to embed. If you don't, Acrobat will use its own font. -
-
-The AFM file is the one previously generated. -
-
-The encoding defines the association between a code (from 0 to 255) and a character. The first -128 are fixed and correspond to ASCII; the following are variable. The encodings are stored in -.map files. Those available are: -
    -
  • cp1250 (Central Europe) -
  • cp1251 (Cyrillic) -
  • cp1252 (Western Europe) -
  • cp1253 (Greek) -
  • cp1254 (Turkish) -
  • cp1255 (Hebrew) -
  • cp1257 (Baltic) -
  • cp1258 (Vietnamese) -
  • cp874 (Thai) -
  • ISO-8859-1 (Western Europe) -
  • ISO-8859-2 (Central Europe) -
  • ISO-8859-4 (Baltic) -
  • ISO-8859-5 (Cyrillic) -
  • ISO-8859-7 (Greek) -
  • ISO-8859-9 (Turkish) -
  • ISO-8859-11 (Thai) -
  • ISO-8859-15 (Western Europe) -
  • ISO-8859-16 (Central Europe) -
  • KOI8-R (Russian) -
  • KOI8-U (Ukrainian) -
-Of course, the font must contain the characters corresponding to the chosen encoding. -
-In the particular case of a symbolic font (that is to say which does not contain letters, such -as Symbol or ZapfDingbats), pass an empty string. -
-The encodings which begin with cp are those used by Windows; Linux systems usually use ISO. -
-Remark: the standard fonts use cp1252. -
-
-The fourth parameter gives the possibility to alter the encoding. Sometimes you may want to add -some characters. For instance, ISO-8859-1 does not contain the euro symbol. To add it at position -164, pass array(164=>'Euro'). -
-
-The last parameter is used to give the type of the font in case it is not embedded (that is to -say the first parameter is empty). -
-
-After you have called the function (create a new file for this and include makefont.php, or -simply add the call directly inside), a .php file is created, with the same name as the .afm one. -You may rename it if you wish. If the case of embedding, the font file is compressed and gives a -second file with .z as extension (except if the compression function is not available, it -requires zlib). You may rename it too, but in this case you have to alter the variable $file -in the .php file accordingly. -
-
-Example: -
-
-MakeFont('c:\\windows\\fonts\\comic.ttf','comic.afm','cp1252'); -
-
-which gives the files comic.php and comic.z. -
-
-Then you have to copy the generated file(s) to the font directory. If the font file -could not be compressed, copy the .ttf or .pfb instead of the .z. -

Declaration of the font in the script

-The last step is the most simple. You just need to call the AddFont() method. For instance: -
-
-
- -$pdf->AddFont('Comic','','comic.php');
-
-

-or simply: -
-
-
- -$pdf->AddFont('Comic');
-
-

-And the font is now available (in regular and underlined styles), usable like the others. If we -had worked with Comic Sans MS Bold (comicbd.ttf), we would have put: -
-
-
- -$pdf->AddFont('Comic','B','comicbd.php');
-
-

-

Example

-Let's now see a small complete example. The font used is Calligrapher, available at -www.abstractfonts.com (a site -offering numerous free TrueType fonts). The first step is the generation of the AFM file: -
-
-ttf2pt1 -a calligra.ttf calligra -
-
-which gives calligra.afm (and calligra.t1a that we can delete). Then we generate the definition -file: -
-
-
- -<?php
require('font/makefont/makefont.php');

MakeFont('calligra.ttf','calligra.afm');
?> -
-

-The function call gives the following report: -
-
-Warning: character Euro is missing
-Warning: character Zcaron is missing
-Warning: character zcaron is missing
-Warning: character eth is missing
-Font file compressed (calligra.z)
-Font definition file generated (calligra.php)
-
-The euro character is not present in the font (it is too old). Three other characters are missing -too, but we are not interested in them anyway. -
-We can now copy the two files to the font directory and write the script: -
-
-
- -<?php
require('fpdf.php');

$pdf=new FPDF();
$pdf->AddFont('Calligrapher','','calligra.php');
$pdf->AddPage();
$pdf->SetFont('Calligrapher','',35);
$pdf->Cell(0,10,'Enjoy new fonts with FPDF!');
$pdf->Output();
?> -
-

- -

About the euro symbol

-The euro character is not present in all encodings, and is not always placed at the same position: -
-
- - - - - - - - - - - - - - - - - - - - - - - -
EncodingPosition
cp1250128
cp1251136
cp1252128
cp1253128
cp1254128
cp1255128
cp1257128
cp1258128
cp874128
ISO-8859-1absent
ISO-8859-2absent
ISO-8859-4absent
ISO-8859-5absent
ISO-8859-7absent
ISO-8859-9absent
ISO-8859-11absent
ISO-8859-15164
ISO-8859-16164
KOI8-Rabsent
KOI8-Uabsent
-
-ISO-8859-1 is widespread but does not include the euro sign. If you need it, the simplest thing -to do is using cp1252 or ISO-8859-15 instead, which are nearly identical but contain the precious -symbol. -
-As for ISO-8859-2, it is possible to use ISO-8859-16 instead, but it contains many differences. -It is therefore simpler to patch the encoding to add the symbol to it, as explained above. The -same is true for the other encodings. -

Font synthesis under Windows

-When a TrueType font is not available in a given style, Windows is able to synthesize it from the -regular version. For instance, there is no Comic Sans MS Italic, but it can be built from Comic -Sans MS Regular. This feature can be used in a PDF file, but unfortunately requires that the -regular font be present in the system (you must not embed it). Here is how to do it: -
    -
  • Generate the definition file for the regular font without embedding (you may rename it to -reflect the desired style) -
  • Open it and append to the variable $name a comma followed by the desired style -(Italic, Bold or BoldItalic) -
-For instance, for the file comici.php: -
-
-$name='ComicSansMS,Italic'; -
-
-It can then be used normally: -
-
-
- -$pdf->AddFont('Comic','I','comici.php');
-
-

-

Reducing the size of TrueType fonts

-Font files are often quite voluminous (more than 100, even 200KB); this is due to the fact that -they contain the characters corresponding to many encodings. zlib compression reduces them but -they remain fairly big. A technique exists to reduce them further. It consists in converting the -font to the Type1 format with ttf2pt1 by specifying the encoding you are interested in; all other -characters will be discarded. -
-For instance, the arial.ttf font shipped with Windows 98 is 267KB (it contains 1296 characters). -After compression it gives 147. Let's convert it to Type1 by keeping only cp1250 characters: -
-
-ttf2pt1 -b -L cp1250.map c:\windows\fonts\arial.ttf arial -
-
-The .map files are located in the font/makefont/ directory of the package. The command produces -arial.pfb and arial.afm. The arial.pfb file is only 35KB, and 30KB after compression. -
-
-It is possible to go even further. If you are interested only by a subset of the encoding (you -probably don't need all 217 characters), you can open the .map file and remove the lines you are -not interested in. This will reduce the file size accordingly. - - From 9a89aff10cccdcafaa12dc1e4f8617275f86319f Mon Sep 17 00:00:00 2001 From: Lucas Cimon <925560+Lucas-C@users.noreply.github.com> Date: Fri, 24 Feb 2023 21:39:45 +0100 Subject: [PATCH 13/17] Using new Table rendering in write_html() --- .../continuous-integration-workflow.yml | 3 +- CHANGELOG.md | 7 +- README.md | 2 +- docs/Tables.md | 2 + docs/index.md | 2 +- fpdf/enums.py | 3 + fpdf/fonts.py | 22 +- fpdf/fpdf.py | 11 + fpdf/html.py | 382 +++++------------- fpdf/table.py | 162 +++++--- test/html/bgcolor_in_table.pdf | Bin 1623 -> 0 bytes test/html/html_features.pdf | Bin 5929 -> 5911 bytes test/html/html_simple_table.pdf | Bin 1221 -> 0 bytes test/html/html_table_line_separators.pdf | Bin 1231 -> 1117 bytes .../html_table_line_separators_issue_137.pdf | Bin 1223 -> 1112 bytes test/html/html_table_with_border.pdf | Bin 1309 -> 1209 bytes .../html_table_with_empty_cell_contents.pdf | Bin 1280 -> 1156 bytes test/html/test_customize_ul.pdf | Bin 1313 -> 0 bytes test/html/test_html.py | 239 +---------- test/html/test_html_whitespace_handling.pdf | Bin 1885 -> 0 bytes test/html/test_img_inside_html_table.pdf | Bin 14797 -> 0 bytes .../test_img_inside_html_table_centered.pdf | Bin 14796 -> 0 bytes ..._inside_html_table_centered_with_align.pdf | Bin 14801 -> 0 bytes ...nside_html_table_centered_with_caption.pdf | Bin 22666 -> 0 bytes ...html_table_without_explicit_dimensions.pdf | Bin 14788 -> 0 bytes test/html/test_img_not_overlapping.pdf | Bin 11198 -> 0 bytes test/table/table_align.pdf | Bin 2112 -> 2124 bytes test/table/table_simple.pdf | Bin 1640 -> 1646 bytes test/table/table_with_cell_fill.pdf | Bin 1707 -> 2246 bytes test/table/table_with_cell_fill2.pdf | Bin 1730 -> 0 bytes test/table/table_with_fixed_col_width.pdf | Bin 1640 -> 1647 bytes test/table/table_with_fixed_row_height.pdf | Bin 1624 -> 1630 bytes test/table/table_with_fixed_width.pdf | Bin 1636 -> 1642 bytes test/table/table_with_headings_styled.pdf | Bin 1694 -> 1708 bytes test/table/table_with_images.pdf | Bin 78789 -> 79296 bytes .../table_with_images_and_img_fill_width.pdf | Bin 78790 -> 79299 bytes test/table/table_with_internal_layout.pdf | Bin 1569 -> 1572 bytes test/table/table_with_minimal_layout.pdf | Bin 1493 -> 1498 bytes test/table/table_with_multiline_cells.pdf | Bin 3044 -> 3050 bytes ...h_multiline_cells_and_fixed_row_height.pdf | Bin 2969 -> 2974 bytes .../table_with_multiline_cells_and_images.pdf | Bin 79961 -> 80470 bytes ...multiline_cells_and_split_over_3_pages.pdf | Bin 5242 -> 5254 bytes .../table_with_single_top_line_layout.pdf | Bin 1350 -> 1360 bytes test/table/table_with_varying_col_widths.pdf | Bin 1637 -> 1643 bytes test/table/test_table.py | 10 +- 45 files changed, 253 insertions(+), 592 deletions(-) delete mode 100644 test/html/bgcolor_in_table.pdf delete mode 100644 test/html/html_simple_table.pdf delete mode 100644 test/html/test_customize_ul.pdf delete mode 100644 test/html/test_html_whitespace_handling.pdf delete mode 100644 test/html/test_img_inside_html_table.pdf delete mode 100644 test/html/test_img_inside_html_table_centered.pdf delete mode 100644 test/html/test_img_inside_html_table_centered_with_align.pdf delete mode 100644 test/html/test_img_inside_html_table_centered_with_caption.pdf delete mode 100644 test/html/test_img_inside_html_table_without_explicit_dimensions.pdf delete mode 100644 test/html/test_img_not_overlapping.pdf delete mode 100644 test/table/table_with_cell_fill2.pdf diff --git a/.github/workflows/continuous-integration-workflow.yml b/.github/workflows/continuous-integration-workflow.yml index f56ddfd61..27c4e6a96 100644 --- a/.github/workflows/continuous-integration-workflow.yml +++ b/.github/workflows/continuous-integration-workflow.yml @@ -75,8 +75,7 @@ jobs: sed -i "s/author:.*/author: v$(python setup.py -V 2>/dev/null)/" mkdocs.yml cp tutorial/notebook.ipynb docs/ mkdocs build - pdoc --html -o public/ fpdf --config "git_link_template='https://github -.com/PyFPDF/fpdf2/blob/{commit}/{path}#L{start_line}-L{end_line}'" + pdoc --html -o public/ fpdf --config "git_link_template='https://github.com/PyFPDF/fpdf2/blob/{commit}/{path}#L{start_line}-L{end_line}'" cd contributors/ && PYTHONUNBUFFERED=1 ./build_contributors_html_page.py PyFPDF/fpdf2 cp -t ../public/ contributors.html contributors-map-small.png - name: Deploy documentation 🚀 diff --git a/CHANGELOG.md b/CHANGELOG.md index 5de6ee083..a0f184ae7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,12 +16,12 @@ in order to get warned about deprecated features used in your code. This can also be enabled programmatically with `warnings.simplefilter('default', DeprecationWarning)`. -## [2.6.2] - Not released yet +## [2.7.0] - Not released yet ### Added - new method [`FPDF.table()`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.table): [documentation](https://pyfpdf.github.io/fpdf2/Tables.html) - [`FPDF.image()`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.image) has a new `keep_aspect_ratio` optional boolean parameter, to fit it inside a given rectangle: [documentation](https://pyfpdf.github.io/fpdf2/Images.html#fitting-an-image-inside-a-rectangle) - [`FPDF.multi_cell()`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.multi_cell) and [`FPDF.write()`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.write) now accept a `wrapmode` argument for word or character based line wrapping ("WORD"/"CHAR"). -- new method `FPDF.preload_image()`: [documentation](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.preload_image) +- new methods: [`FPDF.preload_image()`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.preload_image) & [`FPDF.use_font_style()`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.use_font_style) - new translation of the tutorial in [简体中文](https://pyfpdf.github.io/fpdf2/Tutorial-zh.html) - thanks to @Bubbu0129 - new method [`FPDF.set_fallback_fonts()`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.set_fallback_fonts) allow alternative fonts to be provided if a character on the text is not available on the currently set font - thanks to @andersonhc - documentation on how to embed static [Plotly](https://plotly.com/python/) charts: [link to docs](https://pyfpdf.github.io/fpdf2/Maths.html) @@ -33,10 +33,13 @@ This can also be enabled programmatically with `warnings.simplefilter('default', - all `TitleStyle` constructor parameters are now effectively optional - memory usage was reduced by 10 MiB in some cases, thanks to a small optimization in using `fonttools` ### Changed +* [`FPDF.write_html()`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.write_html) now uses the new [`FPDF.table()`](https://pyfpdf.github.io/fpdf2/Tables.html) method to render `` tags. As a consequence, vertical space before `
` tags has sometimes been reduced. - vector images parsing is now more robust: `fpdf2` can now embed SVG files without `viewPort` or no `height` / `width` - bitonal images are now encoded using `CCITTFaxDecode`, reducing their size in the PDF document - thanks to @eroux - when possible, JPG and group4 encoded TIFFs are now embedded directly without recompression - thanks to @eroux - ICC Profiles of included images are now extracted and turned into PDF objects; they should now be taken into account by PDF viewers - thanks to @eroux +### Removed +* [`FPDF.write_html()`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.write_html) now uses the new [`FPDF.table()`](https://pyfpdf.github.io/fpdf2/Tables.html) method to render `
` tags. As a consequence, it does not support the `height` attribute defined on `` / `` tags. ## [2.6.1] - 2023-01-13 ### Added diff --git a/README.md b/README.md index 31acd5527..5248a5064 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ pip install git+https://github.com/PyFPDF/fpdf2.git@master * Embedding images, including transparency and alpha channel * Arbitrary path drawing and basic [SVG](https://pyfpdf.github.io/fpdf2/SVG.html) import * Embedding [barcodes](https://pyfpdf.github.io/fpdf2/Barcodes.html), [charts & graphs](https://pyfpdf.github.io/fpdf2/Maths.html), [emojis, symbols & dingbats](https://pyfpdf.github.io/fpdf2/EmojisSymbolsDingbats.html) - * [Cell / multi-cell / plaintext writing](https://pyfpdf.github.io/fpdf2/Text.html), with [automatic page breaks](https://pyfpdf.github.io/fpdf2/PageBreaks.html), line break and text justification + * [Tables](https://pyfpdf.github.io/fpdf2/Tables.html) and also [cell / multi-cell / plaintext writing](https://pyfpdf.github.io/fpdf2/Text.html), with [automatic page breaks](https://pyfpdf.github.io/fpdf2/PageBreaks.html), line break and text justification * Choice of measurement unit, page format & margins. Optional page header and footer * Basic [conversion from HTML to PDF](https://pyfpdf.github.io/fpdf2/HTML.html) * A [templating system](https://pyfpdf.github.io/fpdf2/Templates.html) to render PDFs in batchs diff --git a/docs/Tables.md b/docs/Tables.md index 929fb7320..e5f24d34b 100644 --- a/docs/Tables.md +++ b/docs/Tables.md @@ -1,5 +1,7 @@ # Tables +_New in [:octicons-tag-24: 2.7.0](https://github.com/PyFPDF/fpdf2/blob/master/CHANGELOG.md)_ + Tables can be built using the `table()` method. Here is a simple example: diff --git a/docs/index.md b/docs/index.md index 57ba123ec..628463800 100644 --- a/docs/index.md +++ b/docs/index.md @@ -30,7 +30,7 @@ Go try it **now** online in a Jupyter notebook: [![Open In Colab](https://colab. * Embedding images, including transparency and alpha channel, using [Pillow (Python Imaging Library)](https://pillow.readthedocs.io/en/stable/) * Arbitrary path drawing and basic [SVG](SVG.md) import * Embedding [barcodes](Barcodes.md), [charts & graphs](Maths.md), [emojis, symbols & dingbats](EmojisSymbolsDingbats.md) -* [Cell / multi-cell / plaintext writing](Text.md), with [automatic page breaks](PageBreaks.md), line break and text justification +* [Tables](Tables.md), and also [cell / multi-cell / plaintext writing](Text.md), with [automatic page breaks](PageBreaks.md), line break and text justification * Choice of measurement unit, page format & margins. Optional page header and footer * Basic [conversion from HTML to PDF](HTML.md) * A [templating system](Templates.md) to render PDFs in batchs diff --git a/fpdf/enums.py b/fpdf/enums.py index 21261891e..bcc8d8a97 100644 --- a/fpdf/enums.py +++ b/fpdf/enums.py @@ -255,6 +255,9 @@ class TableBordersLayout(CoerciveEnum): MINIMAL = intern("MINIMAL") "Draw only the top horizontal border, below the headings, and internal vertical borders" + HORIZONTAL_LINES = intern("HORIZONTAL_LINES") + "Draw only horizontal lines" + NO_HORIZONTAL_LINES = intern("NO_HORIZONTAL_LINES") "Draw all cells border except horizontal lines, after the headings" diff --git a/fpdf/fonts.py b/fpdf/fonts.py index 78005bf19..4056c94ec 100644 --- a/fpdf/fonts.py +++ b/fpdf/fonts.py @@ -1,6 +1,7 @@ """ Definition of the character widths of all PDF standard fonts. """ +from dataclasses import dataclass, replace from typing import Optional, Union from .drawing import DeviceGray, DeviceRGB @@ -2605,21 +2606,22 @@ } +@dataclass class FontStyle: + family: Optional[str] + emphasis: Optional[TextEmphasis] + size_pt: Optional[int] + # Colors are single number grey scales or (red, green, blue) tuples: + color: Optional[Union[int, tuple, DeviceGray, DeviceRGB]] + fill_color: Optional[Union[int, tuple, DeviceGray, DeviceRGB]] + def __init__( - self, - family: Optional[str] = None, - emphasis: Optional[Union[str, TextEmphasis]] = None, - size_pt: Optional[int] = None, - color: Optional[ - Union[int, tuple, DeviceGray, DeviceRGB] - ] = None, # grey scale or (red, green, blue) - fill_color: Optional[ - Union[int, tuple, DeviceGray, DeviceRGB] - ] = None, # grey scale or (red, green, blue) + self, family=None, emphasis=None, size_pt=None, color=None, fill_color=None ): self.family = family self.emphasis = TextEmphasis.coerce(emphasis) if emphasis else None self.size_pt = size_pt self.color = color self.fill_color = fill_color + + replace = replace diff --git a/fpdf/fpdf.py b/fpdf/fpdf.py index e8bb1953c..ab2af9bad 100644 --- a/fpdf/fpdf.py +++ b/fpdf/fpdf.py @@ -4655,6 +4655,17 @@ def _use_title_style(self, title_style: TitleStyle): @contextmanager def use_font_style(self, font_style: FontStyle): + """ + Sets the provided `fpdf.font.FontStyle` in a local context, + then restore font settings back to they were initially. + This method must be used as a context manager using `with`: + + with pdf.use_font_style(FontStyle(emphasis="BOLD", color=255, size_pt=42)): + put_some_text() + """ + if not font_style: + yield + return prev_font = (self.font_family, self.font_style, self.font_size_pt) self.set_font( font_style.family or self.font_family, diff --git a/fpdf/html.py b/fpdf/html.py index acb774217..d1c14b772 100644 --- a/fpdf/html.py +++ b/fpdf/html.py @@ -9,7 +9,9 @@ import logging, warnings from html.parser import HTMLParser -from .enums import XPos, YPos +from .enums import TextEmphasis, XPos, YPos +from .fonts import FontStyle +from .table import Table import re @@ -227,7 +229,6 @@ def __init__( self.image_map = image_map or (lambda src: src) self.li_tag_indent = li_tag_indent self.dd_tag_indent = dd_tag_indent - self.table_line_separators = table_line_separators self.ul_bullet_char = ul_bullet_char self.style = dict(b=False, i=False, u=False) self.pre_formatted = False @@ -242,42 +243,46 @@ def __init__( self.font_size = pdf.font_size_pt self.set_font(pdf.font_family or "times", size=self.font_size) self.font_color = 0, 0, 0 # initialize font color, r,g,b format - self.table = None # table attributes - self.table_col_width = None # column (header) widths - self.table_col_index = None # current column index - self.td = None # inside a , attributes dict - self.thead = None # inside a , attributes dict - self.tfoot = None # inside a , attributes dict - self.tr_index = None # row index - self.theader = None # table header cells - self.tfooter = None # table footer cells - self.theader_out = self.tfooter_out = False - self.table_row_height = 0 self.heading_level = None self.heading_sizes = dict(**DEFAULT_HEADING_SIZES) self.heading_above = 0.2 # extra space above heading, relative to font size self.heading_below = 0.2 # extra space below heading, relative to font size if heading_sizes: self.heading_sizes.update(heading_sizes) - self._only_imgs_in_td = False self.warn_on_tags_not_matching = warn_on_tags_not_matching self._tags_stack = [] - - def width2unit(self, length): - "Handle conversion of % measures into the measurement unit used" - if length[-1] == "%": - total = self.pdf.w - self.pdf.r_margin - self.pdf.l_margin - if self.table["width"][-1] == "%": - total *= int(self.table["width"][:-1]) / 100 - return int(length[:-1]) * total / 100 - return int(length) + #
` / `` tags anymore, nor `height` / `width` attributes defined on `` tags inside cells, nor `width` attributes defined on `
, attributes dict - self.th = None # inside a , attributes dict - self.tr = None # inside a
-related properties: + self.table_line_separators = table_line_separators + self.table = None + self.table_row = None + self.tr = None + self.td_th = None def handle_data(self, data): trailing_space_flag = TRAILING_SPACE.search(data) - if self.td is not None: # drawing a table? - self._insert_td(data) + if self.td_th is not None: + data = data.strip() + if not data: + return + align = self.td_th.get("align", self.tr.get("align")) + if align: + align = align.upper() + bgcolor = color_as_decimal( + self.td_th.get("bgcolor", self.tr.get("bgcolor", None)) + ) + colspan = int(self.td_th.get("colspan", "1")) + emphasis = 0 + if self.td_th.get("b"): + emphasis |= TextEmphasis.B + if self.td_th.get("i"): + emphasis |= TextEmphasis.I + if self.td_th.get("U"): + emphasis |= TextEmphasis.U + style = None + if bgcolor or emphasis: + style = FontStyle(emphasis=emphasis, fill_color=bgcolor) + self.table_row.cell(text=data, align=align, style=style, colspan=colspan) + self.td_th["rendered"] = True elif self.table is not None: # ignore anything else than td inside a table pass @@ -331,154 +336,6 @@ def handle_data(self, data): self.pdf.write(self.h, data) self.follows_fmt_tag = False - def _insert_td(self, data=""): - self._only_imgs_in_td = False - width = self._td_width() - height = int(self.td.get("height", 0)) // 4 or self.h * 1.30 - if not self.table_row_height: - self.table_row_height = height - elif self.table_row_height > height: - height = self.table_row_height - border = int(self.table.get("border", 0)) - if self.th: - self.set_style("B", True) - border = border or "B" - align = self.td.get("align", "C")[0].upper() - else: - align = self.td.get("align", "L")[0].upper() - border = border and "LR" - bgcolor = color_as_decimal(self.td.get("bgcolor", self.tr.get("bgcolor", ""))) - # parsing table header/footer (drawn later): - if self.thead is not None: - self.theader.append( - ( - dict( - w=width, - h=height, - txt=data, - border=border, - new_x=XPos.RIGHT, - new_y=YPos.TOP, - align=align, - ), - bgcolor, - ) - ) - if self.tfoot is not None: - self.tfooter.append( - ( - dict( - w=width, - h=height, - txt=data, - border=border, - new_x=XPos.RIGHT, - new_y=YPos.TOP, - align=align, - ), - bgcolor, - ) - ) - # check if reached end of page, add table footer and header: - if self.tfooter: - height += self.tfooter[0][0]["h"] - if self.pdf.y + height > self.pdf.page_break_trigger and not self.th: - self.output_table_footer() - self.pdf.add_page(same=True) - self.theader_out = self.tfooter_out = False - if self.tfoot is None and self.thead is None: - if not self.theader_out: - self.output_table_header() - self.box_shadow(width, height, bgcolor) - # self.pdf.x may have shifted due to inside ', + width, + tag, + ) if tag == "img" and "src" in attrs: width = px2mm(int(attrs.get("width", 0))) height = px2mm(int(attrs.get("height", 0))) + if self.table_row: # => in a
: - self.pdf.set_x(self._td_x()) - LOGGER.debug( - "td cell x=%d width=%d height=%d border=%s align=%s '%s'", - self.pdf.x, - width, - height, - border, - align, - data.replace("\n", "\\n"), - ) - self.pdf.cell( - width, - height, - data, - border=border, - align=align, - new_x=XPos.RIGHT, - new_y=YPos.TOP, - ) - - def _td_x(self): - "Return the current table cell left side horizontal position" - prev_cells_total_width = sum( - self.width2unit(width) - for width in self.table_col_width[: self.table_col_index] - ) - return self.table_offset + prev_cells_total_width - - def _td_width(self): - "Return the current table cell width" - # pylint: disable=raise-missing-from - if "width" in self.td: - column_widths = [self.td["width"]] - elif "colspan" in self.td: - i = self.table_col_index - colspan = int(self.td["colspan"]) - column_widths = self.table_col_width[i : i + colspan] - else: - try: - column_widths = [self.table_col_width[self.table_col_index]] - except IndexError: - raise ValueError( - f"Width not specified for table column {self.table_col_index}," - " unable to continue" - ) - return sum(self.width2unit(width) for width in column_widths) - - def box_shadow(self, w, h, bgcolor): - LOGGER.debug("box_shadow w=%d h=%d bgcolor=%s", w, h, bgcolor) - if bgcolor: - fill_color = self.pdf.fill_color - self.pdf.set_fill_color(*bgcolor) - self.pdf.rect(self.pdf.x, self.pdf.y, w, h, "F") - self.pdf.set_fill_color(*fill_color.colors) - - def output_table_header(self): - if self.theader: - b = self.style.get("b") - self.pdf.set_x(self.table_offset) - self.set_style("b", True) - for celldict, bgcolor in self.theader: - self.box_shadow(celldict["w"], celldict["h"], bgcolor) - self.pdf.cell(**celldict) # includes the border - self.set_style("b", b) - self.pdf.ln(self.theader[0][0]["h"]) - self.pdf.set_x(self.table_offset) - # self.pdf.set_x(prev_x) - self.theader_out = True - - def output_table_footer(self): - if self.tfooter: - x = self.pdf.x - self.pdf.set_x(self.table_offset) - for celldict, bgcolor in self.tfooter: - self.box_shadow(celldict["w"], celldict["h"], bgcolor) - self.pdf.cell(**celldict) - self.pdf.ln(self.tfooter[0][0]["h"]) - self.pdf.set_x(x) - if self.table.get("border"): - self.output_table_sep() - self.tfooter_out = True - - def output_table_sep(self): - x1 = self.pdf.x - y1 = self.pdf.y - width = sum(self.width2unit(length) for length in self.table_col_width) - self.pdf.line(x1, y1, x1 + width, y1) - def handle_starttag(self, tag, attrs): attrs = dict(attrs) LOGGER.debug("STARTTAG %s %s", tag, attrs) @@ -494,7 +351,10 @@ def handle_starttag(self, tag, attrs): if tag == "em": tag = "i" if tag in ("b", "i", "u"): - self.set_style(tag, True) + if self.td_th is not None: + self.td_th[tag] = True + else: + self.set_style(tag, True) if tag == "a": self.href = attrs["href"] if tag == "br": @@ -562,72 +422,73 @@ def handle_starttag(self, tag, attrs): self.set_font() self.set_text_color(*self.font_color) if tag == "table": - self.table = {k.lower(): v for k, v in attrs.items()} - if "width" not in self.table: - self.table["width"] = "100%" - if self.table["width"][-1] == "%": - w = self.pdf.w - self.pdf.r_margin - self.pdf.l_margin - w *= int(self.table["width"][:-1]) / 100 - self.table_offset = (self.pdf.w - w) / 2 - self.table_col_width = [] - self.theader_out = self.tfooter_out = False - self.theader = [] - self.tfooter = [] - self.thead = None - self.tfoot = None + self.table = Table(self.pdf) + self.table.line_height = self.h * 1.30 + width = attrs.get("width") + if width: + if width[-1] == "%": + width = self.pdf.epw * int(width[:-1]) / 100 + else: + width = px2mm(int(width)) + self.table.width = width + if "border" in attrs: + self.table.borders_layout = ( + "ALL" if self.table_line_separators else "NO_HORIZONTAL_LINES" + ) + else: + self.table.borders_layout = ( + "HORIZONTAL_LINES" + if self.table_line_separators + else "SINGLE_TOP_LINE" + ) self.pdf.ln() if tag == "tr": - self.tr_index = 0 if self.tr_index is None else (self.tr_index + 1) self.tr = {k.lower(): v for k, v in attrs.items()} - self.table_col_index = 0 - self.table_row_height = 0 - self.pdf.set_x(self.table_offset) - # Adding an horizontal line separator between rows: - if self.table_line_separators and self.tr_index > 0: - self.output_table_sep() - if tag == "td": - self.td = {k.lower(): v for k, v in attrs.items()} - if "width" in self.td and self.table_col_index >= len(self.table_col_width): - assert self.table_col_index == len( - self.table_col_width - ), f"table_col_index={self.table_col_index} #table_col_width={len(self.table_col_width)}" - self.table_col_width.append(self.td["width"]) - if attrs: - self.align = attrs.get("align") - self._only_imgs_in_td = False - if tag == "th": - self.td = {k.lower(): v for k, v in attrs.items()} - self.th = True - if "width" in self.td and self.table_col_index >= len(self.table_col_width): - assert self.table_col_index == len( - self.table_col_width - ), f"table_col_index={self.table_col_index} #table_col_width={len(self.table_col_width)}" - self.table_col_width.append(self.td["width"]) - if tag == "thead": - self.thead = {} - if tag == "tfoot": - self.tfoot = {} + with self.table.row() as row: + self.table_row = row + if tag in ("td", "th"): + self.td_th = {k.lower(): v for k, v in attrs.items()} + if tag == "th": + self.td_th["align"] = "CENTER" + self.td_th["b"] = True + if "height" in attrs: + LOGGER.warning( + 'Ignoring unsupported height="%s" specified on a <%s>', + attrs["height"], + tag, + ) + if "width" in attrs: + width = attrs["width"] + if len(self.table.rows) == 1: # => first table row + if width[-1] == "%": + width = width[:-1] + if not self.table.col_widths: + self.table.col_widths = [] + self.table.col_widths.append(int(width)) + else: + LOGGER.warning( + 'Ignoring width="%s" specified on a <%s> that is not in the first
+ if width or height: + LOGGER.warning( + 'Ignoring unsupported "width" / "height" set on element' + ) + if self.align: + LOGGER.warning("Ignoring unsupported alignment") + self.table_row.cell(img=attrs["src"], img_fill_width=True) + self.td_th["rendered"] = True + return if self.pdf.y + height > self.pdf.page_break_trigger: self.pdf.add_page(same=True) - y = self.pdf.get_y() - if self.table_col_index is not None: - self._only_imgs_in_td = True - # in a " " " " " - ' ' - ' ' + " " + " " " " " " "
: its width must not exceed the cell width: - td_width = self._td_width() - if not width or width > td_width: - if width: # Preserving image aspect ratio: - height *= td_width / width - width = td_width - x = self._td_x() - if self.align and self.align[0].upper() == "C": - x += (td_width - width) / 2 - else: - x = self.pdf.get_x() - if self.align and self.align[0].upper() == "C": - x = self.pdf.w / 2 - width / 2 + x, y = self.pdf.get_x(), self.pdf.get_y() + if self.align and self.align[0].upper() == "C": + x = self.pdf.w / 2 - width / 2 LOGGER.debug( 'image "%s" x=%d y=%d width=%d height=%d', attrs["src"], @@ -636,20 +497,10 @@ def handle_starttag(self, tag, attrs): width, height, ) - image_info = self.pdf.image( + info = self.pdf.image( self.image_map(attrs["src"]), x, y, width, height, link=self.href ) - width = image_info["rendered_width"] - height = image_info["rendered_height"] - self.pdf.set_x(x + width) - if self.table_col_index is not None: - # in a : we grow the cell height according to the image height: - if height > self.table_row_height: - self.table_row_height = height - else: - self.pdf.set_y(y + height) - if tag in ("b", "i", "u"): - self.set_style(tag, True) + self.pdf.set_y(y + info.rendered_height) if tag == "center": self.align = "Center" if tag == "toc": @@ -708,7 +559,8 @@ def handle_endtag(self, tag): if tag == "em": tag = "i" if tag in ("b", "i", "u"): - self.set_style(tag, False) + if not self.td_th is not None: + self.set_style(tag, False) self.follows_fmt_tag = True if tag == "a": self.href = "" @@ -720,37 +572,21 @@ def handle_endtag(self, tag): self.indent -= 1 self.bullet.pop() if tag == "table": - if not self.tfooter_out: - self.output_table_footer() + self.table.render() self.table = None - self.th = False - self.theader = None - self.tfooter = None self.pdf.ln(self.h) - self.tr_index = None - if tag == "thead": - self.thead = None - self.tr_index = None - if tag == "tfoot": - self.tfoot = None - self.tr_index = None - if tag == "tbody": - self.tbody = None - self.tr_index = None if tag == "tr": - if self.tfoot is None: - self.pdf.ln(self.table_row_height) - self.table_col_index = None self.tr = None + self.table_row = None if tag in ("td", "th"): - if self.th: - LOGGER.debug("revert style") - self.set_style("b", False) # revert style - elif self._only_imgs_in_td: - self._insert_td() - self.table_col_index += int(self.td.get("colspan", "1")) - self.td = None - self.th = False + if "rendered" not in self.td_th: + # handle_data() was not called => we call it to produce an empty cell: + bgcolor = color_as_decimal( + self.td_th.get("bgcolor", self.tr.get("bgcolor", None)) + ) + style = FontStyle(fill_color=bgcolor) if bgcolor else None + self.table_row.cell(text="", style=style) + self.td_th = None if tag == "font": # recover last font state face, size, color = self.font_stack.pop() diff --git a/fpdf/table.py b/fpdf/table.py index 8676b7315..65d4f391a 100644 --- a/fpdf/table.py +++ b/fpdf/table.py @@ -1,6 +1,7 @@ from contextlib import contextmanager +from dataclasses import dataclass from numbers import Number -from typing import List +from typing import List, Union from .enums import Align, TableBordersLayout from .fonts import FontStyle @@ -17,7 +18,7 @@ class Table: def __init__(self, fpdf): self._fpdf = fpdf - self._rows = [] + self.rows = [] self.align = "CENTER" """ Sets the table horizontal position relative to the page, @@ -37,6 +38,8 @@ def __init__(self, fpdf): "Defines the visual style of the top headings row: size, color, emphasis..." self.line_height = 2 * fpdf.font_size "Defines how much vertical space a line of text will occupy" + self.markdown = False + "Enable markdown interpretation of cells textual content" self.text_align = "JUSTIFY" "Control text alignment inside cells. Justify by default" self.width = fpdf.epw @@ -46,7 +49,7 @@ def __init__(self, fpdf): def row(self): "Adds a row to the table. Yields a `Row` object." row = Row() - self._rows.append(row) + self.rows.append(row) yield row def render(self): @@ -67,22 +70,15 @@ def render(self): self._fpdf.x = self._fpdf.l_margin elif self._fpdf.x != self._fpdf.l_margin: self._fpdf.l_margin = self._fpdf.x - for i in range(len(self._rows)): + for i in range(len(self.rows)): with self._fpdf.offset_rendering() as test: - self._render_table_row_styled(i) + self._render_table_row(i) if test.page_break_triggered: # pylint: disable=protected-access self._fpdf._perform_page_break() if self.first_row_as_headings: # repeat headings on top: - self._render_table_row_styled(0) - if self.cell_fill_color: - prev_fill_color = self._fpdf.fill_color - self._fpdf.set_fill_color(self.cell_fill_color) - else: - prev_fill_color = None - self._render_table_row_styled(i) - if prev_fill_color: - self._fpdf.set_fill_color(prev_fill_color) + self._render_table_row(0) + self._render_table_row(i) self._fpdf.l_margin = prev_l_margin self._fpdf.x = self._fpdf.l_margin @@ -97,8 +93,8 @@ def get_cell_border(self, i, j): return 1 if self.borders_layout == TableBordersLayout.NONE.value: return 0 - columns_count = max(len(row.cells) for row in self._rows) - rows_count = len(self._rows) + columns_count = max(row.cols_count for row in self.rows) + rows_count = len(self.rows) border = list("LRTB") if self.borders_layout == TableBordersLayout.INTERNAL.value: if i == 0 and "T" in border: @@ -110,39 +106,43 @@ def get_cell_border(self, i, j): if j == columns_count - 1 and "R" in border: border.remove("R") if self.borders_layout == TableBordersLayout.MINIMAL.value: + if (i != 1 or rows_count == 1) and "T" in border: + border.remove("T") if i != 0 and "B" in border: border.remove("B") - if rows_count > 1 and i != 1 and "T" in border: - border.remove("T") if j == 0 and "L" in border: border.remove("L") if j == columns_count - 1 and "R" in border: border.remove("R") if self.borders_layout == TableBordersLayout.NO_HORIZONTAL_LINES.value: + if i not in (0, 1) and "T" in border: + border.remove("T") if i not in (0, rows_count - 1) and "B" in border: border.remove("B") - if rows_count > 1 and i not in (0, 1) and "T" in border: + if self.borders_layout == TableBordersLayout.HORIZONTAL_LINES.value: + if rows_count == 1: + return 0 + border = list("TB") + if i == 0 and "T" in border: border.remove("T") + if i == rows_count - 1 and "B" in border: + border.remove("B") if self.borders_layout == TableBordersLayout.SINGLE_TOP_LINE.value: + if rows_count == 1: + return 0 border = list("TB") + if i != 1 and "T" in border: + border.remove("T") if i != 0 and "B" in border: border.remove("B") - if rows_count > 1 and i != 1 and "T" in border: - border.remove("T") return "".join(border) - def _render_table_row_styled(self, i): - if i == 0 and self.first_row_as_headings: - with self._fpdf.use_font_style(self.headings_style): - self._render_table_row(i, fill=bool(self.headings_style.fill_color)) - else: - self._render_table_row(i) - def _render_table_row(self, i, fill=False, **kwargs): - row = self._rows[i] + row = self.rows[i] lines_heights_per_cell = self._get_lines_heights_per_cell(i) row_height = max(sum(lines_heights) for lines_heights in lines_heights_per_cell) - for j in range(len(row.cells)): + j = 0 + while j < len(row.cells): cell_line_height = row_height / len(lines_heights_per_cell[j]) self._render_table_cell( i, @@ -152,6 +152,7 @@ def _render_table_row(self, i, fill=False, **kwargs): fill=fill, **kwargs, ) + j += row.cells[j].colspan self._fpdf.ln(row_height) # pylint: disable=inconsistent-return-statements @@ -168,9 +169,9 @@ def _render_table_cell( """ If `lines_heights_only` is True, returns a list of lines (subcells) heights. """ - row = self._rows[i] - col_width = self._get_col_width(i, j) + row = self.rows[i] cell = row.cells[j] + col_width = self._get_col_width(i, j, cell.colspan) lines_heights = [] if cell.img: if lines_heights_only: @@ -190,47 +191,63 @@ def _render_table_cell( keep_aspect_ratio=True, ) self._fpdf.set_xy(x, y) - if not fill: + text_align = cell.align or self.text_align + if not isinstance(text_align, (Align, str)): + text_align = text_align[j] + style = cell.style + if not style and i == 0 and self.first_row_as_headings: + style = self.headings_style + if lines_heights_only and style: + style = style.replace(emphasis=None) + if style and style.fill_color: + fill = True + elif not fill: fill = self.cell_fill_color and self.cell_fill_logic(i, j) - text_align = ( - self.text_align - if isinstance(self.text_align, (Align, str)) - else self.text_align[j] - ) - lines = self._fpdf.multi_cell( - w=col_width, - h=row_height, - txt=cell.text, - max_line_height=cell_line_height, - border=self.get_cell_border(i, j), - align=text_align, - new_x="RIGHT", - new_y="TOP", - fill=fill, - split_only=lines_heights_only, - **kwargs, - ) - if lines_heights_only and cell.text: - lines_heights += len(lines) * [self.line_height] + if fill and self.cell_fill_color and not (style and style.fill_color): + style = ( + style.replace(fill_color=self.cell_fill_color) + if style + else FontStyle(fill_color=self.cell_fill_color) + ) + with self._fpdf.use_font_style(style): + lines = self._fpdf.multi_cell( + w=col_width, + h=row_height, + txt=cell.text, + max_line_height=cell_line_height, + border=self.get_cell_border(i, j), + align=text_align, + new_x="RIGHT", + new_y="TOP", + fill=fill, + split_only=lines_heights_only, + markdown=self.markdown, + **kwargs, + ) + if lines_heights_only and not cell.img: + lines_heights += (len(lines) or 1) * [self.line_height] if lines_heights_only: return lines_heights - def _get_col_width(self, i, j): + def _get_col_width(self, i, j, colspan=1): if not self.col_widths: - cols_count = len(self._rows[i].cells) - return self.width / cols_count + cols_count = self.rows[i].cols_count + return colspan * (self.width / cols_count) if isinstance(self.col_widths, Number): - return self.col_widths + return colspan * self.col_widths if j >= len(self.col_widths): raise ValueError( f"Invalid .col_widths specified: missing width for table() column {j + 1} on row {i + 1}" ) # pylint: disable=unsubscriptable-object - col_ratio = self.col_widths[j] / sum(self.col_widths) - return col_ratio * self.width + col_width = 0 + for k in range(j, j + colspan): + col_ratio = self.col_widths[k] / sum(self.col_widths) + col_width += col_ratio * self.width + return col_width def _get_lines_heights_per_cell(self, i) -> List[List[int]]: - row = self._rows[i] + row = self.rows[i] lines_heights = [] for j in range(len(row.cells)): lines_heights.append( @@ -251,30 +268,41 @@ class Row: def __init__(self): self.cells = [] - def cell(self, text="", img=None, img_fill_width=False): + @property + def cols_count(self): + return sum(cell.colspan for cell in self.cells) + + def cell( + self, text="", align=None, style=None, img=None, img_fill_width=False, colspan=1 + ): """ Adds a cell to the row. Args: text (str): string content, can contain several lines. In that case, the row height will grow proportionally. + align (str, fpdf.enums.Align): optional text alignment. + style (fpdf.fonts.FontStyle): optional text style. img: optional. Either a string representing a file path to an image, an URL to an image, an io.BytesIO, or a instance of `PIL.Image.Image`. img_fill_width (bool): optional, defaults to False. Indicates to render the image using the full width of the current table column. + colspan (int): optional number of columns this cell should span. """ if text and img: raise NotImplementedError( "fpdf2 currently does not support inserting text with an image in the same table cell." "Pull Requests are welcome to implement this 😊" ) - self.cells.append(Cell(text, img, img_fill_width)) + self.cells.append(Cell(text, align, style, img, img_fill_width, colspan)) +@dataclass class Cell: "Internal representation of a table cell" - - def __init__(self, text, img, img_fill_width): - self.text = text - self.img = img - self.img_fill_width = img_fill_width + text: str + align: Union[str, Align] + style: FontStyle + img: str + img_fill_width: bool + colspan: int diff --git a/test/html/bgcolor_in_table.pdf b/test/html/bgcolor_in_table.pdf deleted file mode 100644 index 2c061fbea44931dce9a16b009a95abb2eb3feb5f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1623 zcmY!laBHDUpWF|W0 zS13dq07XnKP4$c{6f8^(^(-ubvLTfPsS5f5iRr1uTy}O`sd*_NmCPSDKRpGytU4C$TcWv_wJQKQGleKc_S|4pMZCcK4bS9|pWk-N`7-BTd6MYFbTejtb=~(k^&f`aEvG(O z{Em6_c)LWQ(jt!3*4afjyyEizE?<$Nx5UZLzr|;x+Z@$J8ho$Cwm&eg)Z1kFKGkWd zMtH?{*K(J;)loJ(j?xR0Hg?=Bl zW?!vi3ganZ+@QncV(|UstFrgMyR9rc=DXXkx-VpCASZp+!snR56Eoe!m2X4&{abFm zIl&%qMYiz9xt2>ECpAu=)YzZ1DdeHhoK(L{5A1gQdaBdOK;@3WmJ)YcUtyX@!jP-R@NZal8AJy-~gshX^Rr_A-{D*qR-S(QlKuH%Gq0mHZ zij*3h5{pya@`33|KO{3ZwOBVOKQ|GWN?r4S=^`^PT|qxQGtV)vI1?tor5{|HR07T$ zpd13sRFI4UG6N~Wnc=a*DL*HLavRL?*x(7wPnpS-+X2c_@N5GLBpVxjH$w$b_yIGo zn~?&@n;@340?0W*z^tPmP?Vn>oLZs~tq&}UfT5aN0SsHuTws25g3``V+A|g@z$}rh zat7u;P_g0y%%BPyE>?z?W|oFV#)gKL20##HXsK>spstCexuPgFjmtp6(0~i100I=u zOihhV719(CVn91UKp_tyW(o8GnwX&_raB{YOfd@sU^t-ZwKM>hG^k>R1_r=F6HUwz zia%*@Hc)xyx(!ou9#$i2`qe7aRMpK{_G~gOKX$#?eVb)W%_0}cAD>@lFvXvjF!0l8J*hj# z&&-=kLRy#8ErM~`f+HR?&OF%69)8$4`kq;j)>P>x&7-zN7Zhv{ioNwnX`UglBIq}zyh7vtJe;2?Y4TkUi-)1qLx5EE-5k5 zMCpT{C!dfP&I*WHKgm!`AWFzgXh%`$&xvAY{OfvDvy>0mU18wfXk_)ge)S&{^ZMQU z8^taf&ug4G@516|Y14HMH|HeSJKx}pOY=WpA~BgY^9a}4MsG(S!S(I`co$mf%(_uO z>%feFW}f2bW!?@S0*(|luIB%~Kva|E#00(Frp@JB4=h!i_59CU$s^V+P8+RTPWZp5 z;Fzd;sLySgz)McIWeQyzng4#R;97LUzSVI-{q_W%3;v424$D4lW6@W+DAZ#4WKlq~ zf64VWp1a4VHwW@ORR3~gt8eRvpBrvY)J%Kv@lj<}|A&_w!dVabzbJhDr)K*3w;Lj# z>e)N{-w{fjow!-6W$uN`*OI>&oVq91dqKGBS5w6KrJc_tfWpS#rR>r=94ZvQz7y$i za5^8g-KBodb061o9iUm?uO;4mIK{1ALTDe)zrbHJ?~5iVJ~gcI_+|9t5398NWwWXy z6TYN=IQsdG=)?B=bABvzyfppbbiF^k+h(*F9Ih7POkj)u_43fv6Jkko_|23w&pgn6 z|4zW}YIC;-kMWOPpY-p&)rv5?(V=3v@VbBS^>>$grD9x)cxPOg|Fp&~;)lGV$Ofs& z2JAic#)c?4BKLx?|6v0jwg=VqN2^=9J?FgFW>T>zND#E&0-@0rlgT&6nyk_~O0m*o$9xKY1k`hmyGw2cjOKlCkf?3j0_yxFgN##;6Br+>Ws z5%|kdplQ}OKixGf3y-b7e0rZK!}Ak!7;EC8xarP+kBArKb<1+4=A}Rifz7Wt z)OqSHEEEhtKp{_o3(PPuv^29s7c(+4H^LAzHZ{QzGqJ?fYl=n8%o1X6J(9&n=2#S3 zSej#4VrglNE@o_Ifnl+UkqL$aO-u|7k@ePt{A^-kZi*}j7Bj`P#KhbXMKf5Pg%L&w znpm2cp_^xFV20rsQ$tfm)5-l}wy}dL21XaXB5_4ivNkvg=8keb&p*feTs;j>n7XYXzUiJV0 delta 1563 zcmbQPw^DC|J4?N>5tp4ES8+*EYGN)|#hkriw}WmQh}1mSK9~G^(JQ^z6SKLE4K8Qa z9XQg)@kXL&;Zx^d`=<(@o-|o_(o3J&%WqVd74O;Yb?D)%4x!Ws&o7?j*%xDwFeiX( zv$e(iwfUL}IYr(Ehl~s)RoxD)Y4GR!BsK5Wr*)aH_q;yEwChv2d%fM^H;ExLx$K!$ z4;ArU*`Mg9o$+4LOWN&8R8?SDDD(DE9aN@~tilM^rBopndR_j~5Cg*7)zx;Ncj@2$HrX?~u}ssp8|d&9$`{dV+i>NyY+ zk>4kq)MPeELpt;)-&KpU6}I)WA! z#s}TQ%a}hJZS0O{c5&kOLYIDRR4Yd zp4&`1lMmL<&52fU)W22JS#f>~@4E<~0qb-7O51<#H)*!#(Tr!R*N%NCz?gXKlj2+N z2dB+-?2c7_=m4=-Uwedm8^t{~^>CQqK1@hXnv! zU=LUl@ItC0=hqa@y5LOSD%Nw+CdVZ+S94wx)4lp}OZNU-%XUp-Rp(p%hpSJ}%jR#4 z88fp)^DCALHjR(LQR~Zj7BKA+7LZtQdN0`Sa|4P+PaGd zPMyy)gXKOlpX%JdbMrY4L!Nq53k3rZP{>o@0y7K@EsZVF#f*$B4KT!v&5ba`ObyL3 z#LTdWnH!pc)zu?eY-E8&p{1cIx`D<9hK3ko<^~uRn;4m4IMBqz5XE!#AU~U!SQ?`n zXkvzGiHW%pie|803loS>kUU~yX=Z|Mo~eNahGT$%#b`XaR?Ifm(9+S|)x^-y#lXeV x)zQS*%*fEl#Kg_q)YZTUNV(bB5L6KhN%M(CB^5=fXTSTmafBWK{qF diff --git a/test/html/html_simple_table.pdf b/test/html/html_simple_table.pdf deleted file mode 100644 index f5ef356c9f464699203ae39e5ba935934cf5002d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1221 zcmbtUPe>F|7(djd5u$@ghlrOT>cO3vot@p8S~m9I;F{vHD~O8N?Cx_N-F zg{SCHu7QYchoHKeP!L53Vi1*}6j+A{6bdA<=n{14z5SDeLLGXSH}ie-{l4$}eZOy- zq9LtKbV!^C1b`ExoY%|oL7Ybfh#Y^;NLgS&qORB=$9KV$p$BjQ3<%UBtFptX0L3Lb z6qR~=CUOw)Q9TVU&gbJGN-;R64YoT6kv~ZcjH;M`*9_7QP(G8P04%gqpTKzn_-+J) zIFrw!irE6JyjU$sP$zl@r)_CiiF?%}0uix*s}d8{P5N3xh(QbI%_Ovd#}3Jo+wfRu z4No&N1e&zgj80$(CUFXKd?!R{G6FFR~p`PUmrRO)#99CF$vRJ`L1h8dwS*YTdi(vu7J*eiQMZcZKsFE`MrCoWRTG)z-G50Dz?szlXJ8ZlGey>b*UM`nV7*Z-X->dOh|&4+Q4=TQkbnW6 z?gQ-;7HGGTEEPqddIzg_WYE@vVoMOD5@6a6QI&v}&}mV1tD;j9MOC1uUsRg~p}Ex- zTrlAlMvS(aol4EAg)D7ygKv#GRfc5F6LJ@}o|bI>MB2V>nd<9=s3O9C3@<)FmLZ z@-WLcr`YN51ob0q9Z#~igq^fFVs6v(cY}>mU2el2!-J8Enw*a+yKNK`;(othI$v1D z+&AF;%FV1tSk*GmPx$%y@8f?b_WPDKUXA%s{$6rg=XH+f!7SImpJ{AY;!aq9!?s z*x2a187i1g=47^KG@tCr?96B}xtBS&-poM300b2B6u7_)0|PTtOAIk{6ElQZNl{{E zPHGXCjSZK6aAsAif(4g;P=0=if{}uOLJ*g}XI@&qf;p7!q7ZFk=;mr*>}=p@V(DV( zVrJlEWM*V!aE{H|*&sgt0-^yh>s$xfd&SeuZsOmgWLSfP^j64TGM#=U<<}q6 z&Y-KcXPxi*Z}K>iW$mZ8LRwus#Aq+`{(tosC(AK4PPSnZU~$UNNtqnTj$!~h{yQk0mPlUl@OW5cB%oLQBsV9BK)l%HRsU<9$;GcPS)!2-&5 zQHZv2akH>6w+u5gc62syHghsHb9OX0GP86xb#=6`G&C`GwSy|bqaqd(lZizo6-B9O PT$TogT&k+B{%%|V^VqB) diff --git a/test/html/html_table_line_separators_issue_137.pdf b/test/html/html_table_line_separators_issue_137.pdf index d278ad893969eecb0c994dc5c198cfd9f8fafd4a..d58ffc79616940afdf8b97432f60ad816092fea3 100644 GIT binary patch delta 426 zcmX@kd4prZZ$`6;f1K-$3{1G}?6`_cic%AExhm%LPO#=XWFX-3drp#9hFJAq-);2qkr8vD ze_dHf_MDBb|JI3G+Mkg%@Dd7KQ^6YSaAne^i3J~;JhNJC(~hTY&tDf+)K~DzrhfiO zj%3}duYybGs4TiOF~(bImsY-~?~bCPvvzm-=Xw5(^jK$j=4hAQ45nLtkz3~OT9I9K z{`b3@>`z|%V}C{-x2P0;+UK}cWsz34_cZRSS6&D=C{LZt&eSydHIu+(R%UBP^U03P z&Wsk5TbXmUOidLGKtLf+feXwqFfcPU!4NYyF`R6`B3)y_r5}`^U!q{7V4x7hrSF-S zmakwAWxFUu+qgKnI=h)$S{gVySr|JRxR^PaI9VE)yBV6eI-9teo7oXo5etce#G;al SqSQ1l3j-rARaIAiH!c9`#FoAQ delta 451 zcmcb?ah!9)Z$|Tpf1K+LEzG&>?6`_cic%AExhm#N?YHDR#eTi!@`QDjm74o3OPONdNY={FII>_(@!DdM)H^SJ7cTBg zeSG3$i;YIv`R(TUMw_g^FlJ1aU}~Cd&LqI%l%JC_*@wxA(R^}0lQbKbzMGMP+2mzR z_KX&jpD{TzT29tt&b2ePP%r=ig**i=FvGyW%-9@5%-q-%L(Ib1X!1d3=^9He{h<8( z5(Og#1BDrqoskXrHhNDv9pP>v$?C2 fxvL#v6|s=GNh~UJcjE#8G9#NN diff --git a/test/html/html_table_with_border.pdf b/test/html/html_table_with_border.pdf index 89a8d12f46933e92a5bb9b98839c0fafc47b35b6..9ea51d1460c684ff7aee8e28f2baf94082a83362 100644 GIT binary patch delta 557 zcmbQswUcwgZ$`6;f1K-$4Gg*L?6`_cic%AExhm%LPTZS!*np>{+@AG#S)%LTTiK0e zFQWE3zW&1Q*{JCk0{0)*=h?sa`!29w z{McLJONqU1cN4Y=mwmCGvAJBu?``JEbxgIh>-|0(F3y`jk?*;!-!ivc^*1ld4YJ;Q ztS}RJwb9MCuC}IV#iFU9Qs3WSONon|F3NdGASh{ro$&;XugAW>bxPrjH0O9C+qW$3 z!lJd(|F=)hQ$Kpq;KmY<>pX5>3bxrkm;3W1mFwn)SEnx4>`c+HT`}Q(^v%Ox|K@7V z2|9m*WAEZu3k@uQ0^GT)<`ns#vpoLg^dq+kF73V8}#V1|K#xv3$Bn1!(gLad}HF*7H%h|9)?OFuZX zDpkRPOFt+-zeE9OmO>DhzGq%qzJfWF?V=EEW9H&)>EvqeY-nL=XzFBYZszLh=4N4R pYU1kTXz1$VYH5c@2~= delta 538 zcmdnVIhSj~Z$|Tpf1K-$%#FG1?6`_cic%AExhm%D4czT_#6aN9XVGYH7=LHuke@MzH-LcP9X!UZmIglJP@67$> z^{F!jPd0uRo6G7ecJrWYtIrJeibfUB`^Q{1_MCF6X`cPK#NxiwpHo$5>)D(Im=81h zzToZod?LnrkKg_0nPU9jYOBloH@q=42|qLcz5HuQ@l(^%o@{!_DR!dK*hVdQXAB2x zcu$I#)K`wUO3$mcA72-(RPAZH&2W~_eU-3}{pr%Z$;TX|7e6pNxNQBcE1W8vXVqT2 zyv*M!yq4vlbn@JeN|EZ@zFU;@wR06kXEzuHPJOVev+T=TmD?`9PBT|{J;+#bKUd!afXg>J^lQbKbzMGMP*<^NRdq#`N?##}NmXo`g zb8U@G6bwK>Ay0t|%rG!8H!{W$voJEm5VJI#tjHo$W67l-l%HRsV5DH65X7bLnU|KY zU;$;jC`8*BI61poI2&0wxfnW|nHe}68W=dbni`uMm>3utnYozS5mpfkiSopvl8U0# QG%ibXOD^ z>(5GW@m`o@sh|=kFK{yN(EJA(k)LlGAO3JvQiT6^-n0jgCm)b9VY|fiY~|yIumjcY zj}jPyj!B%})0S_MwP!)q2geH*9{WFRdndlT+~dEx!)l2Gk#74`He7m{Qs4UHrTOl< zXoa;I41q^8^cBtt7p+jdef54(%@axWX%qTbmbW_S-&7Fg*>>%7Hs2bB!nNC7?QPR* zB6np)`uRt%+{S8?yS3NVDI@7*aqxyCKNdWgIAQL#mY9Op9g!b6PJY}nA*O(JXW)lq z_2)dUXZJR}zg_X^c=4sHtkriX8N_a7D`AkIfAH*NN2bQfD$D|t?U=16OEB|HZe_M$ zw3xh)IZxA4!2kpl@)Wqh3^a}0IRyQPyhe` delta 519 zcmZqSY~Y&ko6&sYAJ=*lE;~D};*z4 Xe5IcF#B_G2;RasB<5Yx;#5N7koAsc2-J zls}-u|2AMv*rV@~TV_t&EUBpFGBf7)k%{~V59=*Z`*G*4*p8k32N<0jHns0A+PCQ6 zEC1CR%GxSnA&s1i1o;jZ*&R?mW9w;f-ZV*q<&<%Z?6JQurB3}eU+{K@L;Z{idYnr* z&)Pi7{A1C3ob{5K?}9Xo53DXa4=Y~#s zVZKk<>MEC~371;xJ+0fQbVv6aw{;rRP1eb-OpPK=iN&dI`FSM@`XQOQsl~cZ`8g?* zE0~-Z%_r|>l4j%5cQaBjn|z7Mp3!2m5VJF*<>WBtJX=!*0}xQiQ{VzK3=GUHO)$jF zEsZe5EG#T1zh#!LvEv0>zM6wj!z_4G!xUL0J7l?5L z@ygyx!4Lc%zS1v~)#mOL1Z+f0K%1$lVW1hObb^DnF$K-qHmoBv&k5MDj#mIPZ5V`r zhOX4QQ5plb(S!;z(n)h1wgD|KT1cX3STj(9md^EJc7uF37EmEtYVW`436o(AE5}FCz0R%~+Q8u=qmSnnm2X^ueXSmr@ z-kxZ!@7Ohbitw|~8R^nUdRoso#K>H7NJmpjT+!yi|b zG!BQpJ-qBAWku1}X}=Bj6a`V~w0^X0`ja2Ehg0q@m{InCX}HH-O)<|ZKTW+D{9;kh zwN;U9@v)7gBi(;J8vEm?bu$+(-D9sCkWP2rEGfCezE0H7a=)B@@lt7d{}n;$?=NrJ zKL`6_Wsl*iU(fcv`T3xGsp{TQd}QA08|RNpnfA<|Pxo&5{&uG7+%H2{Uu4P;O#S`B zJnzH3M=~kSx8Z{j8=(z7FhvWQw|B)hyjQIc0K;84NLudnm02}53?Tz>}EC5(+-1Rbh66G~*T)C&dA*_+w1Wvu2Dv3*PGB-An+^xY%kSje^^u`u~rp)lE8_AzgCrl9!afv|BjsUHr6bhlTP-FjLQ{j3^V@#R&" ) # Unable to text position of the image as write html moves to a new line after - # adding the image but it can be seen in the produce test.pdf file. + # adding the image but it can be seen in the resulting html_images.pdf file. assert round(pdf.get_x()) == 10 assert pdf.get_y() == pytest.approx(mm_after_image, abs=0.01) @@ -83,8 +83,8 @@ def test_html_features(tmp_path): "
idnameidname
" @@ -110,8 +110,8 @@ def test_html_features(tmp_path): " " " " " " - ' id' - ' name' + " id" + " name" " " " " "" @@ -160,7 +160,7 @@ def getrow(i): " " " " " " - ' Alice' + ' Alice' " " ) + "".join(getrow(i) for i in range(26)) @@ -175,73 +175,6 @@ def getrow(i): assert_pdf_equal(pdf, HERE / "html_features.pdf", tmp_path) -def test_html_simple_table(tmp_path): - pdf = FPDF() - pdf.set_font_size(30) - pdf.add_page() - pdf.write_html( - """ - - - - - -
leftcenterright
123
456
""" - ) - assert_pdf_equal(pdf, HERE / "html_simple_table.pdf", tmp_path) - - -def test_html_table_line_separators(tmp_path): - pdf = FPDF() - pdf.set_font_size(30) - pdf.add_page() - pdf.write_html( - """ - - - - - -
leftcenterright
123
456
""", - table_line_separators=True, - ) - assert_pdf_equal(pdf, HERE / "html_table_line_separators.pdf", tmp_path) - - -def test_html_table_th_inside_tr_issue_137(tmp_path): - pdf = FPDF() - pdf.add_page() - pdf.write_html( - """ - - - - - - - - -
header1header2
value1value2
""" - ) - assert_pdf_equal(pdf, HERE / "html_table_line_separators_issue_137.pdf", tmp_path) - - -def test_html_table_with_border(tmp_path): - pdf = FPDF() - pdf.set_font_size(30) - pdf.add_page() - pdf.write_html( - """ - - - - - -
leftcenterright
123
456
""" - ) - assert_pdf_equal(pdf, HERE / "html_table_with_border.pdf", tmp_path) - - def test_html_bold_italic_underline(tmp_path): pdf = FPDF() pdf.set_font_size(30) @@ -255,7 +188,7 @@ def test_html_bold_italic_underline(tmp_path): assert_pdf_equal(pdf, HERE / "html_bold_italic_underline.pdf", tmp_path) -def test_customize_ul(tmp_path): +def test_html_customize_ul(tmp_path): html = """
  • term1: definition1
  • term2: definition2
  • @@ -280,135 +213,7 @@ class CustomPDF(FPDF): 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_img_inside_html_table(tmp_path): - pdf = FPDF() - pdf.add_page() - pdf.write_html( - """ - - - - -
    - - - -
    """ - ) - assert_pdf_equal(pdf, HERE / "test_img_inside_html_table.pdf", tmp_path) - - -def test_img_inside_html_table_without_explicit_dimensions(tmp_path): - pdf = FPDF() - pdf.add_page() - pdf.write_html( - """ - - - - -
    - - - -
    """ - ) - assert_pdf_equal( - pdf, - HERE / "test_img_inside_html_table_without_explicit_dimensions.pdf", - tmp_path, - ) - - -def test_img_inside_html_table_centered(tmp_path): - pdf = FPDF() - pdf.add_page() - pdf.write_html( - """ - - - - -
    - -
    - -
    """ - ) - assert_pdf_equal(pdf, HERE / "test_img_inside_html_table_centered.pdf", tmp_path) - - -def test_img_inside_html_table_centered_with_align(tmp_path): - pdf = FPDF() - pdf.add_page() - pdf.write_html( - """ - - - - -
    - - - -
    """ - ) - assert_pdf_equal( - pdf, HERE / "test_img_inside_html_table_centered_with_align.pdf", tmp_path - ) - - -def test_img_inside_html_table_centered_with_caption(tmp_path): - pdf = FPDF() - pdf.add_page() - pdf.write_html( - """ - - - - - - - - - - - -
    Side by side centered pictures and captions
    left captionright caption
    """ - ) - assert_pdf_equal( - pdf, HERE / "test_img_inside_html_table_centered_with_caption.pdf", tmp_path - ) - - -def test_html_table_with_empty_cell_contents(tmp_path): # issue 349 - pdf = FPDF() - pdf.set_font_size(30) - pdf.add_page() - # Reference table cells positions: - pdf.write_html( - """ - - - - - -
    leftcenterright
    123
    456
    """ - ) - # Table with empty cells: - pdf.write_html( - """ - - - - - -
    leftcenterright
    13
    5
    """ - ) - assert_pdf_equal(pdf, HERE / "html_table_with_empty_cell_contents.pdf", tmp_path) + assert_pdf_equal(pdf, HERE / "html_customize_ul.pdf", tmp_path) def test_html_justify_paragraph(tmp_path): @@ -496,28 +301,6 @@ def test_html_custom_heading_sizes(tmp_path): # issue-223 assert_pdf_equal(pdf, HERE / "html_custom_heading_sizes.pdf", tmp_path) -def test_bgcolor_in_table(tmp_path): # issue-512 - pdf = FPDF() - pdf.add_page() - pdf.write_html( - """ - - - - - - - - - - - - -
    CareerQuote
    EngineerThe engineer has been, and is, a maker of history.
    DeveloperLogical thinking, passion and perseverance is the paint on your palette.
    AnalystSeeing what other people can't see gives you great vision.
    None of the aboveI'm sorry. We could not find a quote for your job.
    """ - ) - assert_pdf_equal(pdf, HERE / "bgcolor_in_table.pdf", tmp_path) - - def test_html_superscript(tmp_path): pdf = FPDF() pdf.add_page() @@ -602,7 +385,7 @@ def test_html_whitespace_handling(tmp_path): # Issue 547 """ ) - assert_pdf_equal(pdf, HERE / "test_html_whitespace_handling.pdf", tmp_path) + assert_pdf_equal(pdf, HERE / "html_whitespace_handling.pdf", tmp_path) def test_html_custom_line_height(tmp_path): @@ -622,7 +405,7 @@ def test_html_custom_line_height(tmp_path): assert_pdf_equal(pdf, HERE / "html_custom_line_height.pdf", tmp_path) -def test_img_not_overlapping(tmp_path): +def test_html_img_not_overlapping(tmp_path): pdf = FPDF() pdf.add_page() pdf.write_html( @@ -632,7 +415,7 @@ def test_img_not_overlapping(tmp_path): ) assert_pdf_equal( pdf, - HERE / "test_img_not_overlapping.pdf", + HERE / "html_img_not_overlapping.pdf", tmp_path, ) diff --git a/test/html/test_html_whitespace_handling.pdf b/test/html/test_html_whitespace_handling.pdf deleted file mode 100644 index d19931d27a5f81aa2f4444562aff65942d6026fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1885 zcmbtVT}&KR6b?b_NzKyUPR$?QVCWEi6?B_OgtbouM~0x>)Cca% z%sq3?ckVssJKyB^y!AvlUz9`JTp%nSHy{gDm?XulLe231i(AvH|kSPQJL1F4m*rmU$+OhAjWSq;>f zqF?}D%v59*82}Ra0JV%&CmqpZCZK&P@@PsdswT|XDdCgI>XA%I(IS?-1dyS{^j4f#utJiHSnx<_3Qv?36Y2Qyiew@$YSqGsqU(?vG1~#>aF8g& z)R7dWI?s#*r}p+R8RNHtSNCO(EPe3UXzsvoQ$4o)+VtjARZZ7se%V)4ICcBNF#Pf9 z>fAd^Q-11`9mg-dIe#5?9gA%0$v&QS^w_z0-}%>yU+;=;+eFRIm8SnRu{Aqw>kGRk zy7S)}w2kaYzm}O%5LL7O9;@yQHJrWk-R1b^U-Pb<$fJYXFYWK&T=m?OU+!%D=Ce}` zTMi$dU9|Vt4HP^)*qiYv&?bhSZ+y}A;p`K4zwZAio(;a5dt^+bdJnwal}-2EtK7?Y zC%3-Tq7tT1m5Q4ts}VpSkkv}nkW&VV z4#rx{WhN75;Sop>j9^&UQ1XBjZcPbqJcIKA8EP=u<<^bo;MdK8hhLYGzHxXmPWMNK z^uXn!MF>cH@NkPPAXOx993ZzPZ+1Y=6u<*S`*p1~h)fWou|nbYp-$Yynkb%1ck<~; zK5GtHILkl1(chHzSdrE$B16$$gkuwm2$F`22lf~+~Dwb#Q zJyzKS78l{aHpr}FgAj9Kl^@Hk!Gj#L=6ul3Sng)(lB{6rl7CoGK8i?P=zyk~fD{=M ztVV6q08DMXAmn149xp2jOoHFy4@^SY3F!WaP!bn@&6vn^fOFJHR)UBMRWiF diff --git a/test/html/test_img_inside_html_table.pdf b/test/html/test_img_inside_html_table.pdf deleted file mode 100644 index 462939027012b6ef0383d9f3f12d520ee6188079..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14797 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 Yh4pRhelyR?&d$Py`sR(OoEYl=0n>R!ApigX diff --git a/test/html/test_img_inside_html_table_centered.pdf b/test/html/test_img_inside_html_table_centered.pdf deleted file mode 100644 index fa6ce2c0f4d9da836ec9e990bf8c1b95d33cc642..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14796 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 b=Z~|nzKz}Q$a8RUv2$R)cp)MG2J`;_(%3}C diff --git a/test/html/test_img_inside_html_table_centered_with_align.pdf b/test/html/test_img_inside_html_table_centered_with_align.pdf deleted file mode 100644 index 22db3f56c913b25fc9c7796c06d6353b29174ae0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14801 zcmeIZbx@q!vOXLL5F~hThXjJlAcKWq!6mp8f=tlC-3b~j5PX2(F2M=z5MXe3cX$5{ z+54Qc_dU1n@6`S0`>MY0t*M%Md#!%DS9hS_`Gdl|>Dmx_`CHSKms(=70 zt0>sP%AS%Pl~u;n$c|DQ02@-$MP-#UHZnC30XtJ_v%w@>yj(0CKuRDdI}4B(Hmc%c zZA{6kXaF*{Lw)lG)!54D5su?8unN}3R>Fq%reLc-F)3N!nc7QIS~*x)zyKaqWer@w z4)&C+3RcFVU<(IJt3Skcl#lKy{lkc;fxUqR81xr2k1qbpdn04imic_owb3jv6Z0h&< z9c&GaVXi!`{-3@)di@ti9&P@^k$0vR_QtlbMOqlx8;cnmf{lz(S!Io_K=z*~*}1qM zwe0L|jSVbOogoep{HP+r&&6-5L$u9sqh&c#)l>%M@JR$26J%&TQ{xE-d3$8s8#lw zL`(3^6ZAHq{bMHobo0-ga{XnEA_jKG@4&Dyv8tF_8rv}|fh`SSNfWn%t=7~EM9Hdd zY9(xCXZjBTDyy=?NBiHU@>npi8vCPe9x?tBM()3wFtxW+G`1B5TUvvy9y0=btWXQE zt+KU&p)sX4tCW?Iv9qz!U(!bjV5bB=W(ihSe*_+uOiR1RB2cu2Rk5Kx*cO%oSkfPH z9;@r|6Rg}|MFW6|MgGm?V?q44`IIy^1%0xoAtXdsJAEj9@hZGyS)k*weN2%V)y!Xx%j~=kC|zHotjzIL40mF?gF% zsN1k}1q;V(0O@DAlRmF%?5AyB4|i3FG~^xKQ-^G}+ybExbW9phTigG5D=Gjg$b0f~ z&wnss}#H49N zA}}k49u{|NUm)cs7q}4A!JNQ(5u@Aa6z=5%uxfR~>euAPPF=NTuN}}#3uuqCp?z;R zt^$_Ye$Un9UH+20?^w=Rovb<#m^9S3_rPXG+_*!R!z%22lzdZT~~ zR?e|N@?KaMz`7UH_lEsbO9thMigvM_?y5YK^Le#Qbz_zC)SXeKDB!}C^X}`uhI3u0 zZB4^D7bqvN-|VfL0?4$@>BfCy+(ptU0M+h=;wM zl*n&OOORQ9)8UyGPRAQvQ0bs;${R+u78n;mc@kSXR8UJ(w)tvPVFG&~!EUcE%;|H? zDVLWqa@2fXgH*rnkDyJ8CgrYZxAv`uUl?b5XC5OB_d~*sM9gW8>UQd*bHkc*^-l-J zj$VRHEcppsgCJ-eEO9O@)k51|Cw}N83WOmL$1?&w@5*m(gXP*Q;^sz9ITlJVe>6SY z_#*WCU6E)r&2l6xZ!Tk00$X*q%P?y`R(D{Y%DC!%$56f!v|rf;42>4ek$hJ~r_;8o z?)ti|^Oi|z3#^%B670A*Za;LUbD+cJ>cHYC-w%y*>&Q~h(eE$AsHgj>{>j|PO@2XCm8{S_OHS%eOUhccD)$*hg#agXZF>U7l zc^x9CBZl2Tf0OFRY^?r=FK#LRc`y^<8^B(Bx|p!|%rfr%4~S`9;sY$8`X#8D7^{X+ zwbFcjbrD+nv5)Q8`&*{WHU{5;+MhTGE9Jko4 zk4d^GXFW7|gL_4Xe^U)+fH%7Twdhx)tQ}j@_SonLa4+~SO+|2DDhrmHPJ@6A$ZjS zFw>W}5w-zU7r0s?3Wan3e-pft^V^}lA0I6?6Fl8ciLhff^It&v${L@RNx zY_xUe3dV|P@uLwy3Mr~#D@;S88Kz?3bl$hAfb;EQC**J?21fvUvDbSzxcjnK`3#ZK zep`F^s@|MxVP{X?t=1A84E`up;?fGi7)1aG>`?CtOxUPCVx1WX?cJPZi{>2Jv@}t5IK%Hph$7DB@E8M$;-2I_T~l)sI;hwX=K35K zV2f-Tw)*_N*wW`FSCY(O&to4n{LS_5x=q=eAEyNS_*n@Z#6acDAyy5p>?wR}CpQS* zXOzJ549(9zDEx=Vh5J0e5vk2iw%>s6Sqqiw*~Yg9CZ-z?$fnldgqG6If@N7+`;>cM zTED-$^x&1MH18eU5BDew;fiK;()fJ;Rh6c+YBXTs>>|}s%UjN82BRvsPhQ0|8^8uv z7uL9N`DcRm?PAMs|~|tPOz)q~Gb>x1(hh&^5{r%D&SV!n)!R zt>LWaJ8*a%xnWh4+B~4^P;;QGl6#=EsK&>2R^_~U*7PN#Xv*`y+(C(t~jb1(+aS@eVqmN{h6Wq#BpikM|O;Zb4)c&IN${L<0Su}b?gxdNJN=g zoi}OEHc4e~-%UXnq}ayk{@zE%2cZ{%g2v*k0g+4l#dT6IG%ZxUTq(wa!^bL@Z_~SE zeYt!-AHId@vc5+%b2!r9imiF`7Dcd)0Fx#lo9d_#gpro+}C(2b=xfg z5tdTGhna%CnEGal*F?D6D8diy>cy@bn(=(jzpe100Mrx~lxx;LOKLuEoT%TGU$0R? zr>Ag^)mwc{;k=A@`^7UzY=EJB^=a?P59|`KSru@N%OI-`4m;n3p_E*gXvhEfXa-}$ zBnWc{ZN_CJ-g;8lcv|(L{w?fb@7P{Apk|t`$DdU0`QfKQTlyBgm~Mrhin!Zk8ZiOE z)NvPUC1_d=I=eQ}1^v>=ws0bwv0MHaX{Aw{qRPIT2Gx@M?FVd?w3v+X5{ z2SGPI+<@+>&=RO80zrITelyDjKh(Svi}wakrAAgr@ch1|e53NiDig*6@BGWa!Pu?d z0rR$QP15u17EH`Lmg}jLX*OH@XE$}Lw!IUs2fz|^8jwx5+!vwq@F|$40Zfy3KPZ_T zZ8BBx_t@kX`r=NS^KNny=no{8!=L>b2jOqr^hn-8scpXUw<^>NUGKUu6Y`Rfzk>z@ zel1@zShaBepKmV(p^BFI>KY3AM{PYkb?4d;%cu*+J;CrX-Kz=Y`ngK|WeWqn=pEd3 zW^mNImAm3QR8ZvXcd+3Kr`lu@qR`Sb*t!b87kCtv+Tl(#T;uv&Xn7h9$jI<8qI()y z?l=@rxOs~7bg{7ePQmG`1BL&*H}_CHGE8>hRKy61_xAP-X-+qc@Wfo#HKCRTA9_yw zv^5#Sp}@IJao8CGi-d|f&{(s$H<^?10#J~5ht~9mlhus%=LW6=O32aarv~^VYQEz()l%>Ft@4Nz%9z>1#x}(bS>jBsN{-aW0EL+Q%Ymqx) zMvVY}fIK(dM$tSQhyd%XO8341W}StQwqE?WMK_8RFAt&Ym@ zg*i$qA*+m$Yos|VO!fZ9xTNnrPny3Wd@oBFj9HMK|4a{6eQD?Sf*#vhY?$P-c#Po1 z{Y!#UUt^8S*3WGYC>tC1!q7%Vb;b#fw=t%^1;fdCvR^bj_!&WxQRI-y%fzVKbU|W6 z#;nAOnxk(|%#yfb%vf+4F?NAumT9S}-#Mf55Veyx6C|Z3Hyg``XBtrUDWm$(&+1

    5x$kN&qqIXmPOn}3v~$Ig>hP9I-jYH*IMb& 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 OX`@6{RQB1Ji~a_ES5{O2 diff --git a/test/html/test_img_inside_html_table_without_explicit_dimensions.pdf b/test/html/test_img_inside_html_table_without_explicit_dimensions.pdf deleted file mode 100644 index 78983577fac863fc2217f3c63477ea3827f9a727..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14788 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 diff --git a/test/table/table_with_cell_fill.pdf b/test/table/table_with_cell_fill.pdf index 2f4b5ee29e2fa2a787087a9173bf196172e7df21..09b460e65fe04f1ec86555f5cade9f218f6e62cb 100644 GIT binary patch delta 1407 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 O;bMY7f`YVhI^-|XVPt^- diff --git a/test/table/table_with_fixed_col_width.pdf b/test/table/table_with_fixed_col_width.pdf index 6d0b291e5ddb94b6147faa831a2702fa4dcefe21..88a4e7c0dd242276ba97935a2e5c5ace361b585b 100644 GIT binary patch delta 812 zcmaFC^PXpe17p3R0hgT}S8+*EYGN)|#hkfQ&*$AX;5qibmP__}cUt76|1!6eY*}R4 z*3>a3p53)(Bl8W;wtau+9G#?L#C2KrWX;bX7ynpl9(}cJ!Zxw`ym!_ge+F`fo?Ikw z*Z<>E>#e7jgqj6KU)0cDE4bHUYU$#>r(rhSUv^&lT&^82&zh;OQQvX&l7;$=n<`V)pM7z58BZ-re^8X3?b=H|0I>0;*r(expmALvEUaHStOJkAtTmas#%ssryRX@|Kb)M4!69~bs5le5zdW!R7$lw0Fd$KoG-tCQ>1!{i`V z1u>fd^NyI_s=$12sAtP#|Eg`PRT*Zh6{fR+Qeq6YprPS_Y`foAo2P3j?%-Y`52|v zeOkXps@gR6$2xCcooUA`9T~P{t^RQN{js-Oqzx7W4T=ZJ*gA!*>gZ`&^F6OZx#!vP z4>b=j>zRJ#@LZ{6#5HM^nDH$6`h%aRmNhk1waf?+lw>uWUp9G%blmj^`67;6ri8`w zO72^`zO(hJrQ?$=MvAWrPZ4QB94zSQn3e_y?h%U{B7-TIa7 zS1nl=n5bRl3amaBLi-nhHz{0KHXW-2eap delta 793 zcmaFQ^MYrC17p2`F_)bkS8+*EYGN)|#hl)$XY+0w2(-Mf*7AvE@*;J%m@9hiHopd@j@JnIXzS@@eG;{?FE%x_J5uf@xAXbdId<7|=J9?!V(oFH-YCM@XX}y&i_$`a zKY4BZHnq0Ois$jnuiI|dr@ei@GqX;xY>L;XRc)z{JIgQd+@EH(Y@5@yJ(>x3)4Ojy zGf!;4a(OY+wqEsnj>a|7uV&nucB&xw(6;aI_odgdmucMnu&KosqH(fS8rzmfL5Jq` zw|{Qe-qmExls$3PPDz{knw;gHM@l!OalDyz=<2=LzTbk0yEiKL%h+wcY;st1DPKcw z#;;4V=k^P1l8*kg%)_2!cB>zBG>-9o#c-raJga)!?i=^^ zU!F1Fwd+;dz7L6W)da5}oTaE>6*+z0{Wl*PIepikxZJw_mC4xx+m*}$QeE}`Hr&lT z(z0y(lb46uOJ}9+SayYxgV%TJv6f}wPhNJx%x-C$b-#V_+jxJDfcmNbFJ1YSw(CQz zxUbT*gR>4YXGuM-|Mj*&#@{y0WUuOZ@qMosWwx#Nl5GsU@b%!gdXB{}bu0IM$Q1WA zt_gm{(bKeS(ZL>|=|8)G!IooO;|mg-b$7s{?{gFFBm;#m;wwG1utNr zaDoG6i;pG4(uL1_UOdSE&wupo#pccHnO`y5nVKjVfPg}t0vDKJU}#`!j3H)dYKS3b zWMVP-I;%~Lsi~W*lcS5Vp_#dYfcbez4|1!4|ZCPa5 z)>JYkpWU@(Bl8W;wtasm9Tn2tWVBiKWX+Es7ynpxhOVCN^gHVBzMavl{lB}-^b&84 z`X3U1ZTd9dsBIU|tv+V)*8A#e@5t-*r{`9MJSh&2yt{3o9rq=_ka~meoge2t5IHTG zD-~+qyUu%SU6A~{?TnvQg=UzYdDAz8ZKcD-xK>d{Gmty;^Skxgr;c~ciysr9(=%iD@DH<;qI-j+T32QviwqzZT;Zs4Q+)Q?nJBL$6J0iX~>~>t+ zcUNG3=Be{b*W7yjb5Z-;>@-93d%_HhT+jU6Dt%vL;ZH%M*e|P!&)O#Wt#fE`s=x3) zcK>{!uqIG=14uXsBz);ou+wMdlwH6OD(IJ(tSzum;PdSruiKW_a%sdo4f^%^<)U(4 z)6E|u9a*-lda!!Gbou2vg&sYhi9bQ&-#zw-9O9!LAdEQ@xUTz7WMm(EH{+{E7SXvxp+FzSc6E`MOPNt2ixxP|0FWgpz2OQG5_RH1uw;w##1i+;h4E$3p3Zd#7$f- znn!Get&ZLP&v@@`SX5F`l$yq6Xk=;0 LrK;-c@5TiHdJbHd delta 778 zcmcb|bAxAt17p2~IhUOsS8+*EYGN)|#hl)0XY+0w2(-Mfb-Ny=PaZTQq(5vKNonuy1C5n|?ZKO&(Wf_Q&_n77Ca9d#&&iYkg7I z`TlO@lEoAAmTX)U=yogU%OjoFzxLnhGIz8KpE@n~_1BXE{!PuU^=F#B+mdw`FUfMb zYqCkt^}F6a+uUQB`fS(N=evG?e#K;ehgC`R=~YKkAA1&j=(#Y>x-U00H8r{5Zo2!e zXXb(KnOm-0T->XE@Sw3%^g9dN+lwZo_TIi%-!ku~?3KjTUfbBd_kbn+-&uUq>7DBJ zcwYbPzsvQj7}J@q>74yq|KMVB^;spKOAK$OE&TRsL##i`?N-^!Cog91eI}{)(&2{F zp~dN9`1SW{^1&AcXmCj6=&uOxAd;Ijs3DNZZpSh z6BdWnTy?+h?wDJ~oLG|R4YV~eP4pW?h7i%m9`s>gmPK$~*FDrqi0iRu7 zNaX!zEzZ0mvUwi!D@HqG3k3rZP{>o@0y7K@4UEk(#0-s1F~p3FjV2#swT?A$b91pY zwRAFfaddWda&a>|an5R; zxX59#yo5>Kt80@OPr6Oqzn-V_vx4oi+fyBXJ^FOXW|P;(o!U#*9-Y6t-LIx9$SHJ_ zhRb*7ns?K}W^R$v=2n(ky3}-$xOb%atC)93yB+SY4)c8bdb7gYih9cUS-Tutj?LVu_gje>HZ++u7{qmuJ^LwQXAHrl4CNxn4aiU({teE2}r; zWYGC{`^z4EPH5HKk~4YkrM~b0{{6zCXD*fmdITT0zPtbLW3w8eH5*n4>@=8^O}BbSP~-GC_5>O+3=^JO>U;T#tQZ$OS(F4ykIYF zzA@(xL!zL4_R3eYe;#UYofV)q6lans?PeqPP-mS^rCN*=Cu^0ie^4|S<;X0Mxx$K?uTC+7+5DS zUGuCz`sJbW*zBZ@W_p}93qqrR?yoa{xBPH}p|Q7mWzKx z=IPhm+PX~6PBWCnZSj&-M|*(os99PsyMBS3of=4N#`$*7JN)^#Uzm0&M0u~yZ{xWy zmX(xP>L*~awx_@9*Sin9|DEEQXHXNlVrBbPOIMdnk6$}pAO3vA{~_n$7kc zrrx@Sj5}A>sxnXNRjQAdy!63Pxhsy;eSXEsUOJf8XEF;$QHqnjeQeIiPazMd88 zdr09f zPtF^idX={S!{I|dTF;I~9ng-ta^UA#zWFyUeCga1`y&)+#sN>^#)WcU+TZ#q*PEHt zs^*K=Ma;-#p8zyxh5A)C=~;FYw`-+lqe8)dtNp`;+{;BR^d2HIPhXI*~tfe;C-TJ3r2sHh@c-^hk zWwL!!)b=c9T$!_B@k`;#{f|Il*6t}>fA1p0=dUK4+W#fX*YqlNPP@2bw(8-0ZsU~( zTB0B3O}n))t}g0N?EXUKe2Kcq8JX>YD_s&+s@GbT{ClriuL=~5feVHTMeZt8%8%Id zk@Hq!h?Zc)E5r3|eDB`=XWkKW=`~ksUJ5jo0a^J;SzM+H1`3-GFkfY~HBc}B0fjsT zE-=Hu(7?nJL(I^`97D{=#ANa%R_jvE~H&Xz__u_=k^iOLY!B}Kom+3?c>Ue= z_laLW7g_v}@}JB1?v+B&eC5d}f(NFDOm;B&J4Y#JwI2U?;otPk zC2q%eoS4_5_2udP)F!uCoLq6r^*+toLS|h~FSz_4r+w}(_R#G+qgcQ9Z`;vF-Mu+41wrUoS4+f8zUz z`wCuD`zv|#r)Xbz+U+O*{q|-4_a^sM{mt+01`59i3Low8oBGY{v+k!4^-E{2cwoB6 zcb&tXMUC5Jb$JZQ*PVx~D-0Ly-{Q2DfPMmY|CNA&JyLx<2 z+xL^A9TzgbMDMnj(Oh^r_EX8lqrYZc|KPWiNlje#2;IWT0RG0t$HwTwsQQ zp`oEAhL{l+F=Ios$!u)av92a22Ih{Aj+PdtuI7$TZU*LtCXS9qP9`oEMsAL#u68yA cRm4JaPGV6>MNw)Rm!Yw_IhU%ctG^o;011eM)&Kwi delta 847 zcmZ3(JCApR17p3ZDVLocS8+*EYGN)|#hl)$r}J(*@VI{e$E7#hb-C18=SxPMvsx!E z%6KdUF?EUe!-b{DeV^Nmu@YMox4qh98H-0!Z=>~5_uKkla%ZQCL& za!2{iG0~HEyPRHdy)WDCxy`Gd-7jaVzl-RxsEZnVLT_<$y%XH_h-=T(Ft-yz`K9}9 z_Z{Eb^|9A?kB8G9?b70}-3wxV&WenY3U2x_E$883egEBG4=#;=lK$l7vYsEas(&nq zX_RyG`E@0?e}B!TKT~X0e|fj>nVg+wxWbv_pry5E{&d*XWU6cJXzxEM+7bPwbz8ly zj(@KFzROeO!%w}++V>){_NL>v)?4Ss>9Wq`Ro00Y zxj@JF%o29-Tgw;de_r?R+W!e|^9-sY|E zSrr$VsD(}n_;s+uCJ`JkfyG=dnLU+iB^=xTvj;Btdu8)0<~NLX24)HdAfS+^zy)R) z7#bRwVu%@G5i>S0nk>R*9cyOnWa{MXYGPt)ZerwQ;%H%NW^Cr<>S*lh=w@kdYHDXg dP(>^xuOt?gR1~GAaTyw$8FQ(sy863u0RWRxdZqvX diff --git a/test/table/table_with_images.pdf b/test/table/table_with_images.pdf index ef92320ae88903028ce14ea459c5711d32420f24..304a44db8af3530925edc6d7736edb54961e34eb 100644 GIT binary patch delta 1683 zcmX^5oaMl4mJKG1jHZ)K8C~kl47lvnUv|l_7G1Il5qFvGSs5+13wN<=4OQpKTgrhg=Ez}D( zs-*8}T_(IH(4fAt{QK#%W$evw#os6XGj36TzVPuBu8XE;R+KE+BP?=5`Amzbo|O5l ztwyr1F8;gjQ!+1T;gSTU=-_*tTyF%^4s{)#_iENkwYe`BZeRc3f`9JPkc{LA^~;r? z`~njC4fw-$WO!vAbG15ux9EFW;vA-D8$;^vUfnSL#Sf{-Ia1GAK2{oT?YF(XUMzb4 zY`bQ*9Y+pczj2uTXx9_P4$t|&p1y1M|0Ug$807HQE-(JwtfkM^tlfLMnBSaV#%|ri zY*+O~f_e)-n11^Ztmx`mec{E^xhoFH*|CSI{7~DT%|7Gp+XwnP8Zvb%i%oN$POI(J z@#`&aI#IuRa-XIB?X%IHufGVIWIerA(`#Gfx5lHO*Kz;Ny1l(ScCFQz`DoP~BcJ*s zp-*=BsVfCK3;d9({;_hxqD8hDS3dcLB=FB?))tC+{I>4qnl~Rd>1FV0TTNSbHGFZH zUgesJM{iiDb8MM)u4Q`D-8I`@FJvkEB_g%0s4%(L)+uC7NBse{$o#h-v{|q1-LUz7 z`1ZqUF$V-AW-?pP?P%dmG`My{*{4-R^sVFJY2{5!)h#j+f{ng;-wXG)@*jS!RC!y> zrFZGHaN%&hTh~uGoz`@0xwb-}^ncFj{Vd|=78GiSKhJ)%@aYsKM>Dm((ceBkEILu< zb4_y7uMhHxC6-F7jZ*a0RFn#x6@VVfuw1wzgI{X<9%0cN&Zjk9n{xKtWnMR%;ZQuc z@b?9i#aSMUIOde37Ud(ui*FTo>^T)qmWOMrOo%xIX&q?!q;5bt3bJ_P1@1vQ%!H@U&%Ot4= zs@bW_U4Pkhq(5f5Ox@#{EjLdaJ6EZh`pYPZb;;_K8fd@d`e;(<5*Bjmdz$Pt%lyJH zEz@he)aw%s)~{Q#)2~>fP)D&*g~emV!X7Rkm(0+5Ps0g|{?6#GKk-fdr0T@gJZ^og zAqyS0{C!aWVR!Um1Jjo(tjP`kk8ZMaYdoNLVNLY4?;BH1{Tc2X7cAZO_bQvgZ_lc| zYhC*q{^dS+v}>(r^?|2+0(F;MVz;Qu`{plX*fam4`O}7j(F@AYzFfPt|1!IRbFA)t z2KM#?5fe9EkG;ot_wLQx`_rTT{$+^!STuj~vNT)4Xnjv-XQ#yC)D#7C1p|ek*vaqG z)F%5jb59Oo4PdmKEL)(x`2y>Ugvmkq+LL9Q*(YzPGuT2LFEC0(FApZFe%R zo!atlv1{&W^~Cl`O`UJDK6@5i=(#Y>>e%kJ*~?~adFz}X?|k`_=8c8DiF18sLv(7E z?pWrPbt5g=7=2V=Ho7{2v!5qa; zuhs%kqVymg_$E zcC8TP*t1OX-^z}~TIo{)Ppe;aG_K))F^_~N$dHkm?( zyyqmD)-E%CxHO@B_TRDt2hPn8YU9<T>~1JI%kf;?)z#)pCh-9yi59G>Ri)ST8LcSW$#H}8Al?sosfueB;~D=ku6`Sj|M zhpyGWN?U*-n9<7>dVikoKhJ`PJw|yIrE!;ebf3#`Zrb?r?ymm-F?=`sPFgvK_3sy4 zHbr@pmh(5K#Y%a~EG+9Y+ol=!t(p^fOn1Hu``HUc=O!vh=a(NT6?gc-Ut4+KbFvi6 zHs8=#Q$X7|hw?33qaXirWqlwvfTTvyn_ zYM@}C5Hy*u(QLDAkviXGi$aj(nq7ZFkVrFLI=xSzQU}$P)WMb)JXyoEzWN2t)Y3gQbWMJZK fM_5HHq-;toDyb++P2)1RFg7&dQdM>JcjE#8=Z)Un diff --git a/test/table/table_with_images_and_img_fill_width.pdf b/test/table/table_with_images_and_img_fill_width.pdf index 493b8c7bd08a140ec9e0983ab6d61d0e61f3715a..b97b74c3e04e2ec7a955b229ad6afbf302fe9f03 100644 GIT binary patch delta 1687 zcmX^1oaOLqmJKG1jHZ)K8C~kljJfRWxQa`PQWJBzD(1|cb~f*}fk4aqsxDhIakoEH zOL8u;bxd58@mO3y$hfI@fBw<6|#hkeuiI#*e}z9-;+;h@r=`h-&# zu3ic{A=Ks7dFa3=NxM61%YQR(Dc!uQ>8ZcY{5$Hg?N%Y79O;LqKH{{hV0(8&HrDjz z8jaE&SDgRGTQB_`(0KmJ=>gC70kc=^*9!LPVO%XMo`Uz&SK zAXsP5Gszv|#VId)Olm%|$l5Sh7aZp(sMuG^-JN`QUjK{-CLY026IY)uSp5BsY4?Zv zW=&?H?B3Vsx4r+l^xj^j0=lkUYW#%DKlZu(bTo0Tp z@j7(O;KQu+2XSX6E;YWi;iz!Q2c9CaYimpro;x9aIN_r`6$ zu5*Zg8PAE;C$$qlJ#1fiFZbK+X$sb#rCByYOn2Ub=JW*qcM=nM&wWqa-QNH9wAPQasy@6ynYvuH zlEq(E?M)M`Ge~vF3B7stO~BV5A(!phjL&;8yRSc&J+IMqXL5^KM%C`TW7oCYwpmxE zd!FNr64rFIzO2b9<9raPqT0}X+BpwqabUtQ-oReobAj#oZRXw1BLA4!W_*vIEWz?v z#4)ENwJ0yKBvnD*CABOwIW@@LX>uN`_~Zli?DfXxW?cGy3aAOXcA~AvVF#I`@zLI) zT1sUaizY0ziWCqnoT4Rm&?!@U%d3Qq%wOz(PMYTf$B|;6%f63zAIK?~zxp~^yxk}B{Uq(r+OID}UK>H=vN0UOAu#i*V(`2Vv<`;%(nO@taUY}^N ze%+Fte#H`nI*N@dEFLQs_Hg;QWQNvz8ctaBcSd*piErvBRVS|IaqD9ZS?I9k?}Pde zyQ3Eyn7&kDO>X#qbd#N1;{m-3Yof1x-)O}wFZaQt zU28q74?N`)sJrA6yG2#rH-90+p7|HepEewfUQmAa<=U^;7_cW>U_pC0x1FGJkNqWP1Tr`ZZd>w7voJ0%vUrYM*z7$^kAPJW-JHrcP4dvYji z0Hft(xdQFUed&UmAF*Cfm>it1Jz1`qee>(I435clbvl#l@}<~}VA>2PpU?MWG~6s# zkjOWAem&3T?m7`hMx)7rjOv?@*XuA(UOypib7XTEFQduk4HHrqFq%#mGh|FPwE!8w zrSEB^U}ykk8Y>tYLzyNDh9)2;unYvE)V!4Zq%1B&v+3&%8C@97r++bI%&j*!R4@Pm zg**i=FvGym&>UzMnwXIp&?+=Ba}%INC}Kut<`zI3QN=7QEzHowjEyXycElqrHa0c{ z`3FU_v55i5W2j>0rbg%nnp>D!pzAfaFgG!pu5HXHQ*X|tAC#Y8q5uwWU~uK7aj;i$b)GiGic5fwPgRrK!1zvxR|+i>ry5p`n3^lYyy$p{u2#9bpx*kg6uJsHCDO THI2*M!ot9WOI6j?-;E0Z%*&pD delta 1204 zcmX^7n&sGYmJKG1j3$#!8C~j4Ex7FLxQa`PQWJBzD(3V~JDqpiK*06;udc{#(rz_g zQD&LUM?3P`vb&R)O>MtHh-k4_Hw)<>xV%LVZ&cXYWE`QOyk~mj*D&Op5!X+Pg za!$$C1}|PaK`WZq?|ne|=%`>uF)1mz826b+=aj7Q4#&&O)2jcJX8saiVs*e<}Cs;Jc5$JM~=F@Xd5xx9)K7yPMf! z57~>^RO+uuncsPP;dA!hdgTLpG85Z+*PYFt*J!&lnaND!*W$cghix|eZS(RjI(J|d z$BkA$&l?hKKsVLsJv(tpGV{hGPOA#GZx8x7Z#<~m|F*pJ_obtI{JgEabGKYLTDsw) zY4us9KMCg=_RQKNq$Xc4@#^op3tL%kwgz9?aq(#7S>p{__2oV%*kbcve>-n|Ldufm zh-G?8Y0Dd@>>mEy^!$NEcMKh+P4?b4yL?=`ZQK6JbkB2=QNoV9FKBYA$T%Ma z`uF@%nMf;T-WVH4_VWkiK+5mDXLutQ_=A6&`F)PbvMi4$ugOrG%-d=**@iuU(PDEi zyKv&<^K9CiPiN$FOkR+oJvpsViqUX#V_^%cfr5cT&}6|zv&{}g>U@)}3$-Vo&ajz$ zu3;xoK_H|0=Jky_%#22p7iJi4=56iboqW3`ZSmhp3m8qN|1)AtH8BV2=hF8yQm}-w zj1>%xpiC15Lt_vVm}!70H7_MUDT~X{bovZqMi)l2>35A8bL-8_6bwK>Ay0t|%rG!C zG&98zGcp63grd&K%*YaGJF1w4i6zh-C}PG&#uh*ap^2H91APtz-Uy40jZKX(6q*|t zTcBw+w=e`c7u7&>3nNqG=^CbtGWBL$`a${mB?_=W$V(KeRmrsi%Y z1|}}fMkWU4E`|mcF0O7S#+HW0j&5e=#s+qTRm4Kdp~Rw+ilWpsE^`ZGLsKqQRabvE FE&!*c&mI5( diff --git a/test/table/table_with_internal_layout.pdf b/test/table/table_with_internal_layout.pdf index f47e1eb2f7bf2408f76ec1fc6e42d014acdb9331..e07d611257f3786ada2668b56b38fb2a6485409c 100644 GIT binary patch delta 710 zcmZ3;vxH}ZBV)ZOmz^C~aY<2XVlG$3oV8QW=iN5oX@6hKC3n3$D{@ng{Ou%L7G1VA zb&QE;cdgmTe1o%XU#+mq75P(q7n9t%>?h7Y%J0d!dbLxC>7U)ZUO#x|*krOuW5I9U z`@25}&Xn;C?%LMsrWKg^;^5U%W&f{Y^A_f`too3kSMX-lk_o(5>T@--c<*x8RNv^i zEXQ_x{rZK!U#I`)pR-NOt-WRSVwb9Py+RosUsWklW&2zDf}d@orY`E)ck=2_^U6my zg;kFi3GC|Y%#XJ}d1~?!b=#0*9btk(Yqb2JwBl5B#@}XD(zR-KXKff_r=dcMc_qvL;VlKytf}V zDOc(4cHI6b>vG7-xOWM9555|${b;|s?2g~=MyYK!t=pUPj$WMZ)$Lt4X6|wI10c(^>j3dIe zrk}{LfBE6`CHsTix<9^NPCssS(7};O{rKNy{92!Fe>}Z3{kT;v-}Zk87OF)4Z)KYw zl_yac_2$L>Kg=%G#fLX1GQVaNHB&GE0fjsTE-=Huz|z8Waw4m+s4=>Xp`nGr`vWDq(;SU zGIDc?%nI>}QoJ`W?CX#8IY++h9k-fUZ1Oxf`p~OI39Fjkci$FUCvQ=3wu|YO`HuYa z{;6M%l%AZ$mZdji(uKykt7pxBrfcIIX}s`5qF2EkEsMvdA-*TI>N($P$Jphx74q+W zc`f`x-M__w!G^kf51ngN`j_Tac;?X7q^%r>ZKNitzE^QQc}ijJ+{;_^yjNM=U8*r- z%^@B0_j<1Pl}2|JswD5F8W-OJ+bH|qr=#9}^aTu>_XD^Iu-BKY9RWG>H)s0}AB zi_||B4di&DYcc(0VyVI2-4T6!QQYVDC^gKLU&bQ0Veyq`Ka$(zPhH>RI*<1j=ed`B zXJ%?K?W?(>Il(-seehSpL*ROpUU(T|= z(kw%}?Aq3@kDK^|ncAo4ZTTH(dbsS)*C`t+r`yPG5w%`!9djk*At(2yd$ay&E9Tr& z^=Dsu4ruUnlhBGoO-uGHY&jeKM zvDF@lU+OzHD8<{`TAvH#VL9@A$8D7oxu<{nYIc74WO4lYhOfV6nkN4e7yA>w^WLM7 zHxKguaaZ_6=WI@4e$8lWtY82F3V8}#V1|K#rG*i?n4y7%0fv~Nx%uQCR_j8QRn^ts GjSB$n@iGAb diff --git a/test/table/table_with_minimal_layout.pdf b/test/table/table_with_minimal_layout.pdf index 51b2610c049b6db5a6e2e74e0c9e663f3e0f9d30..5cae1d5c8e9e1cadf087b993021bcaa2161713d0 100644 GIT binary patch delta 651 zcmcc0eT#d817p3JA(x#US8+*EYGN)|#hkfQPUjsm5ODoob5!Scue80eKI2rcj#WV? z`6F6`qJ);Pgnaz2dZ;hHf%`P)(W9*E#MxSEXk#YYIGlc5r9gVy&a~9O4tan~K<;GRdjE zUUt`U?W(8BQ|`~bIJ4sW(TSEqXUbmOdimkL<@G|7V@>5gb50nShCeEibK_Jx=d-IX z{gv=>S=q-r&N}77{Nd(lzUm+6ha6~in8fBO@svZ@{A9&m>zK|-HVX?)<#S&56!(@pgrBR#zkzVeP>!; ztOWnecu@nFwFja%2YyYGeq^!t>SF=c{su11U+?`*XO~ImKHbz|Uw{7a_KQBUvGXUc zs#jVD)Xri%DPe|i@Nw4D6JCZgp1mSCBR5*&+UnFl-xu89;$hLdlj|DyTl*`#LUxSa zM~n?a)}F42y?J-3X$^;1mwnf=tXK`c6>;JQA!{Anx4g{!!+1UZ;>FFP%&!>j42={F zKtLf+feXwqFt9WDszieiWv8kkMCWwnlVvT(GpbaQocG%$2BHFGgDa56D6H8gj$ mFgI{>aWXQuvmvM=7Lv{qi%KerQq#B$4b9BCR8?L5-M9e4s00oG delta 646 zcmcb`eU*EI17p3Z8JC?MS8+*EYGN)|#hj^A&gL~ah_rsUI~u!fw&rK<%^|_FC1$JX z>Km-Qc8N=6L1xYGq&bQIL`o_@p0iBf$1D`#Cv+tE$Lupj6;TNXm{d8R#DADmzCXZ| zV~-EVsTGlm_qfDZJUJzobr@?np3iLa|IBCCkkV1~`N1Wp$00D(O z1uihdz`)YL3|-97z`z7U%+SDavJo1vMd krG=S`lbsDg6|s;cmRM9$QIwj-WoT$-#HFh0>hHz{05<0c@c;k- diff --git a/test/table/table_with_multiline_cells.pdf b/test/table/table_with_multiline_cells.pdf index 4282d976e4998c9390054f9ce169210686c05fd2..10b638aa7cc3a7dca4411bd2944f88de04d0fb2b 100644 GIT binary patch delta 2067 zcmai!dpHw{8^>$e85?uACBX^E18bvhC<%s5%PHrW) znFk@_U`HB?ie@x=q|Lofq5ApN@BDZA4ytl45ryeX3ldyo!2a_12uqwb-m5h4{jQa9DFbJ6j0 z3N_@~R1!?fKFKusGoLya(U`=m8$zN7uhmx&6m?rm8BG*}{dl29T zOsD54TG#Q+jfB(+m7(zbcQ4a8FN)!@TdTwbA5fhNNz2_oklD1ZCE=GiZ}_(aJ^pO- z4n{~!)=(+&l!sQAG6rQKYyO2Mt~&}ES5IJEVgcG9aOS|dkR!)wz{bQHzVArW?@c_? zX(J2ifjP4r^0I4K1l$tAJ(Z;5A}=RUdKNnAzR>SGTrkIEC%+<-OzE)i3y?Hu&mr6&CGdCn>b0(MxcA;-KIop7?W4Gn?UH4` z%+}=J5&~u66O*OaPpo#obE;^!aeF0*eCTkz*Y6oKJT9y@fYT{gl2*ZaT9w#*z^WR? z`LVjDigO?DY0$}w<{p$h*gteK{Ad8od+K;!X;sdHw?G@Hn$CgtSwjk`)w;IU zo>U)4HZ?e3qb=AAj414UDCT)m>k2jcZm`>do zkb^R9I|^=f(7PWF9Kh=8wWY-jJ#NN9KO{b2HF_$v7KZSihBwe~yvjNb~ zWUZTo0zAruiOgdO^Iq&m&qJ#EZAV$Le9=Gszw{QH$lR^7Rqc;Doq4UNYd$d|m*z5TX_pT#H%)f*l74N~TH{L@DCwl*?{`W9$Bbk`ioZ9JqoY90g-Q5`}U|pf4Y>M8w?OQGq?bLAvszFh8O)%KxXxUdIUsf{EL9Us=}R;`?ta z!cU)Bxy=dF9%J=vV+D1HPkYc6LN{SWU|h*(s4SoT`fH+myr94Mp{gqS#fpcNXEyr* z^mx=a;cpH_xREg?)X<+B5|nw(Zp_3Cnz|>l=Dd^Ub}q`Md{X33)5KKWrYzlYCrU%^VS8bvBlXSgQ@yk z`Y-!`US`T+P8J!518GMKP?{3J}2wYG99~E6We~yd` zV1tFJ;`ra$ucLK3-OZGC#0U5E+BJ!^=@TgC05L85LI1*%gRhq8PfaXFFzzvL69?=D z&JIg0EXNh?Pd`pvx}wa$4{IA=7LryuN;#*R|^Yv9}>rzQRAB%*vfZmcg4d-x7r zW_ASa)^du|5N>&7b&sK$6P*4nxGHx>nQItYtmieKtf}Q<>&V}guPk#6dvw1mnyK^- z>c&OdR|bH-vf&YwBG2@@5Z@NqlOv52dOj&Tq_#8d%74v1Enf^Bj`HH+lWC@PHo<=g zBYRHF{DK8DvsH8iIt={z*fJ=Xa>_w^~~R3JGlzkn-iLH zde1wu>?zI93c~y2yVbVHM1wA7B*F58dQ@OU)j{rLP3!1VCYc=vZ!fdmlOMk1Y8j1W zYg2+}^Q(Ww6QslhP0%!Wg&46*?n4=k3jFzlP-PJg)#UsO9suJ_717DubFFQ76h%2CQNk3f zQ%;Ffq@M!D+6ge@$CAy7`(V8@$-Im)I+aI|f{67bQ zL|c8Qq0lJAzc~~JiT_T+BCWsEtdN+3!w`Ea`VbO>B@%I1qBRQT;*2NZoH0lzYlM?E k5sgIPu>`ySOHluL909TMNwKsLFv`l>3T$LV@^AtF7ri04@Bjb+ delta 2061 zcmai!S5y-S7KWEVj06M}0Tm)hN$BY@p-M?;6Dd*$q&IhlZYY9ABy@r_0|*L`T zV8IX&2~k5pU=WFgh=QOZNFPwjurvEKKJ0zE=Rg0$|9|J)`&ngDrP)q`iUnI(fD=x~ zhXqA}ldI_rVSF`0f%wN(p1+AI;Ecp;cS629uA#v4{P|xE_#v|0tJ8M1uziW#N*1v}o-)qi(tFRqV zeozZ124*YO+q+d{qSL9}-9%4!mlwJQ(tajw9jT=W!@cm>_4bghZN1_PD8>k0+x#}3 zc$vqn%iDt;K)Yq#RM~TxjB#*NBxLDtaEf&&~Gs$5pzXKO2N_w2x_ zDao9f7P(k>P_;6l36hg?<-w8cfWz+flv;h)o_A8vRqz0l8vQ~o4^#>XnHsIMTwqVM z77Z2z$LfwfHz0W@gKn5v{qEdsf0KnQQT&K^!E1Y>eJ|@9#NI`Zb==+1UpMikd33iF zE_S@H=qaQ<&YA}(re?x|dWr^RT|4Y%F~;0We){_b*)tf)fZ0oW!_so*2P&9t5!|jG z-Mi|%d)G&(S4TL;i8eHSAax?aAXJNwu^!H!_V9a``G=;cfwyENckA;35X2YnPP<<% zZ59)qx{)~hJvBLF9VX_u2I1EX7{v>;=ne zMv^-md_Jt2!k5q8=$8_I*_BrLZKW}>%EpwshxeR3D7(>92ECg>Wb1Y8B*W_P`}%Va z4PD91r??IPk@r}NV^gG<6G;>RO-`&$`9g*d#?{Urd$0l(=(9Qq=4Lsbm`35MCXna& zYuR94XF&G;r;|y?3=`{BDk`qeXUV-#6`c}^c=}` z!g5G^$vGmNUN30Q;;;TgbzsXQ_8w;uM>b?;iiVt3w0Fuooy-+>T?%^;6OTTYOlmNZ z3pVXu`PxRgg0g!>r9dBQJ!Tv1^u|+kpf4`z@>0Tns%@V+7jvhG{C()K2h4tL+^PCW z=Q2QXx&a;+bk-*{hYb?#UxeV@8HT!lRz3Sj03b ztmC4m$`&ODAYRq)C&>%#;IF=K<(V-YU7CwEX6`_lrM&ULLB-*^(ZwOw}16~TD^l5zUsg}h{WTe^~r{t*ZNXrF=iWGmRW zh?Ue2=Js3WjQ&5@WZZaY1s9dlG^}JqUVmRiD20Ru? z?|+KQLr{X8RyEHEC?>WyoF57pGdRFYUyg9Ya2<+m=Xo($jW)`huT!^zzn5#JXY2gZ zUgP((GAr;5tuxn09Jh52sI+i6N7Z0sIZ$cQ&D!%>>hfcpVXu6IHqCoNb2aplr*ob3 z@PgYo3`qaNS?5sQJ-E5-Vor}+)$b@Dp4FM zviBbkKGZgBq$X{aP&gJ{$3cWZB07zb>MP5Gl3p!#ZGV;`D2|?XAjV-HhD0K6yjM8wq51pjhomf)E5I3MauSyM`#5o179*qm&*eFzGidO(C zt)g}xs-PJz>@^|2^*U2qfl4TvxG7`V|4MHvy_3Lo9^3o0EOTzh8Np6%O}piJ8TtS% z%p1;_;lo0_6Zr5zCh^ToAIq%yJscBP#TE;jz+Ww_^$p1!M*9eL~og5z)4o2aQBEUL2L}wECPd7@nmH+?% diff --git a/test/table/table_with_multiline_cells_and_fixed_row_height.pdf b/test/table/table_with_multiline_cells_and_fixed_row_height.pdf index af0f014118fa323aa3c3c162c74a2dae0d6ec824..8b72e0b386720e41e0305a6e44d07d3def9495c6 100644 GIT binary patch delta 1991 zcmai!Yd8}O8^@!0oAF={u^d_sl}gQQS(`iXb3Xo((UlbG6^7BWd`4q=nUhE7Nh zF^8xK&E^zuVa=&>Xn9PnB1w7nzR&x9dfz@g_ow^%UB55?`?~Ibfnl*>t-A^n337A< zMMcxeK~xZfe=Wa<&WGtZDgI1%B$3}LQQ$*R`pIZGG6fq71SnMHk? zx&a@D=U=9@XQu%_0bXrxE1HtWX`*mGfOi@W#awIBpIkW-2aqc$;Uf4!ZwU#TXiQbbm6t0#Co5;ASw_$Q?Fu$17NBN6O7-^vyFfLW!eo< zI#-(VIJeQ+dK_=p3B?;-%Wi1vfYJ=Zw2z4=+|z?Oh5A8-0|&ETxRI` z_<_~mvD0Do8>)g$pj(X9-Bb4@9Bp_81zF|cd~SUhGZQukREL4yNDHIxQ%GVHvz$C0 zTcR9gbE()ngiFlk^tPNGegZ1={;YgEhM{-OVIl8J(nV~5$%i~xoXwjhO8Y?g=^u#S zd;<+_t_10fYe}e$e=x8nCGxAQ%b6@-Ro1Ia>A3sjdd~JS)XCP7L2UkcN6c;^nxbNV zu0au(%3YK2)XhuO62mL&h9246I3<5*Dz!ku!7S zwT8et#JaCX6mTTUV4Ywxq?p%FwfM29PTSH%Ysb?Y;GVKW1L3G*A9Qvj|LVuL4+`!P z`lkF$>#8k_uLZ}mKX0m*+M7z6YgKF zy`5P}iIp!C9{H`36D2I3V_Q>TWp+{HU_MD_EmeV%Z~UyBqYPdLD!}#%McaoM;Mt`w zn>pRi>KqXugNcOw&o^e}Kcn+tI?0N2>HEtJ)01@0zDMj|l2k0N+tFQtHj2>kG<)Kb z9I__uxdiFK$c8>7?S%bE?5@9+`XKGhhLzRzDkNg@(yzu53Lm8qmiEjmijD-_impEJ`CIhm#P5Zc zx`a4~^AqUMvy6-4qz`DV`&j!D13%TvGd_FSPs8TW6;5;F*mWy!87y(%JTQ&9g7O1v zZF^0N*4B$SRd};RNS1*Z8jm?#V)4z*@yBe(ZyMv~-dYBiy*J3O02Z8RZ`w`TDvI68 z4$9OVVm(d;}CK(0rY3L0A5b=@|#BvZ3=T^ZX*5VBCmnugXk#$lYq zO3mARr&GNxm?)hnRS~!C3KM-r&CEcZoYC7c+;v>w_xwQ3(3azC%k>d0krp{?_&EMa z%P07(uk=0_mwfX%nYsQgsQr4AD(Y9Ujg7|h$eCZxkn%CI@Bcn0&5Ul>c}QEvpcO0l z+&Lk|Q$84KnJSearb2>>Tp>g9()K~nrqP(iu!?&O!(fXTR%t$yj=a5jD{_E3K_9kf z<8Uw9Jqls$KnO9?MjX2T?!XMx|E6if`(Le(l?f{#5?U_wbJm^QTm+20HS>v%}sCE%>YvYB^tJ>F=lzqg#FBnQV%MwUH<1y2tAXcQ(64`H=W6b-kJ*A@i#Vg|nb zmGH$lc)>%85J@*-XNlJ)eF)fflkyYoSX$p{{zP z3uH26lol_I|1=5=uUS#sbrkSja;y8e$+3)1?U19dG;8m6pC`lz$HfVUKaDs{rui^B zE=}syzY3!>#W5R;1ks}zbTS15-wT6*tgPI;aG-wy>LQ>L delta 2041 zcmai#c~sJg7RQHNB3fL=)N&&MvD5+ip@5RbOEfGr_bfHCL@k#v48@d2t=uO`NzGKy zlUnK%4aadS1Iyh8t<0rF%_W`CO0!&=n)l9`Gp|41{pWtq=X}q(f86uEH(x79tI8h4 z0U$Oukn_xN|C1q*$h<7xq4PJ}y_@MOw{8zw|=p4nJ%1|ZPw$u{gM{MkRp zpYA0_&C92DIJ~H}1ofn+f%S!jqfwWZ8QJYC0=EL$yT`Qk6*FH& zC)dnASXsj<*u#LM{b)Zss=A~aHcKAX=oiGe^y-AcKcPs5Jj7b0;9_$K6;^gyN5AJt zx`jk1FP0e}xPNK9|3Oh)txD8g*K83ii&>R}`#1jBXJn)^%V2Awkf9{(A)KIH}n2avdj$pLyp<^;v%D>rQxdaMad~!t`)iZirtc9Fl+sCjT+u6qIH0cO``GpyPq*ODS74N?^^;%z;TUMRT zB@a)u`^ptji_cmWowY$H8rW|lL`s=HeN6X_WSF4~#?wLbAg7(U+soF0_x8LYa<~di zNc-Fb9dhxg&J7v15P7OWpHnsK+KD(X36(x_db&#!*D&kOtA64`=Q6cD!fz+IJX`Fy zz2t2jL_@xxD^{~E69Hte+8^{VMgF=XK9J;GbLnZ4>ec!S(!!|HsZD8Z_8|(cnU&&) zdULP)JMTQvb^ZY-q>@*BBs6$!9dm-V9mP4 zgUwlu9iwb8NeVzD9i^0KDbBDf)lEkh19$$>R?Atg({opYKR=`!Ng<*bl0(5wlEmUN z(%{Y*<>RAWpq=Xrn{uj5klQ9C`FVIlBz>b%{z{GDr&w0JW9kmt>=d!DD+`6Z@OsN< zaCFD=naPi#@_W%GCrXgF>OS>8w>-Njtm%2-km{Gcus2}MZrxyHSWicdIQDjJ3)#bq;_H>2o6v*v}O9XlViilc; zfVhjNa9VV@Jlm;ZrQ*T-xT}|&MPtlob^_{^8q^~bp<5tZs0)?RHsh4a3Q5JK#(6ZK zXCj}a`ORamR3ciYn`=QW=_v=-{f0PgO4_DzkpBH6STa>M&>|jh$c?;fBVPD->*|-| zg2ZIu*#1h2SWhcs{ptZKOtZh*G%%){ts#f7%^OSiS%(>Yx&c?4WSxQ`SGMerSY``d?MNn!v$(s_B;u zGY+%VgM$Vc*{$UBN{tFHJ5zW8+K)gUU7>T2Hz^Z3GlQZppSt5`WKdOcH#13iD@j8e z*2x@0DQrCSY!Cl~;>Byo?AL|fwUgewS}nZ5R`sjV`3hKWTV9xY)DYn~#Sl;1O@ERz zxB&P-*$S|c51{!y?otxR^j&F3+ffVs$s-kr=-vZv9WR|%|nt62RZch$yh2e4it&~^9&%l~< z?d+tf86P^@*k=iq-Gx?8MRN&^C!#Oqv>f%43*L{(SB$Y-BRgr^!CZ5$6^!wFRXk$n z5HIB!cHOE(_hvzW5z7jI1(qTx_lh%k@FGOe#i#QpyED3zt7`hTAg_)1+E(yLCzWS; zLW!gLAcbqkG0Xtqwb!rR1m(YAHQajhFg*hI{<-@5_QNW`IjRdRY@F`6TaMRyTbI~H z3A2w3i`h5Ph~WQ(n_WIrur4-k9vyp2 z@seYszOF&~W&dI~7zJ7CfL&qra72$+(;)t#r~muwzN#?4GY}jU4gJ=ML`Y39_z8%E zhN8a}G!zQ?OQ6jG%y$ff0SN!=!vFyOJB9@;zhf2v@Hb8HzplR- z=0mc?Sz>T_G6wfAa}3tP4o|YQ1uShb7y=qNfWunY5dW{k=Rc?9WH>W2+@B7?SP(2A K2n5;54)P}h)Tv7V diff --git a/test/table/table_with_multiline_cells_and_images.pdf b/test/table/table_with_multiline_cells_and_images.pdf index 270e735278db6e7768417cf51c0c160d95a22121..85210326b74995a96d9b08e09cfc5a006ff8362f 100644 GIT binary patch delta 2659 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 Oh(t2d*x1p{3HdkFC9!G% diff --git a/test/table/table_with_multiline_cells_and_split_over_3_pages.pdf b/test/table/table_with_multiline_cells_and_split_over_3_pages.pdf index 7f507550804631c9e7c5c29f697eaa3510565bb5..6273bfea80684e95eac89794515392facf12347a 100644 GIT binary patch delta 3886 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 delta 3898 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 diff --git a/test/table/table_with_single_top_line_layout.pdf b/test/table/table_with_single_top_line_layout.pdf index 5d7c6f3302a8224f1ba505d1f8be42bb3538efd8..cb979c6d12228a7b8dd3b3baa39e367c4871d954 100644 GIT binary patch delta 497 zcmX@cb%ASx17p3BF_)bkS8+*EYGN)|#hkel&t^3{h_rsM?Ao1UzWv<#b4HxLjzL_# z`UWOuTT9(Ov|rl3p7FTkVv#pN=RVGPKX2iLJS7psn*1_J8yOCP&Onx%);4K-ou;UK z*rIr1<>m{Wt!gJ&j&M32JorV(b?KdQPW2c66Inc&HZGDVK5?#~zFgzgGS=0;b^JG< zo2D(SS(q~`uVIyh>i$gSpoBw*b}jxFe%s_OL%PVzH`_FvRgG)+J~{ZfO6;V2^!H`6S%u!;5KlYw%41LSL{=gFc+FQEAB!Io zV5->M#`KDj(R^|ti?F7-v4Q~zDC8+{ff)t{7UqT+VwPr;*Rt5e8k@OUnwpv$8(6p* zTUa={8o0Qax;mP>nK+xfni)7++Sw3P5etdU#G;alqSQ1lLjxmAE>%@me>W}wVH?Nf delta 501 zcmcb>b&P9+17p3RF_)bkS8+*EYGN)|#hkelPvMh{Y9CC<0Pj=8fr41gl*o`ckkNSc=g#Ij-S_M zjqe#dgf>m`w{YR|iR7?)!I{1%y}`Jv2^+NY z_VaDL@WeiA(#GVp+{(N#(%@me>W}wC?m(x diff --git a/test/table/table_with_varying_col_widths.pdf b/test/table/table_with_varying_col_widths.pdf index 1c0be47bb6cbbf4b8cea23cf112fda14bb1c11d3..b100baf48c85fbce49622a3f0c0a9306fafd1866 100644 GIT binary patch delta 798 zcmaFL^O|RaBV)Z8mz^C~aY<2XVlG$3oVimE=G`{nX?tJGCA+;lEpl3t{Ou%L7Fo76 zb&SbpcjatkzQNhH?{ChHDH%pwn`J%!|M+SAN9K7}_4Lf`f%Wg?vcA4NsqwgU+R9(; zzhcg>t+{&2J9n;D@6~kyYiFJI&0O|rL7Yfs-YKte%PW%;?s9Ua)o(P><2)8|EhBi9 z@6^}63txqQeVBQlU;V1-+joms)wh0lWLG4!YC~Sll!sHV&0X+7E>V4*#NwHm(*4t` z^8RJ3Tk?mB%)ET<@m!eXjCW7Ca&_;${P$LV`^3ost)Jt<#qu}5V`2Tyal7EC#M%>H zxmtV9KK}QmE>*VaQ&7Fw)w3&t3l^k_6+fP&uus>n`Nr+fiRKP@m2Exxt&Cak7#(*q z?PW52>AlxbT_Wgelqr3k@?LYAk#yXcYU}FQkCKI7tJi9dg zUD~b}vD0To>hyXyF|1f$^W$~?ufqjzG#0ZSS&ikybQ^>lGo<(c;eZS8(oHbAB zv#bB^D|eJto_3wk@XFFUl~L7l=K8LBVUat^N1g!1x_;KkT&exO&3S$x)5RdGYU7kI z+X9Ta(}SB%tkie9^7(sP-Rt#dCU7pE4s^Q3>>vfNRq{W_~sO* zK&i=5&Ki4-oYZpec5=OYnB&!`(QByg^t<5qer2iGbGTCTQlNSSSNU~Fk;Lr_I5B<&{_l~fd^rg0e>8yaz`s=E5SaRC5~8e`D_ delta 789 zcmaFO^OR?UBV)Y*mz^C~aY<2XVlG$3oZhJi^KKjPw7sw8lD*!Y7C9|P{`MkU7Fo76 zb&QE;cjatkzQNhH?{ChHDH)f#id6nK|4FFpEZ(^L^b*aZ`*$CAtEmliikz9c=%?zu z**mAMkE&GNDmeAhC6Ps<#gSoITK$iFCp=%ZDs`^2E$cPe`3cI?>W_sb9J%DR%4?x{y{gCGke-arGZO{-=eN*UqxgJyu)VVz#$a zt?P_OuHoBVkA-X6mOt%$d3TmmR&S=folSZbyRSrc>RQ9+V7cc{Iwx*Ep|vvW%+C^w zdZrg`=Umn-)p<4h=;GsT^|N|sNJlq5Sa+78y4>;|`=Yl~Wiy|?n7QzoF~bz~3ELXK zthJp}FPyqQ$MdxtKdLRw`L^Maai~pKd92f6}+^d1Whq^7x+; zJ{ah-D(e-<8SBB}*?&?v<6vOR&nl@S&fhn>&kt0(7$jA@Ipxc?fX#w#$C(ZWM^{`q z?eD(-Yk1ib-o?{fXPq~&n&vQ#?b32*={oo@0y7K@4NMI%#0*U=FvN^ZOebGv zwT?9~Ftju^bhR`wG;nk@F>`h{bu=|_bu)J{b~QINH8r)fA*do2lH?PMN-By{)3^+c N4a~SyRbBnvxBxp=TRH#$ diff --git a/test/table/test_table.py b/test/table/test_table.py index 80dabc388..4530bdc0c 100644 --- a/test/table/test_table.py +++ b/test/table/test_table.py @@ -215,13 +215,7 @@ def test_table_with_cell_fill(tmp_path): with table.row() as row: for datum in data_row: row.cell(datum) - assert_pdf_equal(pdf, HERE / "table_with_cell_fill.pdf", tmp_path) - - -def test_table_with_cell_fill2(tmp_path): - pdf = FPDF() - pdf.add_page() - pdf.set_font("Times", size=16) + pdf.ln() with pdf.table() as table: table.cell_fill_color = (173, 216, 230) # light blue table.cell_fill_logic = lambda i, j: j % 2 @@ -229,7 +223,7 @@ def test_table_with_cell_fill2(tmp_path): with table.row() as row: for datum in data_row: row.cell(datum) - assert_pdf_equal(pdf, HERE / "table_with_cell_fill2.pdf", tmp_path) + assert_pdf_equal(pdf, HERE / "table_with_cell_fill.pdf", tmp_path) def test_table_with_internal_layout(tmp_path): From 1271e60022b36181dbb9cf4175e7e4f546d3e415 Mon Sep 17 00:00:00 2001 From: Lucas Cimon <925560+Lucas-C@users.noreply.github.com> Date: Tue, 28 Feb 2023 22:04:38 +0100 Subject: [PATCH 14/17] API change --- docs/Maths.md | 19 ++- docs/Tables.md | 93 ++++++++----- docs/Tutorial-fr.md | 2 +- docs/Tutorial.md | 2 +- fpdf/fonts.py | 43 +++--- fpdf/fpdf.py | 24 +++- fpdf/html.py | 25 ++-- fpdf/table.py | 169 +++++++++++++---------- test/table/test_table.py | 206 ++++++++++++++-------------- test/table/test_table_with_image.py | 48 +++---- tutorial/tuto5.py | 34 ++--- 11 files changed, 369 insertions(+), 296 deletions(-) diff --git a/docs/Maths.md b/docs/Maths.md index 2c6a67eb0..be36eaef9 100644 --- a/docs/Maths.md +++ b/docs/Maths.md @@ -131,17 +131,16 @@ data = columns + rows # Combine columns and rows in one list pdf = FPDF() pdf.add_page() pdf.set_font("Times", size=10) -with pdf.table() as table: - table.borders_layout = "MINIMAL" - table.cell_fill_color = 200 # grey - table.cell_fill_logic = lambda i, j: i % 2 - table.line_height = pdf.font_size * 2.5 - table.text_align = "CENTER" - table.width= 160 +with pdf.table(borders_layout="MINIMAL", + cell_fill_color=200, # grey + cell_fill_logic=lambda i, j: i % 2, + line_height=pdf.font_size * 2.5, + text_align="CENTER", + width=160) as table: for data_row in data: - with table.row() as row: - for datum in data_row: - row.cell(datum) + row = table.row() + for datum in data_row: + row.cell(datum) pdf.output("table_from_pandas.pdf") ``` diff --git a/docs/Tables.md b/docs/Tables.md index e5f24d34b..0de8eba16 100644 --- a/docs/Tables.md +++ b/docs/Tables.md @@ -20,9 +20,9 @@ pdf.add_page() pdf.set_font("Times", size=16) with pdf.table() as table: for data_row in TABLE_DATA: - with table.row() as row: - for datum in data_row: - row.cell(datum) + row = table.row() + for datum in data_row: + row.cell(datum) pdf.output('table.pdf') ``` Result: @@ -43,28 +43,24 @@ Result: ## Setting table & column widths ```python ... -with pdf.table() as table: - table.width = 150 - table.col_widths = (30, 30, 10, 30) +with pdf.table(width=150, col_widths=(30, 30, 10, 30)) as table: ... ``` Result: ![](table-with-fixed-column-widths.jpg) -`table.align` can be used to set the table horizontal position relative to the page, +`align` can be passed to `table()` to set the table horizontal position relative to the page, when it's not using the full page width. It's centered by default. ## Setting text alignment This can be set globally, or on a per-column basis: ```python ... -with pdf.table() as table: - table.text_align = "CENTER" +with pdf.table(text_align="CENTER") as table: ... pdf.ln() -with pdf.table() as table: - table.text_align = ("CENTER", "CENTER", "RIGHT", "LEFT") +with pdf.table(text_align=("CENTER", "CENTER", "RIGHT", "LEFT")) as table: ... ``` Result: @@ -74,26 +70,24 @@ Result: ## Setting row height ```python ... -with pdf.table() as table: - table.line_height = 2.5 * pdf.font_size +with pdf.table(line_height=2.5 * pdf.font_size) as table: ... ``` ## Disable table headings ```python ... -with pdf.table() as table: - table.first_row_as_headings = False +with pdf.table(first_row_as_headings=False) as table:y ... ``` ## Style table headings ```python ... -with pdf.table() as table: - blue = (0, 0, 255) - grey = (128, 128, 128) - table.headings_style = FontStyle(emphasis="ITALICS", color=blue, fill_color=grey) +blue = (0, 0, 255) +grey = (128, 128, 128) +headings_style = FontStyle(emphasis="ITALICS", color=blue, fill_color=grey) +with pdf.table(headings_styleheadings_style=headings_style) as table: ... ``` Result: @@ -103,9 +97,8 @@ Result: ## Set cells background ```python ... -with pdf.table() as table: - table.cell_fill_color = 200 # grey - table.cell_fill_logic = lambda i, j: i % 2 +greyscale = 200 +with pdf.table(cell_fill_color=greyscale, cell_fill_logic lambda i, j: i % 2) as table: ... ``` Result: @@ -114,9 +107,8 @@ Result: ```python ... -with pdf.table() as table: - table.cell_fill_color = (0, 0, 200) # light blue - table.cell_fill_logic = lambda i, j: j % 2 +lightblue = (173, 216, 230) +with pdf.table(cell_fill_color=lightblue, cell_fill_logic=lambda i, j: j % 2) as table: ... ``` Result: @@ -126,8 +118,7 @@ Result: ## Set borders layout ```python ... -with pdf.table() as table: - table.borders_layout = "INTERNAL" +with pdf.table(borders_layout="INTERNAL") as table: ... ``` Result: @@ -136,8 +127,7 @@ Result: ```python ... -with pdf.table() as table: - table.borders_layout = "MINIMAL" +with pdf.table(borders_layout="MINIMAL") as table: ... ``` Result: @@ -148,8 +138,7 @@ Result: ... pdf.set_draw_color(50) # very dark grey pdf.set_line_width(.5) -with pdf.table() as table: - table.borders_layout = "SINGLE_TOP_LINE" +with pdf.table(borders_layout="SINGLE_TOP_LINE") as table: ... ``` Result: @@ -172,12 +161,12 @@ pdf.add_page() pdf.set_font("Times", size=16) with pdf.table() as table: for i, data_row in enumerate(TABLE_DATA): - with table.row() as row: - for j, datum in enumerate(data_row): - if j == 2 and i > 0: - row.cell(img=datum) - else: - row.cell(datum) + row = table.row() + for j, datum in enumerate(data_row): + if j == 2 and i > 0: + row.cell(img=datum) + else: + row.cell(datum) pdf.output('table_with_images.pdf') ``` Result: @@ -185,7 +174,7 @@ Result: ![](table_with_images.jpg) By default, images height & width are constrained by the row height (based on text content) -and the column width. To render bigger images, you can set the `table.line_height` parameter to increase the row height, or pass `img_fill_width=True` to `.cell()`: +and the column width. To render bigger images, you can set the `line_height` to increase the row height, or pass `img_fill_width=True` to `.cell()`: ```python row.cell(img=datum, img_fill_width=True) @@ -194,6 +183,34 @@ Result: ![](table_with_images_and_img_fill_width.jpg) +## Syntactic sugar + +To simplify `table()` usage, shorter, alternative usage forms are allowed. + +This sample code: +```python +with pdf.table() as table: + for data_row in TABLE_DATA: + row = table.row() + for datum in data_row: + row.cell(datum) +``` + +Can be shortened to the followng code, +by passing lists of strings as the `cells` optional argument of `.row()`: +```python +with pdf.table() as table: + for data_row in TABLE_DATA: + table.row(data_row) +``` + +And even shortened further to a single line, +by passing lists of lists of strings as the `rows` optional argument of `.table()`: +```python +with pdf.table(TABLE_DATA): + pass +``` + ## Table from pandas DataFrame _cf._ https://pyfpdf.github.io/fpdf2/Maths.html#using-pandas diff --git a/docs/Tutorial-fr.md b/docs/Tutorial-fr.md index f400d46f9..c67d71f65 100644 --- a/docs/Tutorial-fr.md +++ b/docs/Tutorial-fr.md @@ -123,7 +123,7 @@ Le premier exemple est généré de la façon la plus simple possible, en fourni Le second tableau introduit quelques améliorations : couleurs, largeur réduite de la table, moindre hauteur des lignes de texte, titres centrés, colonnes avec des largeurs propres, nombres alignés à droite... De plus, les lignes horizontales ont été supprimées. -Cela grâce à la sélection d'un `table.borders_layout` parmi les valeurs disponibles : +Cela grâce à la sélection d'un `borders_layout` parmi les valeurs disponibles : [`TableBordersLayout`](https://pyfpdf.github.io/fpdf2/fpdf/enums.html#fpdf.enums.TableBordersLayout). ## Tuto 6 - Créer des liens et mélanger différents styles de textes ## diff --git a/docs/Tutorial.md b/docs/Tutorial.md index 03b326026..8014802af 100644 --- a/docs/Tutorial.md +++ b/docs/Tutorial.md @@ -184,7 +184,7 @@ The first example is achieved in the most basic way possible, feeding data to [` The second table brings some improvements: colors, limited table width, reduced line height, centered titles, columns with custom widths, figures right aligned... Moreover, horizontal lines have been removed. - This was done by picking a `table.borders_layout` among the available values: + This was done by picking a `borders_layout` among the available values: [`TableBordersLayout`](https://pyfpdf.github.io/fpdf2/fpdf/enums.html#fpdf.enums.TableBordersLayout). ## Tuto 6 - Creating links and mixing text styles ## diff --git a/fpdf/fonts.py b/fpdf/fonts.py index 4056c94ec..db8ae97c8 100644 --- a/fpdf/fonts.py +++ b/fpdf/fonts.py @@ -7,6 +7,28 @@ from .drawing import DeviceGray, DeviceRGB from .enums import TextEmphasis + +@dataclass +class FontStyle: + family: Optional[str] + emphasis: Optional[TextEmphasis] + size_pt: Optional[int] + # Colors are single number grey scales or (red, green, blue) tuples: + color: Optional[Union[int, tuple, DeviceGray, DeviceRGB]] + fill_color: Optional[Union[int, tuple, DeviceGray, DeviceRGB]] + + def __init__( + self, family=None, emphasis=None, size_pt=None, color=None, fill_color=None + ): + self.family = family + self.emphasis = TextEmphasis.coerce(emphasis) if emphasis else None + self.size_pt = size_pt + self.color = color + self.fill_color = fill_color + + replace = replace + + COURIER_FONT = {chr(i): 600 for i in range(256)} CORE_FONTS_CHARWIDTHS = { "courier": COURIER_FONT, @@ -2604,24 +2626,3 @@ "\xfe": 918, "\xff": 0, } - - -@dataclass -class FontStyle: - family: Optional[str] - emphasis: Optional[TextEmphasis] - size_pt: Optional[int] - # Colors are single number grey scales or (red, green, blue) tuples: - color: Optional[Union[int, tuple, DeviceGray, DeviceRGB]] - fill_color: Optional[Union[int, tuple, DeviceGray, DeviceRGB]] - - def __init__( - self, family=None, emphasis=None, size_pt=None, color=None, fill_color=None - ): - self.family = family - self.emphasis = TextEmphasis.coerce(emphasis) if emphasis else None - self.size_pt = size_pt - self.color = color - self.fill_color = fill_color - - replace = replace diff --git a/fpdf/fpdf.py b/fpdf/fpdf.py index ab2af9bad..7ac7617d8 100644 --- a/fpdf/fpdf.py +++ b/fpdf/fpdf.py @@ -4694,12 +4694,30 @@ def use_font_style(self, font_style: FontStyle): @check_page @contextmanager - def table(self): + def table(self, *args, **kwargs): """ Inserts a table, that can be built using the `fpdf.table.Table` object yield. Detailed usage documentation: https://pyfpdf.github.io/fpdf2/Tables.html - """ - table = Table(self) + + Args: + rows: optional. Sequence of rows (iterable) of str to initiate the table cells with text content + align (str, fpdf.enums.Align): optional, default to CENTER. Sets the table horizontal position relative to the page, + when it's not using the full page width + borders_layout (str, fpdf.enums.TableBordersLayout): optional, default to ALL. Control what cell borders are drawn + cell_fill_color (int, tuple, fpdf.drawing.DeviceGray, fpdf.drawing.DeviceRGB): optional. + Defines the cells background color + cell_fill_logic (function): optional. Defines which cells are filled with color in the background + col_widths (int, tuple): optional. Sets column width. Can be a single number or a sequence of numbers + first_row_as_headings (bool): optional, default to True. If False, the first row of the table + is not styled differently from the others + headings_style (fpdf.fonts.FontStyle): optional, default to bold. + Defines the visual style of the top headings row: size, color, emphasis... + line_height (number): optional. Defines how much vertical space a line of text will occupy + markdown (bool): optional, default to False. Enable markdown interpretation of cells textual content + text_align (str, fpdf.enums.Align): optional, default to JUSTIFY. Control text alignment inside cells. + width (number): optional. Sets the table width + """ + table = Table(self, *args, **kwargs) yield table table.render() diff --git a/fpdf/html.py b/fpdf/html.py index d1c14b772..71820de6e 100644 --- a/fpdf/html.py +++ b/fpdf/html.py @@ -422,30 +422,32 @@ def handle_starttag(self, tag, attrs): self.set_font() self.set_text_color(*self.font_color) if tag == "table": - self.table = Table(self.pdf) - self.table.line_height = self.h * 1.30 width = attrs.get("width") if width: if width[-1] == "%": width = self.pdf.epw * int(width[:-1]) / 100 else: width = px2mm(int(width)) - self.table.width = width if "border" in attrs: - self.table.borders_layout = ( + borders_layout = ( "ALL" if self.table_line_separators else "NO_HORIZONTAL_LINES" ) else: - self.table.borders_layout = ( + borders_layout = ( "HORIZONTAL_LINES" if self.table_line_separators else "SINGLE_TOP_LINE" ) + self.table = Table( + self.pdf, + borders_layout=borders_layout, + line_height=self.h * 1.30, + width=width, + ) self.pdf.ln() if tag == "tr": self.tr = {k.lower(): v for k, v in attrs.items()} - with self.table.row() as row: - self.table_row = row + self.table_row = self.table.row() if tag in ("td", "th"): self.td_th = {k.lower(): v for k, v in attrs.items()} if tag == "th": @@ -459,12 +461,13 @@ def handle_starttag(self, tag, attrs): ) if "width" in attrs: width = attrs["width"] - if len(self.table.rows) == 1: # => first table row + # pylint: disable=protected-access + if len(self.table._rows) == 1: # => first table row if width[-1] == "%": width = width[:-1] - if not self.table.col_widths: - self.table.col_widths = [] - self.table.col_widths.append(int(width)) + if not self.table._col_widths: + self.table._col_widths = [] + self.table._col_widths.append(int(width)) else: LOGGER.warning( 'Ignoring width="%s" specified on a <%s> that is not in the first ', diff --git a/fpdf/table.py b/fpdf/table.py index 65d4f391a..f8abc29cb 100644 --- a/fpdf/table.py +++ b/fpdf/table.py @@ -1,4 +1,3 @@ -from contextlib import contextmanager from dataclasses import dataclass from numbers import Number from typing import List, Union @@ -16,67 +15,92 @@ class Table: Detailed usage documentation: https://pyfpdf.github.io/fpdf2/Tables.html """ - def __init__(self, fpdf): - self._fpdf = fpdf - self.rows = [] - self.align = "CENTER" + def __init__( + self, + fpdf, + rows=(), + *, + align="CENTER", + borders_layout=TableBordersLayout.ALL, + cell_fill_color=None, + cell_fill_logic=lambda i, j: True, + col_widths=None, + first_row_as_headings=True, + headings_style=DEFAULT_HEADINGS_STYLE, + line_height=None, + markdown=False, + text_align="JUSTIFY", + width=None, + ): """ - Sets the table horizontal position relative to the page, - when it's not using the full page width + Args: + fpdf (fpdf.FPDF): FPDF current instance + rows: optional. Sequence of rows (iterable) of str to initiate the table cells with text content + align (str, fpdf.enums.Align): optional, default to CENTER. Sets the table horizontal position relative to the page, + when it's not using the full page width + borders_layout (str, fpdf.enums.TableBordersLayout): optional, default to ALL. Control what cell borders are drawn + cell_fill_color (int, tuple, fpdf.drawing.DeviceGray, fpdf.drawing.DeviceRGB): optional. + Defines the cells background color + cell_fill_logic (function): optional. Defines which cells are filled with color in the background + col_widths (int, tuple): optional. Sets column width. Can be a single number or a sequence of numbers + first_row_as_headings (bool): optional, default to True. If False, the first row of the table + is not styled differently from the others + headings_style (fpdf.fonts.FontStyle): optional, default to bold. + Defines the visual style of the top headings row: size, color, emphasis... + line_height (number): optional. Defines how much vertical space a line of text will occupy + markdown (bool): optional, default to False. Enable markdown interpretation of cells textual content + text_align (str, fpdf.enums.Align): optional, default to JUSTIFY. Control text alignment inside cells. + width (number): optional. Sets the table width """ - self.borders_layout = TableBordersLayout.ALL - "Control what cell borders are drawn" - self.cell_fill_color = None - "Defines the cells background color" - self.cell_fill_logic = lambda i, j: True - "Defines which cells are filled with color in the background" - self.col_widths = None - "Sets column width. Can be a single number or a sequence of numbers." - self.first_row_as_headings = True - "If False, the first row of the table is not styled differently from the others" - self.headings_style = DEFAULT_HEADINGS_STYLE - "Defines the visual style of the top headings row: size, color, emphasis..." - self.line_height = 2 * fpdf.font_size - "Defines how much vertical space a line of text will occupy" - self.markdown = False - "Enable markdown interpretation of cells textual content" - self.text_align = "JUSTIFY" - "Control text alignment inside cells. Justify by default" - self.width = fpdf.epw - "Sets the table width" + self._fpdf = fpdf + self._rows = [] + self._align = align + self._borders_layout = borders_layout + self._cell_fill_color = cell_fill_color + self._cell_fill_logic = cell_fill_logic + self._col_widths = col_widths + self._first_row_as_headings = first_row_as_headings + self._headings_style = headings_style + self._line_height = 2 * fpdf.font_size if line_height is None else line_height + self._markdown = markdown + self._text_align = text_align + self._width = fpdf.epw if width is None else width + for row in rows: + self.row(row) - @contextmanager - def row(self): + def row(self, cells=()): "Adds a row to the table. Yields a `Row` object." row = Row() - self.rows.append(row) - yield row + self._rows.append(row) + for cell in cells: + row.cell(cell) + return row def render(self): "This is an internal method called by `fpdf.FPDF.table()` once the table is finished" - if self.width > self._fpdf.epw: + if self._width > self._fpdf.epw: raise ValueError( - f"Invalid value provided .width={self.width}: effective page width is {self._fpdf.epw}" + f"Invalid value provided .width={self._width}: effective page width is {self._fpdf.epw}" ) - table_align = Align.coerce(self.align) + table_align = Align.coerce(self._align) if table_align == Align.J: raise ValueError("JUSTIFY is an invalid value for table .align") prev_l_margin = self._fpdf.l_margin if table_align == Align.C: - self._fpdf.l_margin = (self._fpdf.w - self.width) / 2 + self._fpdf.l_margin = (self._fpdf.w - self._width) / 2 self._fpdf.x = self._fpdf.l_margin elif table_align == Align.R: - self._fpdf.l_margin = self._fpdf.w - self.width + self._fpdf.l_margin = self._fpdf.w - self._width self._fpdf.x = self._fpdf.l_margin elif self._fpdf.x != self._fpdf.l_margin: self._fpdf.l_margin = self._fpdf.x - for i in range(len(self.rows)): + for i in range(len(self._rows)): with self._fpdf.offset_rendering() as test: self._render_table_row(i) if test.page_break_triggered: # pylint: disable=protected-access self._fpdf._perform_page_break() - if self.first_row_as_headings: # repeat headings on top: + if self._first_row_as_headings: # repeat headings on top: self._render_table_row(0) self._render_table_row(i) self._fpdf.l_margin = prev_l_margin @@ -89,14 +113,14 @@ def get_cell_border(self, i, j): to be passed to `fpdf.FPDF.multi_cell()`. Can be overriden to customize this logic """ - if self.borders_layout == TableBordersLayout.ALL.value: + if self._borders_layout == TableBordersLayout.ALL.value: return 1 - if self.borders_layout == TableBordersLayout.NONE.value: + if self._borders_layout == TableBordersLayout.NONE.value: return 0 - columns_count = max(row.cols_count for row in self.rows) - rows_count = len(self.rows) + columns_count = max(row.cols_count for row in self._rows) + rows_count = len(self._rows) border = list("LRTB") - if self.borders_layout == TableBordersLayout.INTERNAL.value: + if self._borders_layout == TableBordersLayout.INTERNAL.value: if i == 0 and "T" in border: border.remove("T") if i == rows_count - 1 and "B" in border: @@ -105,7 +129,7 @@ def get_cell_border(self, i, j): border.remove("L") if j == columns_count - 1 and "R" in border: border.remove("R") - if self.borders_layout == TableBordersLayout.MINIMAL.value: + if self._borders_layout == TableBordersLayout.MINIMAL.value: if (i != 1 or rows_count == 1) and "T" in border: border.remove("T") if i != 0 and "B" in border: @@ -114,12 +138,12 @@ def get_cell_border(self, i, j): border.remove("L") if j == columns_count - 1 and "R" in border: border.remove("R") - if self.borders_layout == TableBordersLayout.NO_HORIZONTAL_LINES.value: + if self._borders_layout == TableBordersLayout.NO_HORIZONTAL_LINES.value: if i not in (0, 1) and "T" in border: border.remove("T") if i not in (0, rows_count - 1) and "B" in border: border.remove("B") - if self.borders_layout == TableBordersLayout.HORIZONTAL_LINES.value: + if self._borders_layout == TableBordersLayout.HORIZONTAL_LINES.value: if rows_count == 1: return 0 border = list("TB") @@ -127,7 +151,7 @@ def get_cell_border(self, i, j): border.remove("T") if i == rows_count - 1 and "B" in border: border.remove("B") - if self.borders_layout == TableBordersLayout.SINGLE_TOP_LINE.value: + if self._borders_layout == TableBordersLayout.SINGLE_TOP_LINE.value: if rows_count == 1: return 0 border = list("TB") @@ -138,7 +162,7 @@ def get_cell_border(self, i, j): return "".join(border) def _render_table_row(self, i, fill=False, **kwargs): - row = self.rows[i] + row = self._rows[i] lines_heights_per_cell = self._get_lines_heights_per_cell(i) row_height = max(sum(lines_heights) for lines_heights in lines_heights_per_cell) j = 0 @@ -169,7 +193,7 @@ def _render_table_cell( """ If `lines_heights_only` is True, returns a list of lines (subcells) heights. """ - row = self.rows[i] + row = self._rows[i] cell = row.cells[j] col_width = self._get_col_width(i, j, cell.colspan) lines_heights = [] @@ -191,23 +215,23 @@ def _render_table_cell( keep_aspect_ratio=True, ) self._fpdf.set_xy(x, y) - text_align = cell.align or self.text_align + text_align = cell.align or self._text_align if not isinstance(text_align, (Align, str)): text_align = text_align[j] style = cell.style - if not style and i == 0 and self.first_row_as_headings: - style = self.headings_style + if not style and i == 0 and self._first_row_as_headings: + style = self._headings_style if lines_heights_only and style: style = style.replace(emphasis=None) if style and style.fill_color: fill = True elif not fill: - fill = self.cell_fill_color and self.cell_fill_logic(i, j) - if fill and self.cell_fill_color and not (style and style.fill_color): + fill = self._cell_fill_color and self._cell_fill_logic(i, j) + if fill and self._cell_fill_color and not (style and style.fill_color): style = ( - style.replace(fill_color=self.cell_fill_color) + style.replace(fill_color=self._cell_fill_color) if style - else FontStyle(fill_color=self.cell_fill_color) + else FontStyle(fill_color=self._cell_fill_color) ) with self._fpdf.use_font_style(style): lines = self._fpdf.multi_cell( @@ -221,41 +245,41 @@ def _render_table_cell( new_y="TOP", fill=fill, split_only=lines_heights_only, - markdown=self.markdown, + markdown=self._markdown, **kwargs, ) if lines_heights_only and not cell.img: - lines_heights += (len(lines) or 1) * [self.line_height] + lines_heights += (len(lines) or 1) * [self._line_height] if lines_heights_only: return lines_heights def _get_col_width(self, i, j, colspan=1): - if not self.col_widths: - cols_count = self.rows[i].cols_count - return colspan * (self.width / cols_count) - if isinstance(self.col_widths, Number): - return colspan * self.col_widths - if j >= len(self.col_widths): + if not self._col_widths: + cols_count = self._rows[i].cols_count + return colspan * (self._width / cols_count) + if isinstance(self._col_widths, Number): + return colspan * self._col_widths + if j >= len(self._col_widths): raise ValueError( f"Invalid .col_widths specified: missing width for table() column {j + 1} on row {i + 1}" ) # pylint: disable=unsubscriptable-object col_width = 0 for k in range(j, j + colspan): - col_ratio = self.col_widths[k] / sum(self.col_widths) - col_width += col_ratio * self.width + col_ratio = self._col_widths[k] / sum(self._col_widths) + col_width += col_ratio * self._width return col_width def _get_lines_heights_per_cell(self, i) -> List[List[int]]: - row = self.rows[i] + row = self._rows[i] lines_heights = [] for j in range(len(row.cells)): lines_heights.append( self._render_table_cell( i, j, - cell_line_height=self.line_height, - row_height=self.line_height, + cell_line_height=self._line_height, + row_height=self._line_height, lines_heights_only=True, ) ) @@ -294,7 +318,9 @@ def cell( "fpdf2 currently does not support inserting text with an image in the same table cell." "Pull Requests are welcome to implement this 😊" ) - self.cells.append(Cell(text, align, style, img, img_fill_width, colspan)) + cell = Cell(text, align, style, img, img_fill_width, colspan) + self.cells.append(cell) + return cell @dataclass @@ -306,3 +332,6 @@ class Cell: img: str img_fill_width: bool colspan: int + + def write(self, text, align=None): + raise NotImplementedError("Not implemented yet") diff --git a/test/table/test_table.py b/test/table/test_table.py index 4530bdc0c..8df6cbd52 100644 --- a/test/table/test_table.py +++ b/test/table/test_table.py @@ -34,22 +34,41 @@ def test_table_simple(tmp_path): pdf.set_font("Times", size=16) with pdf.table() as table: for data_row in TABLE_DATA: - with table.row() as row: - for datum in data_row: - row.cell(datum) + row = table.row() + for datum in data_row: + row.cell(datum) assert_pdf_equal(pdf, HERE / "table_simple.pdf", tmp_path) -def test_table_with_fixed_col_width(tmp_path): +def test_table_with_syntactic_sugar(tmp_path): + pdf = FPDF() + pdf.add_page() + pdf.set_font("Times", size=16) + with pdf.table(TABLE_DATA): + pass + assert_pdf_equal(pdf, HERE / "table_simple.pdf", tmp_path) + pdf = FPDF() pdf.add_page() pdf.set_font("Times", size=16) with pdf.table() as table: - table.col_widths = pdf.epw / 5 + table.row(TABLE_DATA[0]) + table.row(TABLE_DATA[1]) + table.row(TABLE_DATA[2]) + table.row(TABLE_DATA[3]) + table.row(TABLE_DATA[4]) + assert_pdf_equal(pdf, HERE / "table_simple.pdf", tmp_path) + + +def test_table_with_fixed_col_width(tmp_path): + pdf = FPDF() + pdf.add_page() + pdf.set_font("Times", size=16) + with pdf.table(col_widths=pdf.epw / 5) as table: for data_row in TABLE_DATA: - with table.row() as row: - for datum in data_row: - row.cell(datum) + row = table.row() + for datum in data_row: + row.cell(datum) assert_pdf_equal(pdf, HERE / "table_with_fixed_col_width.pdf", tmp_path) @@ -57,12 +76,11 @@ def test_table_with_varying_col_widths(tmp_path): pdf = FPDF() pdf.add_page() pdf.set_font("Times", size=16) - with pdf.table() as table: - table.col_widths = (30, 30, 10, 30) + with pdf.table(col_widths=(30, 30, 10, 30)) as table: for data_row in TABLE_DATA: - with table.row() as row: - for datum in data_row: - row.cell(datum) + row = table.row() + for datum in data_row: + row.cell(datum) assert_pdf_equal(pdf, HERE / "table_with_varying_col_widths.pdf", tmp_path) @@ -71,24 +89,22 @@ def test_table_with_invalid_col_widths(): pdf.add_page() pdf.set_font("Times", size=16) with pytest.raises(ValueError): - with pdf.table() as table: - table.col_widths = (20, 30, 50) + with pdf.table(col_widths=(20, 30, 50)) as table: for data_row in TABLE_DATA: - with table.row() as row: - for datum in data_row: - row.cell(datum) + row = table.row() + for datum in data_row: + row.cell(datum) def test_table_with_fixed_row_height(tmp_path): pdf = FPDF() pdf.add_page() pdf.set_font("Times", size=16) - with pdf.table() as table: - table.line_height = 2.5 * pdf.font_size + with pdf.table(line_height=2.5 * pdf.font_size) as table: for data_row in TABLE_DATA: - with table.row() as row: - for datum in data_row: - row.cell(datum) + row = table.row() + for datum in data_row: + row.cell(datum) assert_pdf_equal(pdf, HERE / "table_with_fixed_row_height.pdf", tmp_path) @@ -98,9 +114,9 @@ def test_table_with_multiline_cells(tmp_path): pdf.set_font("Times", size=16) with pdf.table() as table: for data_row in MULTILINE_TABLE_DATA: - with table.row() as row: - for datum in data_row: - row.cell(datum) + row = table.row() + for datum in data_row: + row.cell(datum) assert_pdf_equal(pdf, HERE / "table_with_multiline_cells.pdf", tmp_path) @@ -108,12 +124,11 @@ def test_table_with_multiline_cells_and_fixed_row_height(tmp_path): pdf = FPDF() pdf.add_page() pdf.set_font("Times", size=16) - with pdf.table() as table: - table.line_height = 2.5 * pdf.font_size + with pdf.table(line_height=2.5 * pdf.font_size) as table: for data_row in MULTILINE_TABLE_DATA: - with table.row() as row: - for datum in data_row: - row.cell(datum) + row = table.row() + for datum in data_row: + row.cell(datum) assert_pdf_equal( pdf, HERE / "table_with_multiline_cells_and_fixed_row_height.pdf", tmp_path ) @@ -123,12 +138,11 @@ def test_table_with_fixed_width(tmp_path): pdf = FPDF() pdf.add_page() pdf.set_font("Times", size=16) - with pdf.table() as table: - table.width = 150 + with pdf.table(width=150) as table: for data_row in TABLE_DATA: - with table.row() as row: - for datum in data_row: - row.cell(datum) + row = table.row() + for datum in data_row: + row.cell(datum) assert_pdf_equal(pdf, HERE / "table_with_fixed_width.pdf", tmp_path) @@ -137,24 +151,22 @@ def test_table_with_invalid_width(): pdf.add_page() pdf.set_font("Times", size=16) with pytest.raises(ValueError): - with pdf.table() as table: - table.width = 200 + with pdf.table(width=200) as table: for data_row in TABLE_DATA: - with table.row() as row: - for datum in data_row: - row.cell(datum) + row = table.row() + for datum in data_row: + row.cell(datum) def test_table_without_headings(tmp_path): pdf = FPDF() pdf.add_page() pdf.set_font("Times", size=16) - with pdf.table() as table: - table.first_row_as_headings = False + with pdf.table(first_row_as_headings=False) as table: for data_row in TABLE_DATA: - with table.row() as row: - for datum in data_row: - row.cell(datum) + row = table.row() + for datum in data_row: + row.cell(datum) assert_pdf_equal(pdf, HERE / "table_without_headings.pdf", tmp_path) @@ -162,12 +174,11 @@ def test_table_with_multiline_cells_and_without_headings(tmp_path): pdf = FPDF() pdf.add_page() pdf.set_font("Times", size=16) - with pdf.table() as table: - table.first_row_as_headings = False + with pdf.table(first_row_as_headings=False) as table: for data_row in MULTILINE_TABLE_DATA + MULTILINE_TABLE_DATA[1:]: - with table.row() as row: - for datum in data_row: - row.cell(datum) + row = table.row() + for datum in data_row: + row.cell(datum) assert_pdf_equal( pdf, HERE / "table_with_multiline_cells_and_without_headings.pdf", tmp_path ) @@ -177,16 +188,14 @@ def test_table_with_headings_styled(tmp_path): pdf = FPDF() pdf.add_page() pdf.set_font("Times", size=16) - with pdf.table() as table: - blue = DeviceRGB(r=0, g=0, b=1) - grey = 128 - table.headings_style = FontStyle( - emphasis="ITALICS", color=blue, fill_color=grey - ) + blue = DeviceRGB(r=0, g=0, b=1) + grey = 128 + headings_style = FontStyle(emphasis="ITALICS", color=blue, fill_color=grey) + with pdf.table(headings_style=headings_style) as table: for data_row in TABLE_DATA: - with table.row() as row: - for datum in data_row: - row.cell(datum) + row = table.row() + for datum in data_row: + row.cell(datum) assert_pdf_equal(pdf, HERE / "table_with_headings_styled.pdf", tmp_path) @@ -196,9 +205,9 @@ def test_table_with_multiline_cells_and_split_over_3_pages(tmp_path): pdf.set_font("Times", size=16) with pdf.table() as table: for data_row in MULTILINE_TABLE_DATA + MULTILINE_TABLE_DATA[1:]: - with table.row() as row: - for datum in data_row: - row.cell(datum) + row = table.row() + for datum in data_row: + row.cell(datum) assert_pdf_equal( pdf, HERE / "table_with_multiline_cells_and_split_over_3_pages.pdf", tmp_path ) @@ -208,21 +217,23 @@ def test_table_with_cell_fill(tmp_path): pdf = FPDF() pdf.add_page() pdf.set_font("Times", size=16) - with pdf.table() as table: - table.cell_fill_color = 200 # grey - table.cell_fill_logic = lambda i, j: i % 2 + greyscale = 200 + with pdf.table( + cell_fill_color=greyscale, cell_fill_logic=lambda i, j: i % 2 + ) as table: for data_row in TABLE_DATA: - with table.row() as row: - for datum in data_row: - row.cell(datum) + row = table.row() + for datum in data_row: + row.cell(datum) pdf.ln() - with pdf.table() as table: - table.cell_fill_color = (173, 216, 230) # light blue - table.cell_fill_logic = lambda i, j: j % 2 + lightblue = (173, 216, 230) + with pdf.table( + cell_fill_color=lightblue, cell_fill_logic=lambda i, j: j % 2 + ) as table: for data_row in TABLE_DATA: - with table.row() as row: - for datum in data_row: - row.cell(datum) + row = table.row() + for datum in data_row: + row.cell(datum) assert_pdf_equal(pdf, HERE / "table_with_cell_fill.pdf", tmp_path) @@ -230,12 +241,11 @@ def test_table_with_internal_layout(tmp_path): pdf = FPDF() pdf.add_page() pdf.set_font("Times", size=16) - with pdf.table() as table: - table.borders_layout = "INTERNAL" + with pdf.table(borders_layout="INTERNAL") as table: for data_row in TABLE_DATA: - with table.row() as row: - for datum in data_row: - row.cell(datum) + row = table.row() + for datum in data_row: + row.cell(datum) assert_pdf_equal(pdf, HERE / "table_with_internal_layout.pdf", tmp_path) @@ -245,12 +255,11 @@ def test_table_with_minimal_layout(tmp_path): pdf.set_font("Times", size=16) pdf.set_draw_color(100) # dark grey pdf.set_line_width(1) - with pdf.table() as table: - table.borders_layout = "MINIMAL" + with pdf.table(borders_layout="MINIMAL") as table: for data_row in TABLE_DATA: - with table.row() as row: - for datum in data_row: - row.cell(datum) + row = table.row() + for datum in data_row: + row.cell(datum) assert_pdf_equal(pdf, HERE / "table_with_minimal_layout.pdf", tmp_path) @@ -260,12 +269,11 @@ def test_table_with_single_top_line_layout(tmp_path): pdf.set_font("Times", size=16) pdf.set_draw_color(50) # very dark grey pdf.set_line_width(0.5) - with pdf.table() as table: - table.borders_layout = "SINGLE_TOP_LINE" + with pdf.table(borders_layout="SINGLE_TOP_LINE") as table: for data_row in TABLE_DATA: - with table.row() as row: - for datum in data_row: - row.cell(datum) + row = table.row() + for datum in data_row: + row.cell(datum) assert_pdf_equal(pdf, HERE / "table_with_single_top_line_layout.pdf", tmp_path) @@ -273,17 +281,15 @@ def test_table_align(tmp_path): pdf = FPDF() pdf.add_page() pdf.set_font("Times", size=16) - with pdf.table() as table: - table.text_align = "CENTER" + with pdf.table(text_align="CENTER") as table: for data_row in TABLE_DATA: - with table.row() as row: - for datum in data_row: - row.cell(datum) + row = table.row() + for datum in data_row: + row.cell(datum) pdf.ln() - with pdf.table() as table: - table.text_align = ("CENTER", "CENTER", "RIGHT", "LEFT") + with pdf.table(text_align=("CENTER", "CENTER", "RIGHT", "LEFT")) as table: for data_row in TABLE_DATA: - with table.row() as row: - for datum in data_row: - row.cell(datum) + row = table.row() + for datum in data_row: + row.cell(datum) assert_pdf_equal(pdf, HERE / "table_align.pdf", tmp_path) diff --git a/test/table/test_table_with_image.py b/test/table/test_table_with_image.py index cba902e32..069f90ebd 100644 --- a/test/table/test_table_with_image.py +++ b/test/table/test_table_with_image.py @@ -45,12 +45,12 @@ def test_table_with_images(tmp_path): pdf.set_font("Times", size=16) with pdf.table() as table: for i, data_row in enumerate(TABLE_DATA): - with table.row() as row: - for j, datum in enumerate(data_row): - if j == 2 and i > 0: - row.cell(img=datum) - else: - row.cell(datum) + row = table.row() + for j, datum in enumerate(data_row): + if j == 2 and i > 0: + row.cell(img=datum) + else: + row.cell(datum) assert_pdf_equal(pdf, HERE / "table_with_images.pdf", tmp_path) @@ -60,12 +60,12 @@ def test_table_with_images_and_img_fill_width(tmp_path): pdf.set_font("Times", size=16) with pdf.table() as table: for i, data_row in enumerate(TABLE_DATA): - with table.row() as row: - for j, datum in enumerate(data_row): - if j == 2 and i > 0: - row.cell(img=datum, img_fill_width=True) - else: - row.cell(datum) + row = table.row() + for j, datum in enumerate(data_row): + if j == 2 and i > 0: + row.cell(img=datum, img_fill_width=True) + else: + row.cell(datum) assert_pdf_equal( pdf, HERE / "table_with_images_and_img_fill_width.pdf", @@ -79,12 +79,12 @@ def test_table_with_multiline_cells_and_images(tmp_path): pdf.set_font("Times", size=16) with pdf.table() as table: for i, data_row in enumerate(MULTILINE_TABLE_DATA): - with table.row() as row: - for j, datum in enumerate(data_row): - if j == 1 and i > 0: - row.cell(img=datum, img_fill_width=True) - else: - row.cell(datum) + row = table.row() + for j, datum in enumerate(data_row): + if j == 1 and i > 0: + row.cell(img=datum, img_fill_width=True) + else: + row.cell(datum) assert_pdf_equal(pdf, HERE / "table_with_multiline_cells_and_images.pdf", tmp_path) @@ -95,9 +95,9 @@ def test_table_with_images_and_text(): with pytest.raises(NotImplementedError): with pdf.table() as table: for i, data_row in enumerate(TABLE_DATA): - with table.row() as row: - for j, datum in enumerate(data_row): - if j == 2 and i > 0: - row.cell(datum.name, img=datum) - else: - row.cell(datum) + row = table.row() + for j, datum in enumerate(data_row): + if j == 2 and i > 0: + row.cell(datum.name, img=datum) + else: + row.cell(datum) diff --git a/tutorial/tuto5.py b/tutorial/tuto5.py index 468e623b8..ceac95c56 100644 --- a/tutorial/tuto5.py +++ b/tutorial/tuto5.py @@ -13,28 +13,28 @@ pdf.add_page() with pdf.table() as table: for data_row in data: - with table.row() as row: - for datum in data_row: - row.cell(datum) + row = table.row() + for datum in data_row: + row.cell(datum) # Styled table: pdf.add_page() pdf.set_draw_color(255, 0, 0) pdf.set_line_width(0.3) -with pdf.table() as table: - table.borders_layout = "NO_HORIZONTAL_LINES" - table.cell_fill_color = (224, 235, 255) - table.cell_fill_logic = lambda i, j: i % 2 - table.col_widths = (42, 39, 35, 42) - table.headings_style = FontStyle( - emphasis="BOLD", color=255, fill_color=(255, 100, 0) - ) - table.line_height = 6 - table.text_align = ("LEFT", "CENTER", "RIGHT", "RIGHT") - table.width = 160 +headings_style = FontStyle(emphasis="BOLD", color=255, fill_color=(255, 100, 0)) +with pdf.table( + borders_layout="NO_HORIZONTAL_LINES", + cell_fill_color=(224, 235, 255), + cell_fill_logic=lambda i, j: i % 2, + col_widths=(42, 39, 35, 42), + headings_style=headings_style, + line_height=6, + text_align=("LEFT", "CENTER", "RIGHT", "RIGHT"), + width=160, +) as table: for data_row in data: - with table.row() as row: - for datum in data_row: - row.cell(datum) + row = table.row() + for datum in data_row: + row.cell(datum) pdf.output("tuto5.pdf") From cbfb6e979c8b4192c6865e7d86640650b1908f15 Mon Sep 17 00:00:00 2001 From: Lucas Cimon <925560+Lucas-C@users.noreply.github.com> Date: Fri, 3 Mar 2023 11:22:35 +0100 Subject: [PATCH 15/17] Changes following @gmischler code review --- docs/Maths.md | 2 +- docs/Tables.md | 4 +-- fpdf/enums.py | 69 +++++++++++++++++++++++++--------------- fpdf/fpdf.py | 2 +- fpdf/html.py | 17 +++++----- fpdf/table.py | 55 ++++++++++++++++++-------------- test/table/test_table.py | 8 ++--- 7 files changed, 90 insertions(+), 67 deletions(-) diff --git a/docs/Maths.md b/docs/Maths.md index be36eaef9..9beacb554 100644 --- a/docs/Maths.md +++ b/docs/Maths.md @@ -133,7 +133,7 @@ pdf.add_page() pdf.set_font("Times", size=10) with pdf.table(borders_layout="MINIMAL", cell_fill_color=200, # grey - cell_fill_logic=lambda i, j: i % 2, + cell_fill_mode="ROWS", line_height=pdf.font_size * 2.5, text_align="CENTER", width=160) as table: diff --git a/docs/Tables.md b/docs/Tables.md index 0de8eba16..3b9d5a16c 100644 --- a/docs/Tables.md +++ b/docs/Tables.md @@ -98,7 +98,7 @@ Result: ```python ... greyscale = 200 -with pdf.table(cell_fill_color=greyscale, cell_fill_logic lambda i, j: i % 2) as table: +with pdf.table(cell_fill_color=greyscale, cell_fill_mode="ROWS") as table: ... ``` Result: @@ -108,7 +108,7 @@ Result: ```python ... lightblue = (173, 216, 230) -with pdf.table(cell_fill_color=lightblue, cell_fill_logic=lambda i, j: j % 2) as table: +with pdf.table(cell_fill_color=lightblue, cell_fill_mode="COLUMNS") as table: ... ``` Result: diff --git a/fpdf/enums.py b/fpdf/enums.py index bcc8d8a97..0ef0d57f7 100644 --- a/fpdf/enums.py +++ b/fpdf/enums.py @@ -108,32 +108,32 @@ class CoerciveIntFlag(IntFlag): @classmethod def coerce(cls, value): """ - Attempt to coerce `value` into a member of this enumeration. -<<<<<<< HEAD -======= - ->>>>>>> Handling page breaks in tables - If value is already a member of this enumeration it is returned unchanged. - Otherwise, if it is a string, attempt to convert it (case insensitively, by - upcasing) as an enumeration name. Otherwise, if it is an int, attempt to - convert it as an enumeration value. -<<<<<<< HEAD - Otherwise, an exception is raised. - Args: - value (IntEnum, str, int): the value to be coerced. -======= - - Otherwise, an exception is raised. - - Args: - value (IntEnum, str, int): the value to be coerced. - ->>>>>>> Handling page breaks in tables - Raises: - ValueError: if `value` is an int but not a member of this enumeration. - ValueError: if `value` is a string but not a member by name. - TypeError: if `value`'s type is neither a member of the enumeration nor an - int or a string. + Attempt to coerce `value` into a member of this enumeration. + <<<<<<< HEAD + ======= + + >>>>>>> Handling page breaks in tables + If value is already a member of this enumeration it is returned unchanged. + Otherwise, if it is a string, attempt to convert it (case insensitively, by + upcasing) as an enumeration name. Otherwise, if it is an int, attempt to + convert it as an enumeration value. + <<<<<<< HEAD + Otherwise, an exception is raised. + Args: + value (IntEnum, str, int): the value to be coerced. + ======= + + Otherwise, an exception is raised. + + Args: + value (IntEnum, str, int): the value to be coerced. + + >>>>>>> Handling page breaks in tables + Raises: + ValueError: if `value` is an int but not a member of this enumeration. + ValueError: if `value` is a string but not a member by name. + TypeError: if `value`'s type is neither a member of the enumeration nor an + int or a string. """ if isinstance(value, cls): return value @@ -238,6 +238,7 @@ def coerce(cls, value): return cls.I if value.upper() == "UNDERLINE": return cls.U + return super(cls, cls).coerce(value) class TableBordersLayout(CoerciveEnum): @@ -265,6 +266,22 @@ class TableBordersLayout(CoerciveEnum): "Draw only the top horizontal border, below the headings" +class TableCellFillMode(CoerciveEnum): + "Defines which table cells to fill" + + NONE = intern("NONE") + "Fill zero table cell" + + ALL = intern("ALL") + "Fill all table cells" + + ROWS = intern("ROWS") + "Fill only table cells in odd rows" + + COLUMNS = intern("COLUMNS") + "Fill only table cells in odd columns" + + class RenderStyle(CoerciveEnum): "Defines how to render shapes" diff --git a/fpdf/fpdf.py b/fpdf/fpdf.py index 7ac7617d8..dd4359553 100644 --- a/fpdf/fpdf.py +++ b/fpdf/fpdf.py @@ -4706,7 +4706,7 @@ def table(self, *args, **kwargs): borders_layout (str, fpdf.enums.TableBordersLayout): optional, default to ALL. Control what cell borders are drawn cell_fill_color (int, tuple, fpdf.drawing.DeviceGray, fpdf.drawing.DeviceRGB): optional. Defines the cells background color - cell_fill_logic (function): optional. Defines which cells are filled with color in the background + cell_fill_mode (str, fpdf.enums.TableCellFillMode): optional. Defines which cells are filled with color in the background col_widths (int, tuple): optional. Sets column width. Can be a single number or a sequence of numbers first_row_as_headings (bool): optional, default to True. If False, the first row of the table is not styled differently from the others diff --git a/fpdf/html.py b/fpdf/html.py index 71820de6e..48d957eea 100644 --- a/fpdf/html.py +++ b/fpdf/html.py @@ -253,10 +253,11 @@ def __init__( self._tags_stack = [] # -related properties: self.table_line_separators = table_line_separators - self.table = None - self.table_row = None - self.tr = None - self.td_th = None + self.table = None # becomes a Table instance when processing
    tags + self.table_row = None # becomes a Row instance when processing tags + self.tr = None # becomes a dict of attributes when processing tags + self.td_th = None # becomes a dict of attributes when processing
    / tags + # "inserted" is a special attribute indicating that a cell has be inserted in self.table_row def handle_data(self, data): trailing_space_flag = TRAILING_SPACE.search(data) @@ -282,7 +283,7 @@ def handle_data(self, data): if bgcolor or emphasis: style = FontStyle(emphasis=emphasis, fill_color=bgcolor) self.table_row.cell(text=data, align=align, style=style, colspan=colspan) - self.td_th["rendered"] = True + self.td_th["inserted"] = True elif self.table is not None: # ignore anything else than td inside a table pass @@ -462,7 +463,7 @@ def handle_starttag(self, tag, attrs): if "width" in attrs: width = attrs["width"] # pylint: disable=protected-access - if len(self.table._rows) == 1: # => first table row + if len(self.table.rows) == 1: # => first table row if width[-1] == "%": width = width[:-1] if not self.table._col_widths: @@ -485,7 +486,7 @@ def handle_starttag(self, tag, attrs): if self.align: LOGGER.warning("Ignoring unsupported alignment") self.table_row.cell(img=attrs["src"], img_fill_width=True) - self.td_th["rendered"] = True + self.td_th["inserted"] = True return if self.pdf.y + height > self.pdf.page_break_trigger: self.pdf.add_page(same=True) @@ -582,7 +583,7 @@ def handle_endtag(self, tag): self.tr = None self.table_row = None if tag in ("td", "th"): - if "rendered" not in self.td_th: + if "inserted" not in self.td_th: # handle_data() was not called => we call it to produce an empty cell: bgcolor = color_as_decimal( self.td_th.get("bgcolor", self.tr.get("bgcolor", None)) diff --git a/fpdf/table.py b/fpdf/table.py index f8abc29cb..0c77ff2be 100644 --- a/fpdf/table.py +++ b/fpdf/table.py @@ -2,7 +2,7 @@ from numbers import Number from typing import List, Union -from .enums import Align, TableBordersLayout +from .enums import Align, TableBordersLayout, TableCellFillMode from .fonts import FontStyle @@ -23,7 +23,7 @@ def __init__( align="CENTER", borders_layout=TableBordersLayout.ALL, cell_fill_color=None, - cell_fill_logic=lambda i, j: True, + cell_fill_mode=TableCellFillMode.NONE, col_widths=None, first_row_as_headings=True, headings_style=DEFAULT_HEADINGS_STYLE, @@ -41,7 +41,7 @@ def __init__( borders_layout (str, fpdf.enums.TableBordersLayout): optional, default to ALL. Control what cell borders are drawn cell_fill_color (int, tuple, fpdf.drawing.DeviceGray, fpdf.drawing.DeviceRGB): optional. Defines the cells background color - cell_fill_logic (function): optional. Defines which cells are filled with color in the background + cell_fill_mode (str, fpdf.enums.TableCellFillMode): optional. Defines which cells are filled with color in the background col_widths (int, tuple): optional. Sets column width. Can be a single number or a sequence of numbers first_row_as_headings (bool): optional, default to True. If False, the first row of the table is not styled differently from the others @@ -53,11 +53,10 @@ def __init__( width (number): optional. Sets the table width """ self._fpdf = fpdf - self._rows = [] self._align = align - self._borders_layout = borders_layout + self._borders_layout = TableBordersLayout.coerce(borders_layout) self._cell_fill_color = cell_fill_color - self._cell_fill_logic = cell_fill_logic + self._cell_fill_mode = TableCellFillMode.coerce(cell_fill_mode) self._col_widths = col_widths self._first_row_as_headings = first_row_as_headings self._headings_style = headings_style @@ -65,13 +64,14 @@ def __init__( self._markdown = markdown self._text_align = text_align self._width = fpdf.epw if width is None else width + self.rows = [] for row in rows: self.row(row) def row(self, cells=()): "Adds a row to the table. Yields a `Row` object." row = Row() - self._rows.append(row) + self.rows.append(row) for cell in cells: row.cell(cell) return row @@ -94,7 +94,7 @@ def render(self): self._fpdf.x = self._fpdf.l_margin elif self._fpdf.x != self._fpdf.l_margin: self._fpdf.l_margin = self._fpdf.x - for i in range(len(self._rows)): + for i in range(len(self.rows)): with self._fpdf.offset_rendering() as test: self._render_table_row(i) if test.page_break_triggered: @@ -113,14 +113,14 @@ def get_cell_border(self, i, j): to be passed to `fpdf.FPDF.multi_cell()`. Can be overriden to customize this logic """ - if self._borders_layout == TableBordersLayout.ALL.value: + if self._borders_layout == TableBordersLayout.ALL: return 1 - if self._borders_layout == TableBordersLayout.NONE.value: + if self._borders_layout == TableBordersLayout.NONE: return 0 - columns_count = max(row.cols_count for row in self._rows) - rows_count = len(self._rows) + columns_count = max(row.cols_count for row in self.rows) + rows_count = len(self.rows) border = list("LRTB") - if self._borders_layout == TableBordersLayout.INTERNAL.value: + if self._borders_layout == TableBordersLayout.INTERNAL: if i == 0 and "T" in border: border.remove("T") if i == rows_count - 1 and "B" in border: @@ -129,7 +129,7 @@ def get_cell_border(self, i, j): border.remove("L") if j == columns_count - 1 and "R" in border: border.remove("R") - if self._borders_layout == TableBordersLayout.MINIMAL.value: + if self._borders_layout == TableBordersLayout.MINIMAL: if (i != 1 or rows_count == 1) and "T" in border: border.remove("T") if i != 0 and "B" in border: @@ -138,12 +138,12 @@ def get_cell_border(self, i, j): border.remove("L") if j == columns_count - 1 and "R" in border: border.remove("R") - if self._borders_layout == TableBordersLayout.NO_HORIZONTAL_LINES.value: + if self._borders_layout == TableBordersLayout.NO_HORIZONTAL_LINES: if i not in (0, 1) and "T" in border: border.remove("T") if i not in (0, rows_count - 1) and "B" in border: border.remove("B") - if self._borders_layout == TableBordersLayout.HORIZONTAL_LINES.value: + if self._borders_layout == TableBordersLayout.HORIZONTAL_LINES: if rows_count == 1: return 0 border = list("TB") @@ -151,7 +151,7 @@ def get_cell_border(self, i, j): border.remove("T") if i == rows_count - 1 and "B" in border: border.remove("B") - if self._borders_layout == TableBordersLayout.SINGLE_TOP_LINE.value: + if self._borders_layout == TableBordersLayout.SINGLE_TOP_LINE: if rows_count == 1: return 0 border = list("TB") @@ -162,7 +162,7 @@ def get_cell_border(self, i, j): return "".join(border) def _render_table_row(self, i, fill=False, **kwargs): - row = self._rows[i] + row = self.rows[i] lines_heights_per_cell = self._get_lines_heights_per_cell(i) row_height = max(sum(lines_heights) for lines_heights in lines_heights_per_cell) j = 0 @@ -193,7 +193,7 @@ def _render_table_cell( """ If `lines_heights_only` is True, returns a list of lines (subcells) heights. """ - row = self._rows[i] + row = self.rows[i] cell = row.cells[j] col_width = self._get_col_width(i, j, cell.colspan) lines_heights = [] @@ -225,8 +225,17 @@ def _render_table_cell( style = style.replace(emphasis=None) if style and style.fill_color: fill = True - elif not fill: - fill = self._cell_fill_color and self._cell_fill_logic(i, j) + elif ( + not fill + and self._cell_fill_color + and self._cell_fill_mode != TableCellFillMode.NONE + ): + if self._cell_fill_mode == TableCellFillMode.ALL: + fill = True + elif self._cell_fill_mode == TableCellFillMode.ROWS: + fill = bool(i % 2) + elif self._cell_fill_mode == TableCellFillMode.COLUMNS: + fill = bool(j % 2) if fill and self._cell_fill_color and not (style and style.fill_color): style = ( style.replace(fill_color=self._cell_fill_color) @@ -255,7 +264,7 @@ def _render_table_cell( def _get_col_width(self, i, j, colspan=1): if not self._col_widths: - cols_count = self._rows[i].cols_count + cols_count = self.rows[i].cols_count return colspan * (self._width / cols_count) if isinstance(self._col_widths, Number): return colspan * self._col_widths @@ -271,7 +280,7 @@ def _get_col_width(self, i, j, colspan=1): return col_width def _get_lines_heights_per_cell(self, i) -> List[List[int]]: - row = self._rows[i] + row = self.rows[i] lines_heights = [] for j in range(len(row.cells)): lines_heights.append( diff --git a/test/table/test_table.py b/test/table/test_table.py index 8df6cbd52..f038c84f7 100644 --- a/test/table/test_table.py +++ b/test/table/test_table.py @@ -218,18 +218,14 @@ def test_table_with_cell_fill(tmp_path): pdf.add_page() pdf.set_font("Times", size=16) greyscale = 200 - with pdf.table( - cell_fill_color=greyscale, cell_fill_logic=lambda i, j: i % 2 - ) as table: + with pdf.table(cell_fill_color=greyscale, cell_fill_mode="ROWS") as table: for data_row in TABLE_DATA: row = table.row() for datum in data_row: row.cell(datum) pdf.ln() lightblue = (173, 216, 230) - with pdf.table( - cell_fill_color=lightblue, cell_fill_logic=lambda i, j: j % 2 - ) as table: + with pdf.table(cell_fill_color=lightblue, cell_fill_mode="COLUMNS") as table: for data_row in TABLE_DATA: row = table.row() for datum in data_row: From ad28b221c62695e73bdeaa1b30919a1290a389f7 Mon Sep 17 00:00:00 2001 From: Lucas Cimon <925560+Lucas-C@users.noreply.github.com> Date: Mon, 27 Mar 2023 10:22:10 +0200 Subject: [PATCH 16/17] Adding test_table_extraction.py & related documentation --- docs/Tables.md | 12 +++ test/requirements.txt | 2 + test/table/test_table_extraction.py | 125 ++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+) create mode 100644 test/table/test_table_extraction.py diff --git a/docs/Tables.md b/docs/Tables.md index 3b9d5a16c..1e7a1c79d 100644 --- a/docs/Tables.md +++ b/docs/Tables.md @@ -247,3 +247,15 @@ pdf.output('table_html.pdf') ``` Note that `write_html` has [some limitations, notably regarding multi-lines cells](HTML.html#supported-html-features). + +## "Parsabilty" of the tables generated + +The PDF file format is not designed to embed structured tables. +Hence, it can be tricky to extract tables data from PDF documents. + +In our tests suite, we ensure that several PDF-tables parsing Python libraries can successfully extract tables in documents generated with `fpdf2`. +Namely, we test [camelot-py](https://camelot-py.readthedocs.io) & [tabula-py](https://tabula-py.readthedocs.io): [test/table/test_table_extraction.py](https://github.com/PyFPDF/fpdf2/blob/master/test/table/test_table_extraction.py). + +Based on those tests, if you want to ease table extraction from the documents you produce, we recommend the following guidelines: +* avoid splitting tables on several pages +* avoid the `INTERNAL` / `MINIMAL` / `SINGLE_TOP_LINE` borders layouts diff --git a/test/requirements.txt b/test/requirements.txt index f93e0cbc3..d5cbd5f10 100644 --- a/test/requirements.txt +++ b/test/requirements.txt @@ -1,5 +1,6 @@ bandit black +camelot-py[base] endesive pylint pytest @@ -7,3 +8,4 @@ pytest-cov pytest-timeout qrcode semgrep +tabula-py diff --git a/test/table/test_table_extraction.py b/test/table/test_table_extraction.py new file mode 100644 index 000000000..47bd0d884 --- /dev/null +++ b/test/table/test_table_extraction.py @@ -0,0 +1,125 @@ +""" +Tests that ensure tables generated by fpdf2 +can be extracted by well-know PDF tables extraction tools +""" +from pathlib import Path + +import camelot +from pandas import DataFrame +from pandas.util.testing import assert_frame_equal +import pytest +import tabula + +# pylint: disable=import-error,no-name-in-module +from test.table.test_table import TABLE_DATA + +HERE = Path(__file__).resolve().parent +TABLE_DATA_AS_DF = DataFrame(TABLE_DATA) +TABLE_DATA_AS_DF = DataFrame( + TABLE_DATA_AS_DF.values[1:], columns=TABLE_DATA_AS_DF.iloc[0] +).astype({"Age": int}) + + +############################################################################### +################################### camelot ################################### +############################################################################### + + +@pytest.mark.parametrize("flavor", ("lattice", "stream")) +@pytest.mark.parametrize( + "filename", + ( + "table_simple.pdf", + "table_with_images.pdf", + "table_with_images_and_img_fill_width.pdf", + "table_with_headings_styled.pdf", + "table_with_internal_layout.pdf", + ), +) +def test_camelot_extract_simple_table(flavor, filename): + _test_camelot_parse(HERE / filename, flavor, 4, 5) + + +@pytest.mark.parametrize( + "filename", + ( + "table_with_minimal_layout.pdf", + "table_with_single_top_line_layout.pdf", + ), +) +def test_camelot_extract_table_ok_with_only_stream_flavor(filename): + _test_camelot_parse(HERE / filename, "stream", 4, 5) + + +@pytest.mark.parametrize( + "filename", + ( + "table_align.pdf", + # "table_with_cell_fill.pdf", + ), +) +def test_camelot_extract_two_tables(filename): + _test_camelot_parse(HERE / filename, "lattice", 4, 5, table_count=2) + + +@pytest.mark.xfail( + reason="camelot does not successfully parse tables splitted on several pages" +) +@pytest.mark.parametrize("flavor", ("lattice", "stream")) +def test_camelot_extract_two_pages_table(flavor): + _test_camelot_parse(HERE / "table_with_multiline_cells.pdf", flavor, 2, 5) + + +def _test_camelot_parse(pdf_path, flavor, col_count, row_count, table_count=1): + tables = camelot.read_pdf(str(pdf_path), flavor=flavor) + assert tables.n == table_count + for table in tables: + assert len(table.cols) == col_count + assert len(table.rows) == row_count + + +############################################################################### +################################### tabula #################################### +############################################################################### + + +@pytest.mark.parametrize( + "filename", + ( + "table_simple.pdf", + "table_with_headings_styled.pdf", + # "table_with_internal_layout.pdf", # tabula only parses the internal cells + "table_with_minimal_layout.pdf", + "table_with_single_top_line_layout.pdf", + ), +) +def test_tabula_extract_simple_table(filename): + dataframes = tabula.read_pdf(HERE / filename, pages="all") + assert len(dataframes) == 1 + for df in dataframes: + assert_frame_equal(df, TABLE_DATA_AS_DF, check_names=False) + + +@pytest.mark.parametrize( + "filename", + ( + "table_align.pdf", + "table_with_cell_fill.pdf", + ), +) +def test_tabula_extract_two_tables(filename): + dataframes = tabula.read_pdf(HERE / filename, pages="all") + assert len(dataframes) == 2 + for df in dataframes: + assert_frame_equal(df, TABLE_DATA_AS_DF, check_names=False) + + +@pytest.mark.xfail( + reason="tabula does not successfully parse tables splitted on several pages" +) +def test_tabula_extract_two_pages_table(): + dataframes = tabula.read_pdf(HERE / "table_with_multiline_cells.pdf", pages="all") + assert len(dataframes) == 2 + for df in dataframes: + _rows_count, cols_count = df.shape + assert cols_count == 2 From 3fd7c7b5e282c12aa9a9f6aa8d73c0e74c4d7b56 Mon Sep 17 00:00:00 2001 From: Lucas Cimon <925560+Lucas-C@users.noreply.github.com> Date: Mon, 27 Mar 2023 12:53:55 +0200 Subject: [PATCH 17/17] Fixing unit tests --- .../continuous-integration-workflow.yml | 10 +- fpdf/output.py | 1 + fpdf/util.py | 10 +- setup.cfg | 2 + test/conftest.py | 32 +++-- test/embed_file_all_optionals.pdf | Bin 1306 -> 1451 bytes test/embed_file_self.pdf | Bin 1148 -> 1486 bytes test/file_attachment_annotation.pdf | Bin 1321 -> 1658 bytes test/html/html_customize_ul.pdf | Bin 0 -> 1313 bytes test/html/html_features.pdf | Bin 5911 -> 5938 bytes test/html/html_img_not_overlapping.pdf | Bin 0 -> 11198 bytes test/html/html_table_line_separators.pdf | Bin 1117 -> 1252 bytes .../html_table_line_separators_issue_137.pdf | Bin 1112 -> 1250 bytes test/html/html_table_with_border.pdf | Bin 1209 -> 1346 bytes .../html_table_with_empty_cell_contents.pdf | Bin 1156 -> 1301 bytes test/html/html_whitespace_handling.pdf | Bin 0 -> 1885 bytes test/image/test_load_image.py | 2 +- test/image/test_oversized.py | 2 +- test/requirements.txt | 5 +- test/table/table_with_cell_fill.pdf | Bin 2246 -> 2250 bytes test/table/test_table_extraction.py | 111 +++++++++--------- test/test_perfs.py | 2 +- 22 files changed, 100 insertions(+), 77 deletions(-) create mode 100644 test/html/html_customize_ul.pdf create mode 100644 test/html/html_img_not_overlapping.pdf create mode 100644 test/html/html_whitespace_handling.pdf diff --git a/.github/workflows/continuous-integration-workflow.yml b/.github/workflows/continuous-integration-workflow.yml index 27c4e6a96..29a8e499a 100644 --- a/.github/workflows/continuous-integration-workflow.yml +++ b/.github/workflows/continuous-integration-workflow.yml @@ -24,7 +24,7 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install system dependencies ⚙️ if: matrix.platform == 'ubuntu-latest' - run: sudo apt-get install libjpeg-dev + run: sudo apt-get install ghostscript libjpeg-dev - name: Install qpdf ⚙️ if: matrix.platform == 'ubuntu-latest' && matrix.python-version != '3.9' # This allows us to run the unit tests WITHOUT qpdf in just one parallel execution run: sudo apt-get install qpdf @@ -35,9 +35,9 @@ jobs: - name: Statically checking code 🔎 if: matrix.python-version == '3.10' && matrix.platform == 'ubuntu-latest' run: | - pylint fpdf test tutorial/tuto*.py - bandit -c .banditrc.yml -r contributors/ fpdf/ tutorial/ - semgrep scan --config auto --lang=py --error --strict --exclude-rule=python.lang.security.insecure-hash-function.insecure-hash-function fpdf + pylint fpdf test tutorial/tuto*.py + bandit -c .banditrc.yml -r contributors/ fpdf/ tutorial/ + semgrep scan --config auto --lang=py --error --strict --exclude-rule=python.lang.security.insecure-hash-function.insecure-hash-function fpdf - name: Ensure code has been autoformatted with black 🖌️ if: matrix.python-version == '3.10' && matrix.platform == 'ubuntu-latest' run: black --check . @@ -59,7 +59,7 @@ jobs: # Ensuring there is no `generate=True` left remaining in calls to assert_pdf_equal: grep -IRF generate=True test/ && exit 1 # Executing all tests: - pytest -vv --final-memory-usage + pytest -vv --trace-memory-usage - name: Uploading coverage report to codecov.io ☑ if: matrix.python-version == '3.10' && matrix.platform == 'ubuntu-latest' run: bash <(curl -s https://codecov.io/bash) diff --git a/fpdf/output.py b/fpdf/output.py index 82221e6d0..571c0a6e4 100644 --- a/fpdf/output.py +++ b/fpdf/output.py @@ -580,6 +580,7 @@ def _add_fonts(self): glyph_names = [ cmap[unicode] for unicode in uni_to_new_code_char if unicode in cmap ] + print(glyph_names) missing_glyphs = [ chr(unicode) diff --git a/fpdf/util.py b/fpdf/util.py index d5aca6e3d..7f916e02b 100644 --- a/fpdf/util.py +++ b/fpdf/util.py @@ -97,11 +97,11 @@ def get_mem_usage(prefix) -> str: # heap_size, stack_size = get_process_heap_and_stack_sizes() # objs_size_sum = get_gc_managed_objs_total_size() pillow = get_pillow_allocated_memory() + # malloc_stats = "Malloc stats: " + get_pymalloc_allocated_over_total_size() + malloc_stats = "" if is_tracing(): - malloc_stats = get_tracemalloc_traced_memory() - else: - malloc_stats = get_pymalloc_allocated_over_total_size() - return f"{prefix:<40} Malloc stats: {malloc_stats} | Pillow: {pillow} | Process RSS: {rss}" + malloc_stats = "Malloc stats: " + get_tracemalloc_traced_memory() + return f"{prefix:<40} {malloc_stats} | Pillow: {pillow} | Process RSS: {rss}" def get_process_rss() -> str: @@ -122,7 +122,7 @@ def get_process_rss_as_mib() -> Union[Number, None]: / 1024 / 1024 ) - except FileNotFoundError: # This file only exists under Linux + except FileNotFoundError: # /proc files only exist under Linux return None diff --git a/setup.cfg b/setup.cfg index 2a552e6fb..81bb971fb 100644 --- a/setup.cfg +++ b/setup.cfg @@ -16,3 +16,5 @@ ignore = E203, E221, E241, E251, E701, E731, W503 [tool:pytest] addopts = --cov=fpdf --cov-report=xml +log_cli = 1 +log_cli_level= WARN diff --git a/test/conftest.py b/test/conftest.py index deaf6ab72..89d78ca84 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -261,13 +261,20 @@ def handler(_, __): def ensure_rss_memory_below(max_in_mib): + """ + Enure there is no unexpected / significant increase between + the process RSS memory BEFORE executing the test, and AFTER. + """ + def actual_decorator(test_func): @functools.wraps(test_func) def wrapper(*args, **kwargs): + start_rss_in_mib = get_process_rss_as_mib() test_func(*args, **kwargs) - rss_in_mib = get_process_rss_as_mib() - if rss_in_mib: - assert rss_in_mib < max_in_mib + if not start_rss_in_mib: + return # not available under Windows + end_rss_in_mib = get_process_rss_as_mib() + assert (end_rss_in_mib - start_rss_in_mib) < max_in_mib return wrapper @@ -278,9 +285,9 @@ def wrapper(*args, **kwargs): # so we require an opt-in through a CLI argument: def pytest_addoption(parser): parser.addoption( - "--final-memory-usage", + "--trace-memory-usage", action="store_true", - help="At the end of the tests execution, display the current memory usage", + help="Trace the memory usage during tests execution", ) parser.addoption( "--pympler-summary", @@ -294,15 +301,26 @@ def pytest_addoption(parser): ) +@pytest.fixture(scope="module", autouse=True) +def module_memory_usage(request): + if request.config.getoption("trace_memory_usage"): + gc.collect() + capmanager = request.config.pluginmanager.getplugin("capturemanager") + with capmanager.global_and_fixture_disabled(): + print("\n") + print_mem_usage("Memory usage:") + yield + + @pytest.fixture(scope="session", autouse=True) def final_memory_usage(request): yield - if request.config.getoption("final_memory_usage"): + if request.config.getoption("trace_memory_usage"): gc.collect() capmanager = request.config.pluginmanager.getplugin("capturemanager") with capmanager.global_and_fixture_disabled(): print("\n") - print_mem_usage("Final memory usage:") + print_mem_usage("Memory usage:") @pytest.fixture(scope="session", autouse=True) diff --git a/test/embed_file_all_optionals.pdf b/test/embed_file_all_optionals.pdf index fe49a5dda583724214c9a87deb7c8f4d560beb04..07cb03370d252f8a0fffc98d9524bd0a04c438a6 100644 GIT binary patch delta 413 zcmbQmwVHcFB9pk0fhCuIKw?p1Zn1)mjec-uRjPuCq0!`x%$k$uGwCT9n3$MaBw3mp z8YP)prluJinOPVZnI$Er7+M$_CYzZ~e#@j%zjeaiJZ43Kmg;#)OIM#ik*Rdo_zCYK zkw0trOAaKJ9engQS$w&O=j^Oy61B!s*~7IOS`{QJ>;9lFbsae|=X>i*M$@Bo>ua6s4wd85)`xaH*=g`nz!f00Q)wU;qFB delta 267 zcmZ3@J&S8YB9o|@IhTGwVo_plv4V|_esE@0s)D)sWJeaw$qSkE6wK0$P0UgZlamZA zOcD)~EfSMb(~=BRO)U(~ER0MOjV8ZmQgJjr=E&Dzz`=6By8dIJZVu1J)~F4g`>%WZ z8*iPF5tQ4i-^A%8p0USQw_a$Y<&EokS?%_o-&4c`7R(oJwo9ENb7}J)IvcyXS~yxbnVCAexS1N77+RWIx>-8f h*$`9_%VlTBRa}x-R8motn#N^mX~w0h>gw;t1pvd?PZ9tC diff --git a/test/embed_file_self.pdf b/test/embed_file_self.pdf index 58cf94515af6c2306b76a484fb0481c0fe44f94e..f8cc77914e383d1f8218764f5a998e0665c1046f 100644 GIT binary patch delta 513 zcmbu4%}T>S6ooNvbbJ8C)rHb!JDIjINi79y+m%qkrF1b#Zky01GiGk85y6M(iwJ!W z-@>A47oAbn& z0u2{}eReaV^QGJx;6$=B`w=B@86Z*qY^=kr17UYuuwMlkus351 zAv)`)?c=FGXrH>a>x_i&`(E1{+JloL-x-`ZEpI5=<9_eYiz(~(nIW0eO^!1rgzK<+ IeKZ-f7s_s@IsgCw delta 173 zcmX@d{fA?NA(N=NIhTGwVo_plv4V|_esE@0s)D)sWDh1ij?}!A)Z)yt)X9gLEjF{V zNHR(om>U`>7=VC6o&pz`VPIemRBpy<9pmh3XzJo`4ogG(kNn%k+MNw)RmxZwfm#V6(zZ(|-lCdlw diff --git a/test/file_attachment_annotation.pdf b/test/file_attachment_annotation.pdf index 171f910cbd4bd4cfa13a981f976ee516fd7eef6a..10cde01011da2489faaddf854831623166ac3cb4 100644 GIT binary patch delta 513 zcmbu4%}T>S6os+6ad5A=x=;#k+UZPVo7Pf@ZCwc!TuPBia@&M9nQ>+kjT@gq`V{U2 zpU0PQ>B=aI_yaCHtHa@PzI*P-^Va=iW!qt#&=a9WVxZrrr|~sHnXR5GjhiY2BEhA! zbyb}C!r&Bo5K1(VN(+}#FCfeitc1u~WqOp(V;g0DBajKr<5U!4QBN?kf~s(4rAp^C zHYP(u86%(F1k(^roFkb>(pVGdSXqFQukj*_HHP39KYr=`M*S!aF{kgI`b+84L>P;j z8nl^esG@qzJ47l>gS;GPBbfqx$4$O&|2J>7x9)CQ;b%)xG9S*@ch`0pXI*H%3Q{0% zrpdV5UfpgSOqu7njyv{7Ubo%$`2KJ_WS%?Xp3A+~;fN3Ve_l+rqY`KRLm delta 174 zcmeyxvyyAWT_#a;b1waW#G=I9Vg(x;{ou^1R0VVM$zPcCI8yUcQj0UoQYYuLSZvuH q25u(Kj;6+THUw3~a@pB&6_+Fyl~fd^rg0e>7#eV?s=E5SaRC6}FD^#_ diff --git a/test/html/html_customize_ul.pdf b/test/html/html_customize_ul.pdf new file mode 100644 index 0000000000000000000000000000000000000000..bca78fad6750539760411b0a83362343e1ba00be GIT binary patch literal 1313 zcmbtUTWAzl7}lB=GG1cw0t!h_A68dQGPm8Gon#xEo!PA+Hd#0EmPK@uJ=u)T&RJ*9 z#-!1Q(hIZ?1zTzv0>zM6wj!z_4G!xUL0J7l?5L z@ygyx!4Lc%zS1v~)#mOL1Z+f0K%1$lVW1hObb^DnF$K-qHmoBv&k5MDj#mIPZ5V`r zhOX4QQ5plb(S!;z(n)h1wgD|KT1cX3STj(9md^EJc7uF37EmEtYVW`436o(AE5}FCz0R%~+Q8u=qmSnnm2X^ueXSmr@ z-kxZ!@7Ohbitw|~8R^nUdRoso#K>H7NJmpjT+!yi|b zG!BQpJ-qBAWku1}X}=Bj6a`V~w0^X0`ja2Ehg0q@m{InCX}HH-O)<|ZKTW+D{9;kh zwN;U9@v)7gBi(;J8vEm?bu$+(-D9sCkWP2rEGfCezE0H7a=)B@@lt7d{}n;$?=NrJ zKL`6_Wsl*iU(fcv`T3xGsp{TQd}QA08|RNpnfA<|Pxo&5{&uG7+%H2{Uu4P;O#S`B zJnzH3M=~kSx8Z{j8=(z7FhvWQw|B)hyjQIc0K;84NLudnm02}53?Tz>}EC5(+-1Rbh66G~*T)C&dA*_+w1Wvu2Dv3*PGB-An+^xY%kSje^^u`u~rp)lE8_AzgCrl9!afv|BjsUHr6bhlTP-FjLQ{j3^V@#R&#;FaS9Gk0X#Dv4FokWtK8HY;LEBB+ zIp?=+XAv;kag;+zas`j_(Zp>H{bD|x{-t&CSC?kas$ul~x7%@keZsc~p>2oGHwa#y z!c-RDF^TDwDoduTzi({FXv%y~`}N)NRg|Q+RuCsPyzLzMWZoZ?f3W(|fl0_pZHm z;l{EP-&IULNXnks_S411a$VPMolnPZJW4%3$HdvE;lhrk(;bZN*1cTE{p02=7X#Or zowJ!H=Juc7{C9ExZk|+cfuL;@rM4wbQaty_%zW9M=NAn(=lhCyDQ~>`#nL)U?UB-| z`jj*OgKkvXgj_#x_TEo_acYg@9%{r{%JmYvSU(V+p50^SfGQSI2@BZ5+OY4;C zB$H?T-*1)|wC3!(Fi-x%L#Jx9!)uRE?)~w?*!*-L%=;bOi zKBea=H3-(^KG&YCUgy*jl%K5BDp-?z*14&FX}O``VUB&eZ)TeYv&#AI>Frcu`|>R{ z@0DgO=ldk3cE-Q+^rzoDwEtGrgE^D^*n8?t3{kR3>jYnaCP$vO_kX(No(82^&EG3! zIPg>P&Inj2L}xUvIVjLx&TRZc^3oea0TZ)$JXy&f9GrH=>(2fJ5FtEosytYv8_Jd zyy<|YNqVCg3+r;d{3X0R$rjum0wQyE-7V7RIKkJhtjxhx7hV75wx7WYi#wfbfSUGY z{L+!Ix%{-}-S<KJU?-Z^7_Rbhhi}a~uXd^_B*v3I-sckf*=}W*8V+T9~1W85vnx zVu%@A7-EQ-8e!@+!y;yG1h%&x*fr+Vs5t1N8%nZ{K6LVu^%@B1KrWhe;Vrg!SZl0-uC5B^64Vf&ACfADD#+o|2 z8Jikgy16)-nL0U|m>D{nI6AwUo0^!qI=LCTn%dbAR1phF&51=N6-B9OT&6}QCS0nj IuKsRZ0M@i=EC2ui delta 1539 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 a5etcl#G;alqSQ1l3j=d5RaIAiH!cA4)Sw&y diff --git a/test/html/html_table_line_separators_issue_137.pdf b/test/html/html_table_line_separators_issue_137.pdf index d58ffc79616940afdf8b97432f60ad816092fea3..647fe738a93cf4e598cc27402ff94efc821eb366 100644 GIT binary patch delta 478 zcmcb?@rZN6Z$|Tpe_ZMfO}OmrxQa`PQWJBzD&|a`xR>vc0Z+?!yH@uIpGSYzdl+n( zB);N`Qp>3(mOXa4&dixwQEu^emgVV9&Ibb|E5xGtXWO#-osjq;{HA7t#>5kg0upvQ zs6OOMGm@`VF}$KD4m*m(F3bEi;e&e7-@Oi|Huw5RasC_fRZVO?FE5*zllcm2Wm zMPGlKd`@#~xg<6B2j3K}i6_dBxL96{5)NBbR;l#M_~ME^22oBMH{98HGx1y)OCr~c z_m6k|mRP+zXqQR#bK_F-~jG@snhB+bU9?`EW6HhCG7J)_0sXH3qFmXo!ZbM4Gb6%0T?Ay0t| z%rG!8Gc&;uGdDBB5VJ6~oP3a3y2g@AKPW%HL;oQX!5ZvvWzwaI1s|F`vs!G^j;C$UUsn{>SMbWFe*Q_0 zWZkQ;f=lP9EV?r>##?EZR=%h2j-sNoc6a*cdH#*`SZ8?VXqVj#rdxiITjuUskzIBE z_q&?xPhR_De?}g+s1$zM=eSj6kyf_%H14ZcUI;fRPklI9nW=Fy8?(S<1!n8XznFL? zr!!kHT1;NRoU3JOs$c*D3V8}#V1|K#nW+hen7N7JWN#Mf8VfG{p#1z21tSFmg&;0{ z&%CsJ1#>9dMIqY8#mUv#&D_$`z|qOV*vY`f%*n*b(!ku!(8Sf*#Le8yjZc!aPr3UHi8DuJMO0fiIYA^53QJsJ@aQs>S+QOzzp|6CD#f zGi+UQFIwL?9NG53uZaEpg_`Rr1+yaN^At^zy({|q!6d~*Rl&*XRUv%O>ce;3)V=*! z_so3B>K!K~mXum#U+74EqGJ8a`jgpS<%N>+6IR4MPyK17*ZyDEq%Bi+9*26gzKZ(I zi}xprzmnxV8+gF;OYx72>i=sOEc+4~_5b<&MZB|0cPj18GJQ3pPA*C3tjFWWkJWBx zL~yhC$}L_i$z$AezW?y_$&Unh^fYswv)E4aC{?^`RLcrZIJ`=`-J+h$pd@`l#SkDFPRdQU-`PDoAHTjq>zZ0C+b}#U2fJBF69Yg;w&GVD1m>MU~U=m<) z%Fjueyq3v{(R}g;CTTVVf%LY@K_m|P_pi1zlh=nAV#G;al TqSQ1lLjyxoE>%@me>W}w_>$h0 delta 525 zcmX@awUcwgZ$`6;e_ZPgx$Nw?ic5-86LYyL=JZb7n|IiNr={GU^>|sL>)%`1jb$&Q z_By`)!tU9w;1IvxC@D~A>Jiy~tBLaOO!n|_#Wvi3Xn5$babw^Lkt4D;M;-e!WO`CA zL|Pn(Y)cT|*&Z(N{)wqy@U`xRb2luG-pHpXDHK-lg1P15!c7AAALiNDzxVqtuwVSx zTj5KIy>53Cwh5Pgv7WKHT*dEg=E-$TwX^H}J{vC1n?I57xvk$aw_No%FUk$F-g~St z6L_`J&9<(#rf9{Ysi9Ke-(O3Ki<~aXc}O5AX@i~d1dXr9zQ1)!;fplqcp}@kEbYRg zwbK8$PtH?6dePv<5|8UVZeI$vJ(sio^CXq)=7v|NF4pW!(Xd@H;eGVY!(adAYRw5c ze}ZH0;#Ug|EPw*sxvS!|u0Cgz@ap`;JrR6J_ zL)k70(Kco-&X!KD=FWx|mWHNIrsig@u5NA?#-=8&j)tx-u9kL$Rm4K#IkBjuq9`?u P%fix3H)KQ8rVrd)P*T*W0tsfoE<6?2wO^37vb^!<8cQzyp#1z21tSFmg&;0{ z&%CsJ1q&$KMIqY8#MsE##K6Ve#N61?!pzyl+|== Vl~fd^rg2%C8*-_ty863u0RU7j#%BNk delta 472 zcmbQr)xtU9H>26aKQ8qq7F>3AT*W0tsfoE<6?3LeJe$X4$kX!vw}{;~ar3ey^_@x= zo!6h0-r~J5$x=ZjPF~<--l6#qG9o|UG(P;{s-y`2@4RUb9#1|XWx{re>DkK14PghW z+aDz`1Raw&y{9eTB5Tirst=AAEIjsq*!E6*ce%%Zb%)gw2O{0}scg9PvOcBt$4m3w zbC)8qM9d?>eD9lu`F+O(7&l5%Cqg-=WM<;3WaO8yV~2P z*F^5hiuCi3Ub&6cCUQJ*M}91LFmb}%Z7nectvez=aGd(0Or z$?DH}T+i-pdVjm()A8aTKmXv_$ze>5lP#GACI>THGn!BCXLe?^ zn0%QzN88lWQo#TO6!H|fzzhQeGfN8$F>?#k$#pE!H5Od@LHYS53PuVB3PD`@o_T5c z3g%F@i$b)Gqp72*ft#g?g^PuurLn2Aqm!GttDB*Po13AtqoJd*9bpx*kQhrWDyb++ RP2;jKG2>EIb@g}S0swtOv;zPD diff --git a/test/html/html_whitespace_handling.pdf b/test/html/html_whitespace_handling.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d19931d27a5f81aa2f4444562aff65942d6026fe GIT binary patch literal 1885 zcmbtVT}&KR6b?b_NzKyUPR$?QVCWEi6?B_OgtbouM~0x>)Cca% z%sq3?ckVssJKyB^y!AvlUz9`JTp%nSHy{gDm?XulLe231i(AvH|kSPQJL1F4m*rmU$+OhAjWSq;>f zqF?}D%v59*82}Ra0JV%&CmqpZCZK&P@@PsdswT|XDdCgI>XA%I(IS?-1dyS{^j4f#utJiHSnx<_3Qv?36Y2Qyiew@$YSqGsqU(?vG1~#>aF8g& z)R7dWI?s#*r}p+R8RNHtSNCO(EPe3UXzsvoQ$4o)+VtjARZZ7se%V)4ICcBNF#Pf9 z>fAd^Q-11`9mg-dIe#5?9gA%0$v&QS^w_z0-}%>yU+;=;+eFRIm8SnRu{Aqw>kGRk zy7S)}w2kaYzm}O%5LL7O9;@yQHJrWk-R1b^U-Pb<$fJYXFYWK&T=m?OU+!%D=Ce}` zTMi$dU9|Vt4HP^)*qiYv&?bhSZ+y}A;p`K4zwZAio(;a5dt^+bdJnwal}-2EtK7?Y zC%3-Tq7tT1m5Q4ts}VpSkkv}nkW&VV z4#rx{WhN75;Sop>j9^&UQ1XBjZcPbqJcIKA8EP=u<<^bo;MdK8hhLYGzHxXmPWMNK z^uXn!MF>cH@NkPPAXOx993ZzPZ+1Y=6u<*S`*p1~h)fWou|nbYp-$Yynkb%1ck<~; zK5GtHILkl1(chHzSdrE$B16$$gkuwm2$F`22lf~+~Dwb#Q zJyzKS78l{aHpr}FgAj9Kl^@Hk!Gj#L=6ul3Sng)(lB{6rl7CoGK8i?P=zyk~fD{=M ztVV6q08DMXAmn149xp2jOoHFy4@^SY3F!WaP!bn@&6vn^fOFJHR)UBMRWiF literal 0 HcmV?d00001 diff --git a/test/image/test_load_image.py b/test/image/test_load_image.py index 163fc265d..17378d94b 100644 --- a/test/image/test_load_image.py +++ b/test/image/test_load_image.py @@ -42,7 +42,7 @@ def test_load_invalid_base64_data(): # ensure memory usage does not get too high - this value depends on Python version: -@ensure_rss_memory_below(max_in_mib=190) +@ensure_rss_memory_below(max_in_mib=6) def test_share_images_cache(tmp_path): images_cache = {} icc_profiles_cache = {} diff --git a/test/image/test_oversized.py b/test/image/test_oversized.py index ed630a68e..67da2c3e3 100644 --- a/test/image/test_oversized.py +++ b/test/image/test_oversized.py @@ -7,7 +7,7 @@ HERE = Path(__file__).resolve().parent IMAGE_PATH = HERE / "png_images/6c853ed9dacd5716bc54eb59cec30889.png" -MAX_MEMORY_MB = 190 # memory usage depends on Python version +MAX_MEMORY_MB = 12 # memory usage depends on Python version def test_oversized_images_warn(caplog): diff --git a/test/requirements.txt b/test/requirements.txt index d5cbd5f10..7d42c72a6 100644 --- a/test/requirements.txt +++ b/test/requirements.txt @@ -1,7 +1,10 @@ bandit black -camelot-py[base] +# camelot-py[base] : does not work due to https://github.com/vinayak-mehta/pdftopng/issues/11 +camelot-py endesive +ghostscript # required by camelot-py[base]: https://github.com/camelot-dev/camelot/blob/master/setup.py#L27 +opencv-python # required by camelot-py[base]: https://github.com/camelot-dev/camelot/blob/master/setup.py#L27 pylint pytest pytest-cov diff --git a/test/table/table_with_cell_fill.pdf b/test/table/table_with_cell_fill.pdf index 09b460e65fe04f1ec86555f5cade9f218f6e62cb..af6346c1303926b34ef2e9204a9f986d57d1848c 100644 GIT binary patch delta 1407 zcmai!dpHw%7{@7T?ev%}#IYoC6dl`aY*QQC+{$gHTyi@qy15;fOqMxwTa+G3w6?U- zTyhGL<60|(Z0SrPqO=$XI}clXaB#-?vp>%J*YEkfzu)tFzwh^b-Y#%2xQ3ukM_2># zcwl@&TzFU%kjnnuUl2Wl(QaF@q(*{HI8n;VP6yU!-_LalTu(rX^1rZG)i8l;J=F!O|YKmjdHG1d6cEH68PixbsT?XZx;Z!6HKWdZ*im;!1 z6v~<#ztdXfQceO#&)yv>ESM?0_6b+_Q(kf9us%yr#KU_&D?2(x0&|kCKg_EP=>d%G zzc|4ZV;iExiU)i&+Us~JlFQUSja;U9v=x9`U3_1Hkqx5ku4W2d*fNq$_mk9n*e8sQ zMt%^F@5(JngjCB|`h5@YNJrOWquRw~Wp#!yPl&>7pt>_zRi}^D7K1>lwcm}T!B_Hg zedblwV^ji5^UnNWHP*6T z^P3r6$G?pnZte$`m^;}xzBaNKic??PrkOj{hcdsJRQF5zq2)H&xFgw8RO=eaMPU<4->jpbgVo)!^A(g zzDC2Lym2nxd@EzQB!gZ~dshwM0^saYnU#(pMN%#ROR5Ae#3|r(%gj-6rf!6eIzCY@ z%rv3isLtD;1K`z}d+qMCYU^oHUxj`|!n`R>uQQT}{}h^QzvGkz ziT*3OGMO9kGZCg9_nrj3ouzdlO*|Qw<~KC`xl}VtrIg;5QL!~h8l;bxu1x3iBGOf? zE#tYr9&Hg$5ZO~BMz@|*8$K@FB6$rZuM}qV{3A~w z!!`^z!7@yD7FxL!+Khf0uOC5(YhHr#% zv@vk=07ux`BEMs3Tf}z^V}rSA1vnf`Afge@a1s#(N7*{rI1&h0TQmmgjI=?KP#7m? gNBoihy%GH1ZVih|pvHwq01;RO7HDSXI_2xv4ox7iruy7^0D=-TnDMn6L{X(PXVqlcFRYeSIR@&|0%5?E)P?#`K!aHE&7r zjLV#lSj%-UTc7W+Bt96y&Vo7rKyuv7pHS}f!G9LLp`A5Ql(ebbIwUR*e@z}NE};@X z(4zz&h?U(|L-Oc>P!k(H6Na_me1Wy$=E ziBHu+BTd+L7b|&uQMA7r;>|M?jyzBNYR%JHtBr~>?h77pvP!=YAa z_K#<+!l$r~6+~+N$|q@&=ERNCL3%gNZ;T(*0aI?pjL>uHS`t2D{nmpQMHgv&%Vu&- z@2H-w`UmHG4#njhFZNwV3B9M3lasSk^#u0n=y>C+Rd%p!t4S!%d4Cdrbc21QP^vt3 zS-~k#rAn*0(|`xk$12tM<-28(pL1JbzehuEfqanWbIKfYWPDk(LeuF z$<=J$Lc%*}gT`=r02XQk9SKw{=s5L^1ddGl-8D-j?5tpt-z@ZY?(zsBdaj!9Ds9MupWv@IjJHElVL zhzty~oVc?7*W2pDbt9h@7UzQWv&_q|W^meJ4=4jMmP}rP*Us5-GAox9e3kE^vN9k& zIwa0xC=TRc*%W~gr7ULR*AHwWChJxOb@Kq1Z(Jtb6_PS=`yP|GfPG~LCZNwlf`7R$ zKdxD2*r%MRN{gSMzGb<6!FCNJr&Y!rE4qHYmjyZo6%E%Yr}ce^6kBeQua;yg>m?xx zK>2P4_zrLu2cb!YJF@T_b)GObrFIiCUn9aP~)`V@Q$o4YI9W0gziE*cuoMaw&}yu8IgZd#hB%)D3e5GO&bad#PDHua~p` znC4VElZ9c3QR=JmlVD`q#;JX#Iz5Q?R3vKGodcJ)*QdvL z)zyf_xf9=OU&s72SZFVFsykI~ViQ#u5D;jva1K;+U5^R!3y0a!4`o}&K0T;(nz(}Y z+|!)gAbt)F(#T9A&NrOEZjs(3j0+x5c6J3wE&z^<(Uuff005i;Ck%-MkO{~C_eSK`e>H}g Uex4aig*xILu~2Jk??4LlKO6jpKmY&$ diff --git a/test/table/test_table_extraction.py b/test/table/test_table_extraction.py index 47bd0d884..31a2ac119 100644 --- a/test/table/test_table_extraction.py +++ b/test/table/test_table_extraction.py @@ -2,6 +2,7 @@ Tests that ensure tables generated by fpdf2 can be extracted by well-know PDF tables extraction tools """ +import sys from pathlib import Path import camelot @@ -14,68 +15,64 @@ from test.table.test_table import TABLE_DATA HERE = Path(__file__).resolve().parent -TABLE_DATA_AS_DF = DataFrame(TABLE_DATA) -TABLE_DATA_AS_DF = DataFrame( - TABLE_DATA_AS_DF.values[1:], columns=TABLE_DATA_AS_DF.iloc[0] -).astype({"Age": int}) +_TMP_DF = DataFrame(TABLE_DATA) +TABLE_DATA_AS_DF = DataFrame(_TMP_DF.values[1:], columns=_TMP_DF.iloc[0]) ############################################################################### ################################### camelot ################################### ############################################################################### - -@pytest.mark.parametrize("flavor", ("lattice", "stream")) -@pytest.mark.parametrize( - "filename", - ( - "table_simple.pdf", - "table_with_images.pdf", - "table_with_images_and_img_fill_width.pdf", - "table_with_headings_styled.pdf", - "table_with_internal_layout.pdf", - ), -) -def test_camelot_extract_simple_table(flavor, filename): - _test_camelot_parse(HERE / filename, flavor, 4, 5) - - -@pytest.mark.parametrize( - "filename", - ( - "table_with_minimal_layout.pdf", - "table_with_single_top_line_layout.pdf", - ), -) -def test_camelot_extract_table_ok_with_only_stream_flavor(filename): - _test_camelot_parse(HERE / filename, "stream", 4, 5) - - -@pytest.mark.parametrize( - "filename", - ( - "table_align.pdf", - # "table_with_cell_fill.pdf", - ), -) -def test_camelot_extract_two_tables(filename): - _test_camelot_parse(HERE / filename, "lattice", 4, 5, table_count=2) - - -@pytest.mark.xfail( - reason="camelot does not successfully parse tables splitted on several pages" -) -@pytest.mark.parametrize("flavor", ("lattice", "stream")) -def test_camelot_extract_two_pages_table(flavor): - _test_camelot_parse(HERE / "table_with_multiline_cells.pdf", flavor, 2, 5) - - -def _test_camelot_parse(pdf_path, flavor, col_count, row_count, table_count=1): - tables = camelot.read_pdf(str(pdf_path), flavor=flavor) - assert tables.n == table_count - for table in tables: - assert len(table.cols) == col_count - assert len(table.rows) == row_count +if sys.platform not in ("cygwin", "win32"): + # Disabling tests as GhostScript is not installed in GitHub Actions pipeline under Windows + + @pytest.mark.parametrize("flavor", ("lattice", "stream")) + @pytest.mark.parametrize( + "filename", + ( + "table_simple.pdf", + "table_with_images.pdf", + "table_with_images_and_img_fill_width.pdf", + "table_with_headings_styled.pdf", + "table_with_internal_layout.pdf", + ), + ) + def test_camelot_extract_simple_table(flavor, filename): + _test_camelot_parse(HERE / filename, flavor, 4, 5) + + @pytest.mark.parametrize( + "filename", + ( + "table_with_minimal_layout.pdf", + "table_with_single_top_line_layout.pdf", + ), + ) + def test_camelot_extract_table_ok_with_only_stream_flavor(filename): + _test_camelot_parse(HERE / filename, "stream", 4, 5) + + @pytest.mark.parametrize( + "filename", + ( + "table_align.pdf", + # "table_with_cell_fill.pdf", + ), + ) + def test_camelot_extract_two_tables(filename): + _test_camelot_parse(HERE / filename, "lattice", 4, 5, table_count=2) + + @pytest.mark.xfail( + reason="camelot does not successfully parse tables splitted on several pages" + ) + @pytest.mark.parametrize("flavor", ("lattice", "stream")) + def test_camelot_extract_two_pages_table(flavor): + _test_camelot_parse(HERE / "table_with_multiline_cells.pdf", flavor, 2, 5) + + def _test_camelot_parse(pdf_path, flavor, col_count, row_count, table_count=1): + tables = camelot.read_pdf(str(pdf_path), flavor=flavor) + assert tables.n == table_count + for table in tables: + assert len(table.cols) == col_count + assert len(table.rows) == row_count ############################################################################### @@ -97,6 +94,7 @@ def test_tabula_extract_simple_table(filename): dataframes = tabula.read_pdf(HERE / filename, pages="all") assert len(dataframes) == 1 for df in dataframes: + df = df.astype({"Age": str}) assert_frame_equal(df, TABLE_DATA_AS_DF, check_names=False) @@ -111,6 +109,7 @@ def test_tabula_extract_two_tables(filename): dataframes = tabula.read_pdf(HERE / filename, pages="all") assert len(dataframes) == 2 for df in dataframes: + df = df.astype({"Age": str}) assert_frame_equal(df, TABLE_DATA_AS_DF, check_names=False) diff --git a/test/test_perfs.py b/test/test_perfs.py index 5c2323e3b..34983b1d7 100644 --- a/test/test_perfs.py +++ b/test/test_perfs.py @@ -8,7 +8,7 @@ HERE = Path(__file__).resolve().parent -@ensure_rss_memory_below(max_in_mib=175) +@ensure_rss_memory_below(max_in_mib=7) @pytest.mark.timeout(40) def test_intense_image_rendering(): png_file_paths = []