pdf_writing_tools 0.0.10 → 0.0.13

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 32f9690ccbc09db00ba94daceb4d34c0f565bb73f3229c3712a00886aa5cce5d
4
- data.tar.gz: 41ed383e3b7ee71992f56b7ced2425902f3a51cb947181220a883f1b720a32ea
3
+ metadata.gz: 8a14c40e1817a741cae4260b4e37b76bbcd86bc8e079414756794eea8ad0f0ce
4
+ data.tar.gz: fdecb3e874950d20978c58048126d88c2c52c14021925cfaec09b7f702c4c574
5
5
  SHA512:
6
- metadata.gz: de956cc911e9cf7ee357ccaa4d35354b0c89893aa8522004c992ebb223b17f3dfb864d9e92aeda7160c8cb3838c254ae346c87108d975d11b1787487cf5077e8
7
- data.tar.gz: ed74125384c0f30f6e5bfa33520672ae6039cb2cdb05b0be4a6f5250145b02d3e8265332bbc134fc34d8b78d018212c9b386ec26ad803a3a8f2e95ca984fc6e6
6
+ metadata.gz: 4e8cff4cb4d7cae857f1abbd87a8509ff13ec0ed6b3c04880851cbacaede5057dd2f5222c2fd2bcc9bb0ed485b3d9d67abdfd1c090e38265c0fa35af92c3fcf3
7
+ data.tar.gz: e1b38b8925c34e2b148e4b32ba3b47ed83d10c69ffc36ea279ff54206b154b173597768ed5d28e0bc51c8943a89a052354a9b3f6750ab266e7f339933cb24f31
data/assets/bullet.png ADDED
Binary file
@@ -11,7 +11,19 @@ module PdfWritingTools
11
11
  # li (elemento di lista non ordinata)
12
12
  # b (grassetto)
13
13
  # i (italico)
14
+ # span
14
15
  # Altri tag non in elenco, vengono ignorati o causano errore
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
+
19
+ # L'oggetto xml, viene letto ricorsivamente. Si crea una lista, contenente
20
+ # dei dizionari. Ciascun dizionario contiene:
21
+ # Il nome di un'azione: :action_name
22
+ # Una lista "data", contenente un dizionario con al suo interno le specifiche
23
+ # da dare a prawn, per "disegnare" del testo o per disegnare un'immagine
24
+ #
25
+ # Le p
26
+
15
27
  def self.draw_xml_object(pdf, xml_object)
16
28
  # Ottengo una lista di azioni, ciascuna delle quali, quando eseguita,
17
29
  # permette di disegnare una parte del documento xml all'interno del pdf
@@ -32,4 +44,342 @@ module PdfWritingTools
32
44
  end
33
45
  actions_list
34
46
  end
