pdf-writer 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. data/ChangeLog +44 -0
  2. data/LICENCE +118 -0
  3. data/README +32 -0
  4. data/bin/loader +54 -0
  5. data/bin/manual +22 -0
  6. data/bin/manual.bat +2 -0
  7. data/demo/chunkybacon.rb +28 -0
  8. data/demo/code.rb +63 -0
  9. data/demo/colornames.rb +843 -0
  10. data/demo/demo.rb +65 -0
  11. data/demo/gettysburg.rb +58 -0
  12. data/demo/hello.rb +18 -0
  13. data/demo/individual-i.rb +81 -0
  14. data/demo/pac.rb +62 -0
  15. data/demo/pagenumber.rb +67 -0
  16. data/demo/qr-language.rb +573 -0
  17. data/demo/qr-library.rb +371 -0
  18. data/images/chunkybacon.jpg +0 -0
  19. data/images/chunkybacon.png +0 -0
  20. data/images/pdfwriter-icon.jpg +0 -0
  21. data/images/pdfwriter-small.jpg +0 -0
  22. data/lib/pdf/charts.rb +13 -0
  23. data/lib/pdf/charts/stddev.rb +431 -0
  24. data/lib/pdf/grid.rb +135 -0
  25. data/lib/pdf/math.rb +108 -0
  26. data/lib/pdf/quickref.rb +330 -0
  27. data/lib/pdf/simpletable.rb +946 -0
  28. data/lib/pdf/techbook.rb +890 -0
  29. data/lib/pdf/writer.rb +2661 -0
  30. data/lib/pdf/writer/arc4.rb +63 -0
  31. data/lib/pdf/writer/fontmetrics.rb +201 -0
  32. data/lib/pdf/writer/fonts/Courier-Bold.afm +342 -0
  33. data/lib/pdf/writer/fonts/Courier-BoldOblique.afm +342 -0
  34. data/lib/pdf/writer/fonts/Courier-Oblique.afm +342 -0
  35. data/lib/pdf/writer/fonts/Courier.afm +342 -0
  36. data/lib/pdf/writer/fonts/Helvetica-Bold.afm +2827 -0
  37. data/lib/pdf/writer/fonts/Helvetica-BoldOblique.afm +2827 -0
  38. data/lib/pdf/writer/fonts/Helvetica-Oblique.afm +3051 -0
  39. data/lib/pdf/writer/fonts/Helvetica.afm +3051 -0
  40. data/lib/pdf/writer/fonts/MustRead.html +1 -0
  41. data/lib/pdf/writer/fonts/Symbol.afm +213 -0
  42. data/lib/pdf/writer/fonts/Times-Bold.afm +2588 -0
  43. data/lib/pdf/writer/fonts/Times-BoldItalic.afm +2384 -0
  44. data/lib/pdf/writer/fonts/Times-Italic.afm +2667 -0
  45. data/lib/pdf/writer/fonts/Times-Roman.afm +2419 -0
  46. data/lib/pdf/writer/fonts/ZapfDingbats.afm +225 -0
  47. data/lib/pdf/writer/graphics.rb +727 -0
  48. data/lib/pdf/writer/graphics/imageinfo.rb +365 -0
  49. data/lib/pdf/writer/lang.rb +43 -0
  50. data/lib/pdf/writer/lang/en.rb +77 -0
  51. data/lib/pdf/writer/object.rb +23 -0
  52. data/lib/pdf/writer/object/action.rb +40 -0
  53. data/lib/pdf/writer/object/annotation.rb +42 -0
  54. data/lib/pdf/writer/object/catalog.rb +39 -0
  55. data/lib/pdf/writer/object/contents.rb +68 -0
  56. data/lib/pdf/writer/object/destination.rb +40 -0
  57. data/lib/pdf/writer/object/encryption.rb +53 -0
  58. data/lib/pdf/writer/object/font.rb +76 -0
  59. data/lib/pdf/writer/object/fontdescriptor.rb +34 -0
  60. data/lib/pdf/writer/object/fontencoding.rb +39 -0
  61. data/lib/pdf/writer/object/image.rb +168 -0
  62. data/lib/pdf/writer/object/info.rb +55 -0
  63. data/lib/pdf/writer/object/outline.rb +30 -0
  64. data/lib/pdf/writer/object/outlines.rb +30 -0
  65. data/lib/pdf/writer/object/page.rb +195 -0
  66. data/lib/pdf/writer/object/pages.rb +115 -0
  67. data/lib/pdf/writer/object/procset.rb +46 -0
  68. data/lib/pdf/writer/object/viewerpreferences.rb +74 -0
  69. data/lib/pdf/writer/ohash.rb +58 -0
  70. data/lib/pdf/writer/oreader.rb +25 -0
  71. data/lib/pdf/writer/state.rb +48 -0
  72. data/lib/pdf/writer/strokestyle.rb +138 -0
  73. data/manual.pwd +5151 -0
  74. metadata +147 -0
