pdf_writing_tools 0.0.13 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/pdf_writing_tools.rb +80 -69
- data/lib/pdf_writing_tools_actions.rb +112 -23
- data/lib/pdf_writing_tools_process.rb +39 -16
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4b7caaad32d50f7cfa65735368f939907750d085d412659f40a1894326370a0a
|
4
|
+
data.tar.gz: 5984d8b0d3db96a0421b1abd79b754d49afbb67979d1a1ccd53d87156d232c2a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2666208041f22a0686e8b78b72e8d2d4c37801bff0d53ce783fb12a795024955f81e17991ce1cba769d00b5be925f1a53e9aec40799aabc280e0d49ec8857b09
|
7
|
+
data.tar.gz: 502ee8caf62cdc962bd59e4e076881001d82edef8fa5bb6f15da0096dae1db0e5e088216549d49534a9f5c5b5d79d55b06976fd9568164622496ea48001f425b
|
data/lib/pdf_writing_tools.rb
CHANGED
@@ -14,16 +14,16 @@ module PdfWritingTools
|
|
14
14
|
# span
|
15
15
|
# Altri tag non in elenco, vengono ignorati o causano errore
|
16
16
|
# Il tag <nothtml> ha lo scopo di sottolineare, che questo markup language non è html, anche
|
17
|
-
# se programmando, cerco di renderlo il più simile possibile all'html.
|
18
|
-
|
17
|
+
# se programmando, cerco di renderlo il più simile possibile all'html.
|
18
|
+
|
19
19
|
# L'oggetto xml, viene letto ricorsivamente. Si crea una lista, contenente
|
20
20
|
# dei dizionari. Ciascun dizionario contiene:
|
21
|
-
# Il nome di un'azione: :action_name
|
21
|
+
# Il nome di un'azione: :action_name
|
22
22
|
# Una lista "data", contenente un dizionario con al suo interno le specifiche
|
23
23
|
# da dare a prawn, per "disegnare" del testo o per disegnare un'immagine
|
24
24
|
#
|
25
25
|
# Le p
|
26
|
-
|
26
|
+
|
27
27
|
def self.draw_xml_object(pdf, xml_object)
|
28
28
|
# Ottengo una lista di azioni, ciascuna delle quali, quando eseguita,
|
29
29
|
# permette di disegnare una parte del documento xml all'interno del pdf
|
@@ -42,7 +42,7 @@ module PdfWritingTools
|
|
42
42
|
actions_list += PdfWritingToolsProcess.process_xml_obj(child, [])
|
43
43
|
end
|
44
44
|
end
|
45
|
-
actions_list
|
45
|
+
actions_list + PdfWritingToolsActions.tr_action + PdfWritingToolsActions.tr_action + actions_list + actions_list
|
46
46
|
end
|
47
47
|
|
48
48
|
|
@@ -55,11 +55,11 @@ module PdfWritingTools
|
|
55
55
|
# x e y, indicano rispettivamente le coordinate x e y del vertice in alto a
|
56
56
|
# sinistra del box.
|
57
57
|
# Il vertice è relativo al margine superiore del pdf, contrariamente a quanto
|
58
|
-
# accade quando si utilizzano le primitive prawn (dove il margine di riferimento è
|
58
|
+
# accade quando si utilizzano le primitive prawn (dove il margine di riferimento è
|
59
59
|
# quello basso della pagina).
|
60
60
|
# Bisogna pertanto prestare attenzione quando si dovessero mischiare primitive prawn
|
61
61
|
# con queste funzioni.
|
62
|
-
def self.draw_cell_fixed_height(pdf, x, y, w, h, t, opts={})
|
62
|
+
def self.draw_cell_fixed_height(pdf, x, y, w, h, t, opts={}, auto_y=false, no_background=false)
|
63
63
|
t = (t.class == String ? [{text: t}] : t)
|
64
64
|
font_size = opts[:font_size] || 10
|
65
65
|
style = opts[:style] || :normal
|
@@ -76,6 +76,8 @@ module PdfWritingTools
|
|
76
76
|
pdf_width = opts[:pdf_width] || 21.cm
|
77
77
|
|
78
78
|
result = ''
|
79
|
+
y_pos1 = auto_y ? pdf.cursor : (pdf_height - y)
|
80
|
+
y_pos2 = auto_y ? pdf.cursor - top_padding : (pdf_height - y - top_padding)
|
79
81
|
|
80
82
|
pdf.canvas do
|
81
83
|
pdf.line_width = 0.5
|
@@ -84,35 +86,21 @@ module PdfWritingTools
|
|
84
86
|
pdf.fill_color(background_color)
|
85
87
|
|
86
88
|
# Disegna lo sfondo della cella
|
87
|
-
|
89
|
+
if no_background
|
90
|
+
else
|
91
|
+
pdf.fill_rectangle([x, y_pos1], w, h)
|
92
|
+
end
|
88
93
|
|
89
94
|
pdf.stroke_color border_color
|
90
|
-
pdf.stroke_rectangle([x,
|
95
|
+
pdf.stroke_rectangle([x, y_pos1], w, h)
|
91
96
|
|
92
97
|
# Colore del testo nella cella
|
93
98
|
pdf.fill_color(font_color)
|
94
|
-
# Disegno il testo contenuto nella cella
|
95
|
-
if false
|
96
|
-
result = pdf.text_box(
|
97
|
-
t,
|
98
|
-
at: [x + left_padding, pdf_height - y - top_padding],
|
99
|
-
width: w - left_padding - right_padding,
|
100
|
-
height: h - top_padding - bottom_padding,
|
101
|
-
size: font_size,
|
102
|
-
style: style,
|
103
|
-
align: align,
|
104
|
-
valign: valign
|
105
|
-
)
|
106
|
-
end
|
107
|
-
|
108
|
-
if true
|
109
|
-
at = [x + left_padding, pdf_height - y - top_padding]
|
110
|
-
width = w - left_padding - right_padding
|
111
|
-
height = h - top_padding - bottom_padding + 1.cm
|
112
|
-
|
113
|
-
pdf.formatted_text_box(t, width: width, height: height, at: at)
|
114
|
-
end
|
115
99
|
|
100
|
+
at = [x + left_padding, y_pos2]
|
101
|
+
width = w - left_padding - right_padding
|
102
|
+
height = h - top_padding - bottom_padding + 1.cm
|
103
|
+
result = pdf.formatted_text_box(t, width: width, height: height, at: at, size: font_size, style: style, align: align, valign: valign)
|
116
104
|
end
|
117
105
|
|
118
106
|
result
|
@@ -124,64 +112,79 @@ module PdfWritingTools
|
|
124
112
|
# della funzione).
|
125
113
|
# Produce un dizionario, con l'altezza della cella disegnata ed eventuale testo non disegnato
|
126
114
|
# (es. nel caso di sopraggiunto fine pagina).
|
127
|
-
# Il campo draw_simulation, serve ad evitare che la cella venga realmente disegnata nel pdf.
|
115
|
+
# Il campo draw_simulation, serve ad evitare che la cella venga realmente disegnata nel pdf.
|
128
116
|
# In questo modo, posso ottenere l'altezza, eventuale testo "avanzato" e prendere decisioni che
|
129
|
-
# non dipendano da un'unica cella, ma da un gruppo di celle, come ad esempio quando devo
|
130
|
-
# disegnare la riga di una tabella che essendo composta da più celle, ha un altezza
|
117
|
+
# non dipendano da un'unica cella, ma da un gruppo di celle, come ad esempio quando devo
|
118
|
+
# disegnare la riga di una tabella che essendo composta da più celle, ha un altezza
|
131
119
|
# che dipende dall'altezza massima delle celle "autoridimensionanti" che la compongono.
|
132
|
-
def self.draw_cell_auto_height(pdf, draw_simulation, x, y, w, t, opts={})
|
120
|
+
def self.draw_cell_auto_height(pdf, draw_simulation, x, y, w, t, opts={}, auto_y=false, no_background=false)
|
133
121
|
font_size = opts[:font_size] || 10
|
134
122
|
style = opts[:style] || :normal
|
135
123
|
align = opts[:align] || :left
|
136
|
-
valign = opts[:
|
124
|
+
valign = opts[:valign] || :top
|
137
125
|
font_color = opts[:font_color] || "000000"
|
138
126
|
border_color = opts[:border_color] || "000000"
|
139
127
|
background_color = opts[:background_color] || "FFFFFF"
|
140
|
-
left_padding = opts[:left_padding] || 5
|
141
|
-
right_padding = opts[:right_padding] || 5
|
142
|
-
top_padding = opts[:top_padding] || 5
|
143
|
-
bottom_padding = opts[:bottom_padding] || 5
|
144
|
-
pdf_height = opts[:pdf_height] || 297.mm
|
145
|
-
pdf_width = opts[:pdf_width] || 21.cm
|
146
|
-
|
128
|
+
left_padding = opts[:left_padding] || 5#
|
129
|
+
right_padding = opts[:right_padding] || 5#
|
130
|
+
top_padding = opts[:top_padding] || 5#
|
131
|
+
bottom_padding = opts[:bottom_padding] || 5#
|
132
|
+
pdf_height = opts[:pdf_height] || 297.mm #
|
133
|
+
pdf_width = opts[:pdf_width] || 21.cm #
|
134
|
+
|
135
|
+
t = (t.class == String ? [{text: t, size: font_size, color: font_color}] : t)
|
136
|
+
|
137
|
+
|
138
|
+
|
147
139
|
result = 0
|
148
|
-
|
140
|
+
y_pos1 = auto_y ? (pdf.cursor - top_padding) : (pdf_height - y - top_padding)
|
141
|
+
y_pos2 = auto_y ? pdf.cursor : (pdf_height - y)
|
142
|
+
|
149
143
|
pdf.canvas do
|
150
|
-
# Non utilizzo l'helper (pdf.
|
151
|
-
# ma io ho bisogno di conoscere l'altezza del box di testo, prima di scriverlo, in
|
144
|
+
# Non utilizzo l'helper (pdf.formatted_text_box), in quanto scriverebbe direttamente nel pdf
|
145
|
+
# ma io ho bisogno di conoscere l'altezza del box di testo formattato, prima di scriverlo, in
|
152
146
|
# modo da poter disegnare PRIMA lo sfondo
|
153
|
-
|
154
|
-
|
155
|
-
|
147
|
+
|
148
|
+
|
149
|
+
b = Prawn::Text::Formatted::Box.new(
|
150
|
+
t,
|
151
|
+
{:at => [x + left_padding, y_pos1 ],
|
156
152
|
:width => w - left_padding-right_padding,
|
157
153
|
:size => font_size,
|
158
154
|
:style => style,
|
159
155
|
:overflow => :expand,
|
160
|
-
:document => pdf
|
161
|
-
|
156
|
+
:document => pdf,
|
157
|
+
:align => align,
|
158
|
+
:valign => valign}) #valign ha un comportamento da indagare, mi fa uscire il testo fuori dal box
|
159
|
+
|
162
160
|
# Effettuo il render, ma in modalità "prova" (dry_run = true), così posso conoscere quale sarà
|
163
161
|
# l'altezza del box prima di disegnarlo
|
164
|
-
|
162
|
+
|
165
163
|
text_overflow = b.render(:dry_run => true)
|
166
|
-
|
164
|
+
#text_overflow = text_overflow[:text] #### Temporaneo
|
165
|
+
|
167
166
|
# Altezza del box, non ancora disegnato
|
168
167
|
h = b.height
|
169
|
-
|
168
|
+
|
170
169
|
if not draw_simulation
|
171
170
|
# Se non sono in simulazione...
|
172
171
|
# ... ora che conosco quale sarà l'altezza del box di testo, posso disegnare lo sfondo
|
173
172
|
pdf.fill_color(background_color) # colore dello sfondo
|
174
173
|
pdf.stroke_color(border_color) # Colore del bordo
|
175
|
-
|
176
|
-
|
177
|
-
|
174
|
+
|
175
|
+
|
176
|
+
|
177
|
+
if no_background
|
178
|
+
else
|
179
|
+
pdf.fill_and_stroke_rectangle([x, y_pos2], (w + left_padding + right_padding), (h+top_padding+bottom_padding))
|
180
|
+
end
|
178
181
|
# ... e infine, sopra lo sfondo disegno il testo
|
179
182
|
pdf.fill_color(font_color) # colore del testo
|
180
|
-
text_overflow = b.render()
|
183
|
+
text_overflow = b.render()
|
181
184
|
|
182
185
|
# text_overflow è l'eventuale testo avanzato
|
183
186
|
end
|
184
|
-
|
187
|
+
|
185
188
|
# La cella potrebbe non riuscire ad espandersi a sufficienza (troppo vicina al
|
186
189
|
# fine pagine, quindi può essere che del testo "avanzi" )
|
187
190
|
result = {height: h + top_padding + bottom_padding, overflow: text_overflow}
|
@@ -191,7 +194,7 @@ module PdfWritingTools
|
|
191
194
|
end
|
192
195
|
|
193
196
|
|
194
|
-
def self.draw_row_fixed_height(pdf, x, y, widths, height, texts, opts={})
|
197
|
+
def self.draw_row_fixed_height(pdf, x, y, widths, height, texts, opts={}, auto_y=false)
|
195
198
|
font_sizes = opts[:font_sizes] || [10]
|
196
199
|
styles = opts[:styles] || [:normal]
|
197
200
|
alignments = opts[:alignments] || [:left]
|
@@ -202,7 +205,7 @@ module PdfWritingTools
|
|
202
205
|
paddings = opts[:paddings] || [{left_padding: 5, right_padding: 5, top_padding: 5, bottom_padding: 5}]
|
203
206
|
pdf_height = opts[:pdf_height] || 297.mm
|
204
207
|
pdf_width = opts[:pdf_width] || 21.cm
|
205
|
-
|
208
|
+
|
206
209
|
offset = 0
|
207
210
|
|
208
211
|
widths.each_with_index do |width, i|
|
@@ -231,14 +234,15 @@ module PdfWritingTools
|
|
231
234
|
cell_opts[:pdf_width] = 21.cm
|
232
235
|
cell_opts[:pdf_height] = 297.mm
|
233
236
|
|
234
|
-
draw_cell_fixed_height( pdf, x+offset, y, width, height, texts[i], cell_opts)
|
237
|
+
draw_cell_fixed_height( pdf, x+offset, y, width, height, texts[i], cell_opts, auto_y)
|
235
238
|
|
236
239
|
offset += width
|
237
240
|
end
|
241
|
+
pdf.y = (pdf.cursor - height)
|
238
242
|
end
|
239
243
|
|
240
|
-
|
241
|
-
def self.draw_row_auto_height(pdf, draw_simulation, x, y, widths, texts, opts = {})
|
244
|
+
# Produce la y su pdf, dove disegnare la prossima riga
|
245
|
+
def self.draw_row_auto_height(pdf, draw_simulation, x, y, widths, texts, opts = {}, auto_y)
|
242
246
|
font_sizes = opts[:font_sizes] || [10]
|
243
247
|
styles = opts[:styles] || [:normal]
|
244
248
|
alignments = opts[:alignments] || [:left]
|
@@ -290,7 +294,7 @@ module PdfWritingTools
|
|
290
294
|
cell_opts[:pdf_height] = 297.mm
|
291
295
|
cell_opts[:pdf_weigth] = 21.cm
|
292
296
|
|
293
|
-
r = draw_cell_auto_height(pdf, draw_simulation = true, x+offset, y, width, texts[i], cell_opts)
|
297
|
+
r = draw_cell_auto_height(pdf, draw_simulation = true, x+offset, y, width, texts[i], cell_opts, auto_y)
|
294
298
|
|
295
299
|
if r[:height] > max_cell_height
|
296
300
|
max_cell_height = r[:height]
|
@@ -299,6 +303,8 @@ module PdfWritingTools
|
|
299
303
|
offset += width
|
300
304
|
end
|
301
305
|
|
306
|
+
# Non voglio che la riga ecceda il margine di pagina, quindi se così fosse
|
307
|
+
# ricalcolo l'altezza di riga per non superare tale margine
|
302
308
|
if y + max_cell_height > pdf_height - pdf_margin_bottom
|
303
309
|
max_cell_height = pdf_height - pdf_margin_bottom - y
|
304
310
|
end
|
@@ -334,7 +340,7 @@ module PdfWritingTools
|
|
334
340
|
|
335
341
|
# ...disegno le celle vere e proprie ad altezza fissa, con l'altezza
|
336
342
|
# ricavata dal passo precedente.
|
337
|
-
r = draw_cell_fixed_height(pdf, x+offset, y, width, max_cell_height, texts[i], opts)
|
343
|
+
r = draw_cell_fixed_height(pdf, x+offset, y, width, max_cell_height, texts[i], opts, auto_y)
|
338
344
|
|
339
345
|
# Gli eventuali "testi residui" (es. raggiunto fine pagina) li raccolgo
|
340
346
|
# nel seguente array
|
@@ -357,19 +363,24 @@ module PdfWritingTools
|
|
357
363
|
end
|
358
364
|
end
|
359
365
|
|
366
|
+
pdf.y = (pdf_height - new_y)
|
367
|
+
|
360
368
|
return new_y
|
361
369
|
end
|
362
370
|
|
371
|
+
# Se tutte le stringhe nella lista sono "" (stringa vuota) produce false
|
372
|
+
# altrimenti produce true.
|
363
373
|
def self.check_no_empty_string_presence(string_list)
|
364
|
-
|
365
|
-
if string_element != ""
|
374
|
+
string_list.each do |string_element|
|
375
|
+
if string_element != "" and string_element != []
|
366
376
|
return true
|
367
377
|
end
|
368
378
|
end
|
379
|
+
|
369
380
|
return false
|
370
381
|
end
|
371
382
|
|
372
|
-
# Dato il percorso file_path, genera un documento xml, a cui sono stati rimossi gli
|
383
|
+
# Dato il percorso file_path, genera un documento xml, a cui sono stati rimossi gli
|
373
384
|
# a capo e gli spazi multipli
|
374
385
|
def self.get_cleaned_xml_from_file(file_path)
|
375
386
|
text = File.read(file_path)
|
@@ -380,6 +391,6 @@ module PdfWritingTools
|
|
380
391
|
# Rimuove le spaziature multiple sostituendole con uno spazio
|
381
392
|
text = text.gsub(/\s+/, ' ')
|
382
393
|
|
383
|
-
Nokogiri::XML(text)
|
394
|
+
Nokogiri::XML(text)
|
384
395
|
end
|
385
396
|
end
|
@@ -1,26 +1,28 @@
|
|
1
|
-
# Questo modulo, si occupa di
|
1
|
+
# Questo modulo, si occupa di
|
2
2
|
|
3
3
|
|
4
4
|
# Le action, definiscono, cosa deve essere fatto (scritto, colorato, disegnato) nel pdf
|
5
5
|
# La forma di una action è una coppia (nome_action, dati_per_la_action)
|
6
6
|
# L'esecuzione di una action consiste nel realizzare la action usando i dati ad essa associati
|
7
|
-
# Quando l'oggetto xml che rappresenta il mio documento pdf da realizzare viene processato,
|
8
|
-
# viene creata una catena (lista) di action.
|
9
|
-
# Alcune action consecutive, possono essere "fuse" tra loro in un'unica action, così da
|
10
|
-
# efficientare il processo di scrittura del file pdf
|
7
|
+
# Quando l'oggetto xml che rappresenta il mio documento pdf da realizzare viene processato,
|
8
|
+
# viene creata una catena (lista) di action.
|
9
|
+
# Alcune action consecutive, possono essere "fuse" tra loro in un'unica action, così da
|
10
|
+
# efficientare il processo di scrittura del file pdf (eseguire singolarmente le action di
|
11
|
+
# scrittura testo ad esempio, rallenta molto la scrittura del pdf).
|
11
12
|
# Ogni singola action, viene poi eseguita, utilizzando le funzioni di prawn.
|
12
13
|
|
13
|
-
# Nella parte PUBLIC di questa classe, inserire solo metodi che generino action
|
14
|
-
# La classe PdfWritingToolsProcess, userà i metodi pubblic di questa classe per generare
|
15
|
-
# una list di action. Fornendo la lista di actions al metodo
|
14
|
+
# Nella parte PUBLIC di questa classe, inserire solo metodi che generino action (ma non le eseguono)
|
15
|
+
# La classe PdfWritingToolsProcess, userà i metodi pubblic di questa classe per generare
|
16
|
+
# una list di action. Fornendo la lista di actions al metodo
|
16
17
|
# PdfWritingToolsActions.execute_actions, verrà dato il via all'esecuzione delle actions...
|
17
18
|
|
18
|
-
# Nella parte PRIVATE di questa classe, inserire solo metodi che eseguano le action
|
19
|
+
# Nella parte PRIVATE di questa classe, inserire solo metodi che eseguano le action (
|
20
|
+
# ossia che realizzino la scrittura del pdf)
|
19
21
|
# ... le singole actions, verrano eseguite tramite i metodi privati di questa classe
|
20
22
|
|
21
23
|
module PdfWritingToolsActions
|
22
24
|
# Esegue le azioni, andando a concatenare quelle "contigue" nella lista,
|
23
|
-
# che riguardano la scrittura di testo.
|
25
|
+
# che riguardano la scrittura di testo.
|
24
26
|
# La lista actions, in sostanza comprende più azioni. Quelle contigue che riguardano
|
25
27
|
# la scrittura di testo, non vanno eseguite singolarmente, ma devono essere "fuse"
|
26
28
|
# e poi eseguite. Le action che riguardano la "scrittura" di un immagine invece, non
|
@@ -31,6 +33,8 @@ module PdfWritingToolsActions
|
|
31
33
|
last_actn_name, data = text_action(pdf, action, last_actn_name, data)
|
32
34
|
elsif action[:action_name] == :draw_image
|
33
35
|
last_actn_name, data = img_action(pdf, action, last_actn_name, data)
|
36
|
+
elsif action[:action_name] == :draw_tr
|
37
|
+
last_actn_name, data = draw_tr(pdf, action, last_actn_name, data)
|
34
38
|
end
|
35
39
|
end
|
36
40
|
|
@@ -43,6 +47,8 @@ module PdfWritingToolsActions
|
|
43
47
|
[{ action_name: :draw_formatted_text, data: [{ text: "\n" }] }]
|
44
48
|
end
|
45
49
|
|
50
|
+
# Per "atomic_text" si intende testo che non contiene ulteriore "struttura"
|
51
|
+
# pesudo html
|
46
52
|
def self.atomic_text_action(atomic_text)
|
47
53
|
[{ action_name: :draw_formatted_text, data: [{ text: atomic_text }] }]
|
48
54
|
end
|
@@ -66,7 +72,8 @@ module PdfWritingToolsActions
|
|
66
72
|
def self.bullet_action
|
67
73
|
[
|
68
74
|
{
|
69
|
-
action_name: :draw_image,
|
75
|
+
action_name: :draw_image,
|
76
|
+
data:
|
70
77
|
{
|
71
78
|
url: File.expand_path("../../assets/bullet.png", __FILE__)
|
72
79
|
# Pallino
|
@@ -75,8 +82,79 @@ module PdfWritingToolsActions
|
|
75
82
|
]
|
76
83
|
end
|
77
84
|
|
85
|
+
def self.tr_action(xml_obj=nil, widths=nil)
|
86
|
+
text = "<tr><td>Uno</td><td>Due</td><td>Tre</td><td>Quattro</td></tr>"
|
87
|
+
widths = [2.cm, 2.cm, 3.cm, 4.cm]
|
88
|
+
xml_obj = Nokogiri::XML(text)
|
89
|
+
[
|
90
|
+
{
|
91
|
+
action_name: :draw_tr,
|
92
|
+
data:
|
93
|
+
{
|
94
|
+
xml_obj: xml_obj,
|
95
|
+
widths: widths
|
96
|
+
}
|
97
|
+
}
|
98
|
+
]
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
|
78
103
|
private
|
79
104
|
|
105
|
+
# Funzione di Prawn che devo capir bene come utilizzare per la generazione
|
106
|
+
# delle tabelle
|
107
|
+
|
108
|
+
####### FORMATTED TEXT BOX (formatted_text_box)
|
109
|
+
# formatted_text_box
|
110
|
+
# https://prawnpdf.org/docs/0.11.1/Prawn/Text/Formatted.html
|
111
|
+
|
112
|
+
# Accetta due parametri: un array di dizionari e (facoltativo) un dizionario di opzioni
|
113
|
+
|
114
|
+
# ARRAY DI DIZIONARI
|
115
|
+
# Ciascun dizionario, contiene il testo da disegnare e informazioni su come
|
116
|
+
# formattarlo.
|
117
|
+
|
118
|
+
# DIZIONARIO DI OPZIONI
|
119
|
+
|
120
|
+
# Come disegnare testo formattato
|
121
|
+
# Posso usare due metodi
|
122
|
+
|
123
|
+
# (entrambi i metodi alla fine, forniscono informazioni sull'altezza del BOX
|
124
|
+
# disegnato e sul testo eventualmente non disegnato)
|
125
|
+
|
126
|
+
##### METODO 1 - In un'unica fase
|
127
|
+
# Utilizzo una funzione di convenienza che disegna immediatamente nel pdf:
|
128
|
+
# formatted_text_box
|
129
|
+
|
130
|
+
##### METODO 2 - In due fasi
|
131
|
+
# - Genero un oggetto con gli stessi parametri di formatted_text_box:
|
132
|
+
# oggetto = Prawn::Text::Formatted.new(array_di_dizionari, dizionario_di_opzioni)
|
133
|
+
# - Eseguo il rendering dell'oggetto
|
134
|
+
# formatted_text_not_rendered_or_overflow = oggetto.render(:dry_run => false)
|
135
|
+
# oggetto.height # altezza del box
|
136
|
+
#
|
137
|
+
# :dry_run true o false, mi permette di scrivere nel pdf o simulare la scrittura
|
138
|
+
# così da avere informazioni sulla dimensione del box da disegnare senza disegnarlo
|
139
|
+
# effettivamente. Perché?
|
140
|
+
# Supponiamo di dover disegnare la riga di una tabella, dove ciascuna cella
|
141
|
+
# della riga, contenga del testo formattato. Le celle della riga possono avere
|
142
|
+
# larghezze differenti, ma devono avere tutte la stessa altezza... ma quale
|
143
|
+
# altezza? Se definisco un'altezza fissa, c'è la possibilità che testo in
|
144
|
+
# eccesso all'interno di una cella venga tagliato, oppure che ci sia troppo
|
145
|
+
# spazio non utilizzato in tutte le celle (il che è visivamente brutto).
|
146
|
+
# Se utilizzo l'autoridimensionamento del formatted_text_box, offerto da prawn,
|
147
|
+
# avrò ciascuna cella con un altezza differente... Utilizzando invece la
|
148
|
+
# "simulazione", prima disegno (in modalità simulata :dry_run => true) la
|
149
|
+
# riga delle tabella con celle ad altezza autoridimensionata, in questo modo
|
150
|
+
# posso capire qual'è l'altezza di cella massima e se una di queste celle
|
151
|
+
# provoca un salto pagina (nel disegno di box autoridimensionati, l'Altezza
|
152
|
+
# del box, non eccede il salto pagina ed il testo che non può essere disegnato
|
153
|
+
# a causa del salto pagina, mi viene restituito dalla funzione di rendering).
|
154
|
+
# Successivamente disegno la riga vera e propria,
|
155
|
+
# questa volta, indicando un'altezza fissa per ciascuna cella (l'altezza massima
|
156
|
+
# di cella ottenuta nella simulazione).
|
157
|
+
|
80
158
|
# Esegue un'azione, andando a scrivere del testo nel PDF, oppure un'immagine
|
81
159
|
def self.execute_action(pdf, action_name, data)
|
82
160
|
if action_name == :draw_formatted_text
|
@@ -85,50 +163,55 @@ module PdfWritingToolsActions
|
|
85
163
|
# Il testo disegnato dopo un immagine, non appare allineato. Per questo
|
86
164
|
# motivo, disegno l'immagine un' po' prima di dove è previsto (spostando il cursore)
|
87
165
|
# per poi ripristinare la posizione originaria del cursore.
|
88
|
-
|
166
|
+
|
89
167
|
# L'operazione di cui sopra, non va eseguita a fondo pagina, altrimenti,
|
90
168
|
# il salto pagina automatico crea problemi sulla realizzazione del pdf,
|
91
169
|
# quindi...
|
92
|
-
|
170
|
+
|
93
171
|
# Se la posizione del cursore (misurata, dal fondo margine di pagina)
|
94
172
|
# è inferiore ad un cm, mi sposto direttamente sulla nuova pagina..
|
95
173
|
if pdf.cursor <= 1.cm
|
96
174
|
pdf.start_new_page
|
97
175
|
end
|
98
|
-
|
176
|
+
|
99
177
|
current_cursor_position = pdf.cursor
|
100
178
|
# Anticipo il disegno dell'immagine spostando il cursore di n unità verso
|
101
179
|
# l'alto
|
102
180
|
n = 0
|
103
181
|
pdf.move_cursor_to(current_cursor_position - n)
|
104
|
-
|
182
|
+
|
105
183
|
# Disegno l'immagine (al momento questo metodo disegna solo il "bullet" degli elenchi)
|
106
184
|
pdf.image(data[:url], height: 6, width: 6)
|
107
|
-
|
185
|
+
|
108
186
|
# Ripristino la posizione originaria del cursore, in modo che il testo
|
109
187
|
# sia allineato all'immagine preceente
|
110
188
|
pdf.move_cursor_to(current_cursor_position)
|
111
|
-
elsif action_name == :
|
189
|
+
elsif action_name == :draw_tr
|
190
|
+
xml_obj = data[:xml_obj]
|
191
|
+
widths = data[:widths]
|
112
192
|
|
193
|
+
current_cursor_position = 297.mm - pdf.cursor
|
194
|
+
|
195
|
+
PdfWritingTools::draw_row_auto_height(pdf, false, 2.cm, current_cursor_position, widths, ["uno", "due", "tre", "quattro"], opts = {}, true)
|
113
196
|
end
|
114
197
|
end
|
115
|
-
|
198
|
+
|
116
199
|
# Esegue last_action, oppure concatena i dati di action e di last_action
|
117
200
|
# action: azione "corrente"
|
118
201
|
# last_action_name: nome dell'azione che precede l'azione corrente
|
119
202
|
# data: dati dell'azione che precede l'azione corrente
|
120
203
|
def self.text_action(pdf, action, last_action_name, data)
|
121
204
|
if last_action_name.nil?
|
122
|
-
# Prima azione della lista (last_action_name = nil), quindi per ora
|
205
|
+
# Prima azione della lista (last_action_name = nil), quindi per ora
|
123
206
|
# nessun concatenamento di dati
|
124
207
|
data = action[:data]
|
125
208
|
elsif last_action_name == :draw_formatted_text
|
126
209
|
# La action attuale richiede di "disegnare" testo formattato, come l'ultima azione
|
127
|
-
# quindi, concateno i dati di questa action, con quelli dell'ultima action
|
210
|
+
# quindi, concateno i dati di questa action, con quelli dell'ultima action
|
128
211
|
data += action[:data]
|
129
212
|
else
|
130
213
|
# La action attuale, differisce dall'ultima, quindi eseguo l'ultima action (che sarà
|
131
|
-
# un'immagine visto che quella attuale è il disegno di testo) e produco i dati di
|
214
|
+
# un'immagine visto che quella attuale è il disegno di testo) e produco i dati di
|
132
215
|
# quella corrente
|
133
216
|
execute_action(pdf, last_action_name, data)
|
134
217
|
data = action[:data]
|
@@ -136,7 +219,7 @@ module PdfWritingToolsActions
|
|
136
219
|
|
137
220
|
[:draw_formatted_text, data]
|
138
221
|
end
|
139
|
-
|
222
|
+
|
140
223
|
# Mentre la "scrittura/disegno" del testo, puo' essere "concatenato", nel caso
|
141
224
|
# delle immagini no. Una action sull' immagine pertanto, interrompe la
|
142
225
|
# possibilita' di concatenare i data delle action di testo. Quindi, eseguo
|
@@ -146,4 +229,10 @@ module PdfWritingToolsActions
|
|
146
229
|
execute_action(pdf, last_action_name, data) unless last_action_name.nil?
|
147
230
|
[:draw_image, action[:data]]
|
148
231
|
end
|
149
|
-
|
232
|
+
|
233
|
+
|
234
|
+
def self.draw_tr(pdf, action, last_action_name, data)
|
235
|
+
execute_action(pdf, last_action_name, data) unless last_action_name.nil?
|
236
|
+
[:draw_tr, action[:data]]
|
237
|
+
end
|
238
|
+
end
|
@@ -58,17 +58,17 @@ module PdfWritingToolsProcess
|
|
58
58
|
# lista indicato da li
|
59
59
|
def self.process_xml_tag_li(xml_obj, _properties, idx=nil)
|
60
60
|
actions_list = []
|
61
|
-
|
61
|
+
|
62
62
|
xml_obj.children.each do |child|
|
63
63
|
actions_list += process_xml_obj(child, [])
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
if idx
|
67
67
|
PdfWritingToolsActions.new_line_action + PdfWritingToolsActions.atomic_text_action(idx) + PdfWritingToolsActions.indent_action(4) + actions_list
|
68
|
-
else
|
68
|
+
else
|
69
69
|
PdfWritingToolsActions.new_line_action + PdfWritingToolsActions.bullet_action + PdfWritingToolsActions.indent_action(4) + actions_list
|
70
70
|
end
|
71
|
-
end
|
71
|
+
end
|
72
72
|
|
73
73
|
# Produce le "actions" che permettono di disegnare nel PDF, il contenuto
|
74
74
|
# del tag p
|
@@ -77,24 +77,26 @@ module PdfWritingToolsProcess
|
|
77
77
|
xml_obj.children.each do |child|
|
78
78
|
actions_list += process_xml_obj(child, properties)
|
79
79
|
end
|
80
|
+
|
80
81
|
PdfWritingToolsActions.new_line_action + actions_list
|
81
82
|
end
|
82
83
|
|
83
|
-
# Al momento assumo che h1 contenga solo testo, poi eventualmente
|
84
|
+
# Al momento assumo che h1 contenga solo testo, poi eventualmente
|
84
85
|
# renderla ricorsiva permettendo a h1 di contenere altri tag.
|
85
86
|
# Sebbene l'xml che sto processando non sia vero html, voglio cercare di dargli
|
86
|
-
# il più possibile lo stesso comportamento. All'interno di h1, possono essere
|
87
|
+
# il più possibile lo stesso comportamento. All'interno di h1, possono essere
|
87
88
|
# presenti solo elementi inline. Al momento non controllo questa cosa, quindi preferisco
|
88
89
|
# tagliare la testa al toro, assumento che h1 contenga solo testo.
|
89
90
|
def self.process_xml_tag_h1(xml_obj, properties)
|
90
91
|
actions_list = process_xml_text(xml_obj.child, [:bold], 16, true)
|
91
|
-
|
92
|
+
|
93
|
+
PdfWritingToolsActions.new_line_action + actions_list + PdfWritingToolsActions.new_line_action * 2
|
92
94
|
end
|
93
95
|
|
94
|
-
# Al momento assumo che span contenga solo testo, poi eventualmente
|
96
|
+
# Al momento assumo che span contenga solo testo, poi eventualmente
|
95
97
|
# renderla ricorsiva permettendo a span di contenere altri tag.
|
96
98
|
# Sebbene l'xml che sto processando non sia vero html, voglio cercare di dargli
|
97
|
-
# il più possibile lo stesso comportamento. All'interno di span, possono essere
|
99
|
+
# il più possibile lo stesso comportamento. All'interno di span, possono essere
|
98
100
|
# presenti solo elementi inline. Al momento non controllo questa cosa, quindi preferisco
|
99
101
|
# tagliare la testa al toro, assumento che span contenga solo testo.
|
100
102
|
def self.process_xml_tag_span(xml_obj, properties)
|
@@ -103,7 +105,7 @@ module PdfWritingToolsProcess
|
|
103
105
|
color = "#000000"
|
104
106
|
|
105
107
|
if span_styles_attributes.has_key?("color")
|
106
|
-
color = span_styles_attributes["color"]
|
108
|
+
color = span_styles_attributes["color"]
|
107
109
|
end
|
108
110
|
|
109
111
|
actions_list = process_xml_text(xml_obj.child, properties, size=12, upcase=false, color)
|
@@ -111,11 +113,30 @@ module PdfWritingToolsProcess
|
|
111
113
|
|
112
114
|
|
113
115
|
|
116
|
+
def self.process_xml_tag_table(xml_obj, properties)
|
117
|
+
# Processo i figli della tabella che devono essere due
|
118
|
+
# thead
|
119
|
+
# tbody
|
120
|
+
xml_obj.children.each do |child|
|
121
|
+
end
|
122
|
+
|
123
|
+
p xml_obj[:width]
|
124
|
+
p 20.cm / 7.0
|
125
|
+
[]
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
def self.process_xml_tag_tr(xml_obj, properties)
|
130
|
+
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
|
114
135
|
# Produce le actions necessarie per disegnare nel PDF un determinato
|
115
136
|
# "tag"
|
116
137
|
def self.process_xml_obj(xml_obj, properties, attributes={})
|
117
138
|
case xml_obj.name
|
118
|
-
when 'text', 'b', 'i', 'ul', 'li', 'p', 'h1', 'ol', 'span'
|
139
|
+
when 'text', 'b', 'i', 'ul', 'li', 'p', 'h1', 'ol', 'span', 'table'
|
119
140
|
@process_xml_tag_table[xml_obj.name].call(xml_obj, properties)
|
120
141
|
when 'br'
|
121
142
|
PdfWritingToolsActions.new_line_action
|
@@ -126,13 +147,13 @@ module PdfWritingToolsProcess
|
|
126
147
|
|
127
148
|
def self.string_to_attributes(s)
|
128
149
|
result = {}
|
129
|
-
|
150
|
+
|
130
151
|
s.split(";").each do |el|
|
131
152
|
e = el.split(":")
|
132
|
-
result[e[0]] = e[1]
|
153
|
+
result[e[0]] = e[1]
|
133
154
|
end
|
134
|
-
|
135
|
-
result
|
155
|
+
|
156
|
+
result
|
136
157
|
end
|
137
158
|
|
138
159
|
@process_xml_tag_table =
|
@@ -145,6 +166,8 @@ module PdfWritingToolsProcess
|
|
145
166
|
'ol' => method(:process_xml_tag_ol),
|
146
167
|
'li' => method(:process_xml_tag_li),
|
147
168
|
'p' => method(:process_xml_tag_p),
|
148
|
-
'h1' => method(:process_xml_tag_h1)
|
169
|
+
'h1' => method(:process_xml_tag_h1),
|
170
|
+
'table' => method(:process_xml_tag_table),
|
171
|
+
'tr' => method(:process_xml_tag_tr)
|
149
172
|
}
|
150
173
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pdf_writing_tools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.15
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- JSalvo1978
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-01-05 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Plugin for write pdf in a simplified manner, using prawn as backend
|
14
14
|
email:
|