depix 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -34,10 +34,10 @@ and method name
34
34
  * <tt>low_quantity</tt> Float
35
35
  * <tt>high_data</tt> Integer
36
36
  * <tt>high_quantity</tt> Float
37
- * <tt>descriptor</tt> String
38
- * <tt>transfer</tt> String
39
- * <tt>colorimetric</tt> String
40
- * <tt>bit_size</tt> String
37
+ * <tt>descriptor</tt> Integer
38
+ * <tt>transfer</tt> Integer
39
+ * <tt>colorimetric</tt> Integer
40
+ * <tt>bit_size</tt> Integer
41
41
  * <tt>packing</tt> Integer
42
42
  * <tt>encoding</tt> Integer
43
43
  * <tt>data_offset</tt> Integer
@@ -79,10 +79,10 @@ and method name
79
79
  * <tt>television</tt> hash of
80
80
  * <tt>time_code</tt> Integer
81
81
  * <tt>user_bits</tt> Integer
82
- * <tt>interlace</tt> String
83
- * <tt>field_number</tt> String
84
- * <tt>video_signal</tt> String
85
- * <tt>padding</tt> String
82
+ * <tt>interlace</tt> Integer
83
+ * <tt>field_number</tt> Integer
84
+ * <tt>video_signal</tt> Integer
85
+ * <tt>padding</tt> Integer
86
86
  * <tt>horizontal_sample_rate</tt> Float
87
87
  * <tt>vertical_sample_rate</tt> Float
88
88
  * <tt>frame_rate</tt> Float
data/History.txt CHANGED
@@ -1,3 +1,6 @@
1
+ === 1.0.1 / 2008-12-18
2
+ * small doc and usability improvements
3
+
1
4
  === 1.0.0 / 2008-12-18
2
5
 
3
6
  * 1 major enhancement
data/README.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  = depix
2
2
 
3
- * http://rubyforge.org/julik/depix
3
+ * http://wiretap.rubyforge.org/depix
4
4
 
5
5
  == DESCRIPTION:
6
6
 
@@ -8,7 +8,7 @@ Read DPX file metadata
8
8
 
9
9
  == SYNOPSIS:
10
10
 
11
- meta = Depix::Reader.new.from_file(dpx_file_path)
11
+ meta = Depix::Reader.from_file(dpx_file_path)
12
12
  puts meta.television.time_code #=> 10:00:00:02
13
13
 
14
14
  The data returned is described in the DPX_HEADER_STRUCTURE[link:files/DPX_HEADER_STRUCTURE_txt.html]. The structs
@@ -21,7 +21,11 @@ The gem also contains an executable called depix-desribe which can be used from
21
21
  == NOTES:
22
22
 
23
23
  The reader tries to be efficient - fast Ruby unpacking is used, some shortcuts are taken. Also don't worry - we do not need to read
24
- the whole DPX file (which usually is around 8mb per frame) to know the details
24
+ the whole DPX file (which usually is around 8mb per frame) to know the details.
25
+
26
+ In the future there will be a possibility to modify and commit the headers, but it's not a priority at this time.
27
+
28
+ Autodesk IFFS systems write the reel name for the file to the orientation.device field
25
29
 
26
30
  == REQUIREMENTS:
27
31
 
data/Rakefile CHANGED
@@ -6,6 +6,7 @@ Hoe.new('depix', Depix::VERSION) do |p|
6
6
  p.developer('Julik Tarkhanov', 'me@julik.nl')
7
7
  p.rubyforge_name = 'wiretap'
8
8
  p.extra_deps.reject! {|e| e[0] == 'hoe' }
9
+ p.remote_rdoc_dir = 'depix'
9
10
  end
10
11
 
11
12
  task :describe_structs do
data/bin/depix-describe CHANGED
@@ -1,8 +1,10 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require File.dirname(__FILE__) + '/../lib/depix'
4
- ARGV.flatten.each do | file |
4
+ if ARGV.flatten.map do | file |
5
5
  data = Depix::Reader.describe_file(file)
