Class: HexaPDF::Document::Pages

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/hexapdf/document/pages.rb

Overview

This class provides methods for managing the pages and page labels of a PDF file.

For page manipulation it uses the methods of HexaPDF::Type::PageTreeNode underneath but provides a more convenient interface.

Page Labels

In addition to page manipulation, the class provides methods for managing the page labels which are alternative descriptions for the pages. In contrast to the page indices which are fixed the page labels can be freely defined.

The way this works is that one can assign page label objects (HexaPDF::Type::PageLabel) to page ranges via the /PageLabels number tree in the catalog. The page label objects specify how the pages in their range shall be labeled. See HexaPDF::Type::PageLabel for examples of page labels.

To facilitate the easy use of page labels the following methods are provided:

  • #page_label

  • #each_labelling_range

  • #add_labelling_range

  • #delete_labelling_range

Instance Method Summary collapse

Constructor Details

#initialize(document) ⇒ Pages

Creates a new Pages object for the given PDF document.



69
70
71
# File 'lib/hexapdf/document/pages.rb', line 69

def initialize(document)
  @document = document
end

Instance Method Details

#<<(page) ⇒ Object

:call-seq:

pages << page            -> pages

Appends the given page at the end and returns the pages object itself to allow chaining.



121
122
123
124
# File 'lib/hexapdf/document/pages.rb', line 121

def <<(page)
  add(page)
  self
end

#[](index) ⇒ Object

Returns the page for the zero-based index, or nil if no such page exists.

Negative indices count backwards from the end, i.e. -1 is the last page.



168
169
170
# File 'lib/hexapdf/document/pages.rb', line 168

def [](index)
  @document.catalog.pages.page(index)
end

#add(page = nil, orientation: nil) ⇒ Object

:call-seq:

pages.add                               -> new_page
pages.add(page)                         -> page
pages.add(media_box, orientation: nil)  -> new_page

Adds the given page or a new empty page at the end and returns it.

If called with a page object as argument, that page object is used. Otherwise #create is called with the arguments media_box and orientation to create a new page.



110
111
112
113
114
115
# File 'lib/hexapdf/document/pages.rb', line 110

def add(page = nil, orientation: nil)
  unless page.kind_of?(HexaPDF::Type::Page)
    page = create(media_box: page, orientation: orientation)
  end
  @document.catalog.pages.add_page(page)
end

#add_labelling_range(start_index, numbering_style: nil, prefix: nil, start_number: nil) ⇒ Object

Adds a new labelling range starting at start_index and returns it.

See HexaPDF::Type::PageLabel for information on the arguments numbering_style, prefix, and start_number.

If a labelling range already exists for the given start_index, its value will be overwritten.

If there are no existing labelling ranges and the given start_index isn’t 0, a default labelling range using start index 0 and numbering style :decimal is added.



241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/hexapdf/document/pages.rb', line 241

def add_labelling_range(start_index, numbering_style: nil, prefix: nil, start_number: nil)
  page_label = @document.wrap({}, type: :PageLabel)
  page_label.numbering_style(numbering_style) if numbering_style
  page_label.prefix(prefix) if prefix
  page_label.start_number(start_number) if start_number

  labels = @document.catalog.page_labels(create: true)
  labels.add_entry(start_index, page_label)
  labels.add_entry(0, {S: :D}) unless labels.find_entry(0)

  page_label
end

#countObject Also known as: size, length

Returns the number of pages in the PDF document. May be zero if the document has no pages yet.



183
184
185
# File 'lib/hexapdf/document/pages.rb', line 183

def count
  @document.catalog.pages.page_count
end

#create(media_box: nil, orientation: nil) ⇒ Object

Creates a page object and returns it without adding it to the page tree.

media_box

If this argument is nil/not specified, the value is taken from the configuration option ‘page.default_media_box’.

If the resulting value is an array with four numbers (specifying the media box), the new page will have these exact dimensions.

If the value is a symbol, it is taken as a reference to a pre-defined media box in HexaPDF::Type::Page::PAPER_SIZE. The orientation can then be used to specify the page orientation.

orientation

If this argument is not specified, it is taken from ‘page.default_media_orientation’. It is only used if media_box is a symbol and not an array.



94
95
96
97
98
99
# File 'lib/hexapdf/document/pages.rb', line 94

def create(media_box: nil, orientation: nil)
  media_box ||= @document.config['page.default_media_box']
  orientation ||= @document.config['page.default_media_orientation']
  box = Type::Page.media_box(media_box, orientation: orientation)
  @document.add({Type: :Page, MediaBox: box})
end

#delete(page) ⇒ Object

Deletes the given page object from the document’s page tree and the document.

Also see: HexaPDF::Type::PageTreeNode#delete_page



154
155
156
# File 'lib/hexapdf/document/pages.rb', line 154

def delete(page)
  @document.catalog.pages.delete_page(page)
end

#delete_at(index) ⇒ Object

Deletes the page object at the given index from the document’s page tree and the document.

Also see: HexaPDF::Type::PageTreeNode#delete_page



161
162
163
# File 'lib/hexapdf/document/pages.rb', line 161

def delete_at(index)
  @document.catalog.pages.delete_page(index)
end

#delete_labelling_range(start_index) ⇒ Object

Deletes the page labelling range starting at start_index and returns the associated page label object.

Note: The page label for the range starting at zero can only be deleted last!



258
259
260
261
262
263
264
265
266
# File 'lib/hexapdf/document/pages.rb', line 258

def delete_labelling_range(start_index)
  return unless (labels = @document.catalog.page_labels)
  if start_index == 0 && labels.each_entry.first(2).size == 2
    raise HexaPDF::Error, "Page labelling range starting at 0 must be deleted last"
  end
  page_label = labels.delete_entry(start_index)
  @document.catalog.delete(:PageLabels) if start_index == 0
  page_label
end

#each(&block) ⇒ Object

:call-seq:

pages.each {|page| block }   -> pages
pages.each                   -> Enumerator

Iterates over all pages inorder.



177
178
179
# File 'lib/hexapdf/document/pages.rb', line 177

def each(&block)
  @document.catalog.pages.each_page(&block)
end

#each_labelling_rangeObject

:call-seq:

pages.each_labelling_range {|first_index, count, page_label| block }   -> pages
pages.each_labelling_range                                             -> Enumerator

Iterates over all defined labelling ranges inorder, yielding the page index of the first page in the labelling range, the number of pages in the range, and the associated page label object.

The last yielded count might be equal or lower than zero in case the document has fewer pages than anticipated by the labelling ranges.



213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/hexapdf/document/pages.rb', line 213

def each_labelling_range
  return to_enum(__method__) unless block_given?
  return unless @document.catalog.page_labels

  last_start = nil
  last_label = nil
  @document.catalog.page_labels.each_entry do |s1, p1|
    yield(last_start, s1 - last_start, @document.wrap(last_label, type: :PageLabel)) if last_start
    last_start = s1
    last_label = p1
  end
  if last_start
    yield(last_start, count - last_start, @document.wrap(last_label, type: :PageLabel))
  end

  self
end

#insert(index, page = nil) ⇒ Object

Inserts the page or a new empty page at the zero-based index and returns it.

Negative indices count backwards from the end, i.e. -1 is the last page. When using negative indices, the page will be inserted after that element. So using an index of -1 will insert the page after the last page.



131
132
133
# File 'lib/hexapdf/document/pages.rb', line 131

def insert(index, page = nil)
  @document.catalog.pages.insert_page(index, page)
end

#move(page, to_index) ⇒ Object

:call-seq:

pages.move(page, to_index)
pages.move(index, to_index)

Moves the given page or the page at the position specified by the zero-based index to the to_index position.

If the page that should be moved, doesn’t exist or is invalid, an error is raised.

Negative indices count backwards from the end, i.e. -1 is the last page. When using a negative index, the page will be moved after that element. So using an index of -1 will move the page after the last page.



147
148
149
# File 'lib/hexapdf/document/pages.rb', line 147

def move(page, to_index)
  @document.catalog.pages.move_page(page, to_index)
end

#page_label(page_index) ⇒ Object

Returns the constructed page label for the given page index.

If no page labels are defined, nil is returned.

See HexaPDF::Type::PageLabel for examples.

Raises:

  • (ArgumentError)


194
195
196
197
198
199
200
201
# File 'lib/hexapdf/document/pages.rb', line 194

def page_label(page_index)
  raise(ArgumentError, 'Page index out of range') if page_index < 0 || page_index >= count
  each_labelling_range do |index, count, label|
    if page_index < index + count
      return label.construct_label(page_index - index)
    end
  end
end

#rootObject

Returns the root of the page tree, a HexaPDF::Type::PageTreeNode object.



74
75
76
# File 'lib/hexapdf/document/pages.rb', line 74

def root
  @document.catalog.pages
end