47
+
48
+
49
+ ######## Disegna una cella di dimensioni fissate, nella data posizione. ######
50
+ # E' Possibile indicare il colore del bordo, dello sfondo, del font e della
51
+ # relativa dimensione (oltre a tutta un'altra serie di parametri (opts), vedere prima
52
+ # parte della funzione)
53
+ # La cella, viene disegnata "globalmente", rispetto al pdf, ossia NON relativamente
54
+ # ad altri contenitori.
55
+ # x e y, indicano rispettivamente le coordinate x e y del vertice in alto a
56
+ # sinistra del box.
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 è
59
+ # quello basso della pagina).
60
+ # Bisogna pertanto prestare attenzione quando si dovessero mischiare primitive prawn
61
+ # con queste funzioni.
62
+ def self.draw_cell_fixed_height(pdf, x, y, w, h, t, opts={})
63
+ t = (t.class == String ? [{text: t}] : t)
64
+ font_size = opts[:font_size] || 10
65
+ style = opts[:style] || :normal
66
+ align = opts[:align] || :left
67
+ valign = opts[:valign] || :top
68
+ font_color = opts[:font_color] || '000000'
69
+ border_color = opts[:border_color] || '000000'
70
+ background_color = opts[:background_color] || 'FFFFFF'
71
+ left_padding = opts[:left_padding] || 5
72
+ right_padding = opts[:right_padding] || 5
73
+ top_padding = opts[:top_padding] || 5
74
+ bottom_padding = opts[:bottom_padding] || 5
75
+ pdf_height = opts[:pdf_height] || 297.mm
76
+ pdf_width = opts[:pdf_width] || 21.cm
77
+
78
+ result = ''
79
+
80
+ pdf.canvas do
81
+ pdf.line_width = 0.5
82
+
83
+ # Colore di sfondo della cella
84
+ pdf.fill_color(background_color)
85
+
86
+ # Disegna lo sfondo della cella
87
+ pdf.fill_rectangle([x, pdf_height - y], w, h)
88
+
89
+ pdf.stroke_color border_color
90
+ pdf.stroke_rectangle([x, pdf_height - y], w, h)
91
+
92
+ # Colore del testo nella cella
93
+ 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
+
116
+ end
117
+
118
+ result
119
+ end
120
+
121
+ # Disegna una cella di altezza variabile nella data posizione, in funzione del contenuto.
122
+ # E' possibile indicare il colore del bordo, dello sfondo della cella e del font e della
123
+ # relativa dimensione del testo ivi contenuto (oltre ad altri parametri, vedi prima parte
124
+ # della funzione).
125
+ # Produce un dizionario, con l'altezza della cella disegnata ed eventuale testo non disegnato
126
+ # (es. nel caso di sopraggiunto fine pagina).
127
+ # Il campo draw_simulation, serve ad evitare che la cella venga realmente disegnata nel pdf.
128
+ # 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
131
+ # 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={})
133
+ font_size = opts[:font_size] || 10
134
+ style = opts[:style] || :normal
135
+ align = opts[:align] || :left
136
+ valign = opts[:align] || :top
137
+ font_color = opts[:font_color] || "000000"
138
+ border_color = opts[:border_color] || "000000"
139
+ 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
+
147
+ result = 0
148
+
149
+ pdf.canvas do
150
+ # Non utilizzo l'helper (pdf.text_box), in quanto scriverebbe direttamente nel pdf
151
+ # ma io ho bisogno di conoscere l'altezza del box di testo, prima di scriverlo, in
152
+ # modo da poter disegnare PRIMA lo sfondo
153
+ b = Prawn::Text::Box.new(
154
+ t || "",
155
+ {:at => [x + left_padding, pdf_height - y - top_padding],
156
+ :width => w - left_padding-right_padding,
157
+ :size => font_size,
158
+ :style => style,
159
+ :overflow => :expand,
160
+ :document => pdf})
161
+
162
+ # Effettuo il render, ma in modalità "prova" (dry_run = true), così posso conoscere quale sarà
163
+ # l'altezza del box prima di disegnarlo
164
+
165
+ text_overflow = b.render(:dry_run => true)
166
+
167
+ # Altezza del box, non ancora disegnato
168
+ h = b.height
169
+
170
+ if not draw_simulation
171
+ # Se non sono in simulazione...
172
+ # ... ora che conosco quale sarà l'altezza del box di testo, posso disegnare lo sfondo
173
+ pdf.fill_color(background_color) # colore dello sfondo
174
+ pdf.stroke_color(border_color) # Colore del bordo
175
+
176
+ pdf.fill_and_stroke_rectangle([x,pdf_height-y], (w + left_padding + right_padding), (h+top_padding+bottom_padding))
177
+
178
+ # ... e infine, sopra lo sfondo disegno il testo
179
+ pdf.fill_color(font_color) # colore del testo
180
+ text_overflow = b.render()
181
+
182
+ # text_overflow è l'eventuale testo avanzato
183
+ end
184
+
185
+ # La cella potrebbe non riuscire ad espandersi a sufficienza (troppo vicina al
186
+ # fine pagine, quindi può essere che del testo "avanzi" )
187
+ result = {height: h + top_padding + bottom_padding, overflow: text_overflow}
188
+ end
189
+
190
+ result
191
+ end
192
+
193
+
194
+ def self.draw_row_fixed_height(pdf, x, y, widths, height, texts, opts={})
195
+ font_sizes = opts[:font_sizes] || [10]
196
+ styles = opts[:styles] || [:normal]
197
+ alignments = opts[:alignments] || [:left]
198
+ valignments = opts[:valignments] || [:top]
199
+ font_colors = opts[:font_colors] || ["000000"]
200
+ border_colors = opts[:border_colors] || ["000000"]
201
+ background_colors = opts[:background_colors] || ["FFFFFF"]
202
+ paddings = opts[:paddings] || [{left_padding: 5, right_padding: 5, top_padding: 5, bottom_padding: 5}]
203
+ pdf_height = opts[:pdf_height] || 297.mm
204
+ pdf_width = opts[:pdf_width] || 21.cm
205
+
206
+ offset = 0
207
+
208
+ widths.each_with_index do |width, i|
209
+ font_size = font_sizes[i] || font_sizes[0]
210
+ style = styles[i] || styles[0]
211
+ align = alignments[i] || alignments[0]
212
+ valign = valignments[i] || valignments[0]
213
+ font_color = font_colors[i] || font_colors[0]
214
+ border_color = border_colors[i] || border_colors[0]
215
+ background_color = background_colors[i] || background_colors[0]
216
+ padding = paddings[i] || paddings[0]
217
+
218
+ cell_opts = {}
219
+
220
+ cell_opts[:font_size] = font_size
221
+ cell_opts[:style] = style
222
+ cell_opts[:align] = align
223
+ cell_opts[:valign] = valign
224
+ cell_opts[:font_color] = font_color
225
+ cell_opts[:border_color] = border_color
226
+ cell_opts[:background_color] = background_color
227
+ cell_opts[:left_padding] = padding[:left_padding]
228
+ cell_opts[:right_padding] = padding[:right_padding]
229
+ cell_opts[:top_padding] = padding[:top_padding]
230
+ cell_opts[:bottom_padding] = padding[:bottom_padding]
231
+ cell_opts[:pdf_width] = 21.cm
232
+ cell_opts[:pdf_height] = 297.mm
233
+
234
+ draw_cell_fixed_height( pdf, x+offset, y, width, height, texts[i], cell_opts)
235
+
236
+ offset += width
237
+ end
238
+ end
239
+
240
+ # Produce la y su pdf, dove disegnare la prossima riga
241
+ def self.draw_row_auto_height(pdf, draw_simulation, x, y, widths, texts, opts = {})
242
+ font_sizes = opts[:font_sizes] || [10]
243
+ styles = opts[:styles] || [:normal]
244
+ alignments = opts[:alignments] || [:left]
245
+ valignments = opts[:valignments] || [:top]
246
+ font_colors = opts[:font_colors] || ["000000"]
247
+ border_colors = opts[:border_colors] || ["000000"]
248
+ background_colors = opts[:background_colors] || ["FFFFFF"]
249
+ paddings = opts[:paddings] || [{left_padding: 5, right_padding: 5, top_padding: 5, bottom_padding: 5}]
250
+ pdf_height = opts[:pdf_height] || 297.mm
251
+ pdf_width = opts[:pdf_width] || 21.cm
252
+ pdf_margin_top = opts[:pdf_margin_top] || 2.cm
253
+ pdf_margin_bottom = opts[:pdf_margin_bottom] || 2.cm
254
+ pdf_margin_left = opts[:pdf_margin_left] || 2.cm
255
+ pdf_margin_right = opts[:pdf_margin_right] || 2.cm
256
+
257
+ new_y = pdf_margin_top
258
+
259
+ loop do
260
+
261
+ max_cell_height = 0
262
+
263
+ # 1 - Cerco l'altezza della riga
264
+ # Per prima cosa, simulo il disegno delle varie celle che compongono la riga.
265
+ # In questo modo, posso sapere quale sarà la massima altezza raggiunta da una
266
+ # cella, ossia l'altezza che deve avere la riga
267
+ offset = 0
268
+ widths.each_with_index do |width, i|
269
+ font_size = font_sizes[i] || font_sizes[0]
270
+ style = styles[i] || styles[0]
271
+ align = alignments[i] || alignments[0]
272
+ valign = valignments[i] || valignments[0]
273
+ font_color = font_colors[i] || font_colors[0]
274
+ border_color = border_colors[i] || border_colors[0]
275
+ background_color = background_colors[i] || background_colors[0]
276
+ padding = paddings[i] || paddings[0]
277
+
278
+ cell_opts = {}
279
+ cell_opts[:font_size] = font_size
280
+ cell_opts[:style] = style
281
+ cell_opts[:align] = align
282
+ cell_opts[:valign] = valign
283
+ cell_opts[:font_color] = font_color
284
+ cell_opts[:border_color] = border_color
285
+ cell_opts[:background_color] = background_color
286
+ cell_opts[:left_padding] = padding[:left_padding]
287
+ cell_opts[:right_padding] = padding[:right_padding]
288
+ cell_opts[:top_padding] = padding[:top_padding]
289
+ cell_opts[:bottom_padding] = padding[:bottom_padding]
290
+ cell_opts[:pdf_height] = 297.mm
291
+ cell_opts[:pdf_weigth] = 21.cm
292
+
293
+ r = draw_cell_auto_height(pdf, draw_simulation = true, x+offset, y, width, texts[i], cell_opts)
294
+
295
+ if r[:height] > max_cell_height
296
+ max_cell_height = r[:height]
297
+ end
298
+
299
+ offset += width
300
+ end
301
+
302
+ if y + max_cell_height > pdf_height - pdf_margin_bottom
303
+ max_cell_height = pdf_height - pdf_margin_bottom - y
304
+ end
305
+
306
+ # A seguito della simulazione, ho ottenuto l'altezza di riga...
307
+ # ... ora passo al disegno vero e proprie delle celle...
308
+ offset = 0
309
+ rtexts = []
310
+ widths.each_with_index do |width, i|
311
+ font_size = font_sizes[i] || font_sizes[0]
312
+ style = styles[i] || styles[0]
313
+ align = alignments[i] || alignments[0]
314
+ valign = valignments[i] || valignments[0]
315
+ font_color = font_colors[i] || font_colors[0]
316
+ border_color = border_colors[i] || border_colors[0]
317
+ background_color = background_colors[i] || background_colors[0]
318
+ padding = paddings[i] || paddings[0]
319
+
320
+ cell_opts = {}
321
+ cell_opts[:font_size] = font_size
322
+ cell_opts[:style] = style
323
+ cell_opts[:align] = align
324
+ cell_opts[:valign] = valign
325
+ cell_opts[:font_color] = font_color
326
+ cell_opts[:border_color] = border_color
327
+ cell_opts[:background_color] = background_color
328
+ cell_opts[:left_padding] = padding[:left_padding]
329
+ cell_opts[:right_padding] = padding[:right_padding]
330
+ cell_opts[:top_padding] = padding[:top_padding]
331
+ cell_opts[:bottom_padding] = padding[:bottom_padding]
332
+ cell_opts[:pdf_height] = 297.mm
333
+ cell_opts[:pdf_weigth] = 21.cm
334
+
335
+ # ...disegno le celle vere e proprie ad altezza fissa, con l'altezza
336
+ # ricavata dal passo precedente.
337
+ r = draw_cell_fixed_height(pdf, x+offset, y, width, max_cell_height, texts[i], opts)
338
+
339
+ # Gli eventuali "testi residui" (es. raggiunto fine pagina) li raccolgo
340
+ # nel seguente array
341
+ rtexts << r
342
+
343
+ offset += width
344
+ end
345
+
346
+ texts = rtexts
347
+
348
+ # Se nei testi residui, sono presenti solo stringhe vuote, posso uscire dal
349
+ # loop, altrimenti, devo cambiare pagina e disegnare una nuova riga con i
350
+ # testi rimanenti
351
+ if !check_no_empty_string_presence(texts)
352
+ new_y = y + max_cell_height
353
+ break
354
+ else
355
+ pdf.start_new_page
356
+ y = pdf_margin_top # Posiziono il cursore ad inizio della nuova pagina
357
+ end
358
+ end
359
+
360
+ return new_y
361
+ end
362
+
363
+ def self.check_no_empty_string_presence(string_list)
364
+ string_list.each do |string_element|
365
+ if string_element != ""
366
+ return true
367
+ end
368
+ end
369
+ return false
370
+ end
371
+
372
+ # Dato il percorso file_path, genera un documento xml, a cui sono stati rimossi gli
373
+ # a capo e gli spazi multipli
374
+ def self.get_cleaned_xml_from_file(file_path)
375
+ text = File.read(file_path)
376
+
377
+ # Rimuove gli a capo e le tabulazioni sostituendoli con uno spazio
378
+ text = text.gsub(/\n|\t/, ' ')
379
+
380
+ # Rimuove le spaziature multiple sostituendole con uno spazio
381
+ text = text.gsub(/\s+/, ' ')
382
+
383
+ Nokogiri::XML(text)
384
+ end
35
385
  end
