rbpdf 1.18.2 → 1.18.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -14,15 +14,15 @@ A template plugin allowing the inclusion of ERB-enabled RBPDF template files.
14
14
  * HTML tag support.
15
15
  * CSS minimum support.
16
16
  * Image
17
- - 8bit PNG image support without RMagick liblary.
18
- - PNG(with alpha channel)/JPEG/GIF image support. (use RMagick liblary)
17
+ - 8bit PNG image support without RMagick library.
18
+ - PNG(with alpha channel)/JPEG/GIF image support. (use RMagick library)
19
19
 
20
20
 
21
21
  ##
22
22
  ## Installing RBPDF
23
23
  ##
24
24
 
25
- RBPDF is distrifuted via RubyGems, and can be installed the usual way that you install gems: by simply typing `gem install rbpdf` on the command line.
25
+ RBPDF is distributed via RubyGems, and can be installed the usual way that you install gems: by simply typing `gem install rbpdf` on the command line.
26
26
 
27
27
  ==
28
28
 
data/lib/rbpdf.rb CHANGED
@@ -363,6 +363,7 @@ class RBPDF
363
363
  @radiobutton_groups ||= []
364
364
  @radio_groups ||= []
365
365
  @textindent ||= 0
366
+ @nested_table = false
366
367
 
367
368
  @start_transaction_y ||= 0
368
369
  @in_thead ||= false
@@ -1110,8 +1111,8 @@ class RBPDF
1110
1111
  # [@access public]
1111
1112
  # [@since 4.5.027 (2009-03-16)]
1112
1113
  #
1113
- def getPageDimensions(pagenum='')
1114
- if pagenum.empty?
1114
+ def getPageDimensions(pagenum=0)
1115
+ if !pagenum.is_a? Integer or pagenum.zero?
1115
1116
  pagenum = @page
1116
1117
  end
1117
1118
  return @pagedim[pagenum]
@@ -1161,15 +1162,15 @@ class RBPDF
1161
1162
  # [@since 1.5.2]
1162
1163
  # [@see] getPageDimensions()
1163
1164
  #
1164
- def getBreakMargin(pagenum='')
1165
- if pagenum.empty?
1165
+ def getBreakMargin(pagenum=0)
1166
+ if !pagenum.is_a? Integer or pagenum.zero?
1166
1167
  return @b_margin
1167
1168
  end
1168
1169
  return @pagedim[pagenum]['bm']
1169
1170
  end
1170
1171
  alias_method :get_break_margin, :getBreakMargin
1171
1172
 
1172
- def GetBreakMargin(pagenum='')
1173
+ def GetBreakMargin(pagenum=0)
1173
1174
  warn "[DEPRECATION] 'GetBreakMargin' is deprecated. Please use 'get_break_margin' instead."
1174
1175
  getBreakMargin(pagenum)
1175
1176
  end
@@ -3287,6 +3288,7 @@ class RBPDF
3287
3288
  # [@since (4.5.019) 2009-02-28]
3288
3289
  #
3289
3290
  def removeSHY(txt='')
3291
+ txt = txt.dup
3290
3292
  # Unicode Data
3291
3293
  # Name : SOFT HYPHEN, commonly abbreviated as SHY
3292
3294
  # HTML Entity (decimal): ­
@@ -4209,6 +4211,7 @@ class RBPDF
4209
4211
  # [@since 1.5]
4210
4212
  #
4211
4213
  def Write(h, txt, link=nil, fill=0, align='', ln=false, stretch=0, firstline=false, firstblock=false, maxh=0)
4214
+ txt = txt.dup
4212
4215
  txt.force_encoding('ASCII-8BIT') if txt.respond_to?(:force_encoding)
4213
4216
  if txt.length == 0
4214
4217
  txt = ' '
@@ -4359,7 +4362,7 @@ class RBPDF
4359
4362
  if ((@current_font['type'] == 'TrueTypeUnicode') or (@current_font['type'] == 'cidfont0')) and arabic
4360
4363
  # with bidirectional algorithm some chars may be changed affecting the line length
4361
4364
  # *** very slow ***
4362
- l = GetArrStringWidth(utf8Bidi(chars[j..i-1], '', @tmprtl))
4365
+ l = GetArrStringWidth(utf8Bidi(chars[j,i-j], '', @tmprtl))
4363
4366
  else
4364
4367
  l += GetCharWidth(c)
4365
4368
  end
@@ -4846,7 +4849,7 @@ class RBPDF
4846
4849
  if (type == '')
4847
4850
  type = getImageFileType(file, imsize)
4848
4851
  else
4849
- type.downcase!
4852
+ type = type.downcase
4850
4853
  type = 'jpeg' if type == 'jpg'
4851
4854
  end
4852
4855
 
@@ -6366,7 +6369,7 @@ protected
6366
6369
  stream = stream.strip
6367
6370
  @apxo_obj_id += 1
6368
6371
  @offsets[@apxo_obj_id] = @bufferlen
6369
- out = @apxo_obj_id + ' 0 obj'
6372
+ out = @apxo_obj_id.to_s + ' 0 obj'
6370
6373
  out << ' <<'
6371
6374
  out << ' /Type /XObject'
6372
6375
  out << ' /Subtype /Form'
@@ -7586,7 +7589,7 @@ protected
7586
7589
  def UTF8StringToArray(str)
7587
7590
  if @cache_utf8_string_to_array[str]
7588
7591
  # return cached value
7589
- return @cache_utf8_string_to_array[str]
7592
+ return @cache_utf8_string_to_array[str].dup
7590
7593
  end
7591
7594
  # check cache size
7592
7595
  if @cache_size_utf8_string_to_array >= @cache_maxsize_utf8_string_to_array
@@ -7602,7 +7605,7 @@ protected
7602
7605
  strarr[pos] = char.unpack('C')[0]
7603
7606
  end
7604
7607
  # insert new value on cache
7605
- @cache_utf8_string_to_array[str] = strarr
7608
+ @cache_utf8_string_to_array[str] = strarr.dup
7606
7609
  return strarr
7607
7610
  end
7608
7611
 
@@ -7661,7 +7664,7 @@ protected
7661
7664
  end
7662
7665
  end
7663
7666
  # insert new value on cache
7664
- @cache_utf8_string_to_array[str] = unicode
7667
+ @cache_utf8_string_to_array[str] = unicode.dup
7665
7668
  return unicode;
7666
7669
  end
7667
7670
 
@@ -9011,6 +9014,7 @@ public
9011
9014
  # [@since 2.4.000 (2008-03-06)]
9012
9015
  #
9013
9016
  def utf8Bidi(ta, str='', forcertl=false)
9017
+ str = str.dup
9014
9018
  # paragraph embedding level
9015
9019
  pel = 0
9016
9020
  # max level
@@ -9567,7 +9571,6 @@ public
9567
9571
 
9568
9572
  ordarray = []
9569
9573
  0.upto(numchars-1) do |i|
9570
- chardata[i][:char]
9571
9574
  ordarray.push chardata[i][:char]
9572
9575
  end
9573
9576
 
@@ -9685,8 +9688,8 @@ public
9685
9688
  # [@access public]
9686
9689
  # [@since 3.0.000 (2008-03-27)]
9687
9690
  #
9688
- def startPageGroup(page='')
9689
- if page.empty?
9691
+ def startPageGroup(page=0)
9692
+ if !page.is_a? Integer or page.zero?
9690
9693
  page = @page + 1
9691
9694
  end
9692
9695
  @newpagegroup[page] = true
@@ -10324,7 +10327,7 @@ protected
10324
10327
  return {}
10325
10328
  end
10326
10329
  # remove comments
10327
- cssdata.gsub!(/\/\*[^\*]*\*\//, '')
10330
+ cssdata = cssdata.gsub(/\/\*[^\*]*\*\//, '')
10328
10331
  # remove newlines and multiple spaces
10329
10332
  cssdata.gsub!(/[\s]+/, ' ')
10330
10333
  # remove some spaces
@@ -10573,6 +10576,7 @@ protected
10573
10576
  # [@since 3.2.000 (2008-06-20)]
10574
10577
  #
10575
10578
  def getHtmlDomArray(html)
10579
+ html = html.dup
10576
10580
  html.force_encoding('UTF-8') if @is_unicode and html.respond_to?(:force_encoding)
10577
10581
  # array of CSS styles ( selector => properties).
10578
10582
  css = {}
@@ -10642,7 +10646,6 @@ protected
10642
10646
  html = "%s" % sanitize(html, :tags=> %w(a b blockquote body br dd del div dl dt em font h1 h2 h3 h4 h5 h6 hr i img li ol p pre small span strong sub sup table tablehead td th thead tr tt u ins ul), :attributes => %w(cellspacing cellpadding bgcolor color value width height src size colspan rowspan style align border face href dir class id nobr stroke strokecolor fill nested))
10643
10647
 
10644
10648
  # replace some blank characters
10645
- html.gsub!(/<br>/, '<br/>')
10646
10649
  html.gsub!(/<pre/, '<xre') # preserve pre tag
10647
10650
  html.gsub!(/<(table|tr|td|th|blockquote|dd|div|dt|h1|h2|h3|h4|h5|h6|br|hr|li|ol|ul|p)([^\>]*)>[\n\r\t]+/, '<\\1\\2>')
10648
10651
  html.gsub!(/@(\r\n|\r)@/, "\n")
@@ -10777,7 +10780,11 @@ protected
10777
10780
  # store header rows on a new table
10778
10781
  if (dom[key]['value'] == 'tr') and (dom[(dom[key]['parent'])]['thead'] == true)
10779
10782
  if empty_string(dom[grandparent]['thead'])
10780
- dom[grandparent]['thead'] = a[dom[grandparent]['elkey']].dup
10783
+ if dom[grandparent]['attribute'].nil? or dom[grandparent]['attribute']['style'].nil?
10784
+ dom[grandparent]['thead'] = a[dom[grandparent]['elkey']].dup
10785
+ else
10786
+ dom[grandparent]['thead'] = '<style>' + dom[grandparent]['value'] + ' {' + dom[grandparent]['attribute']['style'] + '}</style>' + a[dom[grandparent]['elkey']].dup
10787
+ end
10781
10788
  end
10782
10789
  dom[key]['parent'].upto(key) do |i|
10783
10790
  dom[grandparent]['thead'] << a[dom[i]['elkey']]
@@ -10797,12 +10804,12 @@ protected
10797
10804
  # *** opening html tag
10798
10805
  dom[key]['opening'] = true
10799
10806
  dom[key]['parent'] = level[-1]
10800
- if element[-1, 1] != '/'
10801
- # not self-closing tag
10807
+ if element[-1, 1] == '/' or (dom[key]['value'] =~ /(br|img|hr)/)
10808
+ # self-closing tag
10809
+ dom[key]['self'] = true
10810
+ else
10802
10811
  level.push(key)
10803
10812
  dom[key]['self'] = false
10804
- else
10805
- dom[key]['self'] = true
10806
10813
  end
10807
10814
  # copy some values from parent
10808
10815
  parentkey = 0
@@ -11228,7 +11235,10 @@ public
11228
11235
  # [@see] Multicell(), writeHTML(), Cell()
11229
11236
  #
11230
11237
  def writeHTMLCell(w, h, x, y, html='', border=0, ln=0, fill=0, reseth=true, align='', autopadding=true)
11231
- return MultiCell(w, h, html, border, align, fill, ln, x, y, reseth, 0, true, autopadding, 0)
11238
+ @nested_table = true
11239
+ rtn = MultiCell(w, h, html, border, align, fill, ln, x, y, reseth, 0, true, autopadding, 0)
11240
+ @nested_table = false
11241
+ return rtn
11232
11242
  end
11233
11243
  alias_method :write_html_cell, :writeHTMLCell
11234
11244
 
@@ -11957,7 +11967,7 @@ public
11957
11967
  else
11958
11968
  wtmp = @w - @r_margin - @x
11959
11969
  end
11960
- if dom[key]['attribute']['nested'] and (dom[key]['attribute']['nested'] == 'true')
11970
+ if (@nested_table == true) or (dom[key]['attribute']['nested'] and (dom[key]['attribute']['nested'] == 'true'))
11961
11971
  # add margin for nested tables
11962
11972
  wtmp -= @c_margin
11963
11973
  end
@@ -12541,6 +12551,12 @@ public
12541
12551
  xpos += 2 * GetStringWidth(32.chr)
12542
12552
  end
12543
12553
  end
12554
+ if @rtl
12555
+ xpos -= @line_width * 1.5
12556
+ else
12557
+ xpos += @line_width * 1.5
12558
+ end
12559
+
12544
12560
  imglink = ''
12545
12561
  if !@href['url'].nil? and !empty_string(@href['url'])
12546
12562
  imglink = @href['url']
@@ -12573,13 +12589,20 @@ public
12573
12589
  ih = getHTMLUnitToUnits(tag['attribute']['height'], 1, 'px', false)
12574
12590
  end
12575
12591
 
12592
+ # store original margin values
12593
+ l_margin = @l_margin
12594
+ r_margin = @r_margin
12595
+
12596
+ SetLeftMargin(@l_margin + @line_width * 1.5)
12597
+ SetRightMargin(@r_margin + @line_width * 1.5)
12598
+
12576
12599
  begin
12577
12600
  # if (type == 'eps') or (type == 'ai')
12578
12601
  # ImageEps(tag['attribute']['src'], xpos, @y, iw, ih, imglink, true, align, '', border, true)
12579
12602
  # elsif type == 'svg'
12580
12603
  # ImageSVG(tag['attribute']['src'], xpos, @y, iw, ih, imglink, align, '', border, true)
12581
12604
  # else
12582
- result_img = Image(tag['attribute']['src'], xpos, @y, iw, ih, '', imglink, align, false, 300, '', false, false, border, false, false, true)
12605
+ result_img = Image(tag['attribute']['src'], xpos, @y + @line_width * 1.5, iw, ih, '', imglink, align, false, 300, '', false, false, border, false, false, true)
12583
12606
  # end
12584
12607
  rescue => err
12585
12608
  logger.error "pdf: Image: error: #{err.message}"
@@ -12593,6 +12616,11 @@ public
12593
12616
  when 'B'
12594
12617
  @y = @img_rb_y - (tag['fontsize'] / @k)
12595
12618
  end
12619
+
12620
+ # restore original margin values
12621
+ SetLeftMargin(l_margin)
12622
+ SetRightMargin(r_margin)
12623
+
12596
12624
  if result_img == false
12597
12625
  Write(@lasth, File::basename(img_name) + ' ', '', false, '', false, 0, false) unless img_name.nil?
12598
12626
  end
@@ -12961,7 +12989,7 @@ public
12961
12989
  }
12962
12990
  if !in_table_head
12963
12991
  # we are not inside a thead section
12964
- if !parent['cellpadding'].nil?
12992
+ if dom[(parent['parent'])]['attribute']['cellpadding'] ### fix ###
12965
12993
  @c_margin = @old_c_margin
12966
12994
  end
12967
12995
  @lasth = @font_size * @cell_height_ratio
@@ -12980,6 +13008,9 @@ public
12980
13008
  @thead_margins = {}
12981
13009
  end
12982
13010
  end
13011
+ if tag['block'] ### fix ###
13012
+ addHTMLVertSpace(hbz / 2, 0, cell, (dom[key+1].nil? or (dom[key+1]['value'] != 'table')))
13013
+ end
12983
13014
  when 'a'
12984
13015
  @href = {}
12985
13016
  when 'sup'
data/lib/rbpdf/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Rbpdf
2
- VERSION = "1.18.2"
2
+ VERSION = "1.18.3"
3
3
  end
data/rbpdf.gemspec CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
20
20
  Dir.glob("lib/fonts/dejavu-fonts-ttf-*/{AUTHORS,BUGS,LICENSE,NEWS,README}") +
21
21
  Dir.glob("test/*") +
22
22
  ["Rakefile", "rbpdf.gemspec", "Gemfile",
23
- "CHANGELOG", "test_unicode.rbpdf", "README.md",
23
+ "CHANGELOG", "test_unicode.rbpdf", "README.md", "LICENSE.TXT",
24
24
  "utf8test.txt", "logo_example.png" ]
25
25
  spec.rdoc_options += [ '--exclude', 'lib/fonts/',
26
26
  '--exclude', 'lib/htmlcolors.rb',
@@ -9,6 +9,9 @@ class RbpdfTest < ActiveSupport::TestCase
9
9
  def utf8Bidi(ta, str='', forcertl=false)
10
10
  super
11
11
  end
12
+ def cache_utf8_string_to_array(str)
13
+ @cache_utf8_string_to_array[str]
14
+ end
12
15
  end
13
16
 
14
17
  test "Bidi" do
@@ -62,4 +65,67 @@ class RbpdfTest < ActiveSupport::TestCase
62
65
  assert_equal [0x61, 0x62, 0x63, 0x5ea, 0x5d9, 0x5e8, 0x5d1, 0x5e2], ary_str
63
66
  end
64
67
 
68
+ test "Bidi arabic test" do
69
+ pdf = MYPDF.new
70
+
71
+ # Bidirectional Algorithm
72
+ ascii_str = "role"
73
+ utf8_arabic_str_1 = "\xd8\xaf\xd9\x88\xd8\xb1"
74
+ utf8_arabic_char_1 = "\xd8\xaf"
75
+
76
+ # UCS4 charactor -> UTF-8 charactor
77
+ utf8_chr = pdf.unichr(0x62f)
78
+ assert_equal "\xd8\xaf", utf8_chr
79
+
80
+ # UTF-8 string -> array of UCS4 charactor
81
+ ary_ucs4 = pdf.UTF8StringToArray(ascii_str)
82
+ assert_equal [0x72, 0x6f, 0x6c, 0x65], ary_ucs4
83
+ ary_ucs4 = pdf.UTF8StringToArray(utf8_arabic_str_1)
84
+ assert_equal [0x62f, 0x648, 0x631], ary_ucs4
85
+ ary_ucs4 = pdf.UTF8StringToArray(utf8_arabic_char_1)
86
+ assert_equal [0x62f], ary_ucs4
87
+
88
+
89
+ ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str))
90
+ assert_equal [0x72, 0x6f, 0x6c, 0x65], ary_ucs4
91
+
92
+ ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str), ascii_str, 'R')
93
+ assert_equal [0x72, 0x6f, 0x6c, 0x65], ary_ucs4
94
+
95
+ ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray(utf8_arabic_char_1))
96
+ assert_equal [0xfea9], ary_ucs4
97
+ ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray(utf8_arabic_char_1), utf8_arabic_char_1, 'R')
98
+ assert_equal [0xfea9], ary_ucs4
99
+
100
+ ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray(utf8_arabic_str_1))
101
+ assert_equal [0xfeae, 0xfeee, 0xfea9], ary_ucs4
102
+ end
103
+
104
+ test "Bidi date test" do
105
+ pdf = MYPDF.new
106
+
107
+ utf8_date_str_1 = '12/01/2014'
108
+
109
+ pdf.set_rtl(true)
110
+ pdf.set_temp_rtl('rtl')
111
+ # UTF-8 string -> array of UCS4 charactor
112
+ ary_ucs4 = pdf.UTF8StringToArray(utf8_date_str_1)
113
+ assert_equal [0x31, 0x32, 0x2f, 0x30, 0x31, 0x2f, 0x32, 0x30, 0x31, 0x34], ary_ucs4 # 12/01/2014
114
+
115
+ ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray(utf8_date_str_1))
116
+ assert_equal [0x31, 0x32, 0x2f, 0x30, 0x31, 0x2f, 0x32, 0x30, 0x31, 0x34], ary_ucs4 # 12/01/2014
117
+
118
+ ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray(utf8_date_str_1), utf8_date_str_1, 'R')
119
+ assert_equal [0x31, 0x32, 0x2f, 0x30, 0x31, 0x2f, 0x32, 0x30, 0x31, 0x34], ary_ucs4 # 12/01/2014
120
+ end
121
+
122
+ test "UTF8StringToArray cache_utf8_string_to_array test" do
123
+ pdf = MYPDF.new
124
+
125
+ chars = pdf.UTF8StringToArray('1234')
126
+ chars.reverse!
127
+
128
+ rtn = pdf.cache_utf8_string_to_array('1234')
129
+ assert_equal rtn, [0x31, 0x32, 0x33, 0x34]
130
+ end
65
131
  end
@@ -250,4 +250,18 @@ class RbpdfTest < ActiveSupport::TestCase
250
250
  line = pdf.get_num_lines(txt, w)
251
251
  assert_equal line, 3
252
252
  end
253
+
254
+ test "removeSHY encoding test" do
255
+ return unless 'test'.respond_to?(:force_encoding)
256
+
257
+ pdf = RBPDF.new('P', 'mm', 'A4', true, "UTF-8", true)
258
+
259
+ str = 'test'.force_encoding('UTF-8')
260
+ txt = pdf.removeSHY(str)
261
+ assert_equal str.encoding.to_s, 'UTF-8'
262
+
263
+ str = 'test'.force_encoding('ASCII-8BIT')
264
+ txt = pdf.removeSHY(str)
265
+ assert_equal str.encoding.to_s, 'ASCII-8BIT'
266
+ end
253
267
  end
@@ -181,12 +181,55 @@ class RbpdfCssTest < ActiveSupport::TestCase
181
181
  assert_equal dom[1]['value'], 'h2'
182
182
 
183
183
  # <table>
184
+ assert_equal dom[4]['elkey'], 3
184
185
  assert_equal dom[4]['value'], 'table'
185
186
  assert_equal dom[4]['attribute'], {'border'=>'2px #ff0000 solid', 'style'=>';border:2px #ff0000 solid;'}
186
187
  assert_equal dom[4]['style']['border'], '2px #ff0000 solid'
187
188
  assert_equal dom[4]['attribute']['border'], '2px #ff0000 solid'
188
189
  end
189
190
 
191
+ test "CSS Dom table thead test" do
192
+ pdf = MYPDF.new
193
+
194
+ html = '<style> table, td { border: 2px #ff0000 solid; } </style>
195
+ <h2>HTML TABLE THEAD:</h2>
196
+ <table><thead>
197
+ <tr> <th>abc</th> </tr>
198
+ </thead>
199
+ <tbody>
200
+ <tr> <td>def</td> </tr>
201
+ <tr> <td>ghi</td> </tr>
202
+ </tbody></table>'
203
+
204
+ dom = pdf.getHtmlDomArray(html)
205
+ ## remove style tag block (by getHtmlDomArray()) ##
206
+ ## remove thead/tbody tag block (by getHtmlDomArray()) ##
207
+ ## added marker tag (by getHtmlDomArray()) ##
208
+ # '<h2>HTML TABLE:</h2>
209
+ # <table><tr><th>abc<marker style="font-size:0"/></th></tr>
210
+ # <tr><td>def<marker style="font-size:0"/></td></tr></table>'
211
+ assert_equal dom.length, 24
212
+
213
+ assert_equal dom[0]['parent'], 0 # Root
214
+ assert_equal dom[0]['tag'], false
215
+ assert_equal dom[0]['attribute'], {}
216
+
217
+ # <h2>
218
+ assert_equal dom[1]['elkey'], 0
219
+ assert_equal dom[1]['parent'], 0 # parent -> parent tag key
220
+ assert_equal dom[1]['tag'], true
221
+ assert_equal dom[1]['opening'], true
222
+ assert_equal dom[1]['value'], 'h2'
223
+
224
+ # <table>
225
+ assert_equal dom[4]['elkey'], 3
226
+ assert_equal dom[4]['value'], 'table'
227
+ assert_equal dom[4]['attribute'], {'border'=>'2px #ff0000 solid', 'style'=>';border:2px #ff0000 solid;'}
228
+ assert_equal dom[4]['style']['border'], '2px #ff0000 solid'
229
+ assert_equal dom[4]['attribute']['border'], '2px #ff0000 solid'
230
+ assert_equal dom[4]['thead'], '<style>table {;border:2px #ff0000 solid;}</style><table><tr><th>abc<marker style="font-size:0"/></th></tr></tablehead>'
231
+ end
232
+
190
233
  test "CSS Dom line-height test normal" do
191
234
  pdf = MYPDF.new
192
235