1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
|
# Text styling #
## .set_font() ##
Setting emphasis on text can be controlled by using `.set_font(style=...)`:
* `style="B"` indicates **bold**
* `style="I"` indicates _italics_
* `style="S"` indicates <s>strikethrough</s>
* `style="U"` indicates <u>underline</u>
Letters can be combined, for example: `style="BI"` indicates _**bold italics**_
```python
from fpdf import FPDF
pdf = FPDF()
pdf.add_page()
pdf.set_font("Times", size=36)
pdf.cell(text="This")
pdf.set_font(style="B")
pdf.cell(text="is")
pdf.set_font(style="I")
pdf.cell(text="a")
pdf.set_font(style="U")
pdf.cell(text="PDF")
pdf.output("style.pdf")
```
## .set_stretching(stretching=100) ##
Text can be stretched horizontally with this setting, measured in percent.
If the argument is less than 100, then all characters are rendered proportionally narrower and the text string will take less space.
If it is larger than 100, then the width of all characters will be expanded accordingly.
The example shows the same text justified to the same width, with stretching values of 100 and 150.
```python
pdf = FPDF()
pdf.add_page()
pdf.set_font("Helvetica", size=8)
pdf.set_fill_color(255, 255, 0)
pdf.multi_cell(w=50, text=LOREM_IPSUM[:100], new_x="LEFT", fill=True)
pdf.ln()
pdf.set_stretching(150)
pdf.multi_cell(w=50, text=LOREM_IPSUM[:100], new_x="LEFT", fill=True)
```

## .set_char_spacing(spacing=0) ##
This method changes the distance between individual characters of a test string. Normally, characters are placed at a given distance according the width information in the font file. If spacing is larger than 0, then their distance will be larger, creating a gap in between. If it is less than 0, then their distance will be smaller, possibly resulting in an overlap. The change in distance is given in typographic points (Pica), which makes it easy to adapt it relative to the current font size.
Character spacing works best for formatting single line text created by any method, or for highlighting individual words included in a block of text with `.write()`.
**Limitations**: Spacing will only be changed *within* a sequence of characters that `fpdf2` adds to the PDF in one go. This means that there will be no extra distance _eg._ between text parts that are placed successively with `write()`. Also, if you apply different font styles using the Markdown functionality of `.cell()` and `.multi_cell()` or by using `html_write()`, then any parts given different styles will have the original distance between them. This is so because `fpdf2` has to add each styled fragment to the PDF file separately.
The example shows the same text justified to the same width, with char_spacing values of 0 and 10 (font size 8 pt).
```python
pdf = FPDF()
pdf.add_page()
pdf.set_font("Helvetica", size=8)
pdf.set_fill_color(255, 255, 0)
pdf.multi_cell(w=150, text=LOREM_IPSUM[:200], new_x="LEFT", fill=True)
pdf.ln()
pdf.set_char_spacing(10)
pdf.multi_cell(w=150, text=LOREM_IPSUM[:200], new_x="LEFT", fill=True)
```