@@ -0,0 +1,115 @@
1
+ #--
2
+ # PDF::Writer for Ruby.
3
+ # http://rubyforge.org/projects/ruby-pdf/
4
+ # Copyright 2003 - 2005 Austin Ziegler.
5
+ #
6
+ # Licensed under a MIT-style licence. See LICENCE in the main distribution
7
+ # for full licensing information.
8
+ #
9
+ # $Id: pages.rb,v 1.2 2005/05/16 03:59:21 austin Exp $
10
+ #++
11
+ # object which is a parent to the pages in the document
12
+ class PDF::Writer::Object::Pages < PDF::Writer::Object
13
+ def initialize(parent)
14
+ super(parent)
15
+
16
+ @parent.catalog.pages = self
17
+
18
+ @pages = []
19
+ @procset = nil
20
+ @media_box = nil
21
+ @fonts = []
22
+ @xObjects = []
23
+ @bleed_box = nil
24
+ @trim_box = nil
25
+ end
26
+
27
+ def size
28
+ @pages.size
29
+ end
30
+
31
+ def first_page
32
+ @pages[0]
33
+ end
34
+
35
+ # Add the page ID to the end of the page list.
36
+ def <<(p)
37
+ if p.kind_of?(PDF::Writer::Object::Page)
38
+ @pages << p
39
+ elsif p.kind_of?(PDF::Writer::Object::Font)
40
+ @fonts << p
41
+ elsif p.kind_of?(PDF::Writer::External)
42
+ @xObjects << p
43
+ else
44
+ raise ArgumentError, PDF::Message[:req_FPXO]
45
+ end
46
+ end
47
+
48
+ # Add a page to the page list. If p is just a Page, then it will be
49
+ # added to the page list. Otherwise, it will be treated as a Hash with
50
+ # keys :page, :pos, and :rpage. :page is the Page to be added to the
51
+ # list; :pos is :before or :after; :rpage is the Page to which the
52
+ # new Page will be added relative to.
53
+ def add(p)
54
+ if p.kind_of?(PDF::Writer::Object::Page)
55
+ @pages << p
56
+ elsif p.kind_of?(PDF::Writer::FontMetrics)
57
+ @fonts << p
58
+ elsif p.kind_of?(PDF::Writer::External)
59
+ @xObjects << p
60
+ elsif p.kind_of?(Hash)
61
+ # Find a match.
62
+ i = @pages.index(p[:rpage])
63
+ unless i.nil?
64
+ # There is a match; insert the page.
65
+ case p[:pos]
66
+ when :before
67
+ @pages[i, 0] = p[:page]
68
+ when :after
69
+ @pages[i + 1, 0] = p[:page]
70
+ else
71
+ raise ArgumentError, PDF::Message[:invalid_pos]
72
+ end
73
+ end
74
+ else
75
+ raise ArgumentError, PDF::Message[:req_FPXOH]
76
+ end
77
+ end
78
+
79
+ attr_accessor :procset
80
+ # Each of the following should be an array of 4 numbers, the x and y
81
+ # coordinates of the lower left and upper right bounds of the box.
82
+ attr_accessor :media_box
83
+ attr_accessor :bleed_box
84
+ attr_accessor :trim_box
85
+
86
+ def to_s
87
+ unless @pages.empty?
88
+ res = "\n#{@oid} 0 obj\n<< /Type /Pages\n/Kids ["
89
+ @pages.uniq! # uniqify the data...
90
+ @pages.each { |p| res << "#{p.oid} 0 R\n" }
91
+ res << "]\n/Count #{@pages.size}"
92
+ unless @fonts.empty? and @procset.nil?
93
+ res << "\n/Resources <<"
94
+ res << "\n/ProcSet #{@procset.oid} 0 R" unless @procset.nil?
95
+ unless @fonts.empty?
96
+ res << "\n/Font << "
97
+ @fonts.each { |f| res << "\n/F#{f.font_id} #{f.oid} 0 R" }
98
+ res << " >>"
99
+ end
100
+ unless @xObjects.empty?
101
+ res << "\n/XObject << "
102
+ @xObjects.each { |x| res << "\n/#{x.label} #{x.oid} 0 R" }
103
+ res << " >>"
104
+ end
105
+ res << "\n>>"
106
+ res << "\n/MediaBox [#{@media_box.join(' ')}]" unless @media_box.nil? or @media_box.empty?
107
+ res << "\n/BleedBox [#{@bleed_box.join(' ')}]" unless @bleed_box.nil? or @bleed_box.empty?
108
+ res << "\n/TrimBox [#{@trim_box.join(' ')}]" unless @trim_box.nil? or @trim_box.empty?
109
+ end
110
+ res << "\n >>\nendobj"
111
+ else
112
+ "\n#{@oid} 0 obj\n<< /Type /Pages\n/Count 0\n>>\nendobj"
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,46 @@
1
+ #--
2
+ # PDF::Writer for Ruby.
3
+ # http://rubyforge.org/projects/ruby-pdf/
4
+ # Copyright 2003 - 2005 Austin Ziegler.
5
+ #
6
+ # Licensed under a MIT-style licence. See LICENCE in the main distribution
7
+ # for full licensing information.
8
+ #
9
+ # $Id: procset.rb,v 1.2 2005/05/16 03:59:21 austin Exp $
10
+ #++
11
+ # The document Procedure Set. Not necessary in PDF 1.4 or later, but
12
+ # producing applications are recommended to provide the /ProcSet /Resource
13
+ # in any case for older viewers. Viewing applications are *not*
14
+ # recommended to rely on this information being correct.
15
+ #
16
+ # These procedure sets are used only when the content stream is printed to
17
+ # a PostScript output device; the names identify PostScript procedure sets
18
+ # that must be sent to the device to interpret the PDF operators in the
19
+ # content stream. Each element of this array must be one of the following
20
+ # predefined names: 'PDF', 'Text', 'ImageB', 'ImageC', and 'ImageI'. See
21
+ # also Appendix H note 102.
22
+ class PDF::Writer::Object::Procset < PDF::Writer::Object
23
+ def initialize(parent)
24
+ super
25
+
26
+ @info = ["PDF", "Text"]
27
+ @parent.pages.procset = self
28
+ @parent.procset = self
29
+ end
30
+
31
+ # This is to add new items to the procset list, despite the fact that
32
+ # this is considered obselete, the items are required for printing to
33
+ # some PostsCript printers.
34
+ #
35
+ # +p+ may be 'ImageB', 'ImageC', or 'ImageI'.
36
+ def <<(p)
37
+ @info << p
38
+ end
39
+
40
+ def to_s
41
+ info = @info.uniq
42
+ res = "\n#{@oid} 0 obj\n["
43
+ @info.each { |k| res << "/#{k} " }
44
+ res << "]\nendobj"
45
+ end
46
+ end
@@ -0,0 +1,74 @@
1
+ #--
2
+ # PDF::Writer for Ruby.
3
+ # http://rubyforge.org/projects/ruby-pdf/
4
+ # Copyright 2003 - 2005 Austin Ziegler.
5
+ #
6
+ # Licensed under a MIT-style licence. See LICENCE in the main distribution
7
+ # for full licensing information.
8
+ #
9
+ # $Id: viewerpreferences.rb,v 1.2 2005/05/16 03:59:21 austin Exp $
10
+ #++
11
+ # Set the viewer preferences.
12
+ #
13
+ # HideToolbar:: boolean (Optional) A flag specifying whether to hide the
14
+ # viewer application? tool bars when the document is
15
+ # active. Default value: false.
16
+ # HideMenubar:: boolean (Optional) A flag specifying whether to hide the
17
+ # viewer application? menu bar when the document is
18
+ # active. Default value: false.
19
+ # HideWindowUI:: boolean (Optional) A flag specifying whether to hide
20
+ # user interface elements in the document? window (such as
21
+ # scroll bars and navigation controls), leaving only the
22
+ # document? contents displayed. Default value: false.
23
+ # FitWindow:: boolean (Optional) A flag specifying whether to resize
24
+ # the document? window to fit the size of the first
25
+ # displayed page. Default value: false.
26
+ # CenterWindow:: boolean (Optional) A flag specifying whether to position
27
+ # the document? window in the center of the screen.
28
+ # Default value: false.
29
+ # NonFullScreenPageMode:: name (Optional) The document? page mode,
30
+ # specifying how to display the document on
31
+ # exiting full-screen mode. This entry is
32
+ # meaningful only if the value of the PageMode
33
+ # entry in the catalog dictionary is FullScreen;
34
+ # it is ignored otherwise. Default value: UseNone.
35
+ # Direction:: name (Optional; PDF 1.3) The predominant reading
36
+ # order for text: L2R Left to right R2L Right to
37
+ # left (including vertical writing systems such as
38
+ # Chinese, Japanese, and Korean) This entry has no
39
+ # direct effect on the document? contents or page
40
+ # numbering, but can be used to determine the
41
+ # relative positioning of pages when displayed
42
+ # side by side or printed n-up. Default value:
43
+ # L2R.
44
+ #
45
+ # NonFullScreenPageMode Names
46
+ # UseNone:: Neither document outline nor thumbnail images visible
47
+ # UseOutlines:: Document outline visible
48
+ # UseThumbs:: Thumbnail images visible
49
+ #
50
+ # Note that boolean values are represented by the values 'true' and
51
+ # 'false'. Also note that I have not done much testing on changing these
52
+ # values and am not sure how responsive the various viewers and browsers
53
+ # are to them (and setting the direction would be fairly meaningless as
54
+ # none of these character sets are avaliable yet.
55
+ class PDF::Writer::Object::ViewerPreferences < PDF::Writer::Object
56
+ Preferences = %w{HideToolbar HideMenubar HideWindowUI FitWindow CenterWindow NonFullScreenPageMode Direction}
57
+
58
+ def initialize(parent)
59
+ super(parent)
60
+ end
61
+
62
+ Preferences.each do |s|
63
+ attr_accessor s.downcase.intern
64
+ end
65
+
66
+ def to_s
67
+ res = "\n#{@id} 0 obj\n<< "
68
+ Preferences.each do |s|
69
+ v = __send__("#{s.downcase}".intern)
70
+ res << "\n/#{s} /#{v}" unless v.nil?
71
+ end
72
+ res << "\n>>\n"
73
+ end
74
+ end
@@ -0,0 +1,58 @@
1
+ #--
2
+ # PDF::Writer for Ruby.
3
+ # http://rubyforge.org/projects/ruby-pdf/
4
+ # Copyright 2003 - 2005 Austin Ziegler.
5
+ #
6
+ # Licensed under a MIT-style licence. See LICENCE in the main distribution
7
+ # for full licensing information.
8
+ #
9
+ # $Id: ohash.rb,v 1.2 2005/05/16 03:59:21 austin Exp $
10
+ #++
11
+ # Based on [ruby-talk:20551]. Updated to (hopefully) be 1.8 friendly.
12
+ class PDF::Writer::OHash < Hash
13
+ alias_method :store, :[]=
14
+ alias_method :each_pair, :each
15
+
16
+ def initialize(*args)
17
+ @keys = []
18
+ super
19
+ end
20
+
21
+ def []=(key, val)
22
+ @keys << key unless has_key?(key)
23
+ super
24
+ end
25
+
26
+ def delete(key)
27
+ @keys.delete(key) if has_key?(key)
28
+ super
29
+ end
30
+
31
+ def each
32
+ @keys.each { |k| yield k, self[k] }
33
+ end
34
+
35
+ def each_key
36
+ @keys.each { |k| yield k }
37
+ end
38
+
39
+ def each_value
40
+ @keys.each { |k| yield self[k] }
41
+ end
42
+
43
+ def first
44
+ self[@keys[0]]
45
+ end
46
+
47
+ def last
48
+ self[@keys[-1]]
49
+ end
50
+
51
+ def first?(item)
52
+ self[@keys[0]] == item
53
+ end
54
+
55
+ def last?(item)
56
+ self[@keys[-1]] == item
57
+ end
58
+ end
@@ -0,0 +1,25 @@
1
+ #--
2
+ # PDF::Writer for Ruby.
3
+ # http://rubyforge.org/projects/ruby-pdf/
4
+ # Copyright 2003 - 2005 Austin Ziegler.
5
+ #
6
+ # Licensed under a MIT-style licence. See LICENCE in the main distribution
7
+ # for full licensing information.
8
+ #
9
+ # $Id: oreader.rb,v 1.2 2005/05/16 03:59:21 austin Exp $
10
+ #++
11
+ module PDF::Writer::OffsetReader
12
+ def read_o(length = 1, offset = nil)
13
+ @offset ||= 0
14
+ @offset = offset if offset
15
+ ret = self[@offset, length]
16
+ @offset += length
17
+ ret
18
+ end
19
+ def offset
20
+ @offset
21
+ end
22
+ def offset=(o)
23
+ @offset = o || 0
24
+ end
25
+ end
@@ -0,0 +1,48 @@
1
+ #--
2
+ # PDF::Writer for Ruby.
3
+ # http://rubyforge.org/projects/ruby-pdf/
4
+ # Copyright 2003 - 2005 Austin Ziegler.
5
+ #
6
+ # Licensed under a MIT-style licence. See LICENCE in the main distribution
7
+ # for full licensing information.
8
+ #
9
+ # $Id: state.rb,v 1.2 2005/05/16 03:59:21 austin Exp $
10
+ #++
11
+ class PDF::Writer
12
+ class State
13
+ attr_accessor :fill_color
14
+ attr_accessor :stroke_color
15
+ attr_accessor :text_render_style
16
+ attr_accessor :stroke_style
17
+
18
+ def initialize(vals = {})
19
+ @fill_color = vals[:fill_color]
20
+ @stroke_color = vals[:stroke_color]
21
+ @text_render_style = vals[:text_render_style]
22
+ @stroke_style = vals[:stroke_style]
23
+
24
+ yield self if block_given?
25
+ end
26
+
27
+ def blank?
28
+ @fill_color.nil? and @stroke_color.nil? and @stroke_style.nil?
29
+ end
30
+ end
31
+
32
+ class StateStack < ::Array
33
+ alias_method :__push__, :push
34
+ # alias_method :__pop__, :pop
35
+
36
+ def push(obj)
37
+ return self if obj.nil?
38
+ raise TypeError unless obj.kind_of?(PDF::Writer::State)
39
+ return self if obj.blank?
40
+ __push__(obj)
41
+ end
42
+
43
+ # def pop
44
+ # ret = __pop__
45
+ # ret
46
+ # end
47
+ end
48
+ end
@@ -0,0 +1,138 @@
1
+ #--
2
+ # PDF::Writer for Ruby.
3
+ # http://rubyforge.org/projects/ruby-pdf/
4
+ # Copyright 2003 - 2005 Austin Ziegler.
5
+ #
6
+ # Licensed under a MIT-style licence. See LICENCE in the main distribution
7
+ # for full licensing information.
8
+ #
9
+ # $Id: strokestyle.rb,v 1.5 2005/06/02 21:20:35 austin Exp $
10
+ #++
11
+ # A class that represents a style with which lines will be drawn.
12
+ class PDF::Writer::StrokeStyle
13
+ LINE_CAPS = { :butt => 0, :round => 1, :square => 2 }
14
+ LINE_JOINS = { :miter => 0, :round => 1, :bevel => 2 }
15
+ SOLID_LINE = { :pattern => [], :phase => 0 }
16
+
17
+ def initialize(width = 1, options = {})
18
+ @width = width
19
+ @cap = options[:cap]
20
+ @join = options[:join]
21
+ @dash = options[:dash]
22
+ @miter_limit = options[:miter_limit]
23
+
24
+ yield self if block_given?
25
+ end
26
+
27
+ DEFAULT = self.new(1, :cap => :butt, :join => :miter, :dash => SOLID_LINE)
28
+
29
+ # The thickness of the line in PDF units.
30
+ attr_accessor :width
31
+ # The type of cap to put on the line.
32
+ #
33
+ # <tt>:butt</tt>:: The stroke is squared off at the endpoint of the
34
+ # path. There is no projection beyond the end of the
35
+ # path.
36
+ # <tt>:round</tt>:: A semicircular arc with a diameter equal to the
37
+ # line width is drawn around the endpoint and filled
38
+ # in.
39
+ # <tt>:square</tt>:: The stroke continues beyond the endpoint of the
40
+ # path for a distance equal to half the line width
41
+ # and is squared off.
42
+ # +nil+:: Keeps the current line cap.
43
+ attr_accessor :cap
44
+ def cap=(c) #:nodoc:
45
+ if c.nil? or LINE_CAPS.include?(c)
46
+ @cap = c
47
+ else
48
+ raise ArgumentError, "Line cap styles must be nil (none), butt, round, or square."
49
+ end
50
+ end
51
+ # How two lines join together.
52
+ #
53
+ # <tt>:miter</tt>:: The outer edges of the strokes for the two
54
+ # segments are extended until they meet at an angle,
55
+ # as in a picture frame. If the segments meet at too
56
+ # sharp an angle (as defined by the #miter_limit), a
57
+ # bevel join is used instead.
58
+ # <tt>:round</tt>:: An arc of a circle with a diameter equal to the
59
+ # line width is drawn around the point where the two
60
+ # segments meet, connecting the outer edges of the
61
+ # strokes for the two segments. This pie-slice
62
+ # shaped figure is filled in, producing a rounded
63
+ # corner.
64
+ # <tt>:bevel</tt>:: The two segments are finished with butt caps and
65
+ # the the resulting notch beyond the ends of the
66
+ # segments is filled with a triangle, forming a
67
+ # flattened edge on the join.
68
+ # +nil+:: Keeps the current line join.
69
+ attr_accessor :join
70
+ def join=(j) #:nodoc:
71
+ if j.nil? or LINE_JOINS.include?(j)
72
+ @join = j
73
+ else
74
+ raise ArgumentError, "Line join styles must be nil (none), miter, round, or bevel."
75
+ end
76
+ end
77
+ # When two line segments meet and <tt>:miter</tt> joins have been
78
+ # specified, the miter may extend far beyond the thickness of the line
79
+ # stroking the path. #miter_limit imposes a maximum ratio miter length
80
+ # to line width at which point the join will be converted from a miter
81
+ # to a bevel. Adobe points out that the ratio is directly related to the
82
+ # angle between the segments in user space. With [p] representing the
83
+ # angle at which the segments meet:
84
+ #
85
+ # miter_length / line_width == 1 / (sin ([p] / 2))
86
+ #
87
+ # A miter limit of 1.414 converts miters to bevels for [p] less than 90
88
+ # degrees, a limit of 2.0 converts them for [p] less than 60 degrees,
89
+ # and a limit of 10.0 converts them for [p] less than approximately 11.5
90
+ # degrees.
91
+ attr_accessor :miter_limit
92
+ # Controls the pattern of dashes and gaps used to stroke paths. This
93
+ # value must either be +nil+, or a hash with the following values:
94
+ #
95
+ # <tt>:pattern</tt>:: An array of numbers specifying the lengths (in PDF
96
+ # userspace units) of alternating dashes and gaps.
97
+ # The array is processed cyclically, so that a
98
+ # <tt>:pattern</tt> of [3] represents three units
99
+ # on, three units off, and a <tt>:pattern</tt> of
100
+ # [2, 1] represents two units on, one unit off.
101
+ #
102
+ # # - represents on, _ represents off
103
+ # ---___---___--- # pattern [3]
104
+ # --_--_--_--_--_ # pattern [2, 1]
105
+ #
106
+ # <tt>:phase</tt>:: The offset in the <tt>:pattern</tt> where the
107
+ # drawing of the stroke begins. Using a
108
+ # <tt>:phase</tt> of 1, the <tt>:pattern</tt> [3]
109
+ # will start offset by one phase, for two units on,
110
+ # three units off, three units on.
111
+ #
112
+ # --___---___---_ # pattern [3], phase 1
113
+ # -_--_--_--_--_- # pattern [2, 1], phase 1
114
+ #
115
+ # The constant SOLID_LINE may be used to restore line drawing to a solid
116
+ # line; this corresponds to an empty pattern with zero phase ([] 0).
117
+ #
118
+ # Dashed lines wrap around curves and corners just as solid stroked
119
+ # lines do, with normal cap and join handling with no consideration of
120
+ # the dash pattern. A path with several subpaths treats each subpath
121
+ # independently; the complete dash pattern is restarted at the beginning
122
+ # of each subpath.
123
+ attr_accessor :dash
124
+
125
+ def render(debug = false)
126
+ s = ""
127
+ s << "#{width} w" if @width > 0
128
+ s << " #{LINE_CAPS[@cap]} J" if @cap
129
+ s << " #{LINE_JOINS[@join]} j" if @join
130
+ s << " #{@miter_limit} M" if @miter_limit
131
+ if @dash
132
+ s << " ["
133
+ @dash[:pattern].each { |len| s << " #{len}" }
134
+ s << " ] #{@dash[:phase] or 0} d"
135
+ end
136
+ s
137
+ end
138
+ end