6
6
  puts "Describing DPX #{file}. Empty elements are omitted."
7
7
  puts data
8
+ end.empty?
9
+ STDERR.puts "Usage: depix-describe somefile.dpx anotherfile.dpx"
8
10
  end
data/lib/depix.rb CHANGED
@@ -5,8 +5,12 @@ require 'timecode'
5
5
  require File.dirname(__FILE__) + '/depix/structs'
6
6
 
7
7
  module Depix
8
- VERSION = '1.0.0'
9
- BLANK_4, BLANK_2 = 0xFFFFFFFF, 0xFFFF
8
+ VERSION = '1.0.1'
9
+
10
+ BLANK_2 = 0xFFFF #:nodoc:
11
+ BLANK_4 = 0xFFFFFFFF #:nodoc:
12
+ BLANK_F = 0xFFFFFFFF #:nodoc:
13
+ BLANK_CHAR = 0xFF #:nodoc:
10
14
 
11
15
  # Methodic hash - stolen from Camping
12
16
  class H < Hash
@@ -17,11 +21,37 @@ module Depix
17
21
  # => :macadamian
18
22
  #
19
23
  def method_missing(m,*a)
20
- m.to_s=~/=$/?self[$`]=a[0]:a==[]? (self.key?(m.to_sym) ? self[m.to_sym] : super ) : super
24
+ m.to_s=~/=$/ ? (self[$`] = a[0]) : (a == [] ? (self.key?(m.to_s) ? self[m.to_s] : super ) : super)
21
25
  end
22
26
  undef id, type
23
27
  end
24
28
 
29
+ # Offers convenience access to a few common attributes bypassing the piecemeal structs
30
+ module Synthetics
31
+ def keycode
32
+ [film.id, film.type, film.offset, film.prefix, film.count].compact.join(' ')
33
+ end
34
+
35
+ def flame_reel
36
+ orientation.device.to_s.scan(/^(\w+)/).to_s
37
+ end
38
+
39
+ def time_code
40
+ Timecode.from_uint(television.time_code, film.fps)
41
+ end
42
+
43
+ # Get the name of the transfer function (Linear, Logarithmic, ...)
44
+ def colorimetric
45
+ Structs::COLORIMETRIC.invert[image.image_elements[0].colorimetric]
46
+ end
47
+
48
+ # Get the name of the compnent type (RGB, YCbCr, ...)
49
+ def component_type
50
+ Structs::COMPONENT_TYPE.invert[image.image_elements[0].descriptor]
51
+ end
52
+
53
+ end
54
+
25
55
  # Reads the metadata
26
56
  class Reader
27
57
 
@@ -36,12 +66,14 @@ module Depix
36
66
  new.from_string(str)
37
67
  end
38
68
 
69
+ # Returns a printable report on all the headers present in the string
39
70
  def describe_string(str)
40
71
  reader = new
41
72
  result = reader.deep_parse(str, Structs::DPX_INFO)
42
73
  reader.inform(result)
43
74
  end
44
-
75
+
76
+ # Returns a printable report on all the headers present in the file at the path passed
45
77
  def describe_file(path)
46
78
  header = File.open(path, 'r') { |f| f.read(Structs::TEMPLATE_LENGTH) }
47
79
  describe_string(header)
@@ -81,9 +113,12 @@ module Depix
81
113
  end
82
114
 
83
115
  def wrap(result)
84
- self.class.nestify(Structs::TEMPLATE_KEYS, result)
116
+ eich = self.class.nestify(Structs::TEMPLATE_KEYS, result)
117
+ class << eich; include Synthetics; end
118
+ eich
85
119
  end
86
120
 
121
+ # FIXME - currently no array handling
87
122
  def self.nestify(keys, values)
88
123
  auto_hash = H.new do |h,k|
89
124
  h[k] = H.new(&h.default_proc)
@@ -104,20 +139,9 @@ module Depix
104
139
  end
