Class: EideticPDF::PageWriter

Inherits:
Object
  • Object
show all
Includes:
JpegInfo
Defined in:
lib/epdfpw.rb

Overview

:nodoc:

Constant Summary collapse

DEFAULT_FONT =
{ :name => 'Helvetica', :size => 12 }

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from JpegInfo

jpeg?, jpeg_dimensions

Constructor Details

#initialize(doc, options) ⇒ PageWriter

Returns a new instance of PageWriter.



559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
# File 'lib/epdfpw.rb', line 559

def initialize(doc, options)
  # doc: PdfDocumentWriter
  @doc = doc
  @options = options
  @page_style = PageStyle.new(options)
  @units = options[:units] || :pt
  @v_text_align = options[:v_text_align] || :top
  @page_width = @page_style.page_size.x2
  @page_height = @page_style.page_size.y2
  if @page = options[:_page]
    @reused_page = true
  else
    @page = PdfObjects::PdfPage.new(@doc.next_seq, 0, @doc.catalog.pages)
    @page.media_box = @page_style.page_size.clone
    @page.crop_box = @page_style.crop_size.clone
    @page.rotate = @page_style.rotate
    @page.resources = @doc.resources
    @doc.file.body << @page
  end
  @stream = ''.force_encoding(Encoding::ASCII_8BIT)
  @annotations = []
  @char_spacing = @word_spacing = 0.0
  @last_char_spacing = @last_word_spacing = 0.0
  @last_scale = @scale = 1.0
  @last_text_rendering_mode = @text_rendering_mode = 0
  @default_font = options[:font] || DEFAULT_FONT
  @font_color = @default_font[:color] || 0
  @fill_color = options[:fill_color] || 0xFFFFFF
  @line_color = options[:line_color] || 0
  @line_height = options[:line_height] || 1.7
  line_width(options[:line_width] || 1.0, :pt)
  @text_angle = 0.0
  @auto_path = true
  @underline = false
  start_misc
  sub_page(*options[:sub_page] + Array(options[:unscaled])) if options[:sub_page]
  margins(options[:margins] || 0)
  text_encoding(options[:text_encoding])
  @indent = 0
end

Instance Attribute Details

#annotationsObject (readonly)

Returns the value of attribute annotations.



556
557
558
# File 'lib/epdfpw.rb', line 556

def annotations
  @annotations
end

#auto_pathObject (readonly)

Returns the value of attribute auto_path.



557
558
559
# File 'lib/epdfpw.rb', line 557

def auto_path
  @auto_path
end

#docObject (readonly)

Returns the value of attribute doc.



555
556
557
# File 'lib/epdfpw.rb', line 555

def doc
  @doc
end

#pageObject (readonly)

Returns the value of attribute page.



555
556
557
# File 'lib/epdfpw.rb', line 555

def page
  @page
end

#streamObject (readonly)

Returns the value of attribute stream.



556
557
558
# File 'lib/epdfpw.rb', line 556

def stream
  @stream
end

Instance Method Details

#arc(x, y, r, start_angle, end_angle, move_to0 = false) ⇒ Object



985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
# File 'lib/epdfpw.rb', line 985

def arc(x, y, r, start_angle, end_angle, move_to0=false)
  return if start_angle == end_angle

  move_to0 = true unless @in_path
  num_arcs = 1
  ccwcw = 1.0
  arc_span = end_angle - start_angle
  if end_angle < start_angle
    ccwcw = -1.0
  end
  while arc_span.abs.quo(num_arcs) > 90.0
    num_arcs += 1
  end
  angle_bump = arc_span.quo(num_arcs)
  half_bump = 0.5 * angle_bump
  cur_angle = start_angle + half_bump
  num_arcs.times do
    arc_small(x, y, r, cur_angle, half_bump, ccwcw, move_to0)
    move_to0 = false
    cur_angle = cur_angle + angle_bump
  end
end

#arch(x, y, r1, r2, start_angle, end_angle, options = {}, &block) ⇒ Object



1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
# File 'lib/epdfpw.rb', line 1038

def arch(x, y, r1, r2, start_angle, end_angle, options={}, &block)
  return if start_angle == end_angle
  start_angle, end_angle = end_angle, start_angle if options[:reverse]
  border = options[:border].nil? ? true : options[:border]
  fill = options[:fill].nil? ? false : options[:fill]
  clip = options[:clip].nil? ? false : options[:clip] && block_given?
  unless @last_loc == @loc
    gw.stroke if @in_path and @auto_path
    @in_path = false
  end

  line_colors.push(border)
  fill_colors.push(fill)
  check_set(:line_color, :line_width, :line_dash_pattern, :fill_color)
  arc1 = points_for_arc(x, y, r1, start_angle, end_angle)
  arc2 = points_for_arc(x, y, r2, end_angle, start_angle)
  move_to(arc1.first.x, arc1.first.y)
  gw.move_to(to_points(@units, @loc.x), to_points(@units, @loc.y))
  curve_points(arc1)
  line_to(arc2.first.x, arc2.first.y)
  curve_points(arc2)
  line_to(arc1.first.x, arc1.first.y)
  
  gw.save_graphics_state if clip
  auto_stroke_and_fill(:stroke => border, :fill => fill, :clip => clip)
  yield if block_given?
  gw.restore_graphics_state if clip
  line_colors.pop
  fill_colors.pop
  nil
end

#bullet(name, options = {}, &block) ⇒ Object



1691
1692
1693
1694
1695
1696
1697
1698
1699
# File 'lib/epdfpw.rb', line 1691

def bullet(name, options={}, &block)
  return nil if name.nil?
  return @doc.bullets[name.to_sym] unless block_given?
  if width = options[:width]
    units = options[:units] || self.units
    width = to_points(units, width)
  end          
  @doc.bullets[name.to_sym] = Bullet.new(name.to_s, width || 36, block)
end

#canvas_heightObject



690
691
692
# File 'lib/epdfpw.rb', line 690

def canvas_height
  from_points(@units, @canvas_height)
end

#canvas_widthObject



686
687
688
# File 'lib/epdfpw.rb', line 686

def canvas_width
  from_points(@units, @canvas_width)
end

#circle(x, y, r, options = {}, &block) ⇒ Object



909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
# File 'lib/epdfpw.rb', line 909

