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

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 =
(1..32).to_a + [35, 40, 41, 47, 60, 62] + (127..255).to_a

Class Method Summary collapse

Class Method Details

.pdf_object(obj, in_content_stream = false) ⇒ Object

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]]"


51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/pdf/core/pdf_object.rb', line 51

def pdf_object(obj, in_content_stream = false)
  case obj
  when NilClass   then 'null'
  when TrueClass  then 'true'
  when FalseClass then 'false'
  when Numeric
    obj = real(obj) unless obj.is_a?(Integer)

    # NOTE: this can fail on huge floating point numbers, but it seems
    # unlikely to ever happen in practice.
    num_string = String(obj)

    # Truncate trailing fraction zeroes
    num_string.sub(/(\d*)((\.0*$)|(\.0*[1-9]*)0*$)/, '\1\4')
  when Array
    "[#{obj.map { |e| pdf_object(e, in_content_stream) }.join(' ')}]"
  when PDF::Core::LiteralString
    obj = obj.gsub(/[\\\n\r\t\b\f()]/) { |m| "\\#{m}" }
    "(#{obj})"
  when Time
    obj = "#{obj.strftime('D:%Y%m%d%H%M%S%z').chop.chop}'00'"
    obj = obj.gsub(/[\\\n\r\t\b\f()]/) { |m| "\\#{m}" }
    "(#{obj})"
  when PDF::Core::ByteString
    "<#{obj.unpack1('H*')}>"
  when String
    obj = utf8_to_utf16(obj) unless in_content_stream
    "<#{string_to_hex(obj)}>"
  when Symbol
    name_string =
      obj.to_s.unpack('C*').map do |n|
        if ESCAPED_NAME_CHARACTERS.include?(n)
          "##{n.to_s(16).upcase}"
        else
          [n].pack('C*')
        end
      end.join
    "/#{name_string}"
  when ::Hash
    output = +'<< '
    obj.each do |k, v|
      unless k.is_a?(String) || k.is_a?(Symbol)
        raise PDF::Core::Errors::FailedObjectConversion,
          'A PDF Dictionary must be keyed by names'
      end
      output << pdf_object(k.to_sym, in_content_stream) << ' ' <<
        pdf_object(v, in_content_stream) << "\n"
    end
    output << '>>'
  when PDF::Core::Reference
    obj.to_s
  when PDF::Core::NameTree::Node
    pdf_object(obj.to_hash)
  when PDF::Core::NameTree::Value
    "#{pdf_object(obj.name)} #{pdf_object(obj.value)}"
  when PDF::Core::OutlineRoot, PDF::Core::OutlineItem
    pdf_object(obj.to_hash)
  else
    raise PDF::Core::Errors::FailedObjectConversion,
      "This object cannot be serialized to PDF (#{obj.inspect})"
  end
end

.real(num) ⇒ Object



15
16
17
# File 'lib/pdf/core/pdf_object.rb', line 15

def real(num)
  format('%<number>.5f', number: num).sub(/((?<!\.)0)+\z/, '')
end

.real_params(array) ⇒ Object



19
20
21
# File 'lib/pdf/core/pdf_object.rb', line 19

def real_params(array)
  array.map { |e| real(e) }.join(' ')
end

.string_to_hex(str) ⇒ Object

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



31
32
33
# File 'lib/pdf/core/pdf_object.rb', line 31

def string_to_hex(str)
  str.unpack1('H*').force_encoding(::Encoding::US_ASCII)
end

.utf8_to_utf16(str) ⇒ Object



23
24
25
26
# File 'lib/pdf/core/pdf_object.rb', line 23

def utf8_to_utf16(str)
  (+"\xFE\xFF").force_encoding(::Encoding::UTF_16BE) +
    str.encode(::Encoding::UTF_16BE)
end