Class: Pdfrb::Composer

Inherits:
Object
  • Object
show all
Defined in:
lib/pdfrb/composer.rb

Overview

High-level document composition API. Wraps a Document and a Layout::BoxFitter, exposing a DSL for adding text, images, and boxes with automatic page flow.

Usage:

Pdfrb::Composer.new("out.pdf") do |c|
c.style(:heading, font_size: 24)
c.text("Hello world", style: :heading)
c.image("/path/to/logo.png", width: 200)
c.text("Body text flows naturally.")
end

Constant Summary collapse

DEFAULT_PAGE_STYLE =
:default

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(output = nil, page_size: :A4, page_orientation: :portrait, margin: 36, skip_page_creation: false) ⇒ Composer

Returns a new instance of Composer.



20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/pdfrb/composer.rb', line 20

def initialize(output = nil, page_size: :A4, page_orientation: :portrait,
               margin: 36, skip_page_creation: false)
  @document = Pdfrb::Document.new
  @page_styles = {}
  @output_target = output
  @pending_boxes = []

  page_style(DEFAULT_PAGE_STYLE, page_size: page_size,
                                 orientation: page_orientation,
                                 margin: margin)
  @current_style_name = DEFAULT_PAGE_STYLE
  new_page unless skip_page_creation
end

Instance Attribute Details

#current_pageObject (readonly)

Returns the value of attribute current_page.



18
19
20
# File 'lib/pdfrb/composer.rb', line 18

def current_page
  @current_page
end

#current_style_nameObject (readonly)

Returns the value of attribute current_style_name.



18
19
20
# File 'lib/pdfrb/composer.rb', line 18

def current_style_name
  @current_style_name
end

#documentObject (readonly)

Returns the value of attribute document.



18
19
20
# File 'lib/pdfrb/composer.rb', line 18

def document
  @document
end

#page_stylesObject (readonly)

Returns the value of attribute page_styles.



18
19
20
# File 'lib/pdfrb/composer.rb', line 18

def page_styles
  @page_styles
end

Class Method Details

.create(output) {|composer| ... } ⇒ Object

Class-level shortcut: create a document, yield to block, write.

Yields:

  • (composer)


35
36
37
38
39
# File 'lib/pdfrb/composer.rb', line 35

def self.create(output, **)
  composer = new(output, **)
  yield composer
  composer.write
end

Instance Method Details

#box(box_class) ⇒ Object

Add an arbitrary box.



96
97
98
99
# File 'lib/pdfrb/composer.rb', line 96

def box(box_class, **, &)
  box = box_class.new(**, &)
  draw_box_on_current_page(box)
end

#formatted_text(data, **opts) ⇒ Object

Add formatted text (array of style: runs).



84
85
86
# File 'lib/pdfrb/composer.rb', line 84

def formatted_text(data, **opts)
  data.each { |run| text(run[:text], **opts, **run.fetch(:style, {})) }
end

#image(path, width: 0, height: 0, **opts) ⇒ Object

Add an image from a file path.



89
90
91
92
93
# File 'lib/pdfrb/composer.rb', line 89

def image(path, width: 0, height: 0, **opts)
  box = Layout::ImageBox.new(path: path, document: @document,
                             width: width, height: height)
  draw_box_on_current_page(box)
end

#new_page(style_name = nil) ⇒ Object

Create a new page using the named (or current) page style.



57
58
59
60
61
62
63
64
65
# File 'lib/pdfrb/composer.rb', line 57

def new_page(style_name = nil)
  @current_style_name = style_name || next_style_name
  style_obj = @page_styles[@current_style_name]
  page = @document.pages.add
  page.value[:MediaBox] = [0, 0, style_obj.width, style_obj.height]
  @current_page = page
  @pending_boxes = []
  page
end

#page_style(name, **attrs) ⇒ Object

Define a named page style.



52
53
54
# File 'lib/pdfrb/composer.rb', line 52

def page_style(name, **attrs, &)
  @page_styles[name.to_sym] = Layout::PageStyle.new(name: name, **attrs, &)
end

#style(name, base: :base, **properties) ⇒ Object

Define a named text style.



42
43
44
45
# File 'lib/pdfrb/composer.rb', line 42

def style(name, base: :base, **properties)
  @styles ||= {}
  @styles[name.to_sym] = Layout::Style.new(base, **properties)
end

#style?(name) ⇒ Boolean

Returns:

  • (Boolean)


47
48
49
# File 'lib/pdfrb/composer.rb', line 47

def style?(name)
  @styles&.key?(name.to_sym)
end

#text(str, width: 0, height: 0, style: nil, **style_properties) ⇒ Object

Add text using a style.



76
77
78
79
80
81
# File 'lib/pdfrb/composer.rb', line 76

def text(str, width: 0, height: 0, style: nil, **style_properties)
  resolved_style = resolve_style(style, style_properties)
  box = Layout::TextBox.new(text: str, width: width, height: height,
                            style: resolved_style)
  draw_box_on_current_page(box)
end

#write(output = @output_target, optimize: false, **opts) ⇒ Object

Write the document.



102
103
104
105
106
107
108
109
110
# File 'lib/pdfrb/composer.rb', line 102

def write(output = @output_target, optimize: false, **opts)
  flush_pending_boxes
  target = output
  if target.is_a?(String)
    @document.write(target)
  else
    @document.write(io: target)
  end
end

#write_to_string(optimize: false) ⇒ Object



112
113
114
115
116
117
# File 'lib/pdfrb/composer.rb', line 112

def write_to_string(optimize: false, **)
  require "stringio"
  io = StringIO.new
  write(io, optimize: optimize, **)
  io.string
end

#xObject



67
68
69
# File 'lib/pdfrb/composer.rb', line 67

def x
  @cursor_x || 50
end

#yObject



71
72
73
# File 'lib/pdfrb/composer.rb', line 71

def y
  @cursor_y || (@current_page ? 750 : 0)
end