# encoding: utf-8 # # pdf_object.rb : Handles Ruby to PDF object serialization # # Copyright April 2008, Gregory Brown. All Rights Reserved. # # This is free software. Please see the LICENSE and COPYING files for details. # Top level Module # module PDF module Core module_function def real(num) num.to_f.round(4) end def real_params(array) array.map { |e| real(e) }.join(" ") end def utf8_to_utf16(str) "\xFE\xFF".force_encoding(::Encoding::UTF_16BE) + str.encode(::Encoding::UTF_16BE) end # 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 def string_to_hex(str) str.unpack("H*").first.force_encoding(::Encoding::US_ASCII) end # 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: # # PdfObject(true) #=> "true" # PdfObject(false) #=> "false" # PdfObject(1.2124) #=> "1.2124" # PdfObject("foo bar") #=> "(foo bar)" # PdfObject(:Symbol) #=> "/Symbol" # PdfObject(["foo",:bar, [1,2]]) #=> "[foo /bar [1 2]]" # def PdfObject(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.kind_of?(Integer) String(obj) # NOTE: this can fail on huge floating point numbers, # but it seems unlikely to ever happen in practice. when Array "[" << obj.map { |e| PdfObject(e, in_content_stream) }.join(' ') << "]" when PDF::Core::LiteralString obj = obj.gsub(/[\\\n\r\t\b\f\(\)]/n) { |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\(\)]/n) { |m| "\\#{m}" } "(#{obj})" when PDF::Core::ByteString "<" << obj.unpack("H*").first << ">" when String obj = utf8_to_utf16(obj) unless in_content_stream "<" << string_to_hex(obj) << ">" when Symbol "/" + obj.to_s.unpack("C*").map { |n| if n < 33 || n > 126 || [35,40,41,47,60,62].include?(n) "#" + n.to_s(16).upcase else [n].pack("C*") end }.join when ::Hash output = "<< " obj.each do |k,v| unless String === k || Symbol === k raise PDF::Core::Errors::FailedObjectConversion, "A PDF Dictionary must be keyed by names" end output << PdfObject(k.to_sym, in_content_stream) << " " << PdfObject(v, in_content_stream) << "\n" end output << ">>" when PDF::Core::Reference obj.to_s when PDF::Core::NameTree::Node PdfObject(obj.to_hash) when PDF::Core::NameTree::Value PdfObject(obj.name) + " " + PdfObject(obj.value) when PDF::Core::OutlineRoot, PDF::Core::OutlineItem PdfObject(obj.to_hash) else raise PDF::Core::Errors::FailedObjectConversion, "This object cannot be serialized to PDF (#{obj.inspect})" end end end end