@@ -1,4 +1,43 @@
1
+ # Questo modulo, si occupa di
2
+
3
+
4
+ # Le action, definiscono, cosa deve essere fatto (scritto, colorato, disegnato) nel pdf
5
+ # La forma di una action è una coppia (nome_action, dati_per_la_action)
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.
11
+ # Ogni singola action, viene poi eseguita, utilizzando le funzioni di prawn.
12
+
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
16
+ # PdfWritingToolsActions.execute_actions, verrà dato il via all'esecuzione delle actions...
17
+
18
+ # Nella parte PRIVATE di questa classe, inserire solo metodi che eseguano le action
19
+ # ... le singole actions, verrano eseguite tramite i metodi privati di questa classe
20
+
1
21
  module PdfWritingToolsActions
22
+ # Esegue le azioni, andando a concatenare quelle "contigue" nella lista,
23
+ # che riguardano la scrittura di testo.
24
+ # La lista actions, in sostanza comprende più azioni. Quelle contigue che riguardano
25
+ # la scrittura di testo, non vanno eseguite singolarmente, ma devono essere "fuse"
26
+ # e poi eseguite. Le action che riguardano la "scrittura" di un immagine invece, non
27
+ # possono essere fuse, pertanto vanno eseguite singolarmente
28
+ def self.execute_actions(pdf, actions, last_actn_name, data)
29
+ actions.each do |action|
30
+ if action[:action_name] == :draw_formatted_text
31
+ last_actn_name, data = text_action(pdf, action, last_actn_name, data)
32
+ elsif action[:action_name] == :draw_image
33
+ last_actn_name, data = img_action(pdf, action, last_actn_name, data)
34
+ end
35
+ end
36
+
37
+ # Disegno l'ultima action della lista
38
+ execute_action(pdf, last_actn_name, data)
39
+ end
40
+
2
41
  # Questa action contiene istruzioni per disegnare un "a capo" nel PDF
