Module: PdfWritingTools

Defined in:
lib/pdf_writing_tools.rb,
lib/pdf_writing_tools/version.rb

Constant Summary collapse

VERSION =
'0.0.10'.freeze

Class Method Summary collapse

Class Method Details

.check_no_empty_string_presence(string_list) ⇒ Object

Se tutte le stringhe nella lista sono “” (stringa vuota) produce false altrimenti produce true.



425
426
427
428
429
430
431
432
433
# File 'lib/pdf_writing_tools.rb', line 425

def self.check_no_empty_string_presence(string_list)
   string_list.each do |string_element|
		if string_element != "" and string_element != []
			return true
		end
	end

	return false
end

.draw_cell_auto_height(pdf, draw_simulation, x, y, w, t, opts = {}, auto_y = false, no_background = false) ⇒ Object

della funzione). Produce un dizionario, con l’altezza della cella disegnata ed eventuale testo non disegnato (es. nel caso di sopraggiunto fine pagina). Il campo draw_simulation, serve ad evitare che la cella venga realmente disegnata nel pdf. In questo modo, posso ottenere l’altezza, eventuale testo “avanzato” e prendere decisioni che non dipendano da un’unica cella, ma da un gruppo di celle, come ad esempio quando devo disegnare la riga di una tabella che essendo composta da più celle, ha un altezza che dipende dall’altezza massima delle celle “autoridimensionanti” che la compongono.



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/pdf_writing_tools.rb', line 138

def self.draw_cell_auto_height(pdf, draw_simulation, x, y, w, t, opts={}, auto_y=false, no_background=false)
  font_size        = opts[:font_size] || 10
  style            = opts[:style] || :normal
  align            = opts[:align] || :left
  valign           = opts[:valign] || :top
  font_color       = opts[:font_color] || "000000"
  border_color     = opts[:border_color] || "000000"
  background_color = opts[:background_color] || "FFFFFF"
  left_padding     = opts[:left_padding] || 5#
  right_padding    = opts[:right_padding] || 5#
  top_padding      = opts[:top_padding] || 5#
  bottom_padding   = opts[:bottom_padding] || 5#
  pdf_height       = opts[:pdf_height] || 297.mm #
  pdf_width        = opts[:pdf_width] || 21.cm #

  t = (t.class == String ? [{text: t, size: font_size, color: font_color}] : t)



  result = 0

  # Il testo in modalità simulazione, verrà generato in posizione y_pos1, tenendo conto del padding.
  # In questo modo, quando andrò a disegnare la cella vera e propria in posizione y_pos2, il testo
  # avrà il suo "spazio" (padding)
  y_pos1 = auto_y ? (pdf.cursor - top_padding) : (pdf_height - y - top_padding)
  y_pos2 = auto_y ? pdf.cursor : (pdf_height - y)

  pdf.canvas do
    # Non utilizzo l'helper (pdf.formatted_text_box), in quanto scriverebbe direttamente nel pdf
    # ma io ho bisogno di conoscere l'altezza del box di testo formattato, prima di scriverlo, in
    # modo da poter disegnare PRIMA lo sfondo


    b = Prawn::Text::Formatted::Box.new(
          t,
          {:at => [x + left_padding, y_pos1 ],
          :width => w - left_padding-right_padding,
          :size => font_size,
          :style => style,
          :overflow => :expand,
          :document => pdf,
          :align => align,
          :valign => valign}) #valign ha un comportamento da indagare, mi fa uscire il testo fuori dal box

    # Effettuo il render, ma in modalità "prova" (dry_run = true), così posso conoscere quale sarà
    # l'altezza del box prima di disegnarlo

    text_overflow = b.render(:dry_run => true)
    #text_overflow = text_overflow[:text] #### Temporaneo

    # Altezza del box, non ancora disegnato
    h = b.height

    if not draw_simulation
      # Se non sono in simulazione...
      # ... ora che conosco quale sarà l'altezza del box di testo, posso disegnare lo sfondo
      pdf.fill_color(background_color) # colore dello sfondo
      pdf.stroke_color(border_color)   # Colore del bordo


      if no_background
      else
        pdf.fill_and_stroke_rectangle([x, y_pos2], w, h+top_padding+bottom_padding)
      end
      # ... e infine, sopra lo sfondo disegno il testo
      pdf.fill_color(font_color) # colore del testo
      text_overflow = b.render() # text_overflow è l'eventuale testo avanzato
    end

    # La cella potrebbe non riuscire ad espandersi a sufficienza (troppo vicina al
    # fine pagine, quindi può essere che del testo "avanzi" )
    result = {height: h + top_padding + bottom_padding, overflow: text_overflow}
  end

  result
end

.draw_cell_fixed_height(pdf, draw_simulation, x, y, w, h, t, opts = {}, auto_y = false, no_background = false) ⇒ Object