def circle(x, y, r, options={}, &block)
  border = options[:border].nil? ? true : options[:border]
  fill = options[:fill].nil? ? false : options[:fill]
  clip = options[:clip].nil? ? false : options[:clip] && block_given?

  line_colors.push(border)
  fill_colors.push(fill)
  check_set(:line_color, :line_width, :line_dash_pattern, :fill_color)

  points = points_for_circle(x, y, r)
  points.reverse! if options[:reverse]
  curve_points(points)

  gw.save_graphics_state if clip
  auto_stroke_and_fill(:stroke => border, :fill => fill, :clip => clip)
  yield if block_given?
  gw.restore_graphics_state if clip
  line_colors.pop
  fill_colors.pop
  nil
end

#clip(options = {}, &block) ⇒ Object



1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
# File 'lib/epdfpw.rb', line 1207

def clip(options={}, &block)
  gw.save_graphics_state
  if @in_path
    gw.clip
    if options[:fill] and options[:stroke]
      gw.fill_and_stroke
    elsif options[:stroke]
      gw.stroke
    elsif options[:fill]
      gw.fill
    else
      gw.new_path
    end
  end
  save_text_rendering_mode = @text_rendering_mode
  text_clipping_mode(options)
  yield if block_given?
  # gw.clip
  gw.restore_graphics_state
  @text_rendering_mode = save_text_rendering_mode
  @in_path = false
  @auto_path = true
end

#closeObject



600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
# File 'lib/epdfpw.rb', line 600

def close
  end_margins unless @matrix.nil?
  end_sub_page unless @sub_page.nil?
  end_text if @in_text
  end_graph if @in_graph
  end_misc if @in_misc
  pdf_stream = if @options[:compress]
    require 'zlib'
    zipper = Zlib::Deflate.new
    zstream = zipper.deflate(@stream, Zlib::FINISH)
    zpdf_stream = PdfObjects::PdfStream.new(@doc.next_seq, 0, zstream)
    zpdf_stream.filter = 'FlateDecode'
    zpdf_stream
  else
    PdfObjects::PdfStream.new(@doc.next_seq, 0, @stream)
  end
  @doc.file.body << pdf_stream
  @page.annots = @annotations if @annotations.size.nonzero?
  @page.contents << pdf_stream
  @doc.catalog.pages.kids << @page unless @reused_page
  @stream = nil
end

#closed?Boolean

Returns:

  • (Boolean)


623
624
625
# File 'lib/epdfpw.rb', line 623

def closed?
  @stream.nil?
end

#curve(x0, y0, x1, y1, x2, y2, x3, y3) ⇒ Object



847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
# File 'lib/epdfpw.rb', line 847

def curve(x0, y0, x1, y1, x2, y2, x3, y3)
  move_to(x0, y0)
  unless @last_loc == @loc
    if @in_path and @auto_path
      gw.stroke
      @in_path = false
    end
  end
  check_set(:line_color, :line_width, :line_dash_pattern)

  gw.move_to(to_points(@units, @loc.x), to_points(@units, @loc.y)) unless @in_path
  gw.curve_to(
      to_points(@units, x1),
      @page_height - to_points(@units, y1),
      to_points(@units, x2),
      @page_height - to_points(@units, y2),
      to_points(@units, x3),
      @page_height - to_points(@units, y3))
  move_to(x3, y3)
  @last_loc = @loc.clone
  @in_path = true
end

#curve_points(points) ⇒ Object

Raises:

  • (Exception)


870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
# File 'lib/epdfpw.rb', line 870

def curve_points(points)
  raise Exception.new("Need at least 4 points for curve") if points.size < 4
  move_to(points[0].x, points[0].y)
  unless @last_loc == @loc
    if @in_path and @auto_path
      gw.stroke
      @in_path = false
    end
  end

  check_set(:line_color, :line_width, :line_dash_pattern)

  gw.move_to(to_points(@units, @loc.x), to_points(@units, @loc.y)) unless (@loc == @last_loc) and @in_path
  i = 1
  while i + 2 < points.size
    gw.curve_to(
      to_points(@units, points[i].x),
      @page_height - to_points(@units, points[i].y),
      to_points(@units, points[i+1].x),
      @page_height - to_points(@units, points[i+1].y),
      to_points(@units, points[i+2].x),
      @page_height - to_points(@units, points[i+2].y)
    )
    move_to(points[i+2].x, points[i+2].y)
    @last_loc = @loc.clone
    i += 3
  end
  @in_path = true
end

#ellipse(x, y, rx, ry, options = {}, &block) ⇒ Object



937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
# File 'lib/epdfpw.rb', line 937

def ellipse(x, y, rx, ry, options={}, &block)
  rotation = options[:rotation] || 0
  border = options[:border].nil? ? true : options[:border]
  fill = options[:fill].nil? ? false : options[:fill]
  clip = options[:clip].nil? ? false : options[:clip] && block_given?

  line_colors.push(border)
  fill_colors.push(fill)
  check_set(:line_color, :line_width, :line_dash_pattern, :fill_color)

  points = points_for_ellipse(x, y, rx, ry)
  points = rotate_points(make_loc(x, y), points, -rotation)
  points.reverse! if options[:reverse]
  curve_points(points)

  gw.save_graphics_state if clip
  auto_stroke_and_fill(:stroke => border, :fill => fill, :clip => clip)
  yield if block_given?
  gw.restore_graphics_state if clip
  line_colors.pop
  fill_colors.pop
  nil
end

#fillObject

Raises:

  • (Exception)


1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
# File 'lib/epdfpw.rb', line 1171

def fill
  raise Exception.new("Not in graph") unless @in_graph
  raise Exception.new("Not in path") unless @in_path

  check_set(:fill_color)
  gw.fill
  line_colors.pop
  fill_colors.pop
  @in_path = false
  @auto_path = true
end

#fill_and_strokeObject

Raises:

  • (Exception)


1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
# File 'lib/epdfpw.rb', line 1195

def fill_and_stroke
  raise Exception.new("Not in graph") unless @in_graph
  raise Exception.new("Not in path") unless @in_path

  check_set(:fill_color,:line_color)
  gw.fill_and_stroke
  line_colors.pop
  fill_colors.pop
  @in_path = false
  @auto_path = true
end

#fill_color(color = nil) ⇒ Object



1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
# File 'lib/epdfpw.rb', line 1279

def fill_color(color=nil)
  return @fill_color if color.nil?
  if color.is_a?(Array)
    r, g, b = color
    prev_fill_color, @fill_color = @fill_color, color_from_rgb(r, g, b)
  else
    prev_fill_color, @fill_color = @fill_color, color
  end
  prev_fill_color