3
42
  def self.new_line_action
4
43
  [{ action_name: :draw_formatted_text, data: [{ text: "\n" }] }]
@@ -22,64 +61,89 @@ module PdfWritingToolsActions
22
61
  end
23
62
 
24
63
  # Questa action, contiene istruzioni per disegnare un "bullet", ossia
25
- # un oggetto grafico, tipo un segno di spunta accanto all'elemnto di
64
+ # un oggetto grafico, tipo un segno di spunta accanto all'elemento di
26
65
  # una lista
27
66
  def self.bullet_action
28
67
  [
29
68
  {
30
69
  action_name: :draw_image, data:
31
70
  {
32
- url: 'public/bullet.png' # Pallino
71
+ url: File.expand_path("../../assets/bullet.png", __FILE__)
72
+ # Pallino
33
73
  }
34
74
  }
35
75
  ]
36
76
  end
37
77
 
38
- # Esegue last_action, oppure concatena i dati di action e di last_action
39
- def self.text_action(pdf, action, last_action_name, data)
40
- if last_action_name.nil?
41
- data = action[:data]
42
- elsif last_action_name == :draw_formatted_text
43
- data += action[:data]
44
- else
45
- execute_action(pdf, last_action_name, data)
46
- data = action[:data]
47
- end
48
- [:draw_formatted_text, data]
49
- end
78
+ private
50
79
 