105
140
 
106
141
  def unpad(string) # :nodoc:
107
- string.gsub(0xFF.chr, '').gsub(0xFF.chr, '')
142
+ string.gsub("\000", '').gsub(0xFF.chr, '')
108
143
  end
109
144
 
110
- TIME_FIELDS = 7 # :nodoc:
111
-
112
- def uint_to_tc(timestamp) # :nodoc:
113
- shift = 4 * TIME_FIELDS;
114
- tc_elements = (0..TIME_FIELDS).map do
115
- part = ((timestamp >> shift) & 0x0F)
116
- shift -= 4
117
- part
118
- end.join.scan(/(\d{2})/).flatten.map{|e| e.to_i}
119
-
120
- Timecode.at(*tc_elements)
121
- end
145
+ #:startdoc:
122
146
  end
123
147
  end
data/lib/depix/structs.rb CHANGED
@@ -4,10 +4,6 @@ module Depix
4
4
  # Which is a reformulation of http://www.cineon.com/ff_draft.php
5
5
  #
6
6
  # Which is a preamble to some SMPTE crap that you have to buy for 14 bucks. Or download from http://www.cinesite.com/static/scanning/techdocs/dpx_spec.pdf
7
- #
8
- # It's very fragile - in the world of C, everything is fixed length. If Tolstoy wanted to write
9
- # "War and Peace" in C he would need to know the number of letters ahead. It has good and bad
10
- # qualities - the good ones being computers go faster like that. The rest are bad parts.
11
7
  module Structs
12
8
 