Disegna una cella di dimensioni fissate, nella data posizione. ###### E’ Possibile indicare il colore del bordo, dello sfondo, del font e della relativa dimensione (oltre a tutta un’altra serie di parametri (opts), vedere prima parte della funzione) La cella, viene disegnata “globalmente”, rispetto al pdf, ossia NON relativamente ad altri contenitori. x e y, indicano rispettivamente le coordinate x e y del vertice in alto a sinistra del box. Il vertice è relativo al margine superiore del pdf, contrariamente a quanto accade quando si utilizzano le primitive prawn (dove il margine di riferimento è quello basso della pagina). Bisogna pertanto prestare attenzione quando si dovessero mischiare primitive prawn con queste funzioni.



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/pdf_writing_tools.rb', line 62

def self.draw_cell_fixed_height(pdf, draw_simulation, x, y, w, h, t, opts={}, auto_y=false, no_background=false)
  t = (t.class == String ? [{text: t}] : t)
  font_size = opts[:font_size] || 10
  style = opts[:style] || :normal
  align = opts[:align] || :left
  valign = opts[:valign] || :top
  font_color = opts[:font_color] || '000000'
  border_color = opts[:border_color] || '000000'
  background_color = opts[:background_color] || 'FFFFFF'
  left_padding = opts[:left_padding] || 5
  right_padding = opts[:right_padding] || 5
  top_padding = opts[:top_padding] || 5
  bottom_padding = opts[:bottom_padding] || 5
  pdf_height = opts[:pdf_height] || 297.mm
  pdf_width = opts[:pdf_width] || 21.cm

  result = ''
  y_pos1 = auto_y ? pdf.cursor : (pdf_height - y)
  y_pos2 = auto_y ? pdf.cursor - top_padding : (pdf_height - y - top_padding)

  pdf.canvas do
    pdf.line_width = 0.5

    # Colore di sfondo della cella
    pdf.fill_color(background_color)

    # Disegna lo sfondo della cella
    if no_background or draw_simulation
    else
      pdf.fill_rectangle([x, y_pos1], w, h)
    end

    if not draw_simulation
      pdf.stroke_color border_color
      pdf.stroke_rectangle([x, y_pos1], w, h)
    end

    # Colore del testo nella cella
    pdf.fill_color(font_color)

    at = [x + left_padding, y_pos2]
    width = w - left_padding - right_padding
    height = h - top_padding - bottom_padding + 1.cm
    #result = pdf.formatted_text_box(t, width: width, height: height, at: at, size: font_size, style: style, align: align, valign: valign)
  
    b = Prawn::Text::Formatted::Box.new(
      t,
      {
        width: width, 
        height: height, 
        at: at, 
        size: font_size, 
        style: style, 
        align: align, 
        valign: valign, 
        document: pdf
      }      
    ) 
  
    result = b.render(:dry_run => draw_simulation)
  end

  result
end

.draw_row_auto_height(pdf, draw_simulation, x, y, widths, texts, opts = {}, auto_y = true) ⇒ Object

Produce la y su pdf, dove disegnare la prossima riga



264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
# File 'lib/pdf_writing_tools.rb', line 264