51
- # Mentre la "scrittura/disegno" del testo, puo' essere "concatenato", nel caso
52
- # delle immagini no. Una action sulla immagine, pertanto interrompe la
53
- # possibilita' di concatenare i data delle action di testo. Pertanto, eseguo
54
- # in ogni caso last_action, a meno che last_action non sia nil (ossia action
55
- # e' la prima azione della lista)
56
- def self.img_action(pdf, action, last_action_name, data)
57
- execute_action(pdf, last_action_name, data) unless last_action_name.nil?
58
- [:draw_image, action[:data]]
59
- end
80
+ # Esegue un'azione, andando a scrivere del testo nel PDF, oppure un'immagine
81
+ def self.execute_action(pdf, action_name, data)
82
+ if action_name == :draw_formatted_text
83
+ pdf.formatted_text(data, align: :left)
84
+ elsif action_name == :draw_image
85
+ # Il testo disegnato dopo un immagine, non appare allineato. Per questo
86
+ # motivo, disegno l'immagine un' po' prima di dove è previsto (spostando il cursore)
87
+ # per poi ripristinare la posizione originaria del cursore.
88
+
89
+ # L'operazione di cui sopra, non va eseguita a fondo pagina, altrimenti,
90
+ # il salto pagina automatico crea problemi sulla realizzazione del pdf,
91
+ # quindi...
92
+
93
+ # Se la posizione del cursore (misurata, dal fondo margine di pagina)
94
+ # è inferiore ad un cm, mi sposto direttamente sulla nuova pagina..
95
+ if pdf.cursor <= 1.cm
96
+ pdf.start_new_page
97
+ end
98
+
99
+ current_cursor_position = pdf.cursor
100
+ # Anticipo il disegno dell'immagine spostando il cursore di n unità verso
101
+ # l'alto
102
+ n = 0
103
+ pdf.move_cursor_to(current_cursor_position - n)
104
+
105
+ # Disegno l'immagine (al momento questo metodo disegna solo il "bullet" degli elenchi)
106
+ pdf.image(data[:url], height: 6, width: 6)
107
+
108
+ # Ripristino la posizione originaria del cursore, in modo che il testo
109
+ # sia allineato all'immagine preceente
110
+ pdf.move_cursor_to(current_cursor_position)
111
+ elsif action_name == :draw_rectangle
60
112
 
