combine_pdf 0.1.18 → 0.1.19

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
  SHA1:
3
- metadata.gz: 163fdfa7125d90db5036ce74771d1c35b7646bb9
4
- data.tar.gz: 6aa28d4851428dcf7bad4953584df22dcf80ed11
3
+ metadata.gz: 349e06732609e9290dc73720f99ac576b097c53c
4
+ data.tar.gz: 48737dde1fb3bf8e9d838d43795a9aa0d06453bd
5
5
  SHA512:
6
- metadata.gz: c6908ad43c44cad0e96244f901fa07559a2ce81972e23f3f0b2942086f79cdf9f6de9ba55100920d1cd4729cae0001f8e2cae4385e86bd25b6beea7bb7ae72b5
7
- data.tar.gz: 58cdd816035416b8d2dd9ff7e80fdbda593cf7a073da336c2fc31aafb69769424411124b74ef09290a7f3da20ceb24f7b1de8593e38ec6e4185e2a79243e9352
6
+ metadata.gz: a08c2bd768ffb7e41788da436ff7409b609f97986a0dcf78ce168ec9d3ed1e041af8f2389588fe26e44f19b60cce444ed00bb57abc8d6aca22bfaaea24bc7b9f
7
+ data.tar.gz: 92249ecb752f219595a2a55ef0b72ce45dd4cda953df903bf3328f418300fd223378f24186d827b79514b7c734dab3aa39fc28272b0a473423863eba92efe5f6
@@ -2,6 +2,23 @@
2
2
 
3
3
  ***
4
4
 
5
+ Change log v.0.1.20
6
+ (pre-release)
7
+
8
+ No changes yet.
9
+
10
+ ***
11
+
12
+ Change log v.0.1.19
13
+
14
+ **fix**: merged @espinosa's fix for issue #16 which affected windows machines.
15
+
16
+ **feature**: added a #write_table method to the PDF pages, allowing tables to be written on existing PDF pages. This is a destructive method (it changes the table_data array by removing any rows written to the page and leaving the rest of the data untouched, for future writing). Read the documentation before using this method.
17
+
18
+ **update**: stricter parsing for PDF Stream Objects is now enforced. The stricter parsing is NOT final, as it walks a fine line between allowing non-conforming PDF files to be read and risking an error while reading a correctly structured file which has PDF keywords intentionaly embedded in a correctly structured object stream (keywords which would be normally ignored as expected, but which will be recognized as relevant if the parser is less strict about the structure of the PDF file).
19
+
20
+ ***
21
+
5
22
  Change log v.0.1.18
6
23
 
7
24
  **fix**: Thank to Stefan, who reported issue #15 , we discovered that in some cases PDF files presented the wrong PDF standard version, causing an error while attempting to parse their data. The issue has been fixed by allowing the parser to search for PDF Object Streams even when the PDF file claims a PDF version below 1.5.
@@ -12,7 +12,7 @@ module CombinePDF
12
12
  def load(file_name = "")
13
13
  raise TypeError, "couldn't parse and data, expecting type String" unless file_name.is_a?(String) || file_name.is_a?(Pathname)
14
14
  return PDF.new() if file_name == ''
15
- PDF.new( PDFParser.new( IO.read(file_name).force_encoding(Encoding::ASCII_8BIT) ) )
15
+ PDF.new( PDFParser.new( IO.read(file_name, mode: 'rb').force_encoding(Encoding::ASCII_8BIT) ) )
16
16
  end
17
17
  def new(file_name = "")
18
18
  load(file_name)
@@ -66,85 +66,97 @@ module CombinePDF
66
66
  # header_align:: the header text alignment within each column (:right, :left, :center). defaults to :center.
67
67
  # row_align:: the row text alignment within each column. defaults to :left (:right for RTL table).
68
68
  # 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.
69
- # rows_per_page:: the number of rows per page, INCLUDING the header row. deafults to 25.
69
+ # max_rows:: the number of rows per page, INCLUDING the header row. deafults to 25.
70
70
  # page_size:: the size of the page in PDF points. defaults to [0, 0, 595.3, 841.9] (A4).
71
71
  def create_table(options = {})
