Skip to content

Commit

Permalink
Apply suggestions from code review
Browse files Browse the repository at this point in the history
Co-authored-by: Lucas Cimon <925560+Lucas-C@users.noreply.github.com>
  • Loading branch information
gmischler and Lucas-C authored Oct 9, 2023
1 parent a0cbd91 commit b94160b
Show file tree
Hide file tree
Showing 6 changed files with 29 additions and 22 deletions.
30 changes: 19 additions & 11 deletions docs/TextRegion.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ There are two general categories of regions. One defines boundaries for running
Using the different region types and combination always follows the same pattern. The main difference to the normal `FPDF.write()` method is that all added text will first be buffered, and only gets rendered on the page when the context of the region is closed. This is necessary so that text can be aligned within the given boundaries even if its font, style, or size are arbitrarily varied along the way.

* Create the region instance with an `FPDF` method.
<!--
* future: (_If desired, add or subtract other shapes from it (with geometric regions)_).
* Use the `.write()` method to feed text into its buffer.
-->
* Use the `.write()` method of this text region in order to feed text into its buffer.
* Best practise is to use the region instance as a context manager for filling.
* Text will be rendered automatically after closing the context.
* When used as a context manager, you can change all text styling parameters within that context, and they will be used by the added text, but won't leak to the surroundings
Expand All @@ -25,12 +27,18 @@ Using the different region types and combination always follows the same pattern

![](tcols-paragraphs.png)

The graphic shows shows the relationship of page, text areas and paragraphs (with varying alignment) for the example of a two-column layout.
The graphic shows the relationship of page, text areas and paragraphs (with varying alignment) for the example of a two-column layout.


### Text Start Position ###

When rendering, the vertical start position of the text will be at the lowest one out of the current y position, the top of the region (if it has a defined top), or the top margin of the page. The horizontal start position will be either at the current x position if that lies within the boundaries of the region/column, or at the left edge of the region. In both horizontal and vertical positioning, regions with multiple columns may follow additional rules and restrictions.
When rendering, the vertical start position of the text will be at the lowest one out of:
* the current y position
* the top of the region (if it has a defined top)
* the top margin of the page.

The horizontal start position will be either at the current x position, if that lies within the boundaries of the region/column, or at the left edge of the region.
In both horizontal and vertical positioning, regions with multiple columns may follow additional rules and restrictions.


### Interaction between Regions ###
Expand All @@ -40,7 +48,7 @@ Several region instances can exist at the same time. But only one of them can ac

### Common parameters ###

All types of text regions have the following constructor paramters in common:
All types of text regions have the following constructor parameters in common:

* text (str, optional) - text content to add to the region. This is a convenience parameter for cases when all text is available in one piece, and no partition into paragraphs (possibly with different parameters) is required. (Default: None)
* align (Align/str, optional) - the horizontal alignment of the text in the region. (Default: Align.L)
Expand All @@ -54,28 +62,28 @@ All of those values can be overriden for each individual paragraph.

### Common methods ###

* paragraph() [see characteristics parameters below] - establish a new paragraph in the text. The text added to this paragraph will start on a new line.
* write(text: str, link: = None) - write text to the region. This is only permitted when no explicit paragraph is currently active.
* ln(h: float = None) - Start a new line moving either by the current font height or by the parameter "h". Only permitted when no explicit paragraph is currently active.
* render() - if the region is not used as a context manager with "with", this method must be called to actually process the added text.
* `.paragraph()` [see characteristics parameters below] - establish a new paragraph in the text. The text added to this paragraph will start on a new line.
* `.write(text: str, link: = None)` - write text to the region. This is only permitted when no explicit paragraph is currently active.
* `.ln(h: float = None)` - Start a new line moving either by the current font height or by the parameter "h". Only permitted when no explicit paragraph is currently active.
* `.render()` - if the region is not used as a context manager with "with", this method must be called to actually process the added text.


## Paragraphs ##