end

#font(name = nil, size = nil, options = {}) ⇒ Object



1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
# File 'lib/epdfpw.rb', line 1594

def font(name=nil, size=nil, options={})
  return @font || set_default_font if name.nil?
  prev_font = @font
  if name.is_a?(Font)
    @font = name
    name, size = @font.name, @font.size
    options.update(:style => @font.style, :color => @font.color, :encoding => @font.encoding, :sub_type => @font.sub_type)
  end
  size ||= @font.nil? ? @default_font[:size] : @font.size
  @font, @page_font = select_font(name, size, options)
  prev_font
end

#font_color(color = nil) ⇒ Object



1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
# File 'lib/epdfpw.rb', line 1623

def font_color(color=nil)
  return @font_color if color.nil?
  if color.is_a?(Array)
    r, g, b = color
    prev_font_color, @font_color = @font_color, color_from_rgb(r, g, b)
  else
    prev_font_color, @font_color = @font_color, color
  end
  @font.color = @font_color unless @font.nil?
  prev_font_color
end

#font_encoding(encoding = nil) ⇒ Object



1635
1636
1637
1638
1639
1640
1641
# File 'lib/epdfpw.rb', line 1635

def font_encoding(encoding=nil)
  set_default_font if @font.nil?
  return @font.encoding if encoding.nil?
  prev_encoding = @font.encoding
  font(@font.name, @font.size, :style => @font.style, :color => @font.color, :encoding => encoding, :sub_type => @font.sub_type)
  prev_encoding
end

#font_size(size = nil) ⇒ Object



1615
1616
1617
1618
1619
1620
1621
# File 'lib/epdfpw.rb', line 1615

def font_size(size=nil)
  set_default_font if @font.nil?
  return @font.size if size.nil?
  prev_size = @font.size
  font(@font.name, size, :style => @font.style, :color => @font.color, :encoding => @font.encoding, :sub_type => @font.sub_type)
  prev_size
end

#font_style(style = nil) ⇒ Object



1607
1608
1609
1610
1611
1612
1613
# File 'lib/epdfpw.rb', line 1607

def font_style(style=nil)
  set_default_font if @font.nil?
  return @font.style if style.nil?
  prev_style = @font.style
  font(@font.name, @font.size, :style => style, :color => @font.color, :encoding => @font.encoding, :sub_type => @font.sub_type)
  prev_style
end

#height(text = '', units = nil) ⇒ Object



1420
1421
1422
1423
1424
1425
1426
1427
1428
# File 'lib/epdfpw.rb', line 1420

def height(text='', units=nil)
  units ||= @units
  set_default_font if @font.nil?
  if text.respond_to?(:to_str)
    text_height(units) * @line_height
  else
    text.inject(0) { |total, line| total + height(line, units) }
  end
end

#indent(value = nil, absolute = false) ⇒ Object



731
732
733
734
735
736
# File 'lib/epdfpw.rb', line 731

def indent(value=nil, absolute=false)
  return @indent if value.nil?
  prev_indent, @indent = @indent, absolute ? value : @indent + value
  @loc.x = @indent
  prev_indent
end

#line(x, y, angle, length) ⇒ Object



809
810
811
812
813
# File 'lib/epdfpw.rb', line 809

def line(x, y, angle, length)
  lx, ly = rotate_xy_coordinate(1, 0, angle)
  move_to(x, y)
  line_to(x + lx * length, y - ly * length)
end

#line_cap_style(style = nil) ⇒ Object



1231
1232
1233
1234
1235
# File 'lib/epdfpw.rb', line 1231

def line_cap_style(style=nil)
  return @line_cap_style || :butt_cap if style.nil?
  prev_line_cap_style, @line_cap_style = @line_cap_style, style.to_sym if LINE_CAP_STYLES.include?(style.to_sym)
  prev_line_cap_style
end

#line_color(color = nil) ⇒ Object



1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
# File 'lib/epdfpw.rb', line 1268

def line_color(color=nil)
  return @line_color if color.nil?
  if color.is_a?(Array)
    r, g, b = color
    prev_line_color, @line_color = @line_color, color_from_rgb(r, g, b)
  else
    prev_line_color, @line_color = @line_color, color
  end
  prev_line_color
end

#line_dash_pattern(pattern = nil) ⇒ Object



1237
1238
1239
1240
1241
# File 'lib/epdfpw.rb', line 1237

def line_dash_pattern(pattern=nil)
  return @line_dash_pattern if pattern.nil?
  prev_line_dash_pattern, @line_dash_pattern = @line_dash_pattern, pattern
  prev_line_dash_pattern
end

#line_height(height = nil) ⇒ Object



1258
1259
1260
1261
1262
# File 'lib/epdfpw.rb', line 1258

def line_height(height=nil)
  return @line_height if height.nil?
  prev_line_height, @line_height = @line_height, height
  prev_line_height
end

#line_to(x, y) ⇒ Object



793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
# File 'lib/epdfpw.rb', line 793

def line_to(x, y)
  unless @last_loc == @loc
    gw.stroke if @in_path and @auto_path
    @in_path = false
  end

  check_set(:line_color, :line_width, :line_dash_pattern)

  gw.move_to(to_points(@units, @loc.x), to_points(@units, @loc.y)) unless @in_path
  move_to(x, y)
  gw.line_to(to_points(@units, @loc.x), to_points(@units, @loc.y))
  @in_path = true
  @last_loc = @loc.clone
  nil
end

#line_width(value = nil, units = nil) ⇒ Object



1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
# File 'lib/epdfpw.rb', line 1243

def line_width(value=nil, units=nil)
  return from_points(@units, @line_width || 0) if value.nil?
  return from_points(value, @line_width || 0) if value.is_a?(Symbol)
  prev_line_width = @line_width || 0
  if !units.nil?
    u, value = units.to_sym, value.to_f
  elsif value.respond_to?(:to_str) and value =~ /\D+/
    u, value = $&.to_sym, value.to_f
  else
    u = @units
  end
  @line_width = to_points(u, value)
  from_points(@units, prev_line_width)
end

#load_image(image_file_name, stream = nil) ⇒ Object



1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
# File 'lib/epdfpw.rb', line 1643

