5151from ._cmap import _default_fonts_space_width , build_char_map_from_dict
5252from ._doc_common import DocumentInformation , PdfDocCommon
5353from ._encryption import EncryptAlgorithm , Encryption
54+ from ._font import FontDescriptor
5455from ._page import PageObject , Transformation
5556from ._page_labels import nums_clear_range , nums_insert , nums_next
5657from ._reader import PdfReader
@@ -929,23 +930,35 @@ def _update_field_annotation(
929930 da = da .get_object ()
930931 font_properties = da .replace ("\n " , " " ).replace ("\r " , " " ).split (" " )
931932 font_properties = [x for x in font_properties if x != "" ]
933+ # If font name was given when calling this method, then add it to
934+ # the font properties, otherwise read it from the default appearance
932935 if font_name :
933936 font_properties [font_properties .index ("Tf" ) - 2 ] = font_name
934937 else :
935938 font_name = font_properties [font_properties .index ("Tf" ) - 2 ]
939+ # If font size was given when calling this method, then add it to
940+ # the font properties, otherwise read it from the default appearance
936941 font_height = (
937942 font_size
938943 if font_size >= 0
939944 else float (font_properties [font_properties .index ("Tf" ) - 1 ])
940945 )
946+ formatting = {
947+ "wrap" : False ,
948+ "scale" : False ,
949+ }
950+ # Only when font height is 0 in the default appearance (or when there is no default
951+ # appearance, but this should not be the case for a text annotation) set the text
952+ # wrapping and/or font scaling options for generating the appearance stream.
941953 if font_height == 0 :
942954 if field .get (FA .Ff , 0 ) & FA .FfBits .Multiline :
943955 font_height = DEFAULT_FONT_HEIGHT_IN_MULTILINE
956+ formatting ["wrap" ] = True
957+ formatting ["scale" ] = True
944958 else :
945959 font_height = rct .height - 2
960+ formatting ["scale" ] = True
946961 font_properties [font_properties .index ("Tf" ) - 1 ] = str (font_height )
947- da = " " .join (font_properties )
948- y_offset = rct .height - 1 - font_height
949962
950963 # Retrieve font information from local DR ...
951964 dr : Any = cast (
@@ -977,6 +990,7 @@ def _update_field_annotation(
977990 _font_subtype , _ , font_encoding , font_map = build_char_map_from_dict (
978991 200 , font_res
979992 )
993+ font_descriptor = FontDescriptor .from_font_resource (font_res )
980994 try : # remove width stored in -1 key
981995 del font_map [- 1 ]
982996 except KeyError :
@@ -994,6 +1008,7 @@ def _update_field_annotation(
9941008 else :
9951009 logger_warning (f"Font dictionary for { font_name } not found." , __name__ )
9961010 font_full_rev = {}
1011+ font_descriptor = FontDescriptor ()
9971012
9981013 # Retrieve field text and selected values
9991014 field_flags = field .get (FA .Ff , 0 )
@@ -1005,11 +1020,9 @@ def _update_field_annotation(
10051020 else : # /Tx
10061021 txt = field .get ("/V" , "" )
10071022 sel = []
1008- # Escape parentheses (PDF 1.7 reference, table 3.2, Literal Strings)
1009- txt = txt .replace ("\\ " , "\\ \\ " ).replace ("(" , r"\(" ).replace (")" , r"\)" )
10101023 # Generate appearance stream
10111024 ap_stream = generate_appearance_stream (
1012- txt , sel , da , font_full_rev , rct , font_height , y_offset
1025+ txt , sel , font_properties , font_full_rev , font_descriptor , rct , font_height , formatting
10131026 )
10141027
10151028 # Create appearance dictionary
@@ -3536,14 +3549,36 @@ def scale_text(
35363549def generate_appearance_stream (
35373550 txt : str ,
35383551 sel : list [str ],
3539- da : str ,
3552+ font_properties : list [ str ] ,
35403553 font_full_rev : dict [str , bytes ],
3554+ font_descriptor : FontDescriptor ,
35413555 rct : RectangleObject ,
35423556 font_height : float ,
3543- y_offset : float ,
3557+ formatting : dict [ str , bool ] ,
35443558) -> bytes :
3559+ # Only wrap text for non-choice fields, otherwise we break matching sel and line later on.
3560+ if sel :
3561+ formatting ["wrap" ] = False
3562+ if formatting ["scale" ]:
3563+ lines , font_height = scale_text (
3564+ font_descriptor ,
3565+ font_height ,
3566+ rct .width - 3 , # One point margin left and right, and an additional point because the first offset
3567+ # takes one extra point (see below, under "line_number == 0:")
3568+ rct .height - 3 , # One point margin for top and bottom, one point extra for the first line (see y_offset)
3569+ txt ,
3570+ formatting ["wrap" ],
3571+ )
3572+ font_properties [1 ] = str (font_height )
3573+ else :
3574+ lines = txt .replace ("\n " , "\r " ).split ("\r " )
3575+
3576+ y_offset = rct .height - 1 - font_height
3577+ da = " " .join (font_properties )
35453578 ap_stream = f"q\n /Tx BMC \n q\n 1 1 { rct .width - 1 } { rct .height - 1 } re\n W\n BT\n { da } \n " .encode ()
3546- for line_number , line in enumerate (txt .replace ("\n " , "\r " ).split ("\r " )):
3579+ for line_number , line in enumerate (lines ):
3580+ # Escape parentheses (PDF 1.7 reference, table 3.2, Literal Strings)
3581+ line = line .replace ("\\ " , "\\ \\ " ).replace ("(" , r"\(" ).replace (")" , r"\)" )
35473582 if line in sel :
35483583 # may be improved but cannot find how to get fill working => replaced with lined box
35493584 ap_stream += (
0 commit comments