pdf_writing_tools 0.0.10 → 0.0.13

Sign up to get free protection for your applications and to get access to all the features.
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.