Class: Okab::Page
- Inherits:
-
Object
- Object
- Okab::Page
- Defined in:
- lib/okab/page.rb,
sig/okab.rbs
Instance Attribute Summary collapse
-
#annotations ⇒ Array[Array[untyped]]
readonly
Returns the value of attribute annotations.
-
#document ⇒ Document
readonly
Returns the value of attribute document.
-
#height ⇒ Float
readonly
Returns the value of attribute height.
-
#operations ⇒ Array[Array[untyped]]
readonly
Returns the value of attribute operations.
-
#width ⇒ Float
readonly
Returns the value of attribute width.
Instance Method Summary collapse
- #clip {|path| ... } ⇒ self
- #close ⇒ self
- #content(fonts:) ⇒ String
- #curve_to(x1, y1, x2, y2, x3, y3) ⇒ self
- #ellipse(x, y, width, height) ⇒ self
- #fill(color, rule: :nonzero) ⇒ self
- #fill_and_stroke(color, width: 1) ⇒ self
- #glyph(glyph_id, x:, y:, font:, size:, unicode:, color: [0, 0, 0]) ⇒ self
- #image(data, x:, y:, width:, height:, format: :auto) ⇒ self
-
#initialize(document, width:, height:) ⇒ Page
constructor
A new instance of Page.
- #line_to(x, y) ⇒ self
- #link(bounds, uri: nil, page: nil) ⇒ self
- #move_to(x, y) ⇒ self
- #opacity(value) {|arg0| ... } ⇒ self
- #path(outline) ⇒ self
- #rect(x, y, width, height) ⇒ self
- #stroke(color, width: 1, cap: :butt, join: :miter, miter: 10, dash: nil) ⇒ self
- #text(string, x:, y:, font:, size:, color: [0, 0, 0], tracking: 0, bold: false, italic: false) ⇒ self
- #text_block(string, x:, y:, width:, font:, size:, line_height:, align: :left, color: [0, 0, 0], tracking: 0) ⇒ self
- #transform(a, b, c, d, e, f) {|arg0| ... } ⇒ self
- #with_clip(path, rule: :nonzero) {|arg0| ... } ⇒ self
Constructor Details
#initialize(document, width:, height:) ⇒ Page
Returns a new instance of Page.
43 44 45 46 47 |
# File 'lib/okab/page.rb', line 43 def initialize(document, width:, height:) @document, @width, @height = document, Float(width), Float(height) raise ArgumentError, "page dimensions must be finite and positive" unless [@width, @height].all? { |value| value.finite? && value.positive? } @operations, @annotations, @open_clips = [], [], 0 end |
Instance Attribute Details
#annotations ⇒ Array[Array[untyped]] (readonly)
Returns the value of attribute annotations.
41 42 43 |
# File 'lib/okab/page.rb', line 41 def annotations @annotations end |
#document ⇒ Document (readonly)
Returns the value of attribute document.
41 42 43 |
# File 'lib/okab/page.rb', line 41 def document @document end |
#height ⇒ Float (readonly)
Returns the value of attribute height.
41 42 43 |
# File 'lib/okab/page.rb', line 41 def height @height end |
#operations ⇒ Array[Array[untyped]] (readonly)
Returns the value of attribute operations.
41 42 43 |
# File 'lib/okab/page.rb', line 41 def operations @operations end |
#width ⇒ Float (readonly)
Returns the value of attribute width.
41 42 43 |
# File 'lib/okab/page.rb', line 41 def width @width end |
Instance Method Details
#clip {|path| ... } ⇒ self
126 127 128 129 130 131 132 133 134 |
# File 'lib/okab/page.rb', line 126 def clip raise ArgumentError, "clip requires a block" unless block_given? path = Path.new yield path raise ArgumentError, "clip path must not be empty" if path.commands.empty? @operations << [:raw, "q\n#{path.commands.join("\n")}\nW n"] @open_clips += 1 self end |
#close ⇒ self
94 |
# File 'lib/okab/page.rb', line 94 def close = raw("h") |
#content(fonts:) ⇒ String
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
# File 'lib/okab/page.rb', line 208 def content(fonts:) output = +"".b @operations.each do |operation| case operation[0] when :raw then output << operation[1].b << "\n".b when :text _, x, y, font, encoded, size, color, tracking, bold, italic = operation output << "#{color.join(' ')} rg\n" if bold output << "#{color.join(' ')} RG\n#{PDF::Encoding.number((size * 0.035).round(4))} w\n" end matrix = italic ? "1 0 0.2 1 #{PDF::Encoding.number(x)} #{PDF::Encoding.number(y)} Tm" : "#{PDF::Encoding.number(x)} #{PDF::Encoding.number(y)} Td" output << "BT /#{fonts.fetch(font.object_id)} #{PDF::Encoding.number(size)} Tf #{PDF::Encoding.number(tracking)} Tc #{bold ? 2 : 0} Tr #{matrix} #{PDF::Encoding.hex(encoded)} Tj ET\n".b when :image _, name, x, y, width, height = operation output << "q\n#{PDF::Encoding.number(width)} 0 0 #{PDF::Encoding.number(height)} #{PDF::Encoding.number(x)} #{PDF::Encoding.number(y)} cm\n/#{name} Do\nQ\n".b end end @open_clips.times { output << "Q\n".b } output end |
#curve_to(x1, y1, x2, y2, x3, y3) ⇒ self
93 |
# File 'lib/okab/page.rb', line 93 def curve_to(x1, y1, x2, y2, x3, y3) = raw(Path.new.curve_to(x1, y1, x2, y2, x3, y3).commands.last) |
#ellipse(x, y, width, height) ⇒ self
97 98 99 100 |
# File 'lib/okab/page.rb', line 97 def ellipse(x, y, width, height) path = Path.new.ellipse(*[x, y, width, height].map { |value| finite(value, "ellipse bounds") }) raw(path.commands.join("\n")) end |
#fill(color, rule: :nonzero) ⇒ self
107 108 109 110 |
# File 'lib/okab/page.rb', line 107 def fill(color, rule: :nonzero) raise ArgumentError, "fill rule must be nonzero or evenodd" unless %i[nonzero evenodd].include?(rule) raw("#{rgb(color).join(' ')} rg\n#{rule == :evenodd ? 'f*' : 'f'}") end |
#fill_and_stroke(color, width: 1) ⇒ self
124 |
# File 'lib/okab/page.rb', line 124 def fill_and_stroke(color, width: 1) = raw("#{rgb(color).join(' ')} rg\n#{rgb(color).join(' ')} RG\n#{positive(width, 'line width')} w\nB") |
#glyph(glyph_id, x:, y:, font:, size:, unicode:, color: [0, 0, 0]) ⇒ self
60 61 62 63 64 65 66 67 |
# File 'lib/okab/page.rb', line 60 def glyph(glyph_id, x:, y:, font:, size:, unicode:, color: [0, 0, 0]) size = finite(size, "font size") raise ArgumentError, "font size must be positive" unless size.positive? = @document.(font) encoded = .encode_glyph(glyph_id, unicode: unicode) @operations << [:text, finite(x, "x"), finite(y, "y"), , encoded, size, rgb(color), 0.0, false, false] self end |
#image(data, x:, y:, width:, height:, format: :auto) ⇒ self
182 183 184 185 186 187 |
# File 'lib/okab/page.rb', line 182 def image(data, x:, y:, width:, height:, format: :auto) image = data.is_a?(Image) ? data : Image.decode(data, format: format) name = @document.register_image(image) @operations << [:image, name, finite(x, "x"), finite(y, "y"), finite(width, "width"), finite(height, "height")] self end |
#line_to(x, y) ⇒ self
92 |
# File 'lib/okab/page.rb', line 92 def line_to(x, y) = raw(Path.new.line_to(x, y).commands.last) |
#link(bounds, uri: nil, page: nil) ⇒ self
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
# File 'lib/okab/page.rb', line 189 def link(bounds, uri: nil, page: nil) raise ArgumentError, "provide either uri or page" if (!!uri == !!page) x, y, width, height = normalize_bounds(bounds) action = if uri parsed = URI.parse(uri.to_s) valid = (parsed.is_a?(URI::HTTP) && parsed.host && %w[http https].include?(parsed.scheme)) || (parsed.is_a?(URI::MailTo) && !parsed.to.empty?) raise ArgumentError, "link URI must use http, https, or mailto" unless valid [:uri, uri.to_s.freeze] else raise ArgumentError, "destination page belongs to another document" unless page.is_a?(Page) && @document.owns_page?(page) [:page, page] end @annotations << [x, y, width, height, *action] self rescue URI::InvalidURIError raise ArgumentError, "invalid link URI" end |
#move_to(x, y) ⇒ self
91 |
# File 'lib/okab/page.rb', line 91 def move_to(x, y) = raw(Path.new.move_to(x, y).commands.last) |
#opacity(value) {|arg0| ... } ⇒ self
167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/okab/page.rb', line 167 def opacity(value) raise ArgumentError, "opacity requires a block" unless block_given? name = @document.opacity_name(value) start = @operations.length @operations << [:raw, "q\n/#{name} gs"] begin yield self rescue StandardError @operations.slice!(start..) raise end @operations << [:raw, "Q"] self end |
#path(outline) ⇒ self
102 103 104 105 |
# File 'lib/okab/page.rb', line 102 def path(outline) raise ArgumentError, "path must not be empty" unless outline.is_a?(Path) && !outline.commands.empty? raw(outline.commands.join("\n")) end |
#rect(x, y, width, height) ⇒ self
95 |
# File 'lib/okab/page.rb', line 95 def rect(x, y, width, height) = raw(Path.new.rect(x, y, width, height).commands.last) |
#stroke(color, width: 1, cap: :butt, join: :miter, miter: 10, dash: nil) ⇒ self
112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/okab/page.rb', line 112 def stroke(color, width: 1, cap: :butt, join: :miter, miter: 10, dash: nil) raise ArgumentError, "line cap must be butt, round, or square" unless %i[butt round square].include?(cap) raise ArgumentError, "line join must be miter, round, or bevel" unless %i[miter round bevel].include?(join) style = "#{rgb(color).join(' ')} RG\n#{positive(width, 'line width')} w\n#{ {butt: 0, round: 1, square: 2}.fetch(cap) } J\n#{ {miter: 0, round: 1, bevel: 2}.fetch(join) } j\n#{positive(miter, 'miter limit')} M" if dash raise ArgumentError, "dash must contain positive lengths" unless dash.is_a?(Array) && !dash.empty? && dash.all? { |value| value.is_a?(Numeric) && value.finite? && value.positive? } style << "\n[#{dash.map { |value| PDF::Encoding.number(value) }.join(' ')}] 0 d" else style << "\n[] 0 d" end raw("#{style}\nS") end |
#text(string, x:, y:, font:, size:, color: [0, 0, 0], tracking: 0, bold: false, italic: false) ⇒ self
49 50 51 52 53 54 55 56 57 58 |
# File 'lib/okab/page.rb', line 49 def text(string, x:, y:, font:, size:, color: [0, 0, 0], tracking: 0, bold: false, italic: false) validate_text(string) size, tracking = finite(size, "font size"), finite(tracking, "tracking") raise ArgumentError, "font size must be positive" unless size.positive? raise ArgumentError, "bold and italic must be true or false" unless [bold, italic].all? { |value| value == true || value == false } = @document.(font) encoded = .encode(string) @operations << [:text, finite(x, "x"), finite(y, "y"), , encoded, size, rgb(color), tracking, bold, italic] self end |
#text_block(string, x:, y:, width:, font:, size:, line_height:, align: :left, color: [0, 0, 0], tracking: 0) ⇒ self
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/okab/page.rb', line 69 def text_block(string, x:, y:, width:, font:, size:, line_height:, align: :left, color: [0, 0, 0], tracking: 0) validate_text(string) x, y = finite(x, "x"), finite(y, "y") width, size, line_height = finite(width, "width"), finite(size, "font size"), finite(line_height, "line height") raise ArgumentError, "text block dimensions must be positive" unless width.positive? && size.positive? && line_height.positive? raise ArgumentError, "align must be left, center, right, or justify" unless %i[left center right justify].include?(align) face = font.is_a?(EmbeddedFont) ? font.font : normalize_font(font) lines = wrap_lines(string, face, size, width) lines.each_with_index do |line, index| line_width = face.measure(line, size: size) offset = case align when :center then (width - line_width) / 2.0 when :right then width - line_width else 0 end extra = align == :justify && index < lines.length - 1 ? (width - line_width) / [line.length, 1].max : 0 text(line, x: x + offset, y: y - index * line_height, font: face, size: size, color: color, tracking: tracking + extra) end self end |
#transform(a, b, c, d, e, f) {|arg0| ... } ⇒ self
152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/okab/page.rb', line 152 def transform(a, b, c, d, e, f) raise ArgumentError, "transform requires a block" unless block_given? values = [a, b, c, d, e, f].map { |value| finite(value, 'transform') } start = @operations.length @operations << [:raw, "q\n#{values.map { |value| PDF::Encoding.number(value) }.join(' ')} cm"] begin yield self rescue StandardError @operations.slice!(start..) raise end @operations << [:raw, "Q"] self end |
#with_clip(path, rule: :nonzero) {|arg0| ... } ⇒ self
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/okab/page.rb', line 136 def with_clip(path, rule: :nonzero) raise ArgumentError, "clip requires a block" unless block_given? raise ArgumentError, "clip path must not be empty" unless path.is_a?(Path) && !path.commands.empty? raise ArgumentError, "clip rule must be nonzero or evenodd" unless %i[nonzero evenodd].include?(rule) start = @operations.length @operations << [:raw, "q\n#{path.commands.join("\n")}\n#{rule == :evenodd ? 'W*' : 'W'} n"] begin yield self rescue StandardError @operations.slice!(start..) raise end @operations << [:raw, "Q"] self end |