22from typing import Any , Optional , Union , cast
33
44from .._cmap import _default_fonts_space_width , build_char_map_from_dict
5+ from .._codecs .core_fontmetrics import CORE_FONT_METRICS
56from .._font import FontDescriptor
67from .._utils import logger_warning
78from ..constants import AnnotationDictionaryAttributes , FieldDictionaryAttributes
@@ -132,6 +133,7 @@ def _generate_appearance_stream_data(
132133 text : str = "" ,
133134 selection : Optional [list [str ]] = None ,
134135 rectangle : Union [RectangleObject , tuple [float , float , float , float ]] = (0.0 , 0.0 , 0.0 , 0.0 ),
136+ font_descriptor : FontDescriptor = CORE_FONT_METRICS ["Helvetica" ],
135137 font_glyph_byte_map : Optional [dict [str , bytes ]] = None ,
136138 font_name : str = "/Helv" ,
137139 font_size : float = 0.0 ,
@@ -169,10 +171,27 @@ def _generate_appearance_stream_data(
169171
170172 # If font_size is 0, apply the logic for multiline or large-as-possible font
171173 if font_size == 0 :
174+ if selection : # Don't wrap text when dealing with a /Ch field, in order to prevent problems
175+ multiline = False # with matching "selection" with "line" later on.
172176 if multiline :
173177 font_size = DEFAULT_FONT_SIZE_IN_MULTILINE
174178 else :
175179 font_size = rectangle .height - 2
180+ lines , font_size = self ._scale_text (
181+ font_descriptor ,
182+ font_size ,
183+ rectangle .width - 3 , # One point margin left and right, and an additional point because the first
184+ # offset takes one extra point (see below, under "line_number == 0:")
185+ rectangle .height - 3 , # One point margin for top and bottom, one point extra for the first line
186+ # (see y_offset)
187+ text ,
188+ multiline ,
189+ )
190+ else :
191+ lines = [(
192+ font_descriptor .text_width (line ) * font_size / 1000 ,
193+ line
194+ ) for line in text .replace ("\n " , "\r " ).split ("\r " )]
176195
177196 # Set the vertical offset
178197 y_offset = rectangle .height - 1 - font_size
@@ -183,7 +202,7 @@ def _generate_appearance_stream_data(
183202 f"re\n W\n BT\n { default_appearance } \n " .encode ()
184203 )
185204
186- for line_number , line in enumerate (text . replace ( " \n " , " \r " ). split ( " \r " ) ):
205+ for line_number , ( line_width , line ) in enumerate (lines ):
187206 if selection and line in selection :
188207 # Might be improved, but cannot find how to get fill working => replaced with lined box
189208 ap_stream += (
@@ -240,6 +259,7 @@ def __init__(
240259 # If a font resource was added, get the font character map
241260 if font_resource :
242261 font_resource = cast (DictionaryObject , font_resource .get_object ())
262+ font_descriptor = FontDescriptor .from_font_resource (font_resource )
243263 _font_subtype , _ , font_encoding , font_map = build_char_map_from_dict (
244264 200 , font_resource
245265 )
@@ -260,11 +280,13 @@ def __init__(
260280 else :
261281 logger_warning (f"Font dictionary for { font_name } not found." , __name__ )
262282 font_glyph_byte_map = {}
283+ font_descriptor = FontDescriptor ()
263284
264285 ap_stream_data = self ._generate_appearance_stream_data (
265286 text ,
266287 selection ,
267288 rectangle ,
289+ font_descriptor ,
268290 font_glyph_byte_map ,
269291 font_name ,
270292 font_size ,
0 commit comments