72
- defaults = {
73
- headers: nil,
74
- table_data: [[]],
75
- font: nil,
76
- header_font: nil,
77
- max_font_size: 14,
78
- column_widths: nil,
79
- header_color: [0.8, 0.8, 0.8],
80
- main_color: nil,
81
- alternate_color: [0.95, 0.95, 0.95],
82
- font_color: [0,0,0],
83
- border_color: [0,0,0],
84
- border_width: 1,
85
- header_align: :center,
86
- row_align: nil,
87
- direction: :ltr,
88
- rows_per_page: 25,
89
- page_size: [0, 0, 595.3, 841.9] #A4
90
- }
91
- options = defaults.merge options
92
- options[:header_font] = options[:font] unless options[:header_font]
93
- options[:row_align] ||= ( (options[:direction] == :rtl) ? :right : :left )
94
- # assert table_data is an array of arrays
95
- return false unless (options[:table_data].select {|r| !r.is_a?(Array) }).empty?
96
- # compute sizes
97
- page_size = options[:page_size]
98
- top = page_size[3] * 0.9
99
- height = page_size[3] * 0.8 / options[:rows_per_page]
100
- from_side = page_size[2] * 0.1
101
- width = page_size[2] * 0.8
102
- columns = options[:table_data][0].length
103
- column_widths = []
104
- columns.times {|i| column_widths << (width/columns) }
105
- if options[:column_widths]
106
- scale = 0
107
- options[:column_widths].each {|w| scale += w}
108
- column_widths = []
109
- options[:column_widths].each { |w| column_widths << (width*w/scale) }
110
- end
111
- column_widths = column_widths.reverse if options[:direction] == :rtl
112
- # set pdf object and start writing the data
72
+ options[:max_rows] = options[:rows_per_page] if options[:rows_per_page]
73
+
74
+ page_size = options[:page_size] || [0, 0, 595.3, 841.9]
113
75
  table = PDF.new()
114
76
  page = nil
115
- rows_per_page = options[:rows_per_page]
116
- row_number = rows_per_page + 1
117
-
118
- options[:table_data].each do |row_data|
119
- if row_number > rows_per_page
120
- page = create_page page_size
121
- table << page
122
- row_number = 1
123
- # add headers
124
- if options[:headers]
125
- x = from_side
126
- headers = options[:headers]
127
- headers = headers.reverse if options[:direction] == :rtl
128
- column_widths.each_index do |i|
129
- text = headers[i].to_s
130
- 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]})
131
- x += column_widths[i]
132
- end
133
- row_number += 1
134
- end
135
- end
136
- x = from_side
137
- row_data = row_data.reverse if options[:direction] == :rtl
138
- column_widths.each_index do |i|
139
- text = row_data[i].to_s
140
- box_color = options[:main_color]
141
- box_color = options[:alternate_color] if options[:alternate_color] && row_number.odd?
142
- 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)
143
- x += column_widths[i]
144
- end
145
- row_number += 1
77
+ until options[:table_data].empty?
78
+ page = create_page page_size
79
+ page.write_table options
80
+ table << page
146
81
  end
147
82
  table
83
+
84
+ # defaults = {
85
+ # headers: nil,
86
+ # table_data: [[]],
87
+ # font: nil,
88
+ # header_font: nil,
89
+ # max_font_size: 14,
90
+ # column_widths: nil,
91
+ # header_color: [0.8, 0.8, 0.8],
92
+ # main_color: nil,
93
+ # alternate_color: [0.95, 0.95, 0.95],
94
+ # font_color: [0,0,0],
95
+ # border_color: [0,0,0],
96
+ # border_width: 1,
97
+ # header_align: :center,
98
+ # row_align: nil,
99
+ # direction: :ltr,
100
+ # rows_per_page: 25,
101
+ # page_size: [0, 0, 595.3, 841.9] #A4
102
+ # }
103
+ # options = defaults.merge options
104
+ # options[:header_font] = options[:font] unless options[:header_font]
105
+ # options[:row_align] ||= ( (options[:direction] == :rtl) ? :right : :left )
106
+ # # assert table_data is an array of arrays
107
+ # return false unless (options[:table_data].select {|r| !r.is_a?(Array) }).empty?
108
+ # # compute sizes
109
+ # page_size = options[:page_size]
110
+ # top = page_size[3] * 0.9
111
+ # height = page_size[3] * 0.8 / options[:rows_per_page]
112
+ # from_side = page_size[2] * 0.1
113
+ # width = page_size[2] * 0.8
114
+ # columns = options[:table_data][0].length
115
+ # column_widths = []
116
+ # columns.times {|i| column_widths << (width/columns) }
117
+ # if options[:column_widths]
118
+ # scale = 0
119
+ # options[:column_widths].each {|w| scale += w}
120
+ # column_widths = []
121
+ # options[:column_widths].each { |w| column_widths << (width*w/scale) }
122
+ # end
123
+ # column_widths = column_widths.reverse if options[:direction] == :rtl
124
+ # # set pdf object and start writing the data
125
+ # table = PDF.new()
126
+ # page = nil
127
+ # rows_per_page = options[:rows_per_page]
128
+ # row_number = rows_per_page + 1
129
+
130
+ # options[:table_data].each do |row_data|
131
+ # if row_number > rows_per_page
132
+ # page = create_page page_size
133
+ # table << page
134
+ # row_number = 1
135
+ # # add headers
136
+ # if options[:headers]
137
+ # x = from_side
138
+ # headers = options[:headers]
139
+ # headers = headers.reverse if options[:direction] == :rtl
140
+ # column_widths.each_index do |i|
141
+ # text = headers[i].to_s
142
+ # 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]})
143
+ # x += column_widths[i]
144
+ # end
145
+ # row_number += 1
146
+ # end
147
+ # end
148
+ # x = from_side
149
+ # row_data = row_data.reverse if options[:direction] == :rtl
150
+ # column_widths.each_index do |i|
151
+ # text = row_data[i].to_s
152
+ # box_color = options[:main_color]
153
+ # box_color = options[:alternate_color] if options[:alternate_color] && row_number.odd?
154
+ # 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)
155
+ # x += column_widths[i]
156
+ # end
157
+ # row_number += 1
158
+ # end
159
+ # table
148
160
  end
149
161
  def new_table(options = {})
150
162
  create_table options
@@ -43,6 +43,22 @@ module CombinePDF
43
43
  self[:MediaBox].is_a?(Array) ? self[:MediaBox] : self[:MediaBox][:referenced_object]
44
44
  end
45
45
 
46
+ # accessor (setter) for the :CropBox element of the page
47
+ # dimensions:: an Array consisting of four numbers (can be floats) setting the size of the media box.
48
+ def cropbox=(dimensions = [0.0, 0.0, 612.0, 792.0])
49
+ self[:CropBox] = dimensions
50
+ end
51
+
52
+ # accessor (getter) for the :CropBox element of the page
53
+ def cropbox
54
+ (self[:CropBox].is_a?(Array) || self[:CropBox].nil?) ? self[:CropBox] : self[:CropBox][:referenced_object]
55
+ end
56
+
57
+ # get page size
58
+ def page_size
59
+ cropbox || mediabox
60
+ end
61
+
46
62
  # accessor (getter) for the :Resources element of the page
47
63
  def resources
48
64
  self[:Resources] ||= {}
@@ -374,6 +390,104 @@ module CombinePDF
374
390
  end
375
391
 
376
392
 
393
+ # Writes a table to the current page, removing(!) the written rows from the table_data Array.
394
+ #
395
+ # since the table_data Array is updated, it is possible to call this method a few times,
396
+ # each time creating or moving to the next page, until table_data.empty? returns true.
397
+ #
398
+ # accepts a Hash with any of the following keys as well as any of the PDFWriter#textbox options:
399
+ # headers:: an Array of strings with the headers (will be repeated every page).
400
+ # 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.
401
+ # font:: a registered or standard font name (see PDFWriter). defaults to nil (:Helvetica).
402
+ # header_font:: a registered or standard font name for the headers (see PDFWriter). defaults to nil (the font for all the table rows).
403
+ # max_font_size:: the maximum font size. if the string doesn't fit, it will be resized. defaults to 14.
404
+ # 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).
405
+ # header_color:: the header color. defaults to [0.8, 0.8, 0.8] (light gray).
406
+ # main_color:: main row color. defaults to nil (transparent / white).
407
+ # alternate_color:: alternate row color. defaults to [0.95, 0.95, 0.95] (very light gray).
408
+ # font_color:: font color. defaults to [0,0,0] (black).
409
+ # border_color:: border color. defaults to [0,0,0] (black).
410
+ # border_width:: border width in PDF units. defaults to 1.
411
+ # header_align:: the header text alignment within each column (:right, :left, :center). defaults to :center.
412
+ # row_align:: the row text alignment within each column. defaults to :left (:right for RTL table).
413
+ # 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.
414
+ # max_rows:: the maximum number of rows to actually draw, INCLUDING the header row. deafults to 25.
415
+ # xy:: an Array specifying the top-left corner of the table. defaulte to [page_width*0.1, page_height*0.9].
416
+ # size:: an Array specifying the height and the width of the table. defaulte to [page_width*0.8, page_height*0.8].
417
+ def write_table(options = {})
418
+ defaults = {
419
+ headers: nil,
420
+ table_data: [[]],
421
+ font: nil,
422
+ header_font: nil,
423
+ max_font_size: 14,
424
+ column_widths: nil,
425
+ header_color: [0.8, 0.8, 0.8],
426
+ main_color: nil,
427
+ alternate_color: [0.95, 0.95, 0.95],
428
+ font_color: [0,0,0],
429
+ border_color: [0,0,0],
430
+ border_width: 1,
431
+ header_align: :center,
432
+ row_align: nil,
433
+ direction: :ltr,
434
+ max_rows: 25,
435
+ xy: nil,
436
+ size: nil
437
+ }
438
+ options = defaults.merge options
439
+ raise "method call error! not enough rows allowed to create table" if (options[:max_rows].to_i < 1 && options[:headers]) || (options[:max_rows].to_i <= 0)
440
+ options[:header_font] ||= options[:font]
441
+ options[:row_align] ||= ( (options[:direction] == :rtl) ? :right : :left )
442
+ options[:xy] ||= [( (page_size[2]-page_size[0])*0.1 ), ( (page_size[3]-page_size[1])*0.9 )]
443
+ options[:size] ||= [( (page_size[2]-page_size[0])*0.8 ), ( (page_size[3]-page_size[1])*0.8 )]
444
+ # assert table_data is an array of arrays
445
+ return false unless (options[:table_data].select {|r| !r.is_a?(Array) }).empty?
446
+ # compute sizes
447
+ top = options[:xy][1]
448
+ height = options[:size][1] / options[:max_rows]
449
+ from_side = options[:xy][0]
450
+ width = options[:size][0]
451
+ columns = options[:table_data][0].length
452
+ column_widths = []
453
+ columns.times {|i| column_widths << (width/columns) }
454
+ if options[:column_widths]
455
+ scale = 0
456
+ options[:column_widths].each {|w| scale += w}
457
+ column_widths = []
458
+ options[:column_widths].each { |w| column_widths << (width*w/scale) }
459
+ end
460
+ column_widths = column_widths.reverse if options[:direction] == :rtl
461
+ # set count and start writing the data
462
+ row_number = 1
463
+
464
+ until (options[:table_data].empty? || row_number > options[:max_rows])
465
+ # add headers
466
+ if options[:headers] && row_number == 1
467
+ x = from_side
468
+ headers = options[:headers]
469
+ headers = headers.reverse if options[:direction] == :rtl
470
+ column_widths.each_index do |i|
471
+ text = headers[i].to_s
472
+ 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]})
473
+ x += column_widths[i]
474
+ end
475
+ row_number += 1
476
+ end
477
+ x = from_side
478
+ row_data = options[:table_data].shift
479
+ row_data = row_data.reverse if options[:direction] == :rtl
480
+ column_widths.each_index do |i|
481
+ text = row_data[i].to_s
482
+ box_color = (options[:alternate_color] && ( (row_number.odd? && options[:headers]) || row_number.even? ) ) ? options[:alternate_color] : options[:main_color]
483
+ 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)
484
+ x += column_widths[i]
485
+ end
486
+ row_number += 1
487
+ end
488
+ self
489
+ end
490
+
377
491
 
378
492
  ###################################
379
493
  # protected methods
@@ -153,8 +153,12 @@ module CombinePDF
153
153
  ##########################################
154
154
  ## parse a Stream
155
155
  ##########################################
156
- when @scanner.scan(/stream[\r]?[\n]/)
157
- str = @scanner.scan_until(/endstream/)
156
+ # when @scanner.scan(/stream[\r]?[\n]/)
157
+ # str = @scanner.scan_until(/endstream/)
158
+ when @scanner.scan(/stream(\r\n|\r|\n)/)
159
+ str = @scanner.scan_until(/(\r\n|\r|\n)endstream/)
160
+ # raise error if the stream doesn't end.
161
+ raise "Parsing Error: PDF file error - a stream object wasn't properly colsed using 'endstream'!" unless str
158
162
  # need to remove end of stream
159
163
  if out.last.is_a? Hash
160
164
  out.last[:raw_stream_content] = str[0...-10] #cuts only one EON char (\n or \r)
@@ -1,3 +1,3 @@
1
1
  module CombinePDF
2
- VERSION = "0.1.18"
2
+ VERSION = "0.1.19"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: combine_pdf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.18
4
+ version: 0.1.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - Boaz Segev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-27 00:00:00.000000000 Z
11
+ date: 2015-04-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-rc4