Skip to content

Commit bf7f9c8

Browse files
committed
Documentation updates for Xml class and Story recipes
- Includes missing parameters for the some of the functions in the Xml class. - Incudes Story recipe with a layout respecting a "no go area". - Incudes Story recipe which loads some JSON data for use with a list layout.
1 parent b4a8ec9 commit bf7f9c8

File tree

5 files changed

+495
-28
lines changed

5 files changed

+495
-28
lines changed

docs/recipes-stories.rst

Lines changed: 74 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ We extend our "Hello World" example from above and display an image of our plane
152152
-----
153153

154154

155-
Reading External HTML and CSS for a Story
155+
Reading external HTML and CSS for a Story
156156
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
157157

158158
These cases are fairly straightforward.
@@ -174,7 +174,7 @@ As a general recommendation, HTML and CSS sources should be **read as binary fil
174174
-----
175175

176176

177-
How to Output Database Content with Story Templates
177+
How to output database content with Story templates
178178
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
179179

180180
This script demonstrates how to report SQL database content using an **HTML template**.
@@ -220,12 +220,12 @@ The basic idea is letting :ref:`DocumentWriter` output to a PDF in memory. Once
220220
-----
221221

222222

223-
How to Make Multi-Columned Layouts and Access Fonts from Package `pymupdf-fonts <https://github.com/pymupdf/pymupdf-fonts>`_
224-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
223+
How to make multi-columned layouts and access fonts from package `pymupdf-fonts`_
224+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
225225

226226
This script outputs an article (taken from Wikipedia) that contains text and multiple images and uses a 2-column page layout.
227227

228-
In addition, two "Ubuntu" font families from package `pymupdf-fonts <https://github.com/pymupdf/pymupdf-fonts>`_ are used instead of defaulting to Base-14 fonts.
228+
In addition, two "Ubuntu" font families from package `pymupdf-fonts`_ are used instead of defaulting to Base-14 fonts.
229229

230230
Yet another feature used here is that all data -- the images and the article HTML -- are jointly stored in a ZIP file.
231231

@@ -244,6 +244,54 @@ Yet another feature used here is that all data -- the images and the article HTM
244244

245245

246246

247+
How make a layout which wraps around a predefined "no go area" layout
248+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
249+
250+
251+
This is a demo script using PyMuPDF's Story class to output text as a PDF with
252+
a two-column page layout.
253+
254+
The script demonstrates the following features:
255+
256+
* Layout text around images of an existing ("target") PDF.
257+
* Based on a few global parameters, areas on each page are identified, that
258+
can be used to receive text layouted by a Story.
259+
* These global parameters are not stored anywhere in the target PDF and
260+
must therefore be provided in some way.
261+
- The width of the border(s) on each page.
262+
- The fontsize to use for text. This value determines whether the provided
263+
text will fit in the empty spaces of the (fixed) pages of target PDF. It
264+
cannot be predicted in any way. The script ends with an exception if
265+
target PDF has not enough pages, and prints a warning message if not all
266+
pages receive at least some text. In both cases, the FONTSIZE value
267+
can be changed (a float value).
268+
- Use of a 2-column page layout for the text.
269+
* The layout creates a temporary (memory) PDF. Its produced page content
270+
(the text) is used to overlay the corresponding target page. If text
271+
requires more pages than are available in target PDF, an exception is raised.
272+
If not all target pages receive at least some text, a warning is printed.
273+
* The script reads "image-no-go.pdf" in its own folder. This is the "target" PDF.
274+
It contains 2 pages with each 2 images (from the original article), which are
275+
positioned at places that create a broad overall test coverage. Otherwise the
276+
pages are empty.
277+
* The script produces "quickfox-image-no-go.pdf" which contains the original pages
278+
and image positions, but with the original article text laid out around them.
279+
280+
281+
``docs/samples`` files ``quickfox-image-no-go.py``, ``image-no-go.pdf`` & ``quickfox.zip``.
282+
283+
284+
|toggleStart|
285+
286+
.. literalinclude:: samples/quickfox-image-no-go.py
287+
288+
|toggleEnd|
289+
290+
291+
-----
292+
293+
294+
247295
How to output a table
248296
~~~~~~~~~~~~~~~~~~~~~~~~
249297