def load_image(image_file_name, stream=nil)
  image, name = @doc.images[image_file_name]
  return [image, name] unless image.nil?
  stream ||= open(image_file_name, ImageReadMode) { |io| io.read }
  image = PdfObjects::PdfImage.new(@doc.next_seq, 0, stream)
  image.width, image.height, components, image.bits_per_component = jpeg_dimensions(stream)
  image.color_space = { 1 => 'DeviceGray', 3 => 'DeviceRGB', 4 => 'DeviceCMYK' }[components]
  image.filter = 'DCTDecode'
  name = "Im#{@doc.images.size}"
  @doc.file.body << image
  @doc.resources.x_objects[name] = image.reference_object
  @doc.images[image_file_name] = [image, name]
  [image, name]
end

#margin_bottomObject



678
679
680
# File 'lib/epdfpw.rb', line 678

def margin_bottom
  from_points(@units, @margin_bottom)
end

#margin_leftObject



682
683
684
# File 'lib/epdfpw.rb', line 682

def margin_left
  from_points(@units, @margin_left)
end

#margin_rightObject



674
675
676
# File 'lib/epdfpw.rb', line 674

def margin_right
  from_points(@units, @margin_right)
end

#margin_topObject



670
671
672
# File 'lib/epdfpw.rb', line 670

def margin_top
  from_points(@units, @margin_top)
end

#margins(*margins) ⇒ Object



635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
# File 'lib/epdfpw.rb', line 635

def margins(*margins)
  @margins ||= [0] * 4
  return @margins.map { |m| from_points(@units, m) } unless [4,2,1].include?(margins.size)
  margins = margins.first if margins.first.is_a?(Array)
  @margins = case margins.size
    when 4 then margins
    when 2 then margins * 2
    when 1 then margins * 4
    else @margins
    end.map { |m| to_points(@units, m) }
  @margin_top, @margin_right, @margin_bottom, @margin_left = @margins
  if (@matrix || IDENTITY_MATRIX)[4..5] != [@margin_left, -@margin_top]
    if @matrix.nil?
      @matrix = IDENTITY_MATRIX.dup
    else
      gw.restore_graphics_state
    end
    @matrix[4..5] = [@margin_left, -@margin_top]
    gw.save_graphics_state
    gw.concat_matrix(*@matrix)
  end
  @canvas_width = @page_width - @margin_left - @margin_right
  @canvas_height = @page_height - @margin_top - @margin_bottom
  move_to(0, 0)
  nil
end

#move_by(dx, dy) ⇒ Object



788
789
790
791
# File 'lib/epdfpw.rb', line 788

def move_by(dx, dy)
  p = pen_pos
  move_to(p.x + dx, p.y + dy)
end

#move_to(x, y) ⇒ Object



776
777
778
779
# File 'lib/epdfpw.rb', line 776

def move_to(x, y)
  @loc = translate(x, y)
  nil
end

#named_colorsObject



1264
1265
1266
# File 'lib/epdfpw.rb', line 1264

def named_colors
  @doc.named_colors
end

#new_line(count = 1) ⇒ Object



1365
1366
1367
1368
# File 'lib/epdfpw.rb', line 1365

def new_line(count=1)
  @loc = Location.new(@indent, @loc.y - height * count)
  nil
end

#page_heightObject



666
667
668
# File 'lib/epdfpw.rb', line 666

def page_height
  from_points(@units, @page_height)
end

#page_widthObject



662
663
664
# File 'lib/epdfpw.rb', line 662

def page_width
  from_points(@units, @page_width)
end

#paragraph(text, options = {}) ⇒ Object



1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
# File 'lib/epdfpw.rb', line 1430

def paragraph(text, options={})
  width = options[:width] || canvas_width - pen_pos.x
  height = options[:height] || canvas_height - pen_pos.y
  if bul = bullet(options[:bullet])
    save_loc = pen_pos
    bul.proc.call(self)
    move_to(save_loc.x + from_points(units, bul.width), save_loc.y)
    width -= from_points(units, bul.width)
  end
  prev_underline, ul = @underline, options[:underline].nil? ? @underline : options[:underline]
  unless text.is_a?(PdfText::RichText)
    text = PdfText::RichText.new(text, font, :color => @font_color, 
      :char_spacing => @char_spacing, :word_spacing => @word_spacing, 
      :underline => ul)
  end
  dy = 0
  while dy + from_points(@units, text.height) < height and line = text.next(to_points(@units, width))
    save_loc = pen_pos
    line_dy = line.height.quo(UNIT_CONVERSION[units]) * @line_height
    case options[:align]
    when :center then move_to(save_loc.x + (width - from_points(@units, line.width)) / 2.0, save_loc.y)
    when :right then move_to(save_loc.x + width - from_points(@units, line.width), save_loc.y)
    when :justify then
      width_pt = to_points(@units, width)
      delta_pt = width_pt - line.width
      words = (line.tokens / 2) + 1
      if delta_pt.abs.quo(width_pt) < 0.4
        if words == 1
          @word_spacing = 0
          @char_spacing = delta_pt.quo(line.chars - 1)
        elsif delta_pt.abs / words > 3
          @word_spacing = 3
          delta_pt -= (words - 1) * @word_spacing
          @char_spacing = delta_pt.quo(line.chars - 1)
        else
          @word_spacing = delta_pt.quo(words - 1)
          @char_spacing = 0
        end
      end
    end
    while piece = line.shift
      font(piece.font)
      font_color piece.color
      underline piece.underline
      print(piece.text)
    end
    @word_spacing = @char_spacing = 0.0 if options[:align] == :justify
    dy += line_dy
    move_to(save_loc.x, save_loc.y + line_dy)
  end
  underline(prev_underline)
  move_by(-from_points(units, bul.width), 0) unless bul.nil?
  return text.empty? ? nil : text
end

#paragraph_xy(x, y, text, options = {}) ⇒ Object



1485
1486
1487
1488
# File 'lib/epdfpw.rb', line 1485

def paragraph_xy(x, y, text, options={})
  move_to(x, y)
  paragraph(text, options)
end

#path(options = {}, &block) ⇒ Object



1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
# File 'lib/epdfpw.rb', line 1146

