Class: Fasttrack::XMP

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/fasttrack/xmp.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(xmp_ptr = nil) ⇒ XMP

Creates a new XMP object. If a pointer to an XMP chunk is provided, a copy of it will be used; otherwise, a new empty XMP chunk will be created.

Note that if you create an XMP object from a pre-existing pointer, you’ll need to remember to free the original pointer with xmp_free(). Garbage collection will only free the Fasttrack::XMP version for you.

Parameters:

  • xmp_ptr (FFI::Pointer, nil) (defaults to: nil)

    XMP pointer to use, or nil



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/fasttrack/xmp.rb', line 34

def initialize xmp_ptr=nil
  if xmp_ptr and xmp_ptr.is_a? FFI::Pointer
    @xmp_ptr = Exempi.xmp_copy xmp_ptr
  else
    @xmp_ptr = Exempi.xmp_new_empty
  end

  @iterator = nil
  @iterator_opts = nil

  # capture the namespaces that exist at load time, with
  # a count of the number of times each uri is present
  ns_ary = map {|ns,_,_,_| ns}
  @namespaces = ns_ary.uniq.each_with_object(Hash.new(0)) do |ns, hsh|
    hsh[ns] = ns_ary.count(ns) - 1 # one empty item returned per ns
  end

  ObjectSpace.define_finalizer(self, self.class.finalize(@xmp_ptr))
end

Instance Attribute Details

#xmp_ptrFFI::Pointer

The Exempi C pointer for this object. You normally shouldn’t need to access this, but it is exposed so that unwrapped Exempi functions can be called on Fasttrack-tracked objects.

Returns:

  • (FFI::Pointer)


13
14
15
# File 'lib/fasttrack/xmp.rb', line 13

def xmp_ptr
  @xmp_ptr
end

Class Method Details

.finalize(pointer) ⇒ Object



17
18
19
# File 'lib/fasttrack/xmp.rb', line 17

def self.finalize pointer
  proc { Exempi.xmp_free pointer }
end

.finalize_iterator(pointer) ⇒ Object



21
22
23
# File 'lib/fasttrack/xmp.rb', line 21

def self.finalize_iterator pointer
  proc { Exempi.xmp_iterator_free pointer }
end

.from_file_pointer(file_ptr) ⇒ Fasttrack::XMP

Creates a new XMP object based on the metadata in a file represented by an Exempi file pointer. The file must already have been opened using xmp_files_open()

Parameters:

  • file_ptr (FFI::Pointer)

    an Exempi pointer

Returns:



59
60
61
62
63
64
65
# File 'lib/fasttrack/xmp.rb', line 59

def self.from_file_pointer file_ptr
  xmp_ptr = Exempi.xmp_files_get_new_xmp file_ptr
  xmp = Fasttrack::XMP.new xmp_ptr
  Exempi.xmp_free xmp_ptr

  xmp
end

.parse(xml) ⇒ Fasttrack::XMP

Creates a new XMP object from an XML string.

Parameters:

  • xml (String)

    a string containing valid XMP

Returns:



70
71
72
73
74
75
76
# File 'lib/fasttrack/xmp.rb', line 70

def self.parse xml
  ptr = Exempi.xmp_new xml, xml.bytesize
  xmp = Fasttrack::XMP.new ptr
  Exempi.xmp_free ptr

  xmp
end

Instance Method Details

#==(other_xmp) ⇒ Object



220
221
222
# File 'lib/fasttrack/xmp.rb', line 220

def == other_xmp
  serialize == other_xmp.serialize
end

#[](query) ⇒ String?

Fetches an XMP property given a string containing the namespace prefix and the property name, e.g. “tiff:Make”.

Examples:

Returns the value of ‘tiff:Make’

xmp['tiff:Make'] #=> 'Sony'

Parameters:

  • query (String)

    query

Returns:

  • (String, nil)

    the property’s value, or nil if not found



157
158
159
160
161
162
163
164
165
# File 'lib/fasttrack/xmp.rb', line 157

def [] query
  if query =~ /.+:.+/
    ns_prefix, property = query.scan(/(.+):(.+)/).flatten
  end

  ns_uri = namespace_for ns_prefix.downcase.to_sym

  get_property ns_uri, property
end

#[]=(property, value) ⇒ String

Sets an XMP property given a string containing the namespace prefix and the property name, e.g. “tiff:Make”.

Examples:

Sets the value of ‘tiff:Make’ to ‘Sony’

xmp['tiff:Make'] = 'Sony' #=> 'Sony'

Parameters:

  • property (String)

    property

  • value (String)

    value to set

Returns:

  • (String)

    the new value



174
175
176
177
178
179
180
181
182
# File 'lib/fasttrack/xmp.rb', line 174

def []= property, value
  if property =~ /.+:.+/
    ns_prefix, property = property.scan(/(.+):(.+)/).flatten
  end

  ns_uri = namespace_for ns_prefix.downcase.to_sym

  set_property ns_uri, property, value
end

#delete(namespace, prop) ⇒ String? Also known as: delete_property

Deletes a given XMP property. If the property exists returns the deleted property, otherwise returns nil.

Parameters:

  • namespace (String, Symbol)

    namespace URI to use. If a symbol is provided, Fasttrack will look up the URI from a set of common recognized namespaces.

  • prop (String)

    property to look up.

Returns:

  • (String, nil)

    the value of the deleted property, or nil if not found.



189
190
191
192
193
194
195
196
197
198
199
# File 'lib/fasttrack/xmp.rb', line 189

def delete namespace, prop
  if namespace.is_a? Symbol
    namespace = namespace_for namespace
  end

  deleted_prop = get_property namespace, prop
  Exempi.xmp_delete_property @xmp_ptr, namespace, prop
  @namespaces[namespace] -= 1 unless deleted_prop.nil?

  deleted_prop
end

#each {|uri, name, value, options| ... } ⇒ Object

Yield Parameters:

  • uri (String)

    the uri for the property

  • name (String)

    the property’s name

  • value (String)

    the property’s value

  • options (Hash)

    additional metadata about the property



225
226
227
228
229
230
231
# File 'lib/fasttrack/xmp.rb', line 225

def each &block
  return to_enum unless block_given?

  iterate_for do |returned|
    block.call(returned)
  end
end

#each_in_namespace(ns, opts = []) {|uri, name, value, options| ... } ⇒ Enumerator

Iterates over all properties in a specified namespace. The namespace parameter can be the URI of the namespace to use, or a symbol representing the namespace prefix, e.g. :exif. The recognized namespace prefixes are based on a set of common namespace prefixes (generated at runtime in Fasttrack::NAMESPACES) as well as the local namespaces currently in use.

Parameters:

  • ns (String, Symbol)

    namespace to iterate over

  • opts (Array<Symbol>) (defaults to: [])

    a set of options to restrict the iteration; see #each_with_options for supported options

Yield Parameters:

  • uri (String)

    the uri for the property

  • name (String)

    the property’s name

  • value (String)

    the property’s value

  • options (Hash)

    additional metadata about the property

Returns:

  • (Enumerator)

    if no block is given



273
274
275
276
277
278
279
280
# File 'lib/fasttrack/xmp.rb', line 273

def each_in_namespace ns, opts=[], &block
  return enum_for(:each_in_namespace, ns) unless block_given?

  opts = {:namespace => ns}
  iterate_for(opts) do |returned|
    block.call(returned)
  end
end

#each_with_options(opts) {|uri, name, value, options| ... } ⇒ Enumerator

Iterates over all properties, with the iteration rules guided by the specified options. Options should be specified in an array.

Parameters:

  • opts (Array<Symbol>)

    array of one or more options

Options Hash (opts):

  • :properties (Object)

    Iterate the property tree of a TXMPMeta object.

  • :aliases (Object)

    Iterate the global namespace table.

  • :just_children (Object)

    Just do the immediate children of the root, default is subtree.

  • :just_leaf_nodes (Object)

    Just do the leaf nodes, default is all nodes in the subtree.

  • :just_leaf_name (Object)

    Return just the leaf part of the path, default is the full path.

  • :include_aliases (Object)

    Include aliases, default is just actual properties.

  • :omit_qualifiers (Object)

    Omit all qualifiers.

Yield Parameters:

  • uri (String)

    the uri for the property

  • name (String)

    the property’s name

  • value (String)

    the property’s value

  • options (Hash)

    additional metadata about the property

Returns:

  • (Enumerator)

    if no block is given



250
251
252
253
254
255
256
257
258
259
260
# File 'lib/fasttrack/xmp.rb', line 250

def each_with_options opts, &block
  return enum_for(:each_with_options, opts) unless block_given?

  options = opts.map {|o| ("XMP_ITER_"+o.to_s.delete("_")).to_sym}
  # filter out invalid options
  options.keep_if {|o| Exempi::XMP_ITER_OPTIONS.find o}

  iterate_for({:options => options}) do |returned|
    block.call(returned)
  end
end

#get(namespace, prop) ⇒ String? Also known as: get_property

Return an object from the global namespace.

Examples:

Gets the value of the ‘tiff:Make’ property

xmp.get :tiff, 'tiff:Make' #=> 'Sony'
# you can also leave off the namespace prefix
xmp.get :tiff, 'Make' #=> 'Sony'
# You can use the namespace URI string too
xmp.get 'http://ns.adobe.com/tiff/1.0/', 'Make' #=> 'Sony'

Parameters:

  • namespace (String, Symbol)

    namespace URI to use. If a symbol is provided, Fasttrack will look up the URI from a set of common recognized namespaces.

  • prop (String)

    property to look up.

Returns:

  • (String, nil)

    the value of the requested property, or nil if not found.



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/fasttrack/xmp.rb', line 102

def get namespace, prop
  if namespace.is_a? Symbol
    namespace = namespace_for namespace
  end

  prop_str = Exempi.xmp_string_new
  success = Exempi.xmp_get_property @xmp_ptr, namespace, prop, prop_str, nil
  if success
    result = Exempi.xmp_string_cstr prop_str

    result
  else
    result = nil
  end

  Exempi.xmp_string_free prop_str

  result
end

#initialize_copy(orig) ⇒ Object

This ensures that the clone is created with a new XMP pointer.



79
80
81
82
83
84
85
86
87
# File 'lib/fasttrack/xmp.rb', line 79

def initialize_copy orig
  super
  @xmp_ptr = Exempi.xmp_copy @xmp_ptr

  # if we don't do this, the new clone's finalizer will reference
  # the pointer from the original object - not the clone's
  ObjectSpace.undefine_finalizer self
  ObjectSpace.define_finalizer(self, self.class.finalize(@xmp_ptr))
end

#namespacesArray<String>

Returns a list of namespace URIs in use in the specified XMP data.

Returns:

  • (Array<String>)

    an array of URI strings



205
206
207
# File 'lib/fasttrack/xmp.rb', line 205

def namespaces
  @namespaces.keys
end

#rewindObject



282
283
284
# File 'lib/fasttrack/xmp.rb', line 282

def rewind
  @iterator = new_iterator
end

#serializeString

Serializes the XMP object to an XML string.

Returns:

  • (String)


211
212
213
214
215
216
217
218
# File 'lib/fasttrack/xmp.rb', line 211

def serialize
  xmp_str = Exempi.xmp_string_new
  Exempi.xmp_serialize @xmp_ptr, xmp_str, 0, 0
  string = Exempi.xmp_string_cstr xmp_str
  Exempi.xmp_string_free xmp_str

  string
end

#set(namespace, prop, value) ⇒ String Also known as: set_property

Modifies an existing XMP property or creates a new property with the specified value.

Examples:

Sets the ‘tiff:Make’ property to ‘Sony’

xmp.set :tiff, 'tiff:Make', 'Sony' #=> 'Sony'

Parameters:

  • namespace (String, Symbol)

    namespace to use. If a symbol is provided, Fasttrack will look up from a set of common recognized namespaces.

  • prop (String)

    property to set.

  • value (String)

    value to set.

Returns:

  • (String)

    the new value

Raises:

  • (Exempi::ExempiError)

    if Exempi reports that it failed



135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/fasttrack/xmp.rb', line 135

def set namespace, prop, value
  if namespace.is_a? Symbol
    namespace = namespace_for namespace
  end

  success = Exempi.xmp_set_property @xmp_ptr, namespace, prop, value, nil
  if success
    @namespaces[namespace] += 1
    value
  else
    Fasttrack.handle_exempi_failure
  end
end