def self.draw_row_auto_height(pdf, draw_simulation, x, y, widths, texts, opts = {}, auto_y = true)
	font_sizes        = opts[:font_sizes] || [10]
	styles            = opts[:styles] || [:normal]
	alignments        = opts[:alignments] || [:left]
	valignments       = opts[:valignments] || [:top]
	font_colors       = opts[:font_colors] || ["000000"]
	border_colors     = opts[:border_colors] || ["000000"]
	background_colors = opts[:background_colors] || ["FFFFFF"]
	paddings          = opts[:paddings] || [{left_padding: 5, right_padding: 5, top_padding: 5, bottom_padding: 5}]
	pdf_height        = opts[:pdf_height] || 297.mm
	pdf_width         = opts[:pdf_width] || 21.cm
	pdf_margin_top    = opts[:pdf_margin_top] || 2.cm
	pdf_margin_bottom = opts[:pdf_margin_bottom] || 2.cm
	pdf_margin_left   = opts[:pdf_margin_left] || 2.cm
	pdf_margin_right  = opts[:pdf_margin_right] || 2.cm

	new_y = pdf_margin_top

   
   # Se la y della nuova riga (angolo superiore sinistro), esce dal margine di pagina,
   # non posso disegnare la riga in questa pagina, ma devo passare alla successiva
   if (y) > (pdf_height - pdf_margin_bottom)
     pdf.start_new_page
     y = pdf_margin_top
   end

	loop do
		max_cell_height = 0

		# 1 - Cerco l'altezza della riga
		# Per prima cosa, simulo il disegno delle varie celle che compongono la riga.
		# In questo modo, posso sapere quale sarà la massima altezza raggiunta da una
		# cella, ossia l'altezza che deve avere la riga
		offset = 0
     widths.each_with_index do |width, i|
			font_size = font_sizes[i] || font_sizes[0]
			style = styles[i] || styles[0]
			align = alignments[i] || alignments[0]
			valign =  valignments[i] || valignments[0]
			font_color = font_colors[i] || font_colors[0]
			border_color = border_colors[i] || border_colors[0]
			background_color = background_colors[i] || background_colors[0]
			padding = paddings[i] || paddings[0]

       cell_opts = {}
       cell_opts[:font_size] = font_size
       cell_opts[:style] = style
       cell_opts[:align] = align
       cell_opts[:valign] = valign
       cell_opts[:font_color] = font_color
       cell_opts[:border_color] = border_color
       cell_opts[:background_color] = background_color
       cell_opts[:left_padding] = padding[:left_padding]
       cell_opts[:right_padding] = padding[:right_padding]
       cell_opts[:top_padding] = padding[:top_padding]
       cell_opts[:bottom_padding] = padding[:bottom_padding]
       cell_opts[:pdf_height] = pdf_height
       cell_opts[:pdf_width] = pdf_width
       cell_opts[:pdf_margin_top] = pdf_margin_top
       cell_opts[:pdf_margin_bottom] = pdf_margin_bottom
       cell_opts[:pdf_margin_left] = pdf_margin_left
       cell_opts[:pdf_margin_right] = pdf_margin_right

			r = draw_cell_auto_height(pdf, true, x+offset, y, width, texts[i], cell_opts, auto_y)


			if r[:height] > max_cell_height
				max_cell_height = r[:height]
			end

			offset += width
		end


     # Non voglio che la riga ecceda il margine di pagina...
		if (y + max_cell_height) > (pdf_height - pdf_margin_bottom)
			q = 1

       # Se fino al margine di pagina, non ho almeno q cm... **
       if (pdf_height - pdf_margin_bottom - y) < q.cm
         # ...cambio pagina...
         pdf.start_new_page
         # ... e mi riposiziono all'inizio della pagina nuova
         y = pdf_margin_top
       else
         # ... altrimenti, reimposto max_cell_height: la riga verrà spezzata su due pagine.
         max_cell_height = pdf_height - pdf_margin_bottom - y
       end
       
       # ** non voglio imporre il vincolo "una riga deve stare in una pagina", ma contemporaneamente, voglio evitare che 
       # si creino delle righe "sottili" sul bordo inferiore della pagina; così sottili che non vi si possa disegnare testo
       # e quindi appaiano vuote. Questo controllo non è risolutivo: x, dovrebbe dipendere dalla dimensione del carattere
       # usato per il testo della riga, ma in questa fase, x.cm = 1.cm, mi pare una stima sufficiente
		end

		# A seguito della simulazione, ho ottenuto l'altezza di riga...
		# ... ora passo al disegno vero e proprie delle celle...
		offset = 0
		rtexts = []
		widths.each_with_index do |width, i|
			font_size = font_sizes[i] || font_sizes[0]
			style = styles[i] || styles[0]
			align = alignments[i] || alignments[0]
			valign =  valignments[i] || valignments[0]
			font_color = font_colors[i] || font_colors[0]
			border_color = border_colors[i] || border_colors[0]
			background_color = background_colors[i] || background_colors[0]
			padding = paddings[i] || paddings[0]

       cell_opts = {}
       cell_opts[:font_size] = font_size
       cell_opts[:style] = style
       cell_opts[:align] = align
       cell_opts[:valign] = valign
       cell_opts[:font_color] = font_color
       cell_opts[:border_color] = border_color
       cell_opts[:background_color] = background_color
       cell_opts[:left_padding] = padding[:left_padding]
       cell_opts[:right_padding] = padding[:right_padding]
       cell_opts[:top_padding] = padding[:top_padding]
       cell_opts[:bottom_padding] = padding[:bottom_padding]
       cell_opts[:pdf_height] = pdf_height
       cell_opts[:pdf_width] = pdf_width
       cell_opts[:pdf_margin_top] = pdf_margin_top
       cell_opts[:pdf_margin_bottom] = pdf_margin_bottom
       cell_opts[:pdf_margin_left] = pdf_margin_left
       cell_opts[:pdf_margin_right] = pdf_margin_right
       
			# ...disegno le celle vere e proprie ad altezza fissa, con l'altezza
			# ricavata dal passo precedente.
			r = draw_cell_fixed_height(pdf, draw_simulation, x+offset, y, width, max_cell_height, texts[i], cell_opts, auto_y)

			# Gli eventuali "testi residui" (es. raggiunto fine pagina) li raccolgo
			# nel seguente array
			rtexts << r

			offset += width
		end

		texts = rtexts

     # Se nei testi residui, sono presenti solo stringhe vuote, posso uscire dal
     # loop, altrimenti, devo cambiare pagina e disegnare una nuova riga con i
     # testi rimanenti
     if !check_no_empty_string_presence(texts)
       new_y = y + max_cell_height
       break
     else
       pdf.start_new_page
       y = pdf_margin_top # Posiziono il cursore ad inizio della nuova pagina
     end
	end
 

   #pdf.y = (pdf_height - new_y)

	return new_y
end

.draw_row_fixed_height(pdf, x, y, widths, height, texts, opts = {}, auto_y = false) ⇒ Object



216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/pdf_writing_tools.rb', line 216

def self.draw_row_fixed_height(pdf, x, y, widths, height, texts, opts={}, auto_y=false)
	font_sizes        = opts[:font_sizes] || [10]
	styles            = opts[:styles] || [:normal]
	alignments        = opts[:alignments] || [:left]
	valignments       = opts[:valignments] || [:top]
	font_colors       = opts[:font_colors] || ["000000"]
	border_colors     = opts[:border_colors] || ["000000"]
	background_colors = opts[:background_colors] || ["FFFFFF"]
	paddings          = opts[:paddings] || [{left_padding: 5, right_padding: 5, top_padding: 5, bottom_padding: 5}]
	pdf_height        = opts[:pdf_height] || 297.mm
	pdf_width         = opts[:pdf_width] || 21.cm

	offset = 0

	widths.each_with_index do |width, i|
		font_size = font_sizes[i] || font_sizes[0]
		style = styles[i] || styles[0]
		align = alignments[i] || alignments[0]
		valign =  valignments[i] || valignments[0]
		font_color = font_colors[i] || font_colors[0]
		border_color = border_colors[i] || border_colors[0]
		background_color = background_colors[i] || background_colors[0]
		padding = paddings[i] || paddings[0]

     cell_opts = {}

     cell_opts[:font_size] = font_size
     cell_opts[:style] = style
     cell_opts[:align] = align
     cell_opts[:valign] = valign
     cell_opts[:font_color] = font_color
     cell_opts[:border_color] = border_color
     cell_opts[:background_color] = background_color
     cell_opts[:left_padding] = padding[:left_padding]
     cell_opts[:right_padding] = padding[:right_padding]
     cell_opts[:top_padding] = padding[:top_padding]
     cell_opts[:bottom_padding] = padding[:bottom_padding]
     cell_opts[:pdf_width] = pdf_width
     cell_opts[:pdf_height] = pdf_height

		draw_cell_fixed_height( pdf, false, x+offset, y, width, height, texts[i], cell_opts, auto_y)

		offset += width
	end
   pdf.y = (pdf.cursor - height)
end

.draw_xml_object(pdf, xml_object) ⇒ Object

L’oggetto xml, viene letto ricorsivamente. Si crea una lista, contenente dei dizionari. Ciascun dizionario contiene: Il nome di un’azione: :action_name Una lista “data”, contenente un dizionario con al suo interno le specifiche da dare a prawn, per “disegnare” del testo o per disegnare un’immagine

Le p



27
28
29
30
31
32
33
34
# File 'lib/pdf_writing_tools.rb', line 27

def self.draw_xml_object(pdf, xml_object)
  # Ottengo una lista di azioni, ciascuna delle quali, quando eseguita,
  # permette di disegnare una parte del documento xml all'interno del pdf
  actions_list = get_actions_list(xml_object)

  # "Eseguo" le azioni contenute nella lista
  PdfWritingToolsActions.execute_actions(pdf, actions_list, nil, [])
end

.get_actions_list(xml_object) ⇒ Object

Produce le actions necessarie per disegnare nel PDF l’intero documento XML



38
39
40
41
42
43
44
45
46
# File 'lib/pdf_writing_tools.rb', line 38

def self.get_actions_list(xml_object)
  actions_list = []
  if xml_object.name == 'nothtml'
    xml_object.children.each do |child|
      actions_list += PdfWritingToolsProcess.process_xml_obj(child, [])
    end
  end
  actions_list + PdfWritingToolsActions.tr_action + PdfWritingToolsActions.tr_action + actions_list + actions_list
end

.get_cleaned_xml_from_file(file_path) ⇒ Object

Dato il percorso file_path, genera un documento xml, a cui sono stati rimossi gli a capo e gli spazi multipli



437
438
439
440
441
442
443
444
445
446
447
# File 'lib/pdf_writing_tools.rb', line 437

def self.get_cleaned_xml_from_file(file_path)
  text = File.read(file_path)

  # Rimuove gli a capo e le tabulazioni sostituendoli con uno spazio
  text = text.gsub(/\n|\t/, ' ')

  # Rimuove le spaziature multiple sostituendole con uno spazio
  text = text.gsub(/\s+/, ' ')

  Nokogiri::XML(text)
end