@@ -280,7 +328,7 @@ By creating a sequence of :ref:`Story` objects within a grid created via the :re
280328
-----
281329

282330

283-
How to Generate a Table of Contents
331+
How to generate a Table of Contents
284332
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
285333

286334
This script lists the source code of all Python scripts that live in the script's directory.
@@ -310,6 +358,24 @@ It features the following capabilities:
310358
-----
311359

312360

361+
How to display a list from JSON data
362+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
363+
364+
This example takes some JSON data input which it uses to populate a :ref:`Story`. It also contains some visual text formatting and shows how to add links.
365+
366+
367+
``docs/samples`` file ``json-example.py``.
368+
369+
|toggleStart|
370+
371+
.. literalinclude:: samples/json-example.py
372+
373+
|toggleEnd|
374+
375+
376+
377+
-----
378+
313379

314380
.. rubric:: Footnotes
315381

@@ -328,7 +394,9 @@ It features the following capabilities:
328394
329395
330396
397+
.. External Links:
331398
399+
.. _pymupdf-fonts: https://github.com/pymupdf/pymupdf-fonts
332400

333401

334402

docs/samples/image-no-go.pdf

127 KB
Binary file not shown.

docs/samples/json-example.py

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
import fitz
2+
import json
3+
4+
my_json = """
5+
[
6+
{
7+
"name" : "Five-storied Pagoda",
8+
"temple" : "Rurikō-ji",
9+
"founded" : "middle Muromachi period, 1442",
10+
"region" : "Yamaguchi, Yamaguchi",
11+
"position" : "34.190181,131.472917"
12+
},
13+
{
14+
"name" : "Founder's Hall",
15+
"temple" : "Eihō-ji",
16+
"founded" : "early Muromachi period",
17+
"region" : "Tajimi, Gifu",
18+
"position" : "35.346144,137.129189"
19+
},
20+
{
21+
"name" : "Fudōdō",
22+
"temple" : "Kongōbu-ji",
23+
"founded" : "early Kamakura period",
24+
"region" : "Kōya, Wakayama",
25+
"position" : "34.213103,135.580397"
26+
},
27+
{
28+
"name" : "Goeidō",
29+
"temple" : "Nishi Honganji",
30+
"founded" : "Edo period, 1636",
31+
"region" : "Kyoto",
32+
"position" : "34.991394,135.751689"
33+
},
34+
{
35+
"name" : "Golden Hall",
36+
"temple" : "Murō-ji",
37+
"founded" : "early Heian period",
38+
"region" : "Uda, Nara",
39+
"position" : "34.536586819357986,136.0395548452301"
40+
},
41+
{
42+
"name" : "Golden Hall",
43+
"temple" : "Fudō-in",
44+
"founded" : "late Muromachi period, 1540",
45+
"region" : "Hiroshima",
46+
"position" : "34.427014,132.471117"
47+
},
48+
{
49+
"name" : "Golden Hall",
50+
"temple" : "Ninna-ji",
51+
"founded" : "Momoyama period, 1613",
52+
"region" : "Kyoto",
53+
"position" : "35.031078,135.713811"
54+
},
55+
{
56+
"name" : "Golden Hall",
57+
"temple" : "Mii-dera",
58+
"founded" : "Momoyama period, 1599",
59+
"region" : "Ōtsu, Shiga",
60+
"position" : "35.013403,135.852861"
61+
},
62+
{
63+
"name" : "Golden Hall",
64+
"temple" : "Tōshōdai-ji",
65+
"founded" : "Nara period, 8th century",
66+
"region" : "Nara, Nara",
67+
"position" : "34.675619,135.784842"
68+
},
69+
{
70+
"name" : "Golden Hall",
71+
"temple" : "Tō-ji",
72+
"founded" : "Momoyama period, 1603",
73+
"region" : "Kyoto",
74+
"position" : "34.980367,135.747686"
75+
},
76+
{
77+
"name" : "Golden Hall",
78+
"temple" : "Tōdai-ji",
79+
"founded" : "middle Edo period, 1705",
80+
"region" : "Nara, Nara",
81+
"position" : "34.688992,135.839822"
82+
},
83+
{
84+
"name" : "Golden Hall",
85+
"temple" : "Hōryū-ji",
86+
"founded" : "Asuka period, by 693",
87+
"region" : "Ikaruga, Nara",
88+
"position" : "34.614317,135.734458"
89+
},
90+
{
91+
"name" : "Golden Hall",
92+
"temple" : "Daigo-ji",
93+
"founded" : "late Heian period",
94+
"region" : "Kyoto",
95+
"position" : "34.951481,135.821747"
96+
},
97+
{
98+
"name" : "Keigū-in Main Hall",
99+
"temple" : "Kōryū-ji",
100+
"founded" : "early Kamakura period, before 1251",
101+
"region" : "Kyoto",
102+
"position" : "35.015028,135.705425"
103+
},
104+
{
105+
"name" : "Konpon-chūdō",
106+
"temple" : "Enryaku-ji",
107+
"founded" : "early Edo period, 1640",
108+
"region" : "Ōtsu, Shiga",
109+
"position" : "35.070456,135.840942"
110+
},
111+
{
112+
"name" : "Korō",
113+
"temple" : "Tōshōdai-ji",
114+
"founded" : "early Kamakura period, 1240",
115+
"region" : "Nara, Nara",
116+
"position" : "34.675847,135.785069"
117+
},
118+
{
119+
"name" : "Kōfūzō",
120+
"temple" : "Hōryū-ji",
121+
"founded" : "early Heian period",
122+
"region" : "Ikaruga, Nara",
123+
"position" : "34.614439,135.735428"
124+
},
125+
{
126+
"name" : "Large Lecture Hall",
127+
"temple" : "Hōryū-ji",
128+
"founded" : "middle Heian period, 990",
129+
"region" : "Ikaruga, Nara",
130+
"position" : "34.614783,135.734175"
131+
},
132+
{
133+
"name" : "Lecture Hall",
134+
"temple" : "Zuiryū-ji",
135+
"founded" : "early Edo period, 1655",
136+
"region" : "Takaoka, Toyama",
137+
"position" : "36.735689,137.010019"
138+
},
139+
{
140+
"name" : "Lecture Hall",
141+
"temple" : "Tōshōdai-ji",
142+
"founded" : "Nara period, 763",
143+
"region" : "Nara, Nara",
144+
"position" : "34.675933,135.784842"
145+
},
146+
{
147+
"name" : "Lotus Flower Gate",
148+
"temple" : "Tō-ji",
149+
"founded" : "early Kamakura period",
150+
"region" : "Kyoto",
151+
"position" : "34.980678,135.746314"
152+
},
153+
{
154+
"name" : "Main Hall",
155+
"temple" : "Akishinodera",
156+
"founded" : "early Kamakura period",
157+
"region" : "Nara, Nara",
158+
"position" : "34.703769,135.776189"
159+
}
160+
]
161+
162+
"""
163+
164+
# the result is a Python dictionary:
165+
my_dict = json.loads(my_json)
166+
167+
MEDIABOX = fitz.paper_rect("letter") # output page format: Letter
168+
WHERE = MEDIABOX + (36, 36, -36, -36)
169+
writer = fitz.DocumentWriter("json-example.pdf") # create the writer
170+
171+
story = fitz.Story()
172+
body = story.body
173+
174+
for i, entry in enumerate(my_dict):
175+
176+
for attribute, value in entry.items():
177+
para = body.add_paragraph()
178+
179+
if attribute == "position":
180+
para.set_fontsize(10)
181+
para.add_link(f"www.google.com/maps/@{value},14z")
182+
else:
183+
para.add_span()
184+
para.set_color("#990000")
185+
para.set_fontsize(14)
186+
para.set_bold()
187+
para.add_text(f"{attribute} ")
188+
para.add_span()
189+
para.set_fontsize(18)
190+
para.add_text(f"{value}")
191+
192+
body.add_horizontal_line()
193+
194+
# This while condition will check a value from the Story `place` method
195+
# for whether all content for the story has been written (0), otherwise
196+
# more content is waiting to be written (1)
197+
more = 1
198+
while more:
199+
device = writer.begin_page(MEDIABOX) # make new page
200+
more, _ = story.place(WHERE)
201+
story.draw(device)
202+
writer.end_page() # finish page
203+
204+
writer.close() # close output file
205+
206+
del story

0 commit comments

Comments
 (0)