From 06501a04a0ee7d8af2f0750d7c5524d6ef160a83 Mon Sep 17 00:00:00 2001 From: Lucas Cimon <925560+Lucas-C@users.noreply.github.com> Date: Fri, 15 Nov 2024 12:49:00 +0100 Subject: [PATCH] Minor improvements regarding annotations --- CHANGELOG.md | 1 + fpdf/annotations.py | 6 +-- fpdf/enums.py | 16 +++---- fpdf/fpdf.py | 44 +++++++++--------- test/free_text_annotation_all_parameters.pdf | Bin 1166 -> 1166 bytes test/free_text_annotation_text_parameter.pdf | Bin 1153 -> 1153 bytes test/free_text_annotation_width_parameter.pdf | Bin 1153 -> 1153 bytes test/goto_action.pdf | Bin 1504 -> 1504 bytes test/goto_remote_action.pdf | Bin 1155 -> 1155 bytes test/highlighted.pdf | Bin 1383 -> 1383 bytes test/highlighted_over_page_break.pdf | Bin 4178 -> 4178 bytes test/ink_annotation.pdf | Bin 1205 -> 1205 bytes test/launch_action.pdf | Bin 1121 -> 1121 bytes test/named_actions.pdf | Bin 2315 -> 2315 bytes test/text_annotation.pdf | Bin 5033 -> 5033 bytes 15 files changed, 34 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c4ae2c8b..53bd3113f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ This can also be enabled programmatically with `warnings.simplefilter('default', * fixed bug where cells with `rowspan`, `colspan` > 1 and null text were not displayed properly - [issue #1293](https://github.com/py-pdf/fpdf2/issues/1293) ### Changed * improved logic for handling text substitution of the total number of pages, ensuring compatibility with text shaping - [issue #1090](https://github.com/py-pdf/fpdf2/issues/1090) +* all [`AnnotationDict`](https://py-pdf.github.io/fpdf2/fpdf/annotations.html) properties can now be passed to `FPDF.text_annotation()`, `FPDF.free_text_annotation()`, `FPDF.add_action()`, `FPDF.add_text_markup_annotation()` & `FPDF.ink_annotation()`. This includes `title`, `color`, `border_width`... ### Removed * reminder : since release `2.8.1`, `fpdf2` does not support Python 3.7, that reached [end-of-life](https://devguide.python.org/versions/#supported-versions) in 2023 diff --git a/fpdf/annotations.py b/fpdf/annotations.py index 790b1a70e..05114b0ac 100644 --- a/fpdf/annotations.py +++ b/fpdf/annotations.py @@ -30,7 +30,7 @@ def __init__( y: int, width: int, height: int, - flags: Tuple[AnnotationFlag] = DEFAULT_ANNOT_FLAGS, + flags: Union[Tuple[AnnotationFlag], Tuple[str]] = DEFAULT_ANNOT_FLAGS, contents: str = None, dest: Destination = None, action: Action = None, @@ -48,11 +48,11 @@ def __init__( ): self.type = Name("Annot") self.subtype = Name(subtype) - self.rect = f"[{x:.2f} {y:.2f} {x + width:.2f} {y - height:.2f}]" + self.rect = f"[{x:.2f} {y - height:.2f} {x + width:.2f} {y:.2f}]" self.border = f"[0 0 {border_width}]" self.f_t = Name(field_type) if field_type else None self.v = value - self.f = sum(flags) + self.f = sum(tuple(AnnotationFlag.coerce(flag) for flag in flags)) self.contents = PDFString(contents, encrypt=True) if contents else None self.a = action self.dest = dest diff --git a/fpdf/enums.py b/fpdf/enums.py index cb70bdf09..9290e5854 100644 --- a/fpdf/enums.py +++ b/fpdf/enums.py @@ -1012,19 +1012,19 @@ class TextDirection(CoerciveEnum): class Duplex(CoerciveEnum): "The paper handling option that shall be used when printing the file from the print dialog." - Simplex = Name("Simplex") + SIMPLEX = Name("Simplex") "Print single-sided" - DuplexFlipShortEdge = Name("DuplexFlipShortEdge") + DUPLEX_FLIP_SHORT_EDGE = Name("DuplexFlipShortEdge") "Duplex and flip on the short edge of the sheet" - DuplexFlipLongEdge = Name("DuplexFlipLongEdge") + DUPLEX_FLIP_LONG_EDGE = Name("DuplexFlipLongEdge") "Duplex and flip on the long edge of the sheet" class PageBoundaries(CoerciveEnum): - ArtBox = Name("ArtBox") - BleedBox = Name("BleedBox") - CropBox = Name("CropBox") - MediaBox = Name("MediaBox") - TrimBox = Name("TrimBox") + ART_BOX = Name("ArtBox") + BLEED_BOX = Name("BleedBox") + CROP_BOX = Name("CropBox") + MEDIA_BOX = Name("MediaBox") + TRIM_BOX = Name("TrimBox") diff --git a/fpdf/fpdf.py b/fpdf/fpdf.py index dbe857e66..9954cbd88 100644 --- a/fpdf/fpdf.py +++ b/fpdf/fpdf.py @@ -2175,7 +2175,7 @@ def set_link(self, link, y=0, x=0, page=-1, zoom="null"): link.zoom = zoom @check_page - def link(self, x, y, w, h, link, alt_text=None, border_width=0): + def link(self, x, y, w, h, link, alt_text=None, **kwargs): """ Puts a link annotation on a rectangular area of the page. Text or image links are generally put via `FPDF.cell`, @@ -2213,7 +2213,7 @@ def link(self, x, y, w, h, link, alt_text=None, border_width=0): height=h * self.k, action=action, dest=dest, - border_width=border_width, + **kwargs, ) self.pages[self.page].annots.append(link_annot) if alt_text is not None: @@ -2313,15 +2313,13 @@ def file_attachment_annotation( h * self.k, file_spec=embedded_file.file_spec(), name=FileAttachmentAnnotationName.coerce(name) if name else None, - flags=tuple(AnnotationFlag.coerce(flag) for flag in flags), + flags=flags, ) self.pages[self.page].annots.append(annotation) return annotation @check_page - def text_annotation( - self, x, y, text, w=1, h=1, name=None, flags=DEFAULT_ANNOT_FLAGS, title="" - ): + def text_annotation(self, x, y, text, w=1, h=1, name=None, **kwargs): """ Puts a text annotation on a rectangular area of the page. @@ -2344,8 +2342,7 @@ def text_annotation( h * self.k, contents=text, name=AnnotationName.coerce(name) if name else None, - flags=tuple(AnnotationFlag.coerce(flag) for flag in flags), - title=title, + **kwargs, ) self.pages[self.page].annots.append(annotation) return annotation @@ -2358,7 +2355,7 @@ def free_text_annotation( y=None, w=None, h=None, - flags=DEFAULT_ANNOT_FLAGS, + **kwargs, ): """ Puts a free text annotation on a rectangular area of the page. @@ -2373,6 +2370,8 @@ def free_text_annotation( h (float): optional height of the link rectangle. Default value: None, meaning an height equal to the current font size flags (Tuple[fpdf.enums.AnnotationFlag], Tuple[str]): optional list of flags defining annotation properties + color (tuple): a tuple of numbers in the range 0.0 to 1.0, representing a colour used for the annotation background + border_width (float): width of the annotation border """ if not self.font_family: raise FPDFException("No font set, you need to call set_font() beforehand") @@ -2392,15 +2391,15 @@ def free_text_annotation( w * self.k, h * self.k, contents=text, - flags=tuple(AnnotationFlag.coerce(flag) for flag in flags), default_appearance=f"({self.draw_color.serialize()} /F{self.current_font.i} {self.font_size_pt:.2f} Tf)", + **kwargs, ) self.fonts_used_per_page_number[self.page].add(self.current_font.i) self.pages[self.page].annots.append(annotation) return annotation @check_page - def add_action(self, action, x, y, w, h): + def add_action(self, action, x, y, w, h, **kwargs): """ Puts an Action annotation on a rectangular area of the page. @@ -2418,13 +2417,14 @@ def add_action(self, action, x, y, w, h): w * self.k, h * self.k, action=action, + **kwargs, ) self.pages[self.page].annots.append(annotation) return annotation @contextmanager def highlight( - self, text, title="", type="Highlight", color=(1, 1, 0), modification_time=None + self, text, type="Highlight", color=(1, 1, 0), modification_time=None, **kwargs ): """ Context manager that adds a single highlight annotation based on the text lines inserted @@ -2448,10 +2448,10 @@ def highlight( type, text, quad_points=quad_points, - title=title, - color=color, modification_time=modification_time, page=page, + color=color, + **kwargs, ) self._text_quad_points = defaultdict(list) self._record_text_quad_points = False @@ -2472,10 +2472,10 @@ def add_text_markup_annotation( type, text, quad_points, - title="", color=(1, 1, 0), modification_time=None, page=None, + **kwargs, ): """ Adds a text markup annotation on some quadrilateral areas of the page. @@ -2511,24 +2511,24 @@ def add_text_markup_annotation( y=y_max, width=x_max - x_min, height=y_max - y_min, - color=color, modification_time=modification_time, - title=title, quad_points=quad_points, + color=color, + **kwargs, ) self.pages[page].annots.append(annotation) return annotation @check_page def ink_annotation( - self, coords, contents="", title="", color=(1, 1, 0), border_width=1 + self, coords, text="", color=(1, 1, 0), border_width=1, **kwargs ): """ Adds add an ink annotation on the page. Args: coords (tuple): an iterable of coordinates (pairs of numbers) defining a path - contents (str): textual description + text (str): textual description title (str): the text label that shall be displayed in the title bar of the annotation’s pop-up window when open and active. This entry shall identify the user who added the annotation. color (tuple): a tuple of numbers in the range 0.0 to 1.0, representing a colour used for @@ -2547,10 +2547,10 @@ def ink_annotation( width=x_max - x_min, height=y_max - y_min, ink_list=ink_list, - color=color, + contents=text, border_width=border_width, - contents=contents, - title=title, + color=color, + **kwargs, ) self.pages[self.page].annots.append(annotation) return annotation diff --git a/test/free_text_annotation_all_parameters.pdf b/test/free_text_annotation_all_parameters.pdf index 426f31ee41532199b227f9aacdcdac358af85cd6..46ded50e34255e6b0ccff8984197346b035df00c 100644 GIT binary patch delta 125 zcmeCXj xlcR-+lc9;DrIVwjk&&CJoee=1v0Qd`T*W1cMI{wQscBpmre<8Ks;>TSTmWmY9%cXl delta 125 zcmeCVgU~XWcXJ)2gVr-yiVZJ$r@fuT%i<_yDo3Vw3fw`NTsky1C xiHn(mrKPEXlclM%xq+*Zoee=1v0Qd`T*W1cMI{wQscBpmre<8Ks;>TSTmVt|9q<4E diff --git a/test/free_text_annotation_text_parameter.pdf b/test/free_text_annotation_text_parameter.pdf index 28bf0625d5584d28998f0a99c7a58e17b6643d63..5b946f137a42b4eb9573c34c8b4809e696cf5997 100644 GIT binary patch delta 122 zcmZqVY~fw8NLfuoy|tDOx&6|r1)c3j0JiA5z9MX70A7AD4As;aL3Zd?HMz8zHn delta 122 zcmZqVY~PXU}#~aXJV{iVPLp9nDG)*jJcbMvx}vRnTxZbtD}>PnYoLj utBH}Bxv{0Oxtp_vg`EvS6|r1)c3j0JiA5z9MX70A7AD4As;aL3Zd?Er{~gT$ diff --git a/test/free_text_annotation_width_parameter.pdf b/test/free_text_annotation_width_parameter.pdf index 04c1c7600a8fa7bf24bbb71ad743ac8fa211f722..9399dea6070e63ec2cfe0496c8edfaa5c92f60bc 100644 GIT binary patch delta 122 zcmZqVY~r~F unWK@bo2!etsezHDg`EvS6|r1)c3j0JiA5z9MX70A7AD4As;aL3Zd?HWFdcjV delta 122 zcmZqVY~PXU}S2lXK18gVPLp9nDG)*jH|J$v9q(QrKzErlZlI&rHPrF ui>sxfp^34ng{7&1vz-k=6|r1)c3j0JiA5z9MX70A7AD4As;aL3Zd?HM5*OIIfo17jBh7gGaE vGgA{+7Z(dBS4Sr!V>=syDq^|p?6`_c5{pVIic-_K3=NG9xKveL{oS|#DX<-i delta 123 zcmaFB{eXLeDWiayrJjL_g0ZQ&o~eO?iHYfES4KOQSaUN23nLSAS2J@%Hy2|QLl<*1 v3qxlMH&nURT+siC8#v5~QX uk%6Ouqp6#Lxv7bvi=7QY6|r1)c3j0JiA5z9MX70A7AB@#s;aL3Zd?G>b{ww& delta 122 zcmZqXZ06kH$|zuFsb^rKU}9paXKDnbOgD!zUSf(dbv1J`b8~eybvAG{Ff=hWG;(z` tFfq4qH8nOiHFdVMvmvM=mdnnLtGFbwsHCDOHI2){#FR@_)z#mP3jp{A9XS91 diff --git a/test/highlighted.pdf b/test/highlighted.pdf index 3b3119d69dafc1199e521974d52481212a0fe752..eae7ac30a349a5764423b18084f0307a1af4c7f7 100644 GIT binary patch delta 102 zcmaFP^_*+NZbo4$*i7;TvyEu76{~Eu9UGEM1)JY@7+GnC!zU4FD~+7-awe diff --git a/test/highlighted_over_page_break.pdf b/test/highlighted_over_page_break.pdf index 25dffafa76f278a7bcfbf80e1dadf3b14a271bba..cdc6e5dcce00fa96f65e7b1175142700a80b819c 100644 GIT binary patch delta 150 zcmcbla7kgq9wq@ZOFdH)1v3K+Jwsy!BV+T)bGh6%3o}=;3z`_1f}|`>Oh8f=hQ^!c zaz(Jl8XFtCxmdcmx|upV8k)M8IvY7T8#@{qx)@m+nYoy|*x3+N5zA#~$5mXCSX5F` Tl$yq6Y++!+rK;-c@5TiHBvd63 delta 150 zcmcbla7kgq9wq@JV{<)I69qE^3q3<)1vAUZbGh6%3o}=;3tAW&gJdjCOh7Uw2Bw?m zaz(JlS{j?X8aul=nOYiKni^WV7?_(mo13^AxVjk|8#+6?+Sw3P5zA#~$5mXCSX5F` Tl$yq6Y++!+rK;-c@5TiH6h9=~ diff --git a/test/ink_annotation.pdf b/test/ink_annotation.pdf index 6bf2ab1ad02644609469d9d50bae6985f14153bd..051f056b3b65ffbf9d83b2862c80defb4c246e5c 100644 GIT binary patch delta 104 zcmdnWxs`K6IirY~k)@uIrGmMorJk|5g1Nb&o`KQkZpL#=PHxU_rj{0Nu7<9zM$T>~ erskGrE+&?a7ACG{CT4ENhITfDR7{@DA_V|m6B(WW delta 104 zcmdnWxs`K6IirZVxuKqck%GCUrJk|5f|-$}o{{C|ZpL#=PA0}~macA&M$S%-&ZaJI erWQ`-rbcG2295?UE|zAlMs_xYR7{@DA_V|mry0Ni diff --git a/test/launch_action.pdf b/test/launch_action.pdf index 041dfd79c5cc32ec8c5fc54bbafc1be75792f4fd..f93cd023e5a39feda667db4fa380f087c87955c1 100644 GIT binary patch delta 122 zcmaFJ@sMMK2BUz9sh)v}g0Z=oo{@oqiJ9eQ3&yidF@}ytmX?ktj+UmD#ztn2mKJU< v<}QYoCPr??PR^DtE_OBqRm5`H*>M$@Bo>ua6s4wdSr{5}sj9mAyKw;kIpQ7d delta 122 zcmaFJ@sMMK2BUzPrJjL_g0Z=oo{@oqiHYfE3&yidG0tvIE{=vyZZ4L_Ca#927N!Qy vMkW^KE+%ef#%=}%PIfi~Rm5`H*>M$@Bo>ua6s4wdSr{5}sj9mAyKw;kNg5sf diff --git a/test/named_actions.pdf b/test/named_actions.pdf index 1140643fee06c59ffdafbb7a8f2ac78c8ba52f86..76a7ab3c0f63d7b9ea91d4834785e26dd98582ec 100644 GIT binary patch delta 171 zcmeAc>K59-!z5s6s%L1VU}R{aXKt=wW^6fGhA9&&XkucjXKDf!w3>XL$w0u|M9u(qb|{b0$>K#Kcg~6etH4RN1_SnTgfO%+S!%%*oQw%+1o&*wxa=&CJo* Y$=uk$+||U=+1cFK&W4bR$sahR0d9~c5&!@I delta 171 zcmeAc>K59-!z5sAsb^@UU}R{aXKt=wW@tKDhA9&&XkucjXKDf!w3>XL$w0u;LeJ6+ zsM<`=z(T>u++;F8b0$>K#Kcg~6etH4RN1_SnTgfO*v!<;*~rq_z|FwGz}d{z&CtTk Y*u=!i#ni~q#L&^q&W4bR$sahR0dG_#?f?J) diff --git a/test/text_annotation.pdf b/test/text_annotation.pdf index 12c9560b4789223c2db6d4cb8c02faf323803b82..18a23f8496d852f4e815bafa0dae287e5e900555 100644 GIT binary patch delta 881 zcmaKpyG|QH6ov&3SKEMh7aSQuTo74M9OiQ7CQ!H-oG1kag;S)A=#XeE-XT&%GYw4? zrKCVY;(d4m#4|86JA-x`s+IQprSt#u-3{&r58G3@GzvKD3j>1p6(K;S?aY0(TMMi9 zaCX7|pDH>Cn#6<@3M7U^ds=rGFr5e$Kv^Jvr)ee)C>fDZ3?vC?(AdkE0)`230z?ON z+1v~lZ{~VAY6O*9p;jQuR?Sv7WUfD~`P-=#q5$Gs{jm3~!Y4kTT}>_)ch4_=P5M8D z1Zn!*82>4kB4HqW+p+yKqcXROs))FBm3-T=eQx_l*l-UZMWR#z`od%Td#M-7d~bAf z<|a}eGfW{EU-&j-?j}vYIRo@9$M$JC?I?2U=8@EkY6GTx#eefVMYO{R1t#lyL>9C} zRP*xDzAQHFWqYlVG#E;us-o2pYAxl3C|$)+O;*o^w%j-`Eb*$bkt^XmMN|`IvLGm- zsv%ZH7YSBnr1IUoloB&FD}K8(l2BF2fjjF&MD%82V$YTbd1)iDst%I{2@$0vGNX)5Y03+ z2&JTm6e;hMCy00kW@q=Hb(40#|LFW@zP%sckAJ^eV3u8h&;2GV%K4+w5X}|I5Ys zY;>j#7(YTTK~q`fef$S7+e{2j>na`~O zlNP~KVHs~1DrRmnB>}0WlyRp>qklK)j+_bS!Ba0059ejCqj0ynm)CM67a+~N9i1gB zgqm8Og@^S{xa{rZMkGNLY8u*3q3#A_x>8k#ny!X1v&$-9gqy-X#ST$ZjpjW0EcqeS z6eROnMGfa%Q1=0=oKU7Ir93?fA=EVTK1&{I^dw>yPBzD^l0mF#!)M7sjh-aD`g6Rs m(mE`PiNGnUj}A2#6K@MwOmSMozjX4!y?d+l{}bVwJ%0o}9>QY)