combine_pdf 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/combine_pdf.rb +108 -0
- data/lib/combine_pdf/combine_pdf_basic_writer.rb +12 -7
- data/lib/combine_pdf/combine_pdf_fonts.rb +5 -1
- data/lib/combine_pdf/combine_pdf_pdf.rb +22 -6
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c5d50f2ddbf6142442857b65ec46d9565ae774e2
|
4
|
+
data.tar.gz: caaa8ac30c72919c54d28d21a4d30979a40ff41e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0814bd7cfdfbd06d58506dc83f2160099bb6741c60625279850b6d8f525fa970228ce99425223a54998136cecff3593e1530bd0e77f5071d931a173bc26128ff
|
7
|
+
data.tar.gz: 88230912c86e10a0949c63c0a10b358da411a96a615860bd8c62985c2c62ff4d98a05b0fb5982e9f6fab7a6fb3cd8d049254660d6c1c449e84c5922783cf7552
|
data/lib/combine_pdf.rb
CHANGED
@@ -184,6 +184,114 @@ module CombinePDF
|
|
184
184
|
PDFWriter.new mediabox
|
185
185
|
end
|
186
186
|
|
187
|
+
# makes a PDF object containing a table
|
188
|
+
#
|
189
|
+
# all the pages in this PDF object are PDFWriter objects and are
|
190
|
+
# writable using the texbox function (should you wish to add a title, or more info)
|
191
|
+
#
|
192
|
+
# the main intended use of this method is to create indexes (a table of contents) for merged data.
|
193
|
+
#
|
194
|
+
# example:
|
195
|
+
# pdf = CombinePDF.new_table headers: ["header 1", "another header"], table_data: [ ["this is one row", "with two columns"] , ["this is another row", "also two columns", "the third will be ignored"] ]
|
196
|
+
# pdf.save "table_file.pdf"
|
197
|
+
#
|
198
|
+
# accepts a Hash with any of the following keys as well as any of the PDFWriter#textbox options:
|
199
|
+
# headers:: an Array of strings with the headers (will be repeated every page).
|
200
|
+
# table_data:: as Array of Arrays, each containing a string for each column. the first row sets the number of columns. extra columns will be ignored.
|
201
|
+
# font:: a registered or standard font name (see PDFWriter). defaults to nil (:Helvetica).
|
202
|
+
# header_font:: a registered or standard font name for the headers (see PDFWriter). defaults to nil (the font for all the table rows).
|
203
|
+
# max_font_size:: the maximum font size. if the string doesn't fit, it will be resized. defaults to 14.
|
204
|
+
# column_widths:: an array of relative column widths ([1,2] will display only the first two columns, the second twice as big as the first). defaults to nil (even widths).
|
205
|
+
# header_color:: the header color. defaults to [0.8, 0.8, 0.8] (light gray).
|
206
|
+
# main_color:: main row color. defaults to nil (transparent / white).
|
207
|
+
# alternate_color: alternate row color. defaults to [0.95, 0.95, 0.95] (very light gray).
|
208
|
+
# font_color: font color. defaults to [0,0,0] (black).
|
209
|
+
# border_color: border color. defaults to [0,0,0] (black).
|
210
|
+
# border_width: border width in PDF units. defaults to 1.
|
211
|
+
# header_align: the header text alignment within each column (:right, :left, :center). defaults to :center.
|
212
|
+
# row_align:: the row text alignment within each column. defaults to :left (:right for RTL table).
|
213
|
+
# direction: the table's writing direction (:ltr or :rtl). this reffers to the direction of the columns and doesn't effect text (rtl text is automatically recognized). defaults to :ltr.
|
214
|
+
# rows_per_page: the number of rows per page, INCLUDING the header row. deafults to 25.
|
215
|
+
# page_size: the size of the page in PDF points. defaults to [0, 0, 595.3, 841.9] (A4).
|
216
|
+
def new_table (options = {})
|
217
|
+
defaults = {
|
218
|
+
headers: nil,
|
219
|
+
table_data: [[]],
|
220
|
+
font: nil,
|
221
|
+
header_font: nil,
|
222
|
+
max_font_size: 14,
|
223
|
+
column_widths: nil,
|
224
|
+
header_color: [0.8, 0.8, 0.8],
|
225
|
+
main_color: nil,
|
226
|
+
alternate_color: [0.95, 0.95, 0.95],
|
227
|
+
font_color: [0,0,0],
|
228
|
+
border_color: [0,0,0],
|
229
|
+
border_width: 1,
|
230
|
+
header_align: :center,
|
231
|
+
row_align: nil,
|
232
|
+
direction: :ltr,
|
233
|
+
rows_per_page: 25,
|
234
|
+
page_size: [0, 0, 595.3, 841.9] #A4
|
235
|
+
}
|
236
|
+
options = defaults.merge options
|
237
|
+
options[:header_font] = options[:font] unless options[:header_font]
|
238
|
+
options[:row_align] ||= ( (options[:direction] == :rtl) ? :right : :left )
|
239
|
+
# assert table_data is an array of arrays
|
240
|
+
return false unless (options[:table_data].select {|r| !r.is_a?(Array) }).empty?
|
241
|
+
# compute sizes
|
242
|
+
page_size = options[:page_size]
|
243
|
+
top = page_size[3] * 0.9
|
244
|
+
height = page_size[3] * 0.8 / options[:rows_per_page]
|
245
|
+
from_side = page_size[2] * 0.1
|
246
|
+
width = page_size[2] * 0.8
|
247
|
+
columns = options[:table_data][0].length
|
248
|
+
column_widths = []
|
249
|
+
columns.times {|i| column_widths << (width/columns) }
|
250
|
+
if options[:column_widths]
|
251
|
+
scale = 0
|
252
|
+
options[:column_widths].each {|w| scale += w}
|
253
|
+
column_widths = []
|
254
|
+
options[:column_widths].each { |w| column_widths << (width*w/scale) }
|
255
|
+
end
|
256
|
+
column_widths = column_widths.reverse if options[:direction] == :rtl
|
257
|
+
# set pdf object and start writing the data
|
258
|
+
table = PDF.new()
|
259
|
+
page = nil
|
260
|
+
rows_per_page = options[:rows_per_page]
|
261
|
+
row_number = rows_per_page + 1
|
262
|
+
|
263
|
+
options[:table_data].each do |row_data|
|
264
|
+
if row_number > rows_per_page
|
265
|
+
page = create_page page_size
|
266
|
+
table << page
|
267
|
+
row_number = 1
|
268
|
+
# add headers
|
269
|
+
if options[:headers]
|
270
|
+
x = from_side
|
271
|
+
headers = options[:headers]
|
272
|
+
headers = headers.reverse if options[:direction] == :rtl
|
273
|
+
column_widths.each_index do |i|
|
274
|
+
text = headers[i].to_s
|
275
|
+
page.textbox text, {x: x, y: (top - (height*row_number)), width: column_widths[i], height: height, box_color: options[:header_color], text_align: options[:header_align] }.merge(options).merge({font: options[:header_font]})
|
276
|
+
x += column_widths[i]
|
277
|
+
end
|
278
|
+
row_number += 1
|
279
|
+
end
|
280
|
+
end
|
281
|
+
x = from_side
|
282
|
+
row_data = row_data.reverse if options[:direction] == :rtl
|
283
|
+
column_widths.each_index do |i|
|
284
|
+
text = row_data[i].to_s
|
285
|
+
box_color = options[:main_color]
|
286
|
+
box_color = options[:alternate_color] if options[:alternate_color] && row_number.odd?
|
287
|
+
page.textbox text, {x: x, y: (top - (height*row_number)), width: column_widths[i], height: height, box_color: box_color, text_align: options[:row_align]}.merge(options)
|
288
|
+
x += column_widths[i]
|
289
|
+
end
|
290
|
+
row_number += 1
|
291
|
+
end
|
292
|
+
table
|
293
|
+
end
|
294
|
+
|
187
295
|
# adds a correctly formatted font object to the font library.
|
188
296
|
#
|
189
297
|
# registered fonts will remain in the library and will only be embeded in
|
@@ -72,6 +72,7 @@ module CombinePDF
|
|
72
72
|
# height:: the height of the box. negative values will be computed from edge of page. defaults to 0 (end of page).
|
73
73
|
# text_align:: symbol for horizontal text alignment, can be ":center" (default), ":right", ":left"
|
74
74
|
# text_valign:: symbol for vertical text alignment, can be ":center" (default), ":top", ":buttom"
|
75
|
+
# text_padding:: a Float between 0 and 1, setting the padding for the text. defaults to 0.05 (5%).
|
75
76
|
# font:: a registered font name or an Array of names. defaults to ":Helvetica". The 14 standard fonts names are:
|
76
77
|
# - :"Times-Roman"
|
77
78
|
# - :"Times-Bold"
|
@@ -105,6 +106,7 @@ module CombinePDF
|
|
105
106
|
height: -1,
|
106
107
|
text_align: :center,
|
107
108
|
text_valign: :center,
|
109
|
+
text_padding: 0.1,
|
108
110
|
font: nil,
|
109
111
|
font_size: :fit_text,
|
110
112
|
max_font_size: nil,
|
@@ -122,6 +124,9 @@ module CombinePDF
|
|
122
124
|
options[:width] = mediabox[2] - options[:x] + options[:width] if options[:width] <= 0
|
123
125
|
options[:height] = mediabox[3] - options[:y] + options[:height] if options[:height] <= 0
|
124
126
|
|
127
|
+
# reset the padding value
|
128
|
+
options[:text_padding] = 0 if options[:text_padding].to_f >= 1
|
129
|
+
|
125
130
|
# create box stream
|
126
131
|
box_stream = ""
|
127
132
|
# set graphic state for box
|
@@ -199,29 +204,29 @@ module CombinePDF
|
|
199
204
|
text_stream = ""
|
200
205
|
if text.to_s != "" && options[:font_size] != 0 && (options[:font_color] || options[:stroke_color])
|
201
206
|
# compute x and y position for text
|
202
|
-
x = options[:x]
|
203
|
-
y = options[:y]
|
207
|
+
x = options[:x] + (options[:width]*options[:text_padding])
|
208
|
+
y = options[:y] + (options[:height]*options[:text_padding])
|
204
209
|
|
205
210
|
# set the fonts (fonts array, with :Helvetica as fallback).
|
206
211
|
fonts = [*options[:font], :Helvetica]
|
207
212
|
# fit text in box, if requested
|
208
213
|
font_size = options[:font_size]
|
209
214
|
if options[:font_size] == :fit_text
|
210
|
-
font_size = self.fit_text text, fonts, options[:width], options[:height]
|
215
|
+
font_size = self.fit_text text, fonts, (options[:width]*(1-options[:text_padding])), (options[:height]*(1-options[:text_padding]))
|
211
216
|
font_size = options[:max_font_size] if options[:max_font_size] && font_size > options[:max_font_size]
|
212
217
|
end
|
213
218
|
|
214
219
|
text_size = dimensions_of text, fonts, font_size
|
215
220
|
|
216
221
|
if options[:text_align] == :center
|
217
|
-
x = (options[:width] - text_size[0])/2 + x
|
222
|
+
x = ( ( options[:width]*(1-(2*options[:text_padding])) ) - text_size[0] )/2 + x
|
218
223
|
elsif options[:text_align] == :right
|
219
|
-
x = (options[:width] - text_size[0]) + x
|
224
|
+
x = ( ( options[:width]*(1-(1.5*options[:text_padding])) ) - text_size[0] ) + x
|
220
225
|
end
|
221
226
|
if options[:text_valign] == :center
|
222
|
-
y = (options[:height] - text_size[1])/2 + y
|
227
|
+
y = ( ( options[:height]*(1-(2*options[:text_padding])) ) - text_size[1] )/2 + y
|
223
228
|
elsif options[:text_valign] == :top
|
224
|
-
y = (options[:height] - text_size[1]
|
229
|
+
y = ( options[:height]*(1-(1.5*options[:text_padding])) ) - text_size[1] + y
|
225
230
|
end
|
226
231
|
|
227
232
|
# set graphic state for text
|
@@ -217,7 +217,11 @@ module CombinePDF
|
|
217
217
|
old_widths = font_object[:DescendantFonts]
|
218
218
|
old_widths = old_widths[:referenced_object][:indirect_without_dictionary] if old_widths[:is_reference_only]
|
219
219
|
old_widths = old_widths[0][:referenced_object]
|
220
|
-
|
220
|
+
avrg_height = 360
|
221
|
+
avrg_height = old_widths[:XHeight] if old_widths[:XHeight]
|
222
|
+
avrg_height = (avrg_height + old_widths[:CapHeight])/2 if old_widths[:CapHeight]
|
223
|
+
avrg_width = old_widths[:AvgWidth] || 0
|
224
|
+
avarage_bbox = [0, 0, avrg_width, avrg_height] # data is missing for full box metrics, just ignore
|
221
225
|
end
|
222
226
|
|
223
227
|
# compute the metrics values using the appropiate system (TrueType vs. Type0 fonts)
|
@@ -87,17 +87,32 @@ module CombinePDF
|
|
87
87
|
@info = {}
|
88
88
|
if args[0].is_a? PDFParser
|
89
89
|
@objects = args[0].parse
|
90
|
+
# connecting references with original objects
|
91
|
+
serialize_objects_and_references
|
92
|
+
# make sure there is only one Catalog (the latest Catalog)
|
93
|
+
if args[0].root_object[:Root]
|
94
|
+
@objects.delete_if {|obj| obj[:Type] == :Catalog}
|
95
|
+
@objects << args[0].root_object[:Root]
|
96
|
+
else
|
97
|
+
last_calalog = (@objects.select {|obj| obj[:Type] == :Catalog}).last
|
98
|
+
unless last_calalog.nil?
|
99
|
+
@objects.delete_if {|obj| obj[:Type] == :Catalog}
|
100
|
+
@objects << last_calalog
|
101
|
+
end
|
102
|
+
end
|
90
103
|
@version = args[0].version if args[0].version.is_a? Float
|
91
104
|
@info = args[0].info_object || {}
|
92
105
|
elsif args[0].is_a? Array
|
93
106
|
# object initialization
|
94
107
|
@objects = args[0]
|
95
108
|
@version = args[1] if args[1].is_a? Float
|
109
|
+
# connecting references with original objects
|
110
|
+
serialize_objects_and_references
|
96
111
|
elsif args[0].is_a? Hash
|
97
112
|
@objects = args
|
113
|
+
# connecting references with original objects
|
114
|
+
serialize_objects_and_references
|
98
115
|
end
|
99
|
-
# connecting references with original objects
|
100
|
-
serialize_objects_and_references
|
101
116
|
# general globals
|
102
117
|
@string_output = :literal
|
103
118
|
@need_to_rebuild_resources = false
|
@@ -224,6 +239,10 @@ module CombinePDF
|
|
224
239
|
self
|
225
240
|
end
|
226
241
|
end
|
242
|
+
catalogs[:MediaBox] ||= catalogs[:Parent][:referenced_object][:MediaBox] if catalogs[:Parent].is_a?(Hash) && catalogs[:Parent][:referenced_object].is_a?(Hash) && catalogs[:Parent][:referenced_object][:MediaBox]
|
243
|
+
catalogs[:CropBox] ||= catalogs[:Parent][:referenced_object][:CropBox] if catalogs[:CropBox].is_a?(Hash) && catalogs[:CropBox][:referenced_object].is_a?(Hash) && catalogs[:Parent][:referenced_object][:CropBox]
|
244
|
+
catalogs[:MediaBox] = catalogs[:MediaBox][:referenced_object][:indirect_without_dictionary] if catalogs[:MediaBox].is_a?(Hash) && catalogs[:MediaBox][:referenced_object].is_a?(Hash) && catalogs[:MediaBox][:referenced_object][:indirect_without_dictionary]
|
245
|
+
catalogs[:CropBox] = catalogs[:CropBox][:referenced_object][:indirect_without_dictionary] if catalogs[:CropBox].is_a?(Hash) && catalogs[:CropBox][:referenced_object].is_a?(Hash) && catalogs[:CropBox][:referenced_object][:indirect_without_dictionary]
|
227
246
|
page_list << catalogs
|
228
247
|
when :Pages
|
229
248
|
page_list.push *(pages(catalogs[:Kids])) unless catalogs[:Kids].nil?
|
@@ -330,11 +349,8 @@ module CombinePDF
|
|
330
349
|
page_number = opt[:start_at]
|
331
350
|
pages.each do |page|
|
332
351
|
# create a "stamp" PDF page with the same size as the target page
|
333
|
-
mediabox = page[:MediaBox]
|
352
|
+
mediabox = page[:CropBox] || page[:MediaBox] || [0, 0, 595.3, 841.9]
|
334
353
|
stamp = PDFWriter.new mediabox
|
335
|
-
# set the visible dimensions to the CropBox, if it exists.
|
336
|
-
cropbox = page[:CropBox]
|
337
|
-
mediabox = cropbox if cropbox
|
338
354
|
# set stamp text
|
339
355
|
text = opt[:number_format] % page_number
|
340
356
|
# compute locations for text boxes
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: combine_pdf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Boaz Segev
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-09-
|
12
|
+
date: 2014-09-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ruby-rc4
|