61
- # Esegue un azione, andando a scrivere del testo nel PDF oppure un'immagine
62
- def self.execute_action(pdf, action_name, data)
63
- if action_name == :draw_formatted_text
64
- pdf.formatted_text(data, align: :left)
65
- elsif action_name == :draw_image
66
- current_cursor_position = pdf.cursor
67
- pdf.move_cursor_to(current_cursor_position - 3)
68
- pdf.image(data[:url], height: 6, width: 6)
69
- pdf.move_cursor_to(current_cursor_position)
113
+ end
70
114
  end
71
- end
72
-
73
- # Esegue le azioni, andando a concatenare quelle "contigue" nella lista,
74
- # che riguardano la scrittura di testo
75
- def self.execute_actions(pdf, actions, last_actn_name, data)
76
- actions.each do |action|
77
- if action[:action_name] == :draw_formatted_text
78
- last_actn_name, data = text_action(pdf, action, last_actn_name, data)
79
- elsif action[:action_name] == :draw_image
80
- last_actn_name, data = img_action(pdf, action, last_actn_name, data)
115
+
116
+ # Esegue last_action, oppure concatena i dati di action e di last_action
117
+ # action: azione "corrente"
118
+ # last_action_name: nome dell'azione che precede l'azione corrente
119
+ # data: dati dell'azione che precede l'azione corrente
120
+ def self.text_action(pdf, action, last_action_name, data)
121
+ if last_action_name.nil?
122
+ # Prima azione della lista (last_action_name = nil), quindi per ora
123
+ # nessun concatenamento di dati
124
+ data = action[:data]
125
+ elsif last_action_name == :draw_formatted_text
126
+ # 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
128
+ data += action[:data]
129
+ else
130
+ # 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
132
+ # quella corrente
133
+ execute_action(pdf, last_action_name, data)
134
+ data = action[:data]
81
135
  end
