Module: PDF::Core

Defined in:
lib/pdf/core.rb,
lib/pdf/core/page.rb,
lib/pdf/core/text.rb,
lib/pdf/core/utils.rb,
lib/pdf/core/stream.rb,
lib/pdf/core/filters.rb,
lib/pdf/core/renderer.rb,
lib/pdf/core/name_tree.rb,
lib/pdf/core/reference.rb,
lib/pdf/core/pdf_object.rb,
lib/pdf/core/annotations.rb,
lib/pdf/core/byte_string.rb,
lib/pdf/core/filter_list.rb,
lib/pdf/core/destinations.rb,
lib/pdf/core/object_store.rb,
lib/pdf/core/outline_item.rb,
lib/pdf/core/outline_root.rb,
lib/pdf/core/page_geometry.rb,
lib/pdf/core/document_state.rb,
lib/pdf/core/graphics_state.rb,
lib/pdf/core/literal_string.rb

Overview

PDF::Core is concerned with low-level PDF functions such as serialization, content streams and such.

It’s extracted from Prawn but at the moment is not entirely independent.

Defined Under Namespace

Modules: Annotations, Destinations, Errors, Filters, NameTree, PageGeometry, Text, Utils Classes: ByteString, DocumentState, FilterList, GraphicState, GraphicStateStack, LiteralString, ObjectStore, OutlineItem, OutlineRoot, Page, Reference, Renderer, Stream

Constant Summary collapse

ESCAPED_NAME_CHARACTERS =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Characters to escape in name objects

(1..32).to_a + [35, 40, 41, 47, 60, 62] + (127..255).to_a
STRING_ESCAPE_MAP =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

How to escape special characters in literal strings

{ '(' => '\(', ')' => '\)', '\\' => '\\\\', "\r" => '\r' }.freeze

Class Method Summary collapse

Class Method Details

.pdf_object(obj, in_content_stream = false) ⇒ String

Serializes Ruby objects to their PDF equivalents. Most primitive objects will work as expected, but please note that Name objects are represented by Ruby Symbol objects and Dictionary objects are represented by Ruby hashes (keyed by symbols)

Examples:

pdf_object(true)      #=> "true"
pdf_object(false)     #=> "false"
pdf_object(1.2124)    #=> "1.2124"
pdf_object('foo bar') #=> "(foo bar)"
pdf_object(:Symbol)   #=> "/Symbol"
pdf_object(['foo',:bar, [1,2]]) #=> "[foo /bar [1 2]]"

Parameters:

Returns:

  • (String)

Raises:

Source Code
lib/pdf/core/pdf_object.rb, line 77
77
def pdf_object(obj, in_content_stream = false)
78
  case obj
79
  when NilClass then 'null'
80
  when TrueClass then 'true'
81
  when FalseClass then 'false'
82
  when Numeric
83
    num_string = obj.is_a?(Integer) ? String(obj) : real(obj)
84
85
    # Truncate trailing fraction zeroes
86
    num_string.sub!(/(\d*)((\.0*$)|(\.0*[1-9]*)0*$)/, '\1\4')
87
    num_string
88
  when Array
89
    "[#{obj.map { |e| pdf_object(e, in_content_stream) }.join(' ')}]"
90
  when PDF::Core::LiteralString
91
    obj = obj.gsub(/[\\\r()]/, STRING_ESCAPE_MAP)
92
    "(#{obj})"
93
  when Time
94
    obj = "#{obj.strftime('D:%Y%m%d%H%M%S%z').chop.chop}'00'"
95
    obj = obj.gsub(/[\\\r()]/, STRING_ESCAPE_MAP)
96
    "(#{obj})"
97
  when PDF::Core::ByteString
98
    "<#{obj.unpack1('H*')}>"
99
  when String
100
    obj = utf8_to_utf16(obj) unless in_content_stream
101
    "<#{string_to_hex(obj)}>"
102
  when Symbol
103
    (@symbol_str_cache ||= {})[obj] ||= (+'/') << obj.to_s.unpack('C*').map { |n|
104
      if ESCAPED_NAME_CHARACTERS.include?(n)
105
        "##{n.to_s(16).upcase}"
106
      else
107
        n.chr
108
      end
109
    }.join
110
  when ::Hash
111
    output = +'<< '
112
    obj
113
      .sort_by { |k, _v| k.to_s }
114
      .each do |(k, v)|
115
      unless k.is_a?(String) || k.is_a?(Symbol)
116
        raise PDF::Core::Errors::FailedObjectConversion,
117
          'A PDF Dictionary must be keyed by names'
118
      end
119
      output << pdf_object(k.to_sym, in_content_stream) << ' ' <<
120
        pdf_object(v, in_content_stream) << "\n"
121
    end
122
    output << '>>'
123
  when PDF::Core::Reference
124
    obj.to_s
125
  when PDF::Core::NameTree::Node, PDF::Core::OutlineRoot, PDF::Core::OutlineItem
126
    pdf_object(obj.to_hash)
127
  when PDF::Core::NameTree::Value
128
    "#{pdf_object(obj.name)} #{pdf_object(obj.value)}"
129
  else
130
    raise PDF::Core::Errors::FailedObjectConversion,
131
      "This object cannot be serialized to PDF (#{obj.inspect})"
132
  end
133
end

.real(num) ⇒ String

Serializes floating number into a string

Parameters:

  • num (Numeric)

Returns:

  • (String)
Source Code
lib/pdf/core/pdf_object.rb, line 11
11
def real(num)
12
  result = format('%.5f', num)
13
  result.sub!(/((?<!\.)0)+\z/, '')
14
  result
15
end

.real_params(array) ⇒ String

Serializes a n array of numbers. This is specifically for use in PDF content streams.

Parameters:

  • array (Array<Numeric>)

Returns:

  • (String)
Source Code
lib/pdf/core/pdf_object.rb, line 22
22
def real_params(array)
23
  array.map { |e| real(e) }.join(' ')
24
end

.string_to_hex(str) ⇒ String

Encodes any string into a hex representation. The result is a string with only 0-9 and a-f characters. That result is valid ASCII so tag it as such to account for behaviour of different ruby VMs.

Parameters:

  • str (String)

Returns:

  • (String)
Source Code
lib/pdf/core/pdf_object.rb, line 42
42
def string_to_hex(str)
43
  str.unpack1('H*').force_encoding(::Encoding::US_ASCII)
44
end

.utf8_to_utf16(str) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Converts string to UTF-16BE encoding as expected by PDF.

Parameters:

  • str (String)

Returns:

  • (String)
Source Code
lib/pdf/core/pdf_object.rb, line 31
31
def utf8_to_utf16(str)
32
  (+"\xFE\xFF").force_encoding(::Encoding::UTF_16BE) <<
33
    str.encode(::Encoding::UTF_16BE)
34
end