For a more complete support of **Markdown** syntax,
check out this guide to combine `fpdf2` with the `mistletoe` library:
[Combine with Markdown](CombineWithMarkdown.md).
## Subscript, Superscript, and Fractional Numbers
The class attribute `.char_vpos` controls special vertical positioning modes for text:
* "LINE" - normal line text (default)
* "SUP" - superscript (exponent)
* "SUB" - subscript (index)
* "NOM" - nominator of a fraction with "/"
* "DENOM" - denominator of a fraction with "/"
For each positioning mode there are two parameters that can be configured.
The defaults have been set to result in a decent layout with most fonts, and are given in parens.
The size multiplier for the font size:
* `.sup_scale` (0.7)
* `.sub_scale` (0.7)
* `.nom_scale` (0.75)
* `.denom_scale` (0.75)
The lift is given as fraction of the unscaled font size and indicates how much the glyph gets lifted above the base line (negative for below):
* `.sup_lift` (0.4)
* `.sub_lift` (-0.15)
* `.nom_lift` (0.2)
* `.denom_lift` (0.0)
**Limitations:** The individual glyphs will be scaled down as configured. This is not typographically correct, as it will also reduce the stroke width, making them look lighter than the normal text.
Unicode fonts may include characters in the [subscripts and superscripts range](https://en.wikipedia.org/wiki/Unicode_subscripts_and_superscripts). In a high quality font, those glyphs will be smaller than the normal ones, but have a proportionally stronger stroke width in order to maintain the same visual density. If available in good quality, using Characters from this range is preferred and will look better. Unfortunately, many fonts either don't (fully) cover this range, or the glyphs are of unsatisfactory quality. In those cases, this feature of `fpdf2` offers a reliable workaround with suboptimal but consistent output quality.
Practical use is essentially limited to `.write()` and `html_write()`.
The feature does technically work with `.cell()` and `.multi_cell`, but is of limited usefulness there, since you can't change font properties in the middle of a line (there is no markdown support). It currently gets completely ignored by `.text()`.
The example shows the most common use cases:
```python
pdf = fpdf.FPDF()
pdf.add_page()
pdf.set_font("Helvetica", size=20)
pdf.write(text="2")
pdf.char_vpos = "SUP"
pdf.write(text="56")
pdf.char_vpos = "LINE"
pdf.write(text=" more line text")
pdf.char_vpos = "SUB"
pdf.write(text="(idx)")
pdf.char_vpos = "LINE"
pdf.write(text=" end")
pdf.ln()
pdf.write(text="1234 + ")
pdf.char_vpos = "NOM"
pdf.write(text="5")
pdf.char_vpos = "LINE"
pdf.write(text="/")
pdf.char_vpos = "DENOM"
pdf.write(text="16")
pdf.char_vpos = "LINE"
pdf.write(text=" + 987 = x")
```

## .text_mode ##
The PDF spec defines several text modes:

The text mode can be controlled with the `.text_mode` attribute.
With `STROKE` modes, the line width is induced by `.line_width`,
and its color can be configured with [`set_draw_color()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.set_draw_color).
With `FILL` modes, the filling color can be controlled by [`set_fill_color()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.set_fill_color)
or [`set_text_color()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.set_text_color).
With any of the 4 `CLIP` modes, the letters will be filled by vector drawings made afterwards,
as can be seen in this example:
```python
from fpdf import FPDF
pdf = FPDF(orientation="landscape")
pdf.add_page()
pdf.set_font("Helvetica", size=100)
with pdf.local_context(text_mode="STROKE", line_width=2):
pdf.cell(text="Hello world")
# Outside the local context, text_mode & line_width are reverted
# back to their original default values
pdf.ln()
with pdf.local_context(text_mode="CLIP"):
pdf.cell(text="CLIP text mode")
for r in range(0, 250, 2): # drawing concentric circles
pdf.circle(x=130-r/2, y=70-r/2, radius=r)
pdf.output("text-modes.pdf")
```

More examples from [`test_text_mode.py`](https://github.com/py-pdf/fpdf2/blob/master/test/text/test_text_mode.py):
* [text_modes.pdf](https://github.com/py-pdf/fpdf2/blob/master/test/text/text_modes.pdf)
* [clip_text_modes.pdf](https://github.com/py-pdf/fpdf2/blob/master/test/text/clip_text_modes.pdf)
## markdown=True ##
An optional `markdown=True` parameter can be passed to the [`cell()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.cell)
& [`multi_cell()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.multi_cell) methods
in order to enable basic Markdown-like styling: `**bold**, __italics__, --underlined--`.
If the printable text contains a character sequence that would be incorrectly interpreted as a formatting marker, it can be escaped using `\`. The escape character works the same way it generally does in Python (see the example below).
Bold & italics require using dedicated fonts for each style.
For the standard fonts (Courier, Helvetica & Times), those dedicated fonts are configured by default:
```python
from fpdf import FPDF
pdf = FPDF()
pdf.add_page()
pdf.set_font("Times", size=50)
pdf.cell(text="**Lorem** __Ipsum__ --dolor--", markdown=True, new_x='LEFT', new_y='NEXT')
pdf.cell(text="\\**Lorem\\** \\\\__Ipsum\\\\__ --dolor--", markdown=True)
pdf.output("markdown-styled.pdf")
```

Using other fonts means that their variants (bold, italics)
must be registered using `add_font` with `style="B"` and `style="I"`.
Several unit tests in `test/text/` demonstrate that:
* [test_cell_markdown_with_ttf_fonts](https://github.com/py-pdf/fpdf2/blob/2.6.1/test/text/test_cell.py#L155)
* [test_multi_cell_markdown_with_ttf_fonts](https://github.com/py-pdf/fpdf2/blob/2.6.1/test/text/test_multi_cell_markdown.py#L27)
## .write_html() ##
[`.write_html()`](HTML.md) allows to set emphasis on text through the `<b>`, `<i>` and `<u>` tags:
```python
pdf.write_html("""<B>bold</B>
<I>italic</I>
<U>underlined</U>
<B><I><U>all at once!</U></I></B>"""
)
```
|