The primary purpose of paragraphs is to enable variations in horizontal text alignment, while the horizontal extents of the text are managed by the text region. To set the alignment, you can use the `align` argument when creating the paragraph, with the same `Align` values as elsewhere in the library.
The primary purpose of paragraphs is to enable variations in horizontal text alignment, while the horizontal extents of the text are managed by the text region. To set the alignment, you can use the `align` argument when creating the paragraph. Valid values are defined in the [`Align enum`](https://py-pdf.github.io/fpdf2/fpdf/enums.html#fpdf.enums.Align).

Note that the `write()` methods of paragraphs and text regions in general don't accept any other argument than "text" and "link".

For more typographical control, you can use the following arguments. Most of those override the settings of the current region when set, and default to the value set there.

* align (Align, optional) - The horizontal alignment of the paragraph.
* line_height (float, optional) - factor by which the line spacing will be different from the font height. (default: by region)
* top_margin (float, optional) - how much spacing is added above the paragraph. No spacing will be added at the top if the paragraph if the current y position is at (or above) the top margin of the page. (Default: 0.0)
* top_margin (float, optional) - how much spacing is added above the paragraph. No spacing will be added at the top of the paragraph if the current y position is at (or above) the top margin of the page. (Default: 0.0)
* bottom_margin (float, optional) - Those two values determine how much spacing is added below the paragraph. No spacing will be added at the bottom if it would result in overstepping the bottom margin of the page. (Default: 0.0)
* skip_leading_spaces (float, optional) - removes all space characters at the beginning of each line.
* wrapmode (WrapMode, optional)

Other than text regions, paragraphs should alway be used as context managers and never be reused. Violating those rules may result in the entered text turning up on the page out of sequence.
Other than text regions, paragraphs should always be used as context managers and never be reused. Violating those rules may result in the entered text turning up on the page out of sequence.


### Possible future extensions
Expand Down
2 changes: 1 addition & 1 deletion fpdf/fpdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class Image:
from .image_parsing import SUPPORTED_IMAGE_FILTERS, get_img_info, load_image
from .linearization import LinearizedOutputProducer
from .line_break import Fragment, MultiLineBreak, TextLine
from .outline import OutlineSection # , serialize_outline
from .outline import OutlineSection
from .output import OutputProducer, PDFPage, ZOOM_CONFIGS
from .recorder import FPDFRecorder
from .sign import Signature
Expand Down
5 changes: 2 additions & 3 deletions fpdf/html.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
"""

from html.parser import HTMLParser
import logging, warnings
import re
import logging, re, warnings

from .enums import TextEmphasis, XPos, YPos
from .errors import FPDFException
Expand All @@ -23,7 +22,7 @@
# Pattern to substitute whitespace sequences with a single space character each.
# The following are all Unicode characters with White_Space classification plus the newline.
# The pattern excludes the non-breaking spaces that are included in "\s".
# We also exclude the OGHAM SPACE MARK for now, because while being a word seperator,
# We also exclude the OGHAM SPACE MARK for now, because while being a word separator,
# it is usually a graphically visible glyph.
_WS_CHARS = "".join(
(
Expand Down
4 changes: 2 additions & 2 deletions fpdf/line_break.py
Original file line number Diff line number Diff line change
Expand Up @@ -500,9 +500,9 @@ def automatic_break(self, align: Align):
class MultiLineBreak:
def __init__(
self,
fragments: Sequence,
fragments: Sequence[Fragment],
max_width: Union[float, callable],
margins: Sequence,
margins: Sequence[Number],
align: Align = Align.L,
print_sh: bool = False,
wrapmode: WrapMode = WrapMode.WORD,
Expand Down
8 changes: 4 additions & 4 deletions fpdf/text_region.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class Extents(NamedTuple):


class TextRegionMixin:
"""Mix-in to be added FPDF() in order to support text regions."""
"""Mix-in to be added to FPDF() in order to support text regions."""

def __init__(self, *args, **kwargs):
self.clear_text_region()
Expand Down Expand Up @@ -71,7 +71,7 @@ def write(self, text: str, link=None):
raise FPDFException("No font set, you need to call set_font() beforehand")
normalized_string = self.pdf.normalize_text(text).replace("\r", "")
# YYY _preload_font_styles() should accept a "link" argument.
fragments = self.pdf._preload_font_styles(normalized_string, False)
fragments = self.pdf._preload_font_styles(normalized_string, markdown=False)
if link:
for frag in fragments:
frag.link = link
Expand All @@ -82,11 +82,11 @@ def ln(self, h=None):
raise FPDFException("No font set, you need to call set_font() beforehand")
if h is None:
h = self.pdf.font_size * self.line_height
fragment = self.pdf._preload_font_styles("\n", False)[0]
fragment = self.pdf._preload_font_styles("\n", markdown=False)[0]
fragment.graphics_state["font_size_pt"] = h * fragment.k
self._text_fragments.append(fragment)

def build_lines(self, print_sh):
def build_lines(self, print_sh) -> List[LineWrapper]:
text_lines = []
multi_line_break = MultiLineBreak(
self._text_fragments,
Expand Down
2 changes: 1 addition & 1 deletion test/html/test_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ def test_html_custom_line_height(tmp_path):
text-text-text-text-text-text-text-text-text-text-
text-text-text-text-text-text-text-text-text-text-
text-text-text-text-text-text-text-text-text-text-</p>
<p line-height="x"><!-- invalid line-height ignored -->
<p line-height="x"><!-- invalid line-height ignored, default value of 1 will be used -->
text-text-text-text-text-text-text-text-text-text-
text-text-text-text-text-text-text-text-text-text-
text-text-text-text-text-text-text-text-text-text-</p>
Expand Down

0 comments on commit b94160b

Please sign in to comment.