13
9
  COLORIMETRIC = {
@@ -55,7 +51,7 @@ module Depix
55
51
  #:stopdoc:
56
52
 
57
53
  # To avoid fucking up with sizes afterwards
58
- UINT, FLOAT, USHORT, UCHAR = 4, 4, 2, 1
54
+ U32, R32, U16, U8, UCHAR = 4, 4, 2, 1, 1
59
55
 
60
56
  def self.struct_size(struct_const) #:nodoc:
61
57
  struct_const.inject(0){| s, e | s + e[2]}
@@ -67,15 +63,15 @@ module Depix
67
63
 
68
64
  FILE_INFO = Struct[
69
65
  [:magic, String, 4],
70
- [:image_offset, Integer, UINT],
66
+ [:image_offset, Integer, U32],
71
67
 
72
68
  [:version, String, 8],
73
69
 
74
- [:file_size, Integer, UINT],
75
- [:ditto_key, Integer, UINT],
76
- [:generic_size, Integer, UINT],
77
- [:industry_size, Integer, UINT],
78
- [:user_size, Integer, UINT],
70
+ [:file_size, Integer, U32],
71
+ [:ditto_key, Integer, U32],
72
+ [:generic_size, Integer, U32],
73
+ [:industry_size, Integer, U32],
74
+ [:user_size, Integer, U32],
79
75
 
80
76
  [:filename, String, 100],
81
77
  [:timestamp, String, 24],
@@ -83,7 +79,7 @@ module Depix
83
79
  [:project, String, 200],
84
80
  [:copyright, String, 200],
85
81
 
86
- [:encrypt_key, Integer, UINT],
82
+ [:encrypt_key, Integer, U32],
87
83
  [:reserve, String, 104],
88
84
  ]
89
85
 
@@ -95,12 +91,12 @@ module Depix
95
91
  [:count, String, 4],
96
92
  [:format, String, 32],
97
93
 
98
- [:frame_position, Integer, UINT],
99
- [:sequence_extent, Integer, UINT],
100
- [:held_count, Integer, UINT],
94
+ [:frame_position, Integer, U32],
95
+ [:sequence_extent, Integer, U32],
96
+ [:held_count, Integer, U32],
101
97
 
102
- [:frame_rate, Float, FLOAT],
103
- [:shutter_angle, Float, FLOAT],
98
+ [:frame_rate, Float, R32],
99
+ [:shutter_angle, Float, R32],
104
100
 
105
101
  [:frame_id, String, 32],
106
102
  [:slate, String, 100],
@@ -109,57 +105,57 @@ module Depix
109
105
 
110
106
 
111
107
  IMAGE_ELEMENT = Struct[
112
- [:data_sign, Integer, UINT],
113
- [:low_data, Integer, UINT],
114
- [:low_quantity, Float, FLOAT],
115
- [:high_data, Integer, UINT],
116
- [:high_quantity, Float, FLOAT],
108
+ [:data_sign, Integer, U32],
109
+ [:low_data, Integer, U32],
110
+ [:low_quantity, Float, R32],
111
+ [:high_data, Integer, U32],
112
+ [:high_quantity, Float, R32],
117
113
 
118
114
  # TODO: Autoreplace with enum values. Note: with these we will likely be addressing the enums
119
- [:descriptor, String, UCHAR],
120
- [:transfer, String, UCHAR],
121
- [:colorimetric, String, UCHAR],
122
- [:bit_size, String, UCHAR],
115
+ [:descriptor, Integer, U8],
116
+ [:transfer, Integer, U8],
117
+ [:colorimetric, Integer, U8],
118
+ [:bit_size, Integer, U8],
123
119
 
124
- [:packing, Integer, USHORT],
125
- [:encoding, Integer, USHORT],
126
- [:data_offset, Integer, UINT],
127
- [:end_of_line_padding, Integer, UINT],
128
- [:end_of_image_padding, Integer, UINT],
120
+ [:packing, Integer, U16],
121
+ [:encoding, Integer, U16],
122
+ [:data_offset, Integer, U32],
123
+ [:end_of_line_padding, Integer, U32],
124
+ [:end_of_image_padding, Integer, U32],
129
125
  [:description, String, 32],
130
126
  ]
131
127
 
132
128
  IMAGE_ELEMENTS = (0..7).map{|e| [e, IMAGE_ELEMENT, struct_size(IMAGE_ELEMENT)] }
133
129
 
134
130
  IMAGE_INFO = Struct[
135
- [:orientation, Integer, USHORT],
136
- [:number_elements, Integer, USHORT],
131
+ [:orientation, Integer, U16],
132
+ [:number_elements, Integer, U16],
137
133
 
138
- [:pixels_per_line, Integer, UINT],
139
- [:lines_per_element, Integer, UINT],
134
+ [:pixels_per_line, Integer, U32],
135
+ [:lines_per_element, Integer, U32],
140
136
 
141
137
  [:image_elements, IMAGE_ELEMENTS, struct_size(IMAGE_ELEMENTS) ],
142
138
 
143
139
  [:reserve, String, 52],
144
140
  ]
145
141
 
146
- BORDER = (0..3).map{|s| [s, Integer, USHORT] }
142
+ BORDER = (0..3).map{|s| [s, Integer, U16] }
147
143
 
148
144
  ASPECT_RATIO = [
149
- [0, Integer, UINT],
150
- [1, Integer, UINT],
145
+ [0, Integer, U32],
146
+ [1, Integer, U32],
151
147
  ]
152
148
 
153
149
  ORIENTATION_INFO = Struct[
154
150
 
155
- [:x_offset, Integer, UINT],
156
- [:y_offset, Integer, UINT],
151
+ [:x_offset, Integer, U32],
152
+ [:y_offset, Integer, U32],
157
153
 
158
- [:x_center, Float, FLOAT],
159
- [:y_center, Float, FLOAT],
154
+ [:x_center, Float, R32],
155
+ [:y_center, Float, R32],
160
156
 
161
- [:x_size, Integer, UINT],
162
- [:y_size, Integer, UINT],
157
+ [:x_size, Integer, U32],
158
+ [:y_size, Integer, U32],
163
159
 
164
160
  [:filename, String, 100],
165
161
  [:timestamp, String, 24],
@@ -173,30 +169,30 @@ module Depix
173
169
  ]
174
170
 
175
171
  TELEVISION_INFO = Struct[
176
- [:time_code, Integer, UINT],
177
- [:user_bits, Integer, UINT],
172
+ [:time_code, Integer, U32],
173
+ [:user_bits, Integer, U32],
178
174
 
179
- [:interlace, String, UCHAR],
180
- [:field_number, String, UCHAR],
181
- [:video_signal, String, UCHAR],
182
- [:padding, String, UCHAR],
175
+ [:interlace, Integer, U8],
176
+ [:field_number, Integer, U8],
177
+ [:video_signal, Integer, U8],
178
+ [:padding, Integer, U8],
183
179
 
184
- [:horizontal_sample_rate, Float, FLOAT],
185
- [:vertical_sample_rate, Float, FLOAT],
186
- [:frame_rate, Float, FLOAT],
187
- [:time_offset, Float, FLOAT],
188
- [:gamma, Float, FLOAT],
189
- [:black_level, Float, FLOAT],
190
- [:black_gain, Float, FLOAT],
191
- [:break_point, Float, FLOAT],
192
- [:white_level, Float, FLOAT],
193
- [:integration_times, Float, FLOAT],
180
+ [:horizontal_sample_rate, Float, R32],
181
+ [:vertical_sample_rate, Float, R32],
182
+ [:frame_rate, Float, R32],
183
+ [:time_offset, Float, R32],
184
+ [:gamma, Float, R32],
185
+ [:black_level, Float, R32],
186
+ [:black_gain, Float, R32],
187
+ [:break_point, Float, R32],
188
+ [:white_level, Float, R32],
189
+ [:integration_times, Float, R32],
194
190
  [:reserve, String, 76],
195
191
  ]
196
192
 
197
193
  USER_INFO = Struct[
198
194
  [:id, String, 32],
199
- [:user_data, Integer, UINT],
195
+ [:user_data, Integer, U32],
200
196
  ]
201
197
 
202
198
  DPX_INFO = Struct[
@@ -242,7 +238,9 @@ module Depix
242
238
  end
243
239
 
244
240
  def self.integer_template(size, big_endian) #:nodoc:
245
- if size == 2
241
+ if size == 1
242
+ "c"
243
+ elsif size == 2
246
244
  big_endian ? "n" : "v"
247
245
  elsif size == 4
248
246
  big_endian ? "N" : "V"
data/test/test_depix.rb CHANGED
@@ -56,6 +56,16 @@ class StructsTest < Test::Unit::TestCase
56
56
  end
57
57
  end
58
58
 
59
+ class EichTest < Test::Unit::TestCase
60
+ def test_eich
61
+ eich = Depix::H.new
62
+ assert_nothing_raised { assert_not_nil eich.foo = 1 }
63
+ assert_nothing_raised { eich.foo }
64
+ assert_equal ['foo'], eich.keys
65
+ assert_equal 1, eich.foo
66
+ end
67
+ end
68
+
59
69
  class ReaderTest < Test::Unit::TestCase
60
70
  def test_nestify
61
71
  k, v = ["foo", "bar"], [1, 2]
@@ -77,11 +87,65 @@ class ReaderTest < Test::Unit::TestCase
77
87
  assert_equal( {"foo"=>1, "bar"=>{0=>{"dam"=>3, "baz"=>2}}}, Depix::Reader.nestify(k,v))
78
88
  end
79
89
 
80
- def test_parse
90
+ def test_parsed_properly
91
+ file = 'samples/E012_P001_L000002_lin.0001.dpx'
92
+ parsed = Depix::Reader.from_file(file)
93
+ assert_equal "SDPX", parsed.file.magic
94
+ assert_equal 8192, parsed.file.image_offset
95
+ assert_equal "V1.0", parsed.file.version
96
+ assert_equal 319488, parsed.file.file_size
97
+ assert_equal 1, parsed.file.ditto_key
98
+ assert_equal 1664, parsed.file.generic_size
99
+ assert_equal 384, parsed.file.industry_size
100
+ assert_equal 6144, parsed.file.user_size
101
+ assert_equal "E012_P001_L000002_lin.0001.dpx", parsed.file.filename
102
+ assert_equal "2008:12:19:01:18:37:CEST", parsed.file.timestamp
103
+ assert_equal "UTODESK", parsed.file.creator
104
+ assert_equal 0, parsed.image.orientation
105
+ assert_equal 1, parsed.image.number_elements
106
+ assert_equal 320, parsed.image.pixels_per_line
107
+ assert_equal 240, parsed.image.lines_per_element
108
+ assert_equal 0, parsed.image.image_elements[0].data_sign
109
+ assert_equal 0, parsed.image.image_elements[0].low_data
110
+ assert_equal 0.0, parsed.image.image_elements[0].low_quantity
111
+ assert_equal 1023, parsed.image.image_elements[0].high_data
112
+ assert_in_delta 2.04699993133545, parsed.image.image_elements[0].high_quantity, 1.0 ** -10
113
+
114
+ assert_equal 50, parsed.image.image_elements[0].descriptor # RGB :-)
115
+ assert_equal 2, parsed.image.image_elements[0].transfer
116
+ assert_equal 2, parsed.image.image_elements[0].colorimetric
117
+ assert_equal 10, parsed.image.image_elements[0].bit_size
118
+ assert_equal 1, parsed.image.image_elements[0].packing
119
+ assert_equal 0, parsed.image.image_elements[0].encoding
120
+ assert_equal 8192, parsed.image.image_elements[0].data_offset
121
+ assert_equal 0, parsed.image.image_elements[0].end_of_line_padding
122
+ assert_equal 0, parsed.image.image_elements[0].end_of_image_padding
123
+ assert_equal "IMAGE DESCRIPTION DATA P", parsed.image.image_elements[0].description
124
+ # assert_equal "E012x�", parsed.orientation.device - this is where Flame writes the reel
125
+ assert_equal 853, parsed.orientation.aspect_ratio[0]
126
+ assert_equal 640, parsed.orientation.aspect_ratio[1]
127
+
128
+ assert_equal '75', parsed.film.id
129
+ assert_equal '00', parsed.film.type
130
+ assert_equal '19', parsed.film.offset
131
+ assert_equal '740612', parsed.film.prefix
132
+ assert_equal '9841', parsed.film.count
133
+ assert_equal 1, parsed.film.frame_position
134
+ assert_equal 2, parsed.film.sequence_extent
135
+ assert_equal 1, parsed.film.held_count
136
+ assert_equal 25.0, parsed.film.frame_rate
137
+ assert_equal 18157848, parsed.television.time_code
138
+ assert_equal 0, parsed.television.user_bits
139
+ end
140
+
141
+ def test_syntethics
142
+ assert_nothing_raised { Depix::Synthetics }
143
+
81
144
  file = 'samples/E012_P001_L000002_lin.0001.dpx'
82
145
  parsed = Depix::Reader.from_file(file)
83
- assert_equal 'SDPX', parsed.file.magic
84
- assert_equal 320, image.pixels_per_line
85
- assert_equal 240, image.lines_per_element
146
+ assert_equal "75 00 19 740612 9841", parsed.keycode
147
+ assert_equal :RGB, parsed.component_type
148
+ assert_equal :Linear, parsed.colorimetric
149
+ assert_equal "E012", parsed.flame_reel
86
150
  end
87
151
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: depix
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julik Tarkhanov
@@ -50,7 +50,7 @@ files:
50
50
  - test/samples/E012_P001_L000002_log.0001.dpx
51
51
  - test/samples/E012_P001_L000002_log.0002.dpx
52
52
  has_rdoc: true
53
- homepage: http://rubyforge.org/julik/depix
53
+ homepage: http://wiretap.rubyforge.org/depix
54
54
  post_install_message:
55
55
  rdoc_options:
56
56
  - --main