tracksperanto 2.9.5 → 2.9.6

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.
Files changed (51) hide show
  1. data/Gemfile +1 -1
  2. data/History.txt +5 -0
  3. data/bin/tracksperanto +32 -22
  4. data/lib/export/equalizer3.rb +1 -1
  5. data/lib/export/equalizer4.rb +1 -1
  6. data/lib/import/flame_stabilizer.rb +3 -3
  7. data/lib/import/nuke_script.rb +25 -7
  8. data/lib/middleware/base.rb +14 -7
  9. data/lib/middleware/crop.rb +9 -2
  10. data/lib/middleware/flip.rb +5 -3
  11. data/lib/middleware/flop.rb +4 -2
  12. data/lib/middleware/golden.rb +5 -2
  13. data/lib/middleware/length_cutoff.rb +6 -2
  14. data/lib/middleware/lerp.rb +5 -2
  15. data/lib/middleware/lint.rb +5 -0
  16. data/lib/middleware/move_to_first.rb +50 -0
  17. data/lib/middleware/pad.rb +8 -2
  18. data/lib/middleware/prefix.rb +6 -2
  19. data/lib/middleware/reformat.rb +6 -3
  20. data/lib/middleware/scaler.rb +6 -2
  21. data/lib/middleware/shift.rb +7 -2
  22. data/lib/middleware/slipper.rb +6 -2
  23. data/lib/middleware/start_trim.rb +6 -6
  24. data/lib/pipeline/base.rb +34 -38
  25. data/lib/tracksperanto.rb +18 -1
  26. data/lib/tracksperanto/format_detector.rb +26 -26
  27. data/lib/tracksperanto/parameters.rb +56 -0
  28. data/lib/tracksperanto/yield_non_empty.rb +15 -0
  29. data/test/import/test_nuke_import.rb +16 -1
  30. data/test/middleware/test_crop_middleware.rb +5 -0
  31. data/test/middleware/test_flip_middleware.rb +4 -19
  32. data/test/middleware/test_flop_middleware.rb +4 -9
  33. data/test/middleware/test_golden_middleware.rb +3 -10
  34. data/test/middleware/test_length_cutoff_middleware.rb +5 -0
  35. data/test/middleware/test_lerp_middleware.rb +6 -20
  36. data/test/middleware/test_lint_middleware.rb +5 -0
  37. data/test/middleware/test_move_to_first_frame_middleware.rb +38 -0
  38. data/test/middleware/test_pad_middleware.rb +5 -0
  39. data/test/middleware/test_prefix.rb +4 -0
  40. data/test/middleware/test_reformat_middleware.rb +3 -2
  41. data/test/middleware/test_scaler_middleware.rb +5 -0
  42. data/test/middleware/test_shift_middleware.rb +5 -0
  43. data/test/middleware/test_slip_middleware.rb +5 -0
  44. data/test/middleware/test_start_trim_middleware.rb +3 -9
  45. data/test/test_cli.rb +3 -3
  46. data/test/test_format_detector.rb +1 -1
  47. data/test/test_parameters.rb +38 -0
  48. data/test/test_tracksperanto.rb +10 -0
  49. data/test/test_yield_non_empty.rb +11 -0
  50. data/tracksperanto.gemspec +11 -5
  51. metadata +27 -21
@@ -2,8 +2,12 @@
2
2
  # This middleware prepends the names of the trackers passing through it with a prefix
3
3
  # and an underscore
4
4
  class Tracksperanto::Middleware::Prefix < Tracksperanto::Middleware::Base
5
- attr_accessor :prefix
6
- cast_to_string :prefix
5
+
6
+ parameter :prefix, :cast => :string, :desc => "The prefix to apply", :default => "trk_"
7
+
8
+ def self.action_description
9
+ "Prefix tracker names with text"
10
+ end
7
11
 
8
12
  def start_tracker_segment(tracker_name)
9
13
  prefixed_name = [prefix.gsub(/_$/, ''), tracker_name]
@@ -5,9 +5,12 @@ require File.dirname(__FILE__) + '/scaler'
5
5
  # applying proxy tracks to full-res images
6
6
  class Tracksperanto::Middleware::Reformat < Tracksperanto::Middleware::Base
7
7
 
8
- # To which format we have to scale
9
- attr_accessor :width, :height
10
- cast_to_int :width, :height
8
+ parameter :width, :cast => :int, :desc => "New comp width in px", :default => 1080
9
+ parameter :height, :cast => :int, :desc => "New comp height in px", :default => 1080
10
+
11
+ def self.action_description
12
+ "Reformat the comp together with it's trackers to conform to a specific format"
13
+ end
11
14
 
12
15
  # Called on export start
13
16
  def start_export( img_width, img_height)
@@ -3,8 +3,12 @@
3
3
  class Tracksperanto::Middleware::Scaler < Tracksperanto::Middleware::Base
4
4
  DEFAULT_FACTOR = 1
5
5
 
6
- attr_accessor :x_factor, :y_factor
7
- cast_to_float :x_factor, :y_factor
6
+ parameter :x_factor, :cast => :float, :desc => "Factor to scale by", :default => DEFAULT_FACTOR
7
+ parameter :y_factor, :cast => :float, :desc => "Factor to scale by", :default => 0.5
8
+
9
+ def self.action_description
10
+ "Scale the comp by a specified factor"
11
+ end
8
12
 
9
13
  # Called on export start
10
14
  def start_export( img_width, img_height)
@@ -1,8 +1,13 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  # This middleware moves the keyframs by a preset number of pixels
3
3
  class Tracksperanto::Middleware::Shift < Tracksperanto::Middleware::Base
4
- attr_accessor :x_shift, :y_shift
5
- cast_to_float :x_shift, :y_shift
4
+
5
+ parameter :x_shift, :cast => :float, :desc => "Amount of horizontal shift (in px)", :default => 0
6
+ parameter :y_shift, :cast => :float, :desc => "Amount of vertical shift (in px)", :default => 0
7
+
8
+ def self.action_description
9
+ "Move all the trackers by a specified number of pixels"
10
+ end
6
11
 
7
12
  def export_point(frame, float_x, float_y, float_residual)
8
13
  super(frame, float_x + @x_shift.to_f, float_y + @y_shift.to_f, float_residual)
@@ -2,8 +2,12 @@
2
2
  # Slips the keyframe positions by a specific integer amount of frames, positive values slip forward (later in time). Useful if you just edited some stuff onto
3
3
  # the beginning if your sequence and need to extend your tracks.
4
4
  class Tracksperanto::Middleware::Slipper < Tracksperanto::Middleware::Base
5
- attr_accessor :slip
6
- cast_to_int :slip
5
+
6
+ parameter :slip, :cast => :int, :desc => "Number of frames to slip related to the current frames", :default => 0
7
+
8
+ def self.action_description
9
+ "Slip all the tracker keyframes in time"
10
+ end
7
11
 
8
12
  def export_point(frame, float_x, float_y, float_residual)
9
13
  super(frame + @slip.to_i, float_x, float_y, float_residual)
@@ -1,17 +1,17 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  # This middleware removes all keyframes before frame 0, and skips trackers entirely if they are all before frame 0
3
3
  class Tracksperanto::Middleware::StartTrim < Tracksperanto::Middleware::Base
4
- attr_accessor :enabled
4
+
5
+ def self.action_description
6
+ "Remove all the keyframes that are on frames below 1"
7
+ end
5
8
 
6
9
  def start_export( img_width, img_height)
7
- if @enabled
8
- @exporter = Tracksperanto::Middleware::LengthCutoff.new(@exporter, :min_length => 1) # Ensure at least one keyframe
9
- end
10
-
10
+ @exporter = Tracksperanto::Middleware::LengthCutoff.new(@exporter, :min_length => 1) # Ensure at least one keyframe
11
11
  super
12
12
  end
13
13
 
14
14
  def export_point(frame, float_x, float_y, float_residual)
15
- return super unless (@enabled && frame < 0)
15
+ return super unless frame < 0
16
16
  end
17
17
  end
data/lib/pipeline/base.rb CHANGED
@@ -161,49 +161,45 @@ module Tracksperanto::Pipeline
161
161
 
162
162
  @ios.push(io_with_progress)
163
163
 
164
- @accumulator = Obuf.new
164
+ importer.io = io_with_progress
165
+ obuf = Obuf.new(Tracksperanto::YieldNonEmpty.new(importer))
165
166
 
166
- begin
167
-
168
- importer.io = io_with_progress
169
- importer.each {|t| @accumulator.push(t) unless t.empty? }
170
-
171
- report_progress(percent_complete = 50.0, "Validating #{@accumulator.size} imported trackers")
172
- raise NoTrackersRecoveredError if @accumulator.size.zero?
173
-
174
- report_progress(percent_complete, "Starting export")
175
-
176
- percent_per_tracker = (100.0 - percent_complete) / @accumulator.size
177
-
178
- # Use the width and height provided by the parser itself
179
- exporter.start_export(importer.width, importer.height)
167
+ report_progress(percent_complete = 50.0, "Validating #{obuf.size} imported trackers")
168
+ raise NoTrackersRecoveredError if obuf.size.zero?
169
+
170
+ report_progress(percent_complete, "Starting export")
171
+
172
+ percent_per_tracker = (100.0 - percent_complete) / obuf.size
173
+
174
+ # Use the width and height provided by the parser itself
175
+ exporter.start_export(importer.width, importer.height)
176
+
177
+ # Now send each tracker through the middleware chain
178
+ obuf.each_with_index do | t, tracker_idx |
180
179
 
181
- # Now send each tracker through the middleware chain
182
- @accumulator.each_with_index do | t, tracker_idx |
183
-
184
- kf_weight = percent_per_tracker / t.keyframes.length
185
- points += 1
186
- exporter.start_tracker_segment(t.name)
187
- t.each_with_index do | kf, idx |
188
- keyframes += 1
189
- exporter.export_point(kf.frame, kf.abs_x, kf.abs_y, kf.residual)
190
- report_progress(
191
- percent_complete += kf_weight,
192
- "Writing keyframe #{idx+1} of #{t.name.inspect}, #{@accumulator.size - tracker_idx} trackers to go"
193
- )
194
- end
195
- exporter.end_tracker_segment
180
+ kf_weight = percent_per_tracker / t.keyframes.length
181
+ points += 1
182
+ exporter.start_tracker_segment(t.name)
183
+ t.each_with_index do | kf, idx |
184
+ keyframes += 1
185
+ exporter.export_point(kf.frame, kf.abs_x, kf.abs_y, kf.residual)
186
+ report_progress(
187
+ percent_complete += kf_weight,
188
+ "Writing keyframe #{idx+1} of #{t.name.inspect}, #{obuf.size - tracker_idx} trackers to go"
189
+ )
196
190
  end
197
- exporter.end_export
191
+ exporter.end_tracker_segment
192
+ end
193
+ exporter.end_export
194
+
195
+ report_progress(100.0, "Wrote #{points} points and #{keyframes} keyframes")
198
196
 
199
- report_progress(100.0, "Wrote #{points} points and #{keyframes} keyframes")
197
+ obuf.clear
200
198
 
201
- [points, keyframes]
202
- ensure
203
- @accumulator.clear
204
- @ios.map!{|e| e.close! rescue e.close }
205
- @ios.clear
206
- end
199
+ @ios.map!{|e| e.close! rescue e.close }
200
+ @ios.clear
201
+
202
+ return [points, keyframes]
207
203
  end
208
204
 
209
205
  # Setup output files and return a single output
data/lib/tracksperanto.rb CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  module Tracksperanto
5
5
  PATH = File.expand_path(File.dirname(__FILE__))
6
- VERSION = '2.9.5'
6
+ VERSION = '2.9.6'
7
7
 
8
8
  module Import; end
9
9
  module Export; end
@@ -38,6 +38,21 @@ module Tracksperanto
38
38
  def middleware_names
39
39
  middlewares.map{|e| e.const_name }
40
40
  end
41
+
42
+ def exporters
43
+ sort_on_human_name(@exporters)
44
+ end
45
+
46
+ def importers
47
+ sort_on_human_name(@importers)
48
+ end
49
+
50
+ private
51
+
52
+ def sort_on_human_name(array)
53
+ array.sort!{|a, b| a.human_name <=> b.human_name }
54
+ array
55
+ end
41
56
  end
42
57
 
43
58
  self.exporters, self.importers, self.middlewares = [], [], []
@@ -86,6 +101,8 @@ end
86
101
  simple_export
87
102
  uv_coordinates
88
103
  buffering_reader
104
+ parameters
105
+ yield_non_empty
89
106
  ).each do | submodule |
90
107
  require File.join(Tracksperanto::PATH, "tracksperanto", submodule)
91
108
  end
@@ -8,32 +8,32 @@ class Tracksperanto::FormatDetector
8
8
  freeze
9
9
  end
10
10
 
11
+ # Tells if an importer has been found for this file
12
+ def match?
13
+ !!@importer_klass
14
+ end
15
+
16
+ # Returns the importer if there is one
17
+ def importer_klass
18
+ @importer_klass
19
+ end
20
+
21
+ # Tells if comp size needs to be provided
22
+ def auto_size?
23
+ match? ? importer_klass.autodetects_size? : false
24
+ end
25
+
26
+ # Returns the human name of the importer
27
+ def human_importer_name
28
+ match? ? importer_klass.human_name : "Unknown format"
29
+ end
30
+
11
31
  private
12
- def perform_detection(for_path)
13
- return unless (for_path && !for_path.to_s.empty?)
14
- ext = File.extname(for_path.downcase)
15
- @importer_klass = Tracksperanto.importers.find{ |i| i.distinct_file_ext == ext }
16
- end
32
+
33
+ def perform_detection(for_path)
34
+ return unless (for_path && !for_path.to_s.empty?)
35
+ ext = File.extname(for_path.downcase)
36
+ @importer_klass = Tracksperanto.importers.find{ |i| i.distinct_file_ext == ext }
37
+ end
17
38
 
18
- public
19
-
20
- # Tells if an importer has been found for this extension
21
- def match?
22
- !!@importer_klass
23
- end
24
-
25
- # Returns the importer if there is one
26
- def importer_klass
27
- @importer_klass
28
- end
29
-
30
- # Tells if comp size needs to be provided
31
- def auto_size?
32
- match? ? importer_klass.autodetects_size? : false
33
- end
34
-
35
- # Returns the human name of the importer
36
- def human_importer_name
37
- match? ? importer_klass.human_name : "Unknown format"
38
- end
39
39
  end
@@ -0,0 +1,56 @@
1
+ module Tracksperanto::Parameters
2
+
3
+ def self.included(into)
4
+ into.extend(self)
5
+ super
6
+ end
7
+
8
+ class Parameter
9
+ include Tracksperanto::BlockInit
10
+
11
+ # The name of the paramenter and the related object attribute
12
+ attr_accessor :name
13
+
14
+ # Whether the attribute is required
15
+ attr_accessor :required
16
+
17
+ # Default value of the attribute
18
+ attr_accessor :default
19
+
20
+ # The cast for the attribute (like :int or :float)
21
+ attr_accessor :cast
22
+
23
+ # Attribute description for the UI
24
+ attr_accessor :desc
25
+
26
+ def apply_to(to_class)
27
+ to_class.send(:attr_accessor, name)
28
+
29
+ if cast
30
+ cast_call = "cast_to_#{cast}"
31
+ to_class.send(cast_call, name)
32
+ end
33
+
34
+ if required
35
+ to_class.safe_reader name
36
+ end
37
+
38
+ end
39
+ end
40
+
41
+ # Defines a parameter, options conform to the Parameter class.
42
+ # The parameter will of course add an attr_accessor to your class for the specified parameter,
43
+ # but it will also
44
+ def parameter(name, options = {})
45
+ options = {:name => name}.merge(options)
46
+ param = Parameter.new(options)
47
+ parameters.push(param)
48
+ param.apply_to(self)
49
+ end
50
+
51
+ # Returns the array of the parameters defined for this class
52
+ def parameters
53
+ @ui_parameters ||= []
54
+ @ui_parameters
55
+ end
56
+ end
@@ -0,0 +1,15 @@
1
+ # An Enumerable wrapper that will only yield non-empty elements
2
+ class Tracksperanto::YieldNonEmpty
3
+
4
+ include Enumerable
5
+
6
+ def initialize(obj)
7
+ @obj = obj
8
+ end
9
+
10
+ def each
11
+ @obj.each do | item |
12
+ yield(item) unless item.empty?
13
+ end
14
+ end
15
+ end
@@ -6,7 +6,7 @@ class NukeImportTest < Test::Unit::TestCase
6
6
 
7
7
  def test_introspects_properly
8
8
  i = Tracksperanto::Import::NukeScript
9
- assert_equal "Nuke .nk script file", i.human_name
9
+ assert_equal "Nuke .nk script file with Tracker or Reconcile3D nodes", i.human_name
10
10
  assert !i.autodetects_size?
11
11
  end
12
12
 
@@ -20,6 +20,21 @@ class NukeImportTest < Test::Unit::TestCase
20
20
  assert_equal 45, trackers.length
21
21
  end
22
22
 
23
+
24
+ def test_parsing_from_reconciles
25
+ fixture = File.open(File.dirname(__FILE__) + '/samples/nuke/reconciles.nk')
26
+
27
+ parser = Tracksperanto::Import::NukeScript.new(:io => fixture)
28
+ parser.width = 2048
29
+ parser.height = 1176
30
+
31
+ trackers = parser.to_a.reject{|e| e.empty? }
32
+
33
+ assert_equal 5, trackers.length
34
+ assert_equal 128, trackers[0].length
35
+ end
36
+
37
+
23
38
  def test_parsing_from_nuke
24
39
  fixture = File.open(File.dirname(__FILE__) + '/samples/nuke/one_tracker_with_break.nk')
25
40
 
@@ -2,6 +2,11 @@
2
2
  require File.expand_path(File.dirname(__FILE__)) + '/../helper'
3
3
 
4
4
  class CropMiddlewareTest < Test::Unit::TestCase
5
+
6
+ def test_action_description
7
+ assert_equal "Crop or pad the image by a specified number of pixels", Tracksperanto::Middleware::Crop.action_description
8
+ end
9
+
5
10
  def test_crop_supports_hash_init
6
11
  receiver = flexmock
7
12
  m = Tracksperanto::Middleware::Crop.new(receiver, :left => 13, :right => 0, :top => 25)
@@ -2,14 +2,9 @@
2
2
  require File.expand_path(File.dirname(__FILE__)) + '/../helper'
3
3
 
4
4
  class FlipMiddlewareTest < Test::Unit::TestCase
5
- def test_flip_supports_hash_init
6
- receiver = flexmock
7
-
8
- m = Tracksperanto::Middleware::Flip.new(receiver)
9
- assert !m.enabled
10
-
11
- m = Tracksperanto::Middleware::Flip.new(receiver, :enabled => true)
12
- assert m.enabled
5
+
6
+ def test_action_description
7
+ assert_equal "Mirrors all the tracker paths horizontally", Tracksperanto::Middleware::Flip.action_description
13
8
  end
14
9
 
15
10
  def test_export_with_enabled_flip
@@ -17,17 +12,7 @@ class FlipMiddlewareTest < Test::Unit::TestCase
17
12
  receiver.should_receive(:start_export).once.with(110, 120)
18
13
  receiver.should_receive(:export_point).once.with(1, 100, 95, 0)
19
14
 
20
- m = Tracksperanto::Middleware::Flip.new(receiver, :enabled => true)
21
- m.start_export(110, 120)
22
- m.export_point(1, 10, 95, 0)
23
- end
24
-
25
- def test_export_with_disabled_flip
26
- receiver = flexmock(:exporter)
27
- receiver.should_receive(:start_export).once.with(110, 120)
28
- receiver.should_receive(:export_point).once.with(1, 10, 95, 0)
29
-
30
- m = Tracksperanto::Middleware::Flip.new(receiver, :enabled => false)
15
+ m = Tracksperanto::Middleware::Flip.new(receiver)
31
16
  m.start_export(110, 120)
32
17
  m.export_point(1, 10, 95, 0)
33
18
  end