def path(options={}, &block)
  check_set(:line_color, :line_width, :line_dash_pattern, :fill_color)
  stroke = options[:stroke].nil? ? false : options[:stroke]
  fill = options[:fill].nil? ? false : options[:fill]
  line_colors.push(stroke)
  fill_colors.push(fill)
  @auto_path = false
  if block_given?
    yield
    if options[:fill] and options[:stroke]
      gw.fill_and_stroke
    elsif options[:stroke]
      gw.stroke
    elsif options[:fill]
      gw.fill
    else
      gw.new_path
    end
    line_colors.pop
    fill_colors.pop
    @in_path = false
    @auto_path = true
  end
end

#pen_pos(x = nil, y = nil) ⇒ Object



781
782
783
784
785
786
# File 'lib/epdfpw.rb', line 781

def pen_pos(x=nil, y=nil)
  return translate(@loc.x, @loc.y) if x.nil?
  prev_loc = translate(@loc.x, @loc.y)
  move_to(x, y)
  prev_loc
end

#pie(x, y, r, start_angle, end_angle, options = {}) ⇒ Object



1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
# File 'lib/epdfpw.rb', line 1008

def pie(x, y, r, start_angle, end_angle, options={})
  border = options[:border].nil? ? true : options[:border]
  fill = options[:fill].nil? ? false : options[:fill]
  clip = options[:clip].nil? ? false : options[:clip] && block_given?
  unless @last_loc == @loc
    gw.stroke if @in_path and @auto_path
    @in_path = false
  end

  line_colors.push(border)
  fill_colors.push(fill)
  check_set(:line_color, :line_width, :line_dash_pattern, :fill_color)

  move_to(x, y)
  gw.move_to(to_points(@units, @loc.x), to_points(@units, @loc.y))
  @last_loc = @loc.clone
  @in_path = true
  start_angle, end_angle = end_angle, start_angle if options[:reverse]
  arc(x, y, r, start_angle, end_angle)
  line_to(x, y)

  gw.save_graphics_state if clip
  auto_stroke_and_fill(:stroke => border, :fill => fill, :clip => clip)
  yield if block_given?
  gw.restore_graphics_state if clip
  line_colors.pop
  fill_colors.pop
  nil
end

#points_for_arc(x, y, r, start_angle, end_angle) ⇒ Object



961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
# File 'lib/epdfpw.rb', line 961

def points_for_arc(x, y, r, start_angle, end_angle)
  return nil if start_angle == end_angle

  num_arcs = 1
  ccwcw = 1.0
  arc_span = end_angle - start_angle
  if end_angle < start_angle
    ccwcw = -1.0
  end
  while arc_span.abs.quo(num_arcs) > 90.0
    num_arcs += 1
  end
  angle_bump = arc_span.quo(num_arcs)
  half_bump = 0.5 * angle_bump
  cur_angle = start_angle + half_bump
  points = []
  num_arcs.times do |i|
    points << points_for_arc_small(x, y, r, cur_angle, half_bump, ccwcw)
    points.last.shift if i > 0
    cur_angle = cur_angle + angle_bump
  end
  points.flatten
end

#points_for_circle(x, y, r) ⇒ Object

def curve_to(points) end



903
904
905
906
907
# File 'lib/epdfpw.rb', line 903

def points_for_circle(x, y, r)
  points = (1..4).inject([]) { |points, q| points + get_quadrant_bezier_points(q, x, y, r) }
  [12,8,4].each { |i| points.delete_at(i) }
  points
end

#points_for_ellipse(x, y, rx, ry) ⇒ Object



931
932
933
934
935
# File 'lib/epdfpw.rb', line 931

def points_for_ellipse(x, y, rx, ry)
  points = (1..4).inject([]) { |points, q| points + get_quadrant_bezier_points(q, x, y, rx, ry) }
  [12,8,4].each { |i| points.delete_at(i) }
  points
end

#points_for_polygon(x, y, r, sides, options = {}) ⇒ Object



1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
# File 'lib/epdfpw.rb', line 1070

def points_for_polygon(x, y, r, sides, options={})
  step = 360.0 / sides
  angle = step / 2 + 90
  points = (0..sides).collect do
    px, py = rotate_xy_coordinate(1, 0, angle)
    angle += step
    make_loc(x + px * r, y + py * r)
  end
  rotation = options[:rotation] || 0
  points = rotate_points(make_loc(x, y), points, -rotation) unless rotation.zero?
  points.reverse! if options[:reverse]
  points
end

#polygon(x, y, r, sides, options = {}, &block) ⇒ Object



1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
# File 'lib/epdfpw.rb', line 1084

def polygon(x, y, r, sides, options={}, &block)
  border = options[:border].nil? ? true : options[:border]
  fill = options[:fill].nil? ? false : options[:fill]
  clip = options[:clip].nil? ? false : options[:clip] && block_given?
  unless @last_loc == @loc
    gw.stroke if @in_path and @auto_path
    @in_path = false
  end

  points = points_for_polygon(x, y, r, sides, options)
  line_colors.push(border)
  fill_colors.push(fill)
  check_set(:line_color, :line_width, :line_dash_pattern, :fill_color)

  points.each_with_index do |point, i|
    if i == 0
      move_to(point.x, point.y)
    else
      line_to(point.x, point.y)
    end
  end
  gw.save_graphics_state if clip
  auto_stroke_and_fill(:stroke => border, :fill => fill, :clip => clip)
  yield if block_given?
  gw.restore_graphics_state if clip
  line_colors.pop
  fill_colors.pop
  nil
end


1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
# File 'lib/epdfpw.rb', line 1290

def print(text, options={}, &block)
  text = text.to_s
  return if text.empty?
  text = @ic.iconv(text) unless @ic.nil?
  align = options[:align]
  angle = options[:angle] || 0.0
  @scale = options[:scale] || 1.0
  prev_underline = underline(options[:underline]) unless options[:underline].nil?
  prev_v_text_align = v_text_align(options[:v_text_align]) unless options[:v_text_align].nil?
  clip = options[:clip] && block_given?
  if clip
    gw.save_graphics_state
    text_clipping_mode(options)
  end
  start_text unless @in_text
  check_set(:font, :font_color, :line_color, :v_text_align, :spacing, :scale, :text_rendering_mode)
  ds = width(text, true)
  if align
    prev_loc = @loc.clone
    @loc = case align
    when :left then @loc
    when :center then add_vector(@loc, angle + 180, ds.quo(2))
    when :right then add_vector(@loc, angle + 180, ds)
    end
  end
  if (@text_angle != angle) or (angle != 0.0)
    set_text_angle(angle, @loc.x, @loc.y)
  elsif @loc != @last_loc
    tw.move_by(to_points(@units, @loc.x - @last_loc.x), to_points(@units, @loc.y - @last_loc.y))
  end
  tw.show(text)
  # if @ic.nil?
  #   tw.show(text)
  # else
  #   text = @ic.iconv(text)
  #   tw.show_wide(text)
  # end
  @last_loc = @loc.clone
  new_loc = (angle == 0.0) ? Location.new(@loc.x + ds, @loc.y) : add_vector(@loc, angle, ds)
  draw_underline(translate_p(@last_loc), translate_p(new_loc), @font.underline_position, @font.underline_thickness, angle) if @underline
  underline(prev_underline) unless options[:underline].nil?
  v_text_align(prev_v_text_align) unless options[:v_text_align].nil?
  @loc = align ? prev_loc : new_loc
  if clip
    yield
    gw.restore_graphics_state
  end
  nil