136
+
137
+ [:draw_formatted_text, data]
82
138
  end
83
- execute_action(pdf, last_actn_name, data)
84
- end
85
- end
139
+
140
+ # Mentre la "scrittura/disegno" del testo, puo' essere "concatenato", nel caso
141
+ # delle immagini no. Una action sull' immagine pertanto, interrompe la
142
+ # possibilita' di concatenare i data delle action di testo. Quindi, eseguo
143
+ # in ogni caso last_action, a meno che last_action non sia nil (ossia action
144
+ # e' la prima azione della lista)
145
+ def self.img_action(pdf, action, last_action_name, data)
146
+ execute_action(pdf, last_action_name, data) unless last_action_name.nil?
147
+ [:draw_image, action[:data]]
148
+ end
149
+ end
@@ -23,8 +23,8 @@ module PdfWritingToolsProcess
23
23
 
24
24
  # Produce la "action" che permette di disegnare nel pdf, il testo con le
25
25
  # proprieta' specificate in proprerties
26
- def self.process_xml_text(xml_obj, properties, size = 12, upcase = false)
27
- data = { text: (upcase ? xml_obj.text.upcase : xml_obj.text) + ' ', styles: properties, size: size }
26
+ def self.process_xml_text(xml_obj, properties, size = 12, upcase = false, color = "#000000")
27
+ data = { text: (upcase ? xml_obj.text.upcase : xml_obj.text) + ' ', styles: properties, size: size, color: color[1..-1] }
28
28
  [{ action_name: :draw_formatted_text, data: [data] }]
29
29
  end
30
30
 
@@ -58,6 +58,7 @@ 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
  xml_obj.children.each do |child|
62
63
  actions_list += process_xml_obj(child, [])
63
64
  end
@@ -67,7 +68,7 @@ module PdfWritingToolsProcess
67
68
  else
68
69
  PdfWritingToolsActions.new_line_action + PdfWritingToolsActions.bullet_action + PdfWritingToolsActions.indent_action(4) + actions_list
69
70
  end
70
- end
71
+ end
71
72
 
72
73
  # Produce le "actions" che permettono di disegnare nel PDF, il contenuto
73
74
  # del tag p
@@ -79,16 +80,42 @@ module PdfWritingToolsProcess
79
80
  PdfWritingToolsActions.new_line_action + actions_list
80
81
  end
81
82
 
83
+ # Al momento assumo che h1 contenga solo testo, poi eventualmente
84
+ # renderla ricorsiva permettendo a h1 di contenere altri tag.
85
+ # 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
+ # presenti solo elementi inline. Al momento non controllo questa cosa, quindi preferisco
88
+ # tagliare la testa al toro, assumento che h1 contenga solo testo.
82
89
  def self.process_xml_tag_h1(xml_obj, properties)
83
90
  actions_list = process_xml_text(xml_obj.child, [:bold], 16, true)
84
91
  PdfWritingToolsActions.new_line_action + actions_list + PdfWritingToolsActions.new_line_action * 2
85
92
  end
86
93
 
94
+ # Al momento assumo che span contenga solo testo, poi eventualmente
95
+ # renderla ricorsiva permettendo a span di contenere altri tag.
96
+ # 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
98
+ # presenti solo elementi inline. Al momento non controllo questa cosa, quindi preferisco
99
+ # tagliare la testa al toro, assumento che span contenga solo testo.
100
+ def self.process_xml_tag_span(xml_obj, properties)
101
+ span_styles_attributes = string_to_attributes(xml_obj[:style])
102
+
103
+ color = "#000000"
104
+
105
+ if span_styles_attributes.has_key?("color")
106
+ color = span_styles_attributes["color"]
107
+ end
108
+
109
+ actions_list = process_xml_text(xml_obj.child, properties, size=12, upcase=false, color)
110
+ end
111
+
112
+
113
+
87
114
  # Produce le actions necessarie per disegnare nel PDF un determinato
88
115
  # "tag"
89
- def self.process_xml_obj(xml_obj, properties)
116
+ def self.process_xml_obj(xml_obj, properties, attributes={})
90
117
  case xml_obj.name
91
- when 'text', 'b', 'i', 'ul', 'li', 'p', 'h1', 'ol'
118
+ when 'text', 'b', 'i', 'ul', 'li', 'p', 'h1', 'ol', 'span'
92
119
  @process_xml_tag_table[xml_obj.name].call(xml_obj, properties)
93
120
  when 'br'
94
121
  PdfWritingToolsActions.new_line_action
@@ -97,9 +124,21 @@ module PdfWritingToolsProcess
97
124
  end
98
125
  end
99
126
 
127
+ def self.string_to_attributes(s)
128
+ result = {}
129
+
130
+ s.split(";").each do |el|
131
+ e = el.split(":")
132
+ result[e[0]] = e[1]
133
+ end
134
+
135
+ result
136
+ end
137
+
100
138
  @process_xml_tag_table =
101
139
  {
102
140
  'text' => method(:process_xml_text),
141
+ 'span' => method(:process_xml_tag_span),
103
142
  'b' => method(:process_xml_tag_b),
104
143
  'i' => method(:process_xml_tag_i),
105
144
  'ul' => method(:process_xml_tag_ul),
metadata CHANGED
@@ -1,53 +1,24 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pdf_writing_tools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.10
4
+ version: 0.0.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - JSalvo1978
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-07-28 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: rails
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: 4.2.8
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: 4.2.8
27
- - !ruby/object:Gem::Dependency
28
- name: sqlite3
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- description: Plugin for pdf writing
11
+ date: 2023-08-07 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Plugin for write pdf in a simplified manner, using prawn as backend
42
14
  email:
43
15
  - gianmario.salvetti@gmail.com
44
16
  executables: []
45
17
  extensions: []
46
18
  extra_rdoc_files: []
47
19
  files:
48
- - MIT-LICENSE
49
- - README.rdoc
50
20
  - Rakefile
21
+ - assets/bullet.png
51
22
  - lib/pdf_writing_tools.rb
52
23
  - lib/pdf_writing_tools/green-check-mark-sign-addition-icon-vector-13230189.jpg
53
24
  - lib/pdf_writing_tools/version.rb
@@ -96,6 +67,7 @@ post_install_message:
96
67
  rdoc_options: []
97
68
  require_paths:
98
69
  - lib
70
+ - assets
99
71
  required_ruby_version: !ruby/object:Gem::Requirement
100
72
  requirements:
101
73
  - - ">="
data/MIT-LICENSE DELETED
@@ -1,20 +0,0 @@
1
- Copyright 2018 Gianmario Salvetti
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc DELETED
@@ -1,3 +0,0 @@
1
- = PdfWritingTools
2
-
3
- This project rocks and uses MIT-LICENSE.