Class: HexaPDF::Document::Destinations

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

Overview

This class provides methods for creating and managing the destinations of a PDF file.

A destination describes a particular view of a PDF document, consisting of the page, the view location and a magnification factor. See Destination for details.

Such destinations may be directly specified where needed, e.g. for link annotations, or they may be named and later referenced through the name. This class allows to create destinations with or without a name.

See: PDF1.7 s12.3.2

Defined Under Namespace

Classes: Destination

Instance Method Summary collapse

Constructor Details

#initialize(document) ⇒ Destinations

Creates a new Destinations object for the given PDF document.



227
228
229
# File 'lib/hexapdf/document/destinations.rb', line 227

def initialize(document)
  @document = document
end

Instance Method Details

#[](name) ⇒ Object

:call-seq:

destinations[name]    -> destination

Returns the destination registered under the given name or nil if no destination was registered under that name.



492
493
494
# File 'lib/hexapdf/document/destinations.rb', line 492

def [](name)
  destinations.find_entry(name)
end

#add(name, destination) ⇒ Object

:call-seq:

destinations.add(name, destination)

Adds the given destination under name to the destinations name tree.

If the name does already exist, an error is raised.



444
445
446
# File 'lib/hexapdf/document/destinations.rb', line 444

def add(name, destination)
  destinations.add_entry(name, destination)
end

#create(type, page, **options) ⇒ Object

:call-seq:

destinations.create(type, page, **options)      -> dest or name

Creates a new destination array with the given type (see Destination for all available type names; PDF internal type names are also allowed) and page by calling the respective create_type method.



303
304
305
# File 'lib/hexapdf/document/destinations.rb', line 303

def create(type, page, **options)
  send("create_#{Destination::TYPE_MAPPING.fetch(type, type)}", page, **options)
end

#create_fit_bounding_box(page, name: nil) ⇒ Object

:call-seq:

destinations.create_fit_bounding_box(page)            -> dest
destinations.create_fit_bounding_box(page, name: nil) -> name

Creates a new fit to bounding box destination array for the given arguments and returns it or, in case a name is given, the name.

The argument page is described in detail in the Destination class description.

If the argument name is given, the created destination array is added to the destinations name tree under that name for reuse later, overwriting an existing entry if there is one.



401
402
403
404
# File 'lib/hexapdf/document/destinations.rb', line 401

def create_fit_bounding_box(page, name: nil)
  destination = [page, Destination::REVERSE_TYPE_MAPPING.fetch(:fit_bounding_box)]
  name ? (add(name, destination); name) : destination
end

#create_fit_bounding_box_horizontal(page, name: nil, top: nil) ⇒ Object

:call-seq:

destinations.create_fit_bounding_box_horizontal(page, top: nil)            -> dest
destinations.create_fit_bounding_box_horizontal(page, name: nil, top: nil) -> name

Creates a new fit bounding box horizontal destination array for the given arguments and returns it or, in case a name is given, the name.

The arguments +page and top are described in detail in the Destination class description.

If the argument name is given, the created destination array is added to the destinations name tree under that name for reuse later, overwriting an existing entry if there is one.



417
418
419
420
# File 'lib/hexapdf/document/destinations.rb', line 417

def create_fit_bounding_box_horizontal(page, name: nil, top: nil)
  destination = [page, Destination::REVERSE_TYPE_MAPPING.fetch(:fit_bounding_box_horizontal), top]
  name ? (add(name, destination); name) : destination
end

#create_fit_bounding_box_vertical(page, name: nil, left: nil) ⇒ Object

:call-seq:

destinations.create_fit_bounding_box_vertical(page, left: nil)            -> dest
destinations.create_fit_bounding_box_vertical(page, name: nil, left: nil) -> name

Creates a new fit bounding box vertical destination array for the given arguments and returns it or, in case a name is given, the name.

The arguments +page and left are described in detail in the Destination class description.

If the argument name is given, the created destination array is added to the destinations name tree under that name for reuse later, overwriting an existing entry if there is one.



433
434
435
436
# File 'lib/hexapdf/document/destinations.rb', line 433

def create_fit_bounding_box_vertical(page, name: nil, left: nil)
  destination = [page, Destination::REVERSE_TYPE_MAPPING.fetch(:fit_bounding_box_vertical), left]
  name ? (add(name, destination); name) : destination
end

#create_fit_page(page, name: nil) ⇒ Object

:call-seq:

destinations.create_fit_page(page)            -> dest
destinations.create_fit_page(page, name: nil) -> name

Creates a new fit to page destination array for the given arguments and returns it or, in case a name is given, the name.

The argument page is described in detail in the Destination class description.

If the argument name is given, the created destination array is added to the destinations name tree under that name for reuse later, overwriting an existing entry if there is one.



335
336
337
338
# File 'lib/hexapdf/document/destinations.rb', line 335

def create_fit_page(page, name: nil)
  destination = [page, Destination::REVERSE_TYPE_MAPPING.fetch(:fit_page)]
  name ? (add(name, destination); name) : destination
end

#create_fit_page_horizontal(page, name: nil, top: nil) ⇒ Object

:call-seq:

destinations.create_fit_page_horizontal(page, top: nil)            -> dest
destinations.create_fit_page_horizontal(page, name: nil, top: nil) -> name

Creates a new fit page horizontal destination array for the given arguments and returns it or, in case a name is given, the name.

The arguments +page and top are described in detail in the Destination class description.

If the argument name is given, the created destination array is added to the destinations name tree under that name for reuse later, overwriting an existing entry if there is one.



351
352
353
354
# File 'lib/hexapdf/document/destinations.rb', line 351

def create_fit_page_horizontal(page, name: nil, top: nil)
  destination = [page, Destination::REVERSE_TYPE_MAPPING.fetch(:fit_page_horizontal), top]
  name ? (add(name, destination); name) : destination
end

#create_fit_page_vertical(page, name: nil, left: nil) ⇒ Object

:call-seq:

destinations.create_fit_page_vertical(page, left: nil)            -> dest
destinations.create_fit_page_vertical(page, name: nil, left: nil) -> name

Creates a new fit page vertical destination array for the given arguments and returns it or, in case a name is given, the name.

The arguments +page and left are described in detail in the Destination class description.

If the argument name is given, the created destination array is added to the destinations name tree under that name for reuse later, overwriting an existing entry if there is one.



367
368
369
370
# File 'lib/hexapdf/document/destinations.rb', line 367

def create_fit_page_vertical(page, name: nil, left: nil)
  destination = [page, Destination::REVERSE_TYPE_MAPPING.fetch(:fit_page_vertical), left]
  name ? (add(name, destination); name) : destination
end

#create_fit_rectangle(page, left:, bottom:, right:, top:, name: nil) ⇒ Object

:call-seq:

destinations.create_fit_rectangle(page, left:, bottom:, right:, top:)            -> dest
destinations.create_fit_rectangle(page, name: nil, left:, bottom:, right:, top:) -> name

Creates a new fit to rectangle destination array for the given arguments and returns it or, in case a name is given, the name.

The arguments page, left, bottom, right and top are described in detail in the Destination class description.

If the argument name is given, the created destination array is added to the destinations name tree under that name for reuse later, overwriting an existing entry if there is one.



384
385
386
387
388
# File 'lib/hexapdf/document/destinations.rb', line 384

def create_fit_rectangle(page, left:, bottom:, right:, top:, name: nil)
  destination = [page, Destination::REVERSE_TYPE_MAPPING.fetch(:fit_rectangle),
                 left, bottom, right, top]
  name ? (add(name, destination); name) : destination
end

#create_xyz(page, name: nil, left: nil, top: nil, zoom: nil) ⇒ Object

:call-seq:

destinations.create_xyz(page, left: nil, top: nil, zoom: nil)            -> dest
destinations.create_xyz(page, name: nil, left: nil, top: nil, zoom: nil) -> name

Creates a new xyz destination array for the given arguments and returns it or, in case a name is given, the name.

The arguments page, left, top and zoom are described in detail in the Destination class description.

If the argument name is given, the created destination array is added to the destinations name tree under that name for reuse later, overwriting an existing entry if there is one.



319
320
321
322
# File 'lib/hexapdf/document/destinations.rb', line 319

def create_xyz(page, name: nil, left: nil, top: nil, zoom: nil)
  destination = [page, Destination::REVERSE_TYPE_MAPPING.fetch(:xyz), left, top, zoom]
  name ? (add(name, destination); name) : destination
end

#delete(name) ⇒ Object

:call-seq:

destinations.delete(name)    -> destination

Deletes the given destination from the destinations name tree and returns it or nil if no destination was registered under that name.



453
454
455
# File 'lib/hexapdf/document/destinations.rb', line 453

def delete(name)
  destinations.delete_entry(name)
end

#eachObject

:call-seq:

destinations.each {|name, dest| block }  -> destinations
destinations.each                        -> Enumerator

Iterates over all named destinations of the PDF, yielding the name and the destination

wrapped into a Destination object.


502
503
504
505
506
507
508
509
510
# File 'lib/hexapdf/document/destinations.rb', line 502

def each
  return to_enum(__method__) unless block_given?

  destinations.each_entry do |name, dest|
    yield(name, Destination.new(dest))
  end

  self
end

#resolve(value) ⇒ Object

:call-seq:

destinations.resolve(string_name)    -> destination or nil
destinations.resolve(symbol_name)    -> destination or nil
destinations.resolve(dest_array)     -> destination or nil

Resolves the given value to a valid destination object, if possible, or otherwise returns nil.

  • If the given value is a string, it is treated as a destination name and looked up in the destination name tree.

  • If the given value is a symbol, it is treated as an old-style destination name and looked up in the destination dictionary.

  • If the given value is an array, it is treated as a destination array itself.



472
473
474
475
476
477
478
479
480
481
482
483
484
485
# File 'lib/hexapdf/document/destinations.rb', line 472

def resolve(value)
  result = case value
           when String
             destinations.find_entry(value)
           when PDFArray
             value.value
           when Array
             value
           when Symbol
             @document.catalog[:Dests]&.[](value)
           end
  result = Destination.new(result) if result
  result&.valid? ? result : nil
end

#use_or_create(value) ⇒ Object

:call-seq:

destinations.use_or_create(name)           -> name
destinations.use_or_create(destination)    -> destination
destinations.use_or_create(page)           -> destination
destinations.use_or_create(type:, page, **options)           -> destination

Uses the given destination name/array or creates a destination array based on the given value.

This is the main utility method for other parts of HexaPDF for getting a valid destination array based on various different types of the given value:

String

If a string is provided, it is assumed to be a named destination. If the named destination exists, the value itself is returned. Otherwise an error is raised.

Array

If a valid destination array is provided, it is returned. Otherwise an error is raised.

Page dictionary

If the value is a valid page dictionary object, a fit to page (#create_fit_page) destination array is created and returned.

Integer

If the value is an integer, it is interpreted as a zero-based page index and a fit to page (#create_fit_page) destination array is created and returned.

Hash containing at least :type and :page

If the value is a hash, the :type key specifies the type of the destination that should be created and the :page key the target page. Which other keys are allowed depends on the destination type, so see the various create_XXX methods. Uses #create to do the job.



267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'lib/hexapdf/document/destinations.rb', line 267

def use_or_create(value)
  case value
  when String
    if self[value]
      value
    else
      raise HexaPDF::Error, "Named destination '#{value}' doesn't exist"
    end
  when Array
    raise HexaPDF::Error, "Invalid destination array" unless Destination.new(value).valid?
    value
  when HexaPDF::Dictionary
    if value.type != :Page
      raise HexaPDF::Error, "Invalid dictionary type '#{value.type}' given, needs to be a page"
    end
    create_fit_page(value)
  when Integer
    if value < 0 || value >= @document.pages.count
      raise ArgumentError, "Page index #{value} out of bounds"
    end
    create_fit_page(@document.pages[value])
  when Hash
    type = value.delete(:type) { raise ArgumentError, "Missing keyword argument :type" }
    page = value.delete(:page) { raise ArgumentError, "Missing keyword argument :page" }
    create(type, page, **value)
  else
    raise ArgumentError, "Invalid argument type '#{value.class}'"
  end
end