end


1681
1682
1683
1684
1685
# File 'lib/epdfpw.rb', line 1681

def print_image(data, x=nil, y=nil, width=nil, height=nil)
  image_file_name = data.hash.to_s
  image, name = load_image(image_file_name, data)
  print_image_file(image_file_name, x, y, width, height)
end


1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
# File 'lib/epdfpw.rb', line 1658

def print_image_file(image_file_name, x=nil, y=nil, width=nil, height=nil)
  image, name = load_image(image_file_name)
  x ||= pen_pos.x
  y ||= pen_pos.y
  if width.nil? and height.nil?
    width, height = image.width, image.height
  elsif width.nil?
    height = to_points(@units, height)
    width = height * image.width.quo(image.height)
  elsif height.nil?
    width = to_points(@units, width)
    height = width * image.height.quo(image.width)
  else
    width, height = to_points(@units, width), to_points(@units, height)
  end
  end_path if @in_path
  gw.save_graphics_state
  gw.concat_matrix(width, 0, 0, height, to_points(@units, x), to_points(@units, page_height - y) - height)
  mw.x_object(name)
  gw.restore_graphics_state
  [from_points(@units, width), from_points(@units, height)]
end


1687
1688
1689
# File 'lib/epdfpw.rb', line 1687

def print_link(s, uri)
  # TODO
end


1340
1341
1342
1343
# File 'lib/epdfpw.rb', line 1340

def print_xy(x, y, text, options={}, &block)
  move_to(x, y)
  print(text, options, &block)
end

#puts(text = '', options = {}, &block) ⇒ Object



1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
# File 'lib/epdfpw.rb', line 1345

def puts(text='', options={}, &block)
  # if it's not a real string, assume it's an enumeration of strings
  unless text.respond_to?(:to_str)
    text.each { |t| puts(t, options) }
  else
    prev_loc = @loc.clone
    print(text, options, &block)
    @loc = options[:indent] ? Location.new(prev_loc.x, prev_loc.y - height) : Location.new(@indent, prev_loc.y - height)
  end
  nil
end

#puts_xy(x, y, text, options = {}, &block) ⇒ Object



1357
1358
1359
1360
1361
1362
1363
# File 'lib/epdfpw.rb', line 1357

def puts_xy(x, y, text, options={}, &block)
  move_to(x, y)
  prev_indent = indent(x, true)
  puts(text, options, &block)
  indent(prev_indent, true)
  nil
end

#rectangle(x, y, width, height, options = {}, &block) ⇒ Object



815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
# File 'lib/epdfpw.rb', line 815

def rectangle(x, y, width, height, options={}, &block)
  border = options[:border].nil? ? true : options[:border]
  fill = options[:fill].nil? ? false : options[:fill]
  clip = options[:clip].nil? ? false : options[:clip] && block_given?
  gw.stroke if @in_path and @auto_path

  line_colors.push(border)
  fill_colors.push(fill)
  check_set(:line_color, :line_width, :line_dash_pattern, :fill_color)

  if options[:corners]
    draw_rounded_rectangle(x, y, width, height, options)
  elsif options[:path] or options[:reverse]
    draw_rectangle_path(x, y, width, height, options)
  else
    gw.rectangle(
      to_points(@units, x),
      @page_height - to_points(@units, y + height),
      to_points(@units, width),
      to_points(@units, height))
  end

  gw.save_graphics_state if clip
  auto_stroke_and_fill(:stroke => border, :fill => fill, :clip => clip)
  yield if block_given?
  gw.restore_graphics_state if clip
  line_colors.pop
  fill_colors.pop
  move_to(x + width, y)
  nil
end

#rotate(angle, x, y, &block) ⇒ Object



1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
# File 'lib/epdfpw.rb', line 1701

def rotate(angle, x, y, &block)
  return unless block_given?
  end_path if @in_path
  check_set(:line_color, :line_width, :line_dash_pattern, :fill_color)

  theta = angle.degrees
  v_cos = Math::cos(theta)
  v_sin = Math::sin(theta)

  xx, xy = to_points(@units, x), @page_height - to_points(@units, y)
  rot_x, rot_y = rotate_xy_coordinate(xx, xy, angle)
  gw.save_graphics_state
  gw.concat_matrix(v_cos, v_sin, -v_sin, v_cos, xx - rot_x, xy - rot_y)
  @last_page_font = nil
  yield
  gw.restore_graphics_state
  @last_page_font = nil
end

#scale(x, y, scale_x, scale_y, &block) ⇒ Object



1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
# File 'lib/epdfpw.rb', line 1720

def scale(x, y, scale_x, scale_y, &block)
  return unless x && scale_x && y && scale_y && block_given?
  end_path if @in_path
  check_set(:line_color, :line_width, :line_dash_pattern, :fill_color)
  sub_area = IDENTITY_MATRIX.dup
  # a: Sx (horizontal scaling, 1 unit in new is x units in old)
  # b: 
  # c: 
  # d: Sy (vertical scaling, 1 unit in new is y units in old)
  # e: Tx (horizontal translation of the origin)
  # f: Ty (vertical translation of the origin)
  sub_area[0] = scale_x
  sub_area[3] = scale_y
  sub_area[4] = to_points(@units, x)
  sub_area[5] = to_points(@units, -y)
  save_page_height = @page_height
  @page_height = save_page_height.quo(scale_y)
  gw.save_graphics_state
  gw.concat_matrix(*sub_area)
  @last_page_font = nil
  yield
  end_text if @in_text
  end_graph if @in_graph
  gw.restore_graphics_state
  @last_page_font = nil
  @page_height = save_page_height
end

#select_font(name, size, options = {}) ⇒ Object



1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
# File 'lib/epdfpw.rb', line 1510

def select_font(name, size, options={})
  unless @ic.nil?
    @ic.close
    @ic = nil
  end
  weight = options[:weight] || ''
  style = weight + (options[:style] || '')
  font = Font.new(name, size, style, options[:color], pdf_encoding(options[:encoding] || 'WinAnsiEncoding', name))
  font.sub_type = options[:sub_type] || 'Type1'
  punc = (font.sub_type == 'TrueType') ? ',' : '-'
  full_name = name.gsub(' ','')
  full_name << punc << font.style unless font.style.empty?
  if @options[:built_in_fonts]
    if font.sub_type == 'Type1'
      metrics = PdfK::font_metrics(full_name)
    elsif font.sub_type == 'TrueType'
      metrics = PdfTT::font_metrics(full_name)
    end
  else
    if font.sub_type == 'Type1'
      weight = 'Bold' if weight.empty? and /Bold/i =~ style
      afm = AFM::find_font(name, weight, style)
      full_name = afm.font_name unless afm.nil?
      metrics = AFM::font_metrics(full_name, :encoding => font.encoding)
    elsif font.sub_type == 'TrueType'
      raise Exception.new("Non-built-in TrueType fonts not supported yet.")
    elsif font.sub_type == 'Type0'
      # metrics = AFM::font_metrics(full_name, :encoding => :unicode)
      # require 'iconv'
      # @ic = Iconv.new('UCS-2BE', iconv_encoding(font.encoding))
    else
      raise Exception.new("Unsupported subtype #{font.sub_type}.")
    end
  end
  unless text_encoding.nil? or (font.encoding == 'StandardEncoding') or (font.encoding == text_encoding)
    if ''.respond_to?(:encoding) # Ruby 1.9+
      @ic = FakeIconv.new(iconv_encoding(font.encoding), iconv_encoding(text_encoding))
    else
      @ic = Iconv.new(iconv_encoding(font.encoding)+'//IGNORE', iconv_encoding(text_encoding))
    end
  end
  font.widths, font.ascent, font.descent = metrics.widths, metrics.ascent, metrics.descent
  font.height = font.ascent + font.descent.abs
  font.underline_position = metrics.underline_position * -0.001 * font.size
  font.underline_thickness = metrics.underline_thickness * 0.001 * font.size
  font_key = "#{full_name}/#{font.encoding}-#{font.sub_type}"
  page_font = @doc.fonts[font_key]
  unless page_font
    widths = nil
    if metrics.needs_descriptor
      descriptor = PdfObjects::PdfFontDescriptor.new(@doc.next_seq, 0, full_name, metrics.flags, metrics.b_box, 
        metrics.missing_width, metrics.stem_v, metrics.stem_h, metrics.italic_angle,
        metrics.cap_height, metrics.x_height, metrics.ascent, metrics.descent, metrics.leading,
        metrics.max_width, metrics.avg_width)
      @doc.file.body << descriptor
      widths = PdfObjects::IndirectObject.new(@doc.next_seq, 0, PdfObjects::PdfInteger.ary(metrics.widths))
      @doc.file.body << widths
    else
      descriptor = nil
      widths = nil
    end
    page_font = "F#{@doc.fonts.size}"
    f = PdfObjects::PdfFont.new(@doc.next_seq, 0, font.sub_type, full_name, 0, 255, widths, descriptor)
    @doc.file.body << f
    if PdfObjects::PdfFont.standard_encoding?(font.encoding)
      f.encoding = font.encoding
    else
      encoding = @doc.encodings[font.encoding]
      if encoding.nil?
        encoding = PdfObjects::PdfFontEncoding.new(@doc.next_seq, 0, 'WinAnsiEncoding', metrics.differences)
        @doc.encodings[font.encoding] = encoding
        @doc.file.body << encoding
      end
      f.encoding = encoding.reference_object
      # raise Exception.new("Unsupported encoding #{font.encoding}")
    end
    @doc.resources.fonts[page_font] = f.reference_object
    @doc.fonts[font_key] = page_font
  end
  font_color(options[:color]) if options[:color]
  text_rendering_mode(options)
  [font, page_font]
end

#star(x, y, r1, r2, points, options = {}, &block) ⇒ Object



1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
# File 'lib/epdfpw.rb', line 1114

def star(x, y, r1, r2, points, options={}, &block)
  return if points < 5
  border = options[:border].nil? ? true : options[:border]
  fill = options[:fill].nil? ? false : options[:fill]
  clip = options[:clip].nil? ? false : options[:clip] && block_given?
  unless @last_loc == @loc
    gw.stroke if @in_path and @auto_path
    @in_path = false
  end

  rotation = options[:rotation] || 0
  r2 ||= (points - 2).quo(points * 1.5)
  vertices1 = points_for_polygon(x, y, r1, points, options)
  vertices2 = points_for_polygon(x, y, r2, points, options.merge(:rotation => rotation + (360.0 / points / 2)))
  line_colors.push(border)
  fill_colors.push(fill)
  check_set(:line_color, :line_width, :line_dash_pattern, :fill_color)

  move_to(vertices2[0].x, vertices2[0].y)
  points.times do |i|
    line_to(vertices1[i].x, vertices1[i].y)
    line_to(vertices2[i+1].x, vertices2[i+1].y)
  end
  gw.save_graphics_state if clip
  auto_stroke_and_fill(:stroke => border, :fill => fill, :clip => clip)
  yield if block_given?
  gw.restore_graphics_state if clip
  line_colors.pop
  fill_colors.pop
  nil
end

#strokeObject

Raises:

  • (Exception)


1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
# File 'lib/epdfpw.rb', line 1183

def stroke
  raise Exception.new("Not in graph") unless @in_graph
  raise Exception.new("Not in path") unless @in_path

  check_set(:line_color)
  gw.stroke
  line_colors.pop
  fill_colors.pop
  @in_path = false
  @auto_path = true
end

#sub_page(x, pages_across, y, pages_down, unscaled = false) ⇒ Object



738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
# File 'lib/epdfpw.rb', line 738

def sub_page(x, pages_across, y, pages_down, unscaled=false)
  unless @matrix.nil?
    gw.restore_graphics_state
    @matrix = nil
  end
  gw.restore_graphics_state unless @sub_page.nil?
  return unless x && pages_across && y && pages_down
  if unscaled
    @canvas_width = @page_width.quo(pages_across)
    @canvas_height = @page_height.quo(pages_down)
    @sub_page = IDENTITY_MATRIX.dup
    @sub_page[4] = @canvas_width * x
    @sub_page[5] = @canvas_height * (pages_down - 1 - y)
  else
    ps = PageStyle.new(@options.merge(:orientation => sub_orientation(pages_across, pages_down)))
    width = ps.page_size.x2
    height = ps.page_size.y2

    ratio_w = @page_width.quo(pages_across * width)
    ratio_h = @page_height.quo(pages_down * height)
    ratio = [ratio_w, ratio_h].min
    @sub_page = IDENTITY_MATRIX.dup
    @sub_page[0] = ratio
    @sub_page[3] = ratio
    @sub_page[4] = @page_width.quo(pages_across) * x
    @sub_page[5] = @page_height.quo(pages_down) * (pages_down - 1 - y)
    if ratio_w >= ratio_h
      @page_width, @page_height = width, height
    else
      @page_width, @page_height = width, width / ratio_w
    end
  end

  gw.save_graphics_state
  gw.concat_matrix(*@sub_page)
  @last_font = @last_page_font = nil
end

#tab(&block) ⇒ Object



701
702
703
704
705
706
707
708
709
710
711
# File 'lib/epdfpw.rb', line 701

def tab(&block)
  return if @tabs.nil?
  p = pen_pos
  x = @tabs.detect { |stop| stop > p.x }
  if x.nil?
    dy = block_given? ? yield : height
    move_to(@tabs.first, p.y + dy)
  else
    move_to(x, p.y)
  end
end

#tabs(tabs = nil) ⇒ Object



694
695
696
697
698
699
# File 'lib/epdfpw.rb', line 694

def tabs(tabs=nil)
  return @tabs if tabs.nil?
  return @tabs = nil if tabs == false or tabs.empty?
  tabs = tabs.split(',') if tabs.respond_to?(:to_str)
  @tabs = tabs.map { |stop| stop.to_f }.select { |stop| stop > 0 }.sort
end

#text_ascent(units = nil) ⇒ Object



1408
1409
1410
1411
1412
# File 'lib/epdfpw.rb', line 1408

def text_ascent(units=nil)
  units ||= @units
  set_default_font if @font.nil?
  0.001 * @font.ascent * @font.size.quo(UNIT_CONVERSION[units])
end

#text_encoding(value = nil) ⇒ Object



1748
1749
1750
1751
# File 'lib/epdfpw.rb', line 1748

def text_encoding(value=nil)
  return @text_encoding if value.nil?
  @text_encoding = value
end

#text_height(units = nil) ⇒ Object



1414
1415
1416
1417
1418
# File 'lib/epdfpw.rb', line 1414

def text_height(units=nil)
  units ||= @units
  set_default_font if @font.nil?
  0.001 * @font.height * @font.size.quo(UNIT_CONVERSION[units])
end

#truetype_font_namesObject



1506
1507
1508
# File 'lib/epdfpw.rb', line 1506

def truetype_font_names
  @doc.truetype_font_names
end

#type1_font_namesObject



1502
1503
1504
# File 'lib/epdfpw.rb', line 1502

def type1_font_names
  @doc.type1_font_names
end

#underline(underline = nil) ⇒ Object



1496
1497
1498
1499
1500
# File 'lib/epdfpw.rb', line 1496

def underline(underline=nil)
  return @underline if underline.nil?
  prev_underline, @underline = @underline, underline
  prev_underline
end

#units(units = nil) ⇒ Object



627
628
629
630
631
632
633
# File 'lib/epdfpw.rb', line 627

def units(units=nil)
  return @units if units.nil? or units == @units
  @loc = convert_units(@loc, @units, units)
  @last_loc = convert_units(@last_loc, @units, units) unless @last_loc.nil?
  prev_units, @units = @units, units
  prev_units
end

#v_text_align(vta = nil) ⇒ Object



1490
1491
1492
1493
1494
# File 'lib/epdfpw.rb', line 1490

def v_text_align(vta=nil)
  return @v_text_align if vta.nil?
  prev_vta, @v_text_align = @v_text_align, vta
  prev_vta
end

#vtab(&block) ⇒ Object



720
721
722
723
724
725
726
727
728
729
# File 'lib/epdfpw.rb', line 720

def vtab(&block)
  return if @vtabs.nil?
  p = pen_pos
  y = @vtabs.detect { |stop| stop > p.y }
  if y.nil?
    move_to(p.x + yield, @vtabs.first) if block_given?
  else
    move_to(p.x, y)
  end
end

#vtabs(tabs = nil) ⇒ Object



713
714
715
716
717
718
# File 'lib/epdfpw.rb', line 713

def vtabs(tabs=nil)
  return @vtabs if tabs.nil?
  return @vtabs = nil if tabs == false or tabs.empty?
  tabs = tabs.split(',') if tabs.respond_to?(:to_str)
  @vtabs = tabs.map { |stop| stop.to_f }.select { |stop| stop > 0 }.sort
end

#width(text, encoded = false) ⇒ Object



1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
# File 'lib/epdfpw.rb', line 1370

def width(text, encoded=false)
  set_default_font if @font.nil?
  result = 0.0
  fsize = @font.size * 0.001
  text = @ic.iconv(text) unless @ic.nil? or encoded
  text.each_byte do |b|
    result += fsize * @font.widths[b] + @char_spacing
    result += @word_spacing if b == 32 # space
  end
  from_points(@units, result - @char_spacing)
end

#wrap(text, width) ⇒ Object



1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
# File 'lib/epdfpw.rb', line 1382

def wrap(text, width)
  re = /\n|\t|[ ]|[\S]+-+|[\S]+/
  words = text.scan(re)
  word_tuples = words.map { |word| [width(word), word] }
  line_length = 0
  lines = word_tuples.inject(['']) do |lines, tuple|
    if tuple[1] == "\n"
      lines << ''
      line_length = 0
    elsif line_length == 0
      unless tuple[1] == ' '
        lines.last << tuple[1]
        line_length += tuple[0]
      end
    elsif line_length + tuple[0] > width
      lines << ''
      line_length = 0
      redo
    else          
      lines.last << tuple[1]
      line_length += tuple[0]
    end
    lines
  end
end