Class: Riff::MetaEditor

Inherits:
Object
  • Object
show all
Defined in:
lib/riff/info.rb

Overview

Th MetaEditor class provides a reader-writer for the INFO meta-chunk on RIFF AVI and WAVE files.

Aside from the stated methods, there is a convenience method for every attribute name listed in the MetaEditor.available_names array, thus, these lines are equivalent:

editor.author = "Me Myself"
editor.artist = "Me Myself"
editor['IART'] = "Me Myself"

Note that some names map to the same fourcc.

Also note that RIFF INFO datums are generally encoded using ISO-8859-1 WinANSI. We expect to be able to support this more fully with Ruby 1.9 and its integrated text encoding facilities.

Constant Summary collapse

ATTRIBUTE_FOURCCs =
[ 'IARL', 'IART','ICSM','ICMT', 'ICOP', 'ICRD',
'ICRP', 'IDIM', 'IDPI', 'IENG','IGNR', 'IKEY',
'ILGT', 'IMED', 'INAM', 'IPLT', 'IPRD', 'ISBJ',
'ISFT', 'ISHP', 'ISRC', 'ISRF', 'ITCH']
ATTRIBUTE_NAMES =
{
 'Archival Location' =>  'IARL', 
 'Artist'            =>  'IART',
 'Author'            =>  'IART', 
 'Comissioned'       =>  'ICSM', 
 'Comment'           =>  'ICMT',
 'Description'       =>  'ICMT', 
 'Copyright'         =>  'ICOP', 
 'Date Created'      =>  'ICRD', 
 'Cropped'           =>  'ICRP', 
 'Dimensions'        =>  'IDIM', 
 'Dots Per Inch'     =>  'IDPI', 
 'Engineer'          =>  'IENG', 
 'Genre'             =>  'IGNR', 
 'Keywords'          =>  'IKEY', 
 'Lightness'         =>  'ILGT', 
 'Medium'            =>  'IMED', 
 'Title'             =>  'INAM',
 'Name'              =>  'INAM', 
 'Number of Colors'  =>  'IPLT', 
 'Product'           =>  'IPRD', 
 'Subject'           =>  'ISBJ', 
 'Software'          =>  'ISFT', 
 'Encoding Application' =>  'ISFT', 
 'Sharpness'         =>  'ISHP', 
 'Source'            =>  'ISRC', 
 'Source Form'       =>  'ISRF', 
 'Technician'        =>  'ITCH' 
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path) ⇒ MetaEditor

Creates a MetaEditor object for the file locates at path

If you provide a block, the MetaEditor itself will be yielded, and a save! will be called upon the block closing.



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/riff/info.rb', line 129

def initialize(path) #:yields: self
  reader = Reader.open(path,'r')
  @pad_out = 1024
  @path = path
  @metadata = {}
  @dirty = false
  infoChunk = reader.root_chunk.find {|c| c.signature == 'INFO'}
  if infoChunk && infoChunk.is_list?
    infoChunk.each do |subChunk|
      @metadata[subChunk.fourcc] = subChunk.body
    end
  end
  if block_given?
    yield self
    save!
  end
  self
end

Instance Attribute Details

#pad_outObject

the number of bytes padding to add after the INFO chunk. The default is 1024 bytes.



48
49
50
# File 'lib/riff/info.rb', line 48

def pad_out
  @pad_out
end

#pathObject (readonly)

the path to the file being edited



44
45
46
# File 'lib/riff/info.rb', line 44

def path
  @path
end

Class Method Details

.available_names(fourcc) ⇒ Object

Returns an array of all the settable attributes for the file



116
117
118
# File 'lib/riff/info.rb', line 116

def MetaEditor.available_names(fourcc)
  return ATTRIBUTE_NAMES.keys
end

.fourcc_for_name(name) ⇒ Object

Gives the fourcc the class will map to a given English name



121
122
123
# File 'lib/riff/info.rb', line 121

def MetaEditor.fourcc_for_name(name)
  return ATTRIBUTE_NAMES[name]
end

.names_for_fourcc(fourcc) ⇒ Object

Returns an array of English names for a fourcc tag



111
112
113
# File 'lib/riff/info.rb', line 111

def MetaEditor.names_for_fourcc(fourcc)
  return (ATTRIBUTE_NAMES.select {|k,v| v == fourcc}).map {|a| a[0]}
end

Instance Method Details

#[](fourcc) ⇒ Object

Get a metadatum by fourcc



149
150
151
# File 'lib/riff/info.rb', line 149

def [](fourcc)
  return @metadata[fourcc]
end

#[]=(fourcc, value) ⇒ Object

Set a metadatum by fourcc



154
155
156
157
# File 'lib/riff/info.rb', line 154

def []=(fourcc,value)
  @dirty = true
  @metadata[fourcc] = value
end

#each_metadatumObject

Yields each metadatum



160
161
162
163
164
# File 'lib/riff/info.rb', line 160

def each_metadatum
  @metadata.each_pair do |fourcc,value|
    yield fourcc,value
  end
end

#save!Object

Commit the changed metadata to the file. Presently, the complete file is rewritten to a temp file and then is moved to the name of the target.

If a pad_out number is specified, a “JUNK” chunk with a payload of pad_out bytes will be added after the INFO chunk.

If you have not modified any metadatums of the file, this method will have no effect on the system.



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/riff/info.rb', line 174

def save!
  return unless @dirty
  tempPath = File.dirname(path) + "/" + (([?a] *16).map {|i| (i + rand(26)).chr}).join + ".tmp"
  Reader.open(path,'r') do |reader|
    begin
      Builder.create(tempPath,reader.root_chunk.signature) do |riffwriter|
        riffwriter.list('INFO') do |infochunk|
          @metadata.each_pair do |key,value|
            infochunk.chunk(key) { |io| io << value }
          end
        end
        if @pad_out > 0
          riffwriter.chunk("JUNK") do |jnk|
            jnk << "\0" * @pad_out
          end
        end
        reader.root_chunk.each do |ck|
          unless ck.is_list? && ck.signature == 'INFO' then
            riffwriter.chunk(ck.fourcc) {|io| io << ck.body}
          end #unless
        end
      end
    rescue Exception => e
      File.unlink(tempPath) if FileTest.exist?(tempPath)
      raise e
    end
  end
  File.rename(tempPath,path)
end