tracksperanto 2.9.5 → 2.9.6

Sign up to get free protection for your applications and to get access to all the features.
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
data/Gemfile CHANGED
@@ -1,7 +1,7 @@
1
1
  # -*- ruby -*-
2
2
  source :rubygems
3
3
 
4
- gem "obuf", "~> 1.0.4"
4
+ gem "obuf", "~> 1.1.0"
5
5
  gem "progressive_io", "~> 1.0"
6
6
  gem "flame_channel_parser", "~> 4.0"
7
7
  gem "progressbar", "0.10.0"
data/History.txt CHANGED
@@ -1,3 +1,8 @@
1
+ === 2.9.6
2
+
3
+ * Add Nuke Reconcile3D support
4
+ * Add Middleware::Base.parameters for automatic GUI building
5
+
1
6
  === 2.9.5
2
7
 
3
8
  * Export a Maya ASCII scene instead of a MEL script
data/bin/tracksperanto CHANGED
@@ -17,7 +17,7 @@ require 'progressbar'
17
17
  require "update_hints"
18
18
 
19
19
  def disclaimer
20
- "Please consider a small donation to keep Tracksperanto going. http://guerilla-di.org/source-and-license/\n"+
20
+ "Please consider a small donation to keep Tracksperanto going: http://guerilla-di.org/source-and-license/\n"+
21
21
  "For information and support please contact info#{64.chr}guerilla-di.org"
22
22
  end
23
23
 
@@ -29,13 +29,21 @@ writers = Tracksperanto.exporter_names
29
29
 
30
30
  op = OptionParser.new
31
31
 
32
- def mw(name, option, default_value = nil)
32
+ def mw(*name_option_and_default_value)
33
33
  Proc.new do |value|
34
+ name, option, default_value = name_option_and_default_value
34
35
  v = value.nil? ? default_value : value
35
- $middlewares.push([name, {option => v}])
36
+ mw_tuple = [name]
37
+ mw_tuple.push({option => v}) if option
38
+
39
+ $middlewares.push(mw_tuple)
36
40
  end
37
41
  end
38
42
 
43
+ def mwd(name)
44
+ Tracksperanto.get_middleware(name).action_description
45
+ end
46
+
39
47
  def list_exporters(dest = $stderr)
40
48
  dest.puts "The following export modules are available:"
41
49
  Tracksperanto.exporters.each do | exporter |
@@ -66,32 +74,35 @@ op.on(" -w", "--width WIDTH_IN_PIXELS", Integer, "Absolute input comp width in p
66
74
  op.on(" -h", "--height HEIGHT_IN_PIXELS", Integer, "Absolute input comp height in pixels (will try to autodetect)") {|w| options[:height] = w }
67
75
  op.on(" -o", "--only EXPORTER_NAME", String, "Only export the selected format, format must be one of #{writers.join(", ")}") { |f| writer_class_name = f }
68
76
 
69
- op.on(" -xs", "--xscale X_SCALING_FACTOR", Float, "Scale the result in X by this factor (1.0 is the default)", &mw("Scaler", :x_factor))
77
+ op.on(" -xs", "--xscale X_SCALING_FACTOR", Float, mwd("Scaler"), &mw("Scaler", :x_factor))
70
78
 
71
- op.on(" -pad", "--pad PAD_FRACTION_VALUES_COMMA_SEPARATED", String, "Pad the comp by these ratios") do | pads|
79
+ op.on(" -pad", "--pad PAD_FRACTION_VALUES_COMMA_SEPARATED", String, mwd("Pad")) do | pads|
72
80
  left, right, top, bottom = pads.split(",").map{|e| e.to_f }
73
81
  $middlewares.push(["Pad", {"left_pad" => left, "right_pad"=> right, "top_pad" => top, "bottom_pad" => bottom}])
74
82
  end
75
83
 
76
- op.on(" -crop", "--crop CROP_VALUES_COMMA_SEPARATED", String, "Crop or unpad the comp by these pixel values") do | pads|
84
+ op.on(" -crop", "--crop CROP_VALUES_COMMA_SEPARATED", String, mwd("Crop")) do | pads|
77
85
  left, right, top, bottom = pads.split(",").map{|e| e.to_i }
78
86
  $middlewares.push(["Crop", {"left" => left, "right"=> right, "top" => top, "bottom" => bottom}])
79
87
  end
80
88
 
81
- op.on(" -ys", "--yscale Y_SCALING_FACTOR", Float, "Scale the result in Y by this factor (1.0 is the default)", &mw("Scaler", :y_factor))
82
- op.on(" -t", "--trim", "Trim the start frames (do not allow negative frame values)", &mw("StartTrim", :enabled, true)) # Before slip!
83
- op.on(" -s", "--slip FRAMES", Integer, "Slip the result by this number of frames, positive is 'later'", &mw("Slipper", :slip))
84
-
85
- op.on(" -g", "--golden", "Reset the residuals of all trackers to 0 (ignore correlation)", &mw("Golden", :enabled, true))
89
+ op.on(" -ys", "--yscale Y_SCALING_FACTOR", Float, mwd("Scaler"), &mw("Scaler", :y_factor))
90
+ op.on(" -t", "--trim", Float, mwd("StartTrim"), &mw("StartTrim")) # Before slip!
91
+ op.on(" -s", "--slip FRAMES", Integer, mwd("Slipper"), &mw("Slipper", :slip))
92
+ op.on(" -g", "--golden", mwd("Golden"), &mw("Golden"))
93
+ op.on(" -m", "--min-length LENGTH_IN_FRAMES", Integer, mwd("LengthCutoff"), &mw("LengthCutoff", :min_length))
94
+ op.on(" -p", "--prefix PREFIX", String, mwd("Prefix"), &mw("Prefix", :prefix))
95
+ op.on("--lerp", mwd("Lerp"), &mw("Lerp"))
96
+ op.on("--flip", mwd("Flip"), &mw("Flip"))
97
+ op.on("--flop", mwd("Flop"), &mw("Flop"))
98
+
99
+ # TODO - multiparameters
86
100
  op.on(" -rx", "--reformat-x NEW_PIX_WIDTH", Integer, "Reformat the comp to this width and scale all tracks to it", &mw("Reformat", :width))
87
101
  op.on(" -ry", "--reformat-y NEW_PIX_HEIGHT", Integer, "Reformat the comp to this height and scale all tracks to it", &mw("Reformat", :height))
88
- op.on(" -m", "--min-length LENGTH_IN_FRAMES", Integer, "Only export trackers having more than X keyframes", &mw("LengthCutoff", :min_length))
89
102
  op.on(" -xm", "--xshift X_IN_PIXELS", Float, "Move the points left or right", &mw("Shift", :x_shift))
90
103
  op.on(" -ym", "--yshift Y_IN_PIXELS", Float, "Move the points up or down", &mw("Shift", :y_shift))
91
- op.on(" -p", "--prefix PREFIX", String, "A prefix to prepend to tracker names in bulk", &mw("Prefix", :prefix))
92
- op.on("--lerp", "Linearly interpolate missing keyframes", &mw("Lerp", :enabled, true))
93
- op.on("--flip", "Flip the comp horizontally", &mw("Flip", :enabled, true))
94
- op.on("--flop", "Flop the comp vertically", &mw("Flop", :enabled, true))
104
+
105
+
95
106
  op.on("--list-exporters", "Show available export modules") do
96
107
  list_exporters; exit(0)
97
108
  end
@@ -131,22 +142,21 @@ begin
131
142
  pipe = Tracksperanto::Pipeline::Base.new(:progress_block => progress, :middleware_tuples => $middlewares)
132
143
  pipe.exporters = [Tracksperanto.get_exporter(writer_class_name)] if writer_class_name
133
144
  pipe.run(input_file, options)
145
+ pbar.finish
146
+ $stdout.puts "Found and converted %d trackers with %d keyframes." % [pipe.converted_points, pipe.converted_keyframes]
134
147
  rescue Tracksperanto::UnknownExporterError => damn
135
148
  $stderr.puts damn.message
136
149
  list_exporters($stderr)
137
- exit(2)
150
+ fail "Unknown exporter"
138
151
  rescue Tracksperanto::UnknownImporterError => damn
139
152
  $stderr.puts damn.message
140
153
  list_importers($stderr)
141
- exit(2)
154
+ fail "Unknown importer"
142
155
  rescue Tracksperanto::UnknownMiddlewareError => damn
143
156
  $stderr.puts damn.message
144
- $stderr.puts "This is a bug, please report it"
145
- exit(2)
157
+ fail "This is a bug, please report it"
146
158
  rescue Exception => damn
147
159
  fail damn.message
148
- ensure
149
- pbar.finish
150
160
  end
151
161
 
152
162
  puts disclaimer
@@ -1,5 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
- # Export for 3DE v3 point files
2
+ # Export for 3DE v3 point files. 3DE always starts frames at 1.
3
3
  class Tracksperanto::Export::Equalizer3 < Tracksperanto::Export::Base
4
4
 
5
5
  HEADER = '// 3DE Multiple Tracking Curves Export %d x %d * %d frames'
@@ -1,5 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
- # Export for 3DE v4 point files
2
+ # Export for 3DE v4 point files. 3DE always starts frames at 1.
3
3
  class Tracksperanto::Export::Equalizer4 < Tracksperanto::Export::Base
4
4
 
5
5
  def self.desc_and_extension
@@ -131,8 +131,8 @@ class Tracksperanto::Import::FlameStabilizer < Tracksperanto::Import::Base
131
131
 
132
132
  def find_base_x_and_y(track_tuples, shift_tuples)
133
133
  base_track_tuple = track_tuples.find do | track_tuple |
134
- shift_tuples.find { |shift_tuple| shift_tuple[0] == track_tuple [0] }
135
- end || track_tuples[0]
136
- base_track_tuple[1..2]
134
+ shift_tuples.find { |shift_tuple| shift_tuple[0] == track_tuple[0] }
135
+ end
136
+ (base_track_tuple || track_tuples[0])[1..2]
137
137
  end
138
138
  end
@@ -5,7 +5,7 @@ require File.expand_path(File.dirname(__FILE__)) + "/nuke_grammar/utils"
5
5
  class Tracksperanto::Import::NukeScript < Tracksperanto::Import::Base
6
6
 
7
7
  def self.human_name
8
- "Nuke .nk script file"
8
+ "Nuke .nk script file with Tracker or Reconcile3D nodes"
9
9
  end
10
10
 
11
11
  def self.distinct_file_ext
@@ -16,7 +16,9 @@ class Tracksperanto::Import::NukeScript < Tracksperanto::Import::Base
16
16
  io = Tracksperanto::ExtIO.new(@io)
17
17
  while line = io.gets_and_strip
18
18
  if line =~ TRACKER_3_PATTERN
19
- scan_tracker_node(io).each { |t| yield(t) }
19
+ scan_tracker_node(io).each(&Proc.new)
20
+ elsif line =~ RECONCILE_PATTERN
21
+ scan_reconcile_node(io).each(&Proc.new)
20
22
  end
21
23
  end
22
24
  end
@@ -24,9 +26,26 @@ class Tracksperanto::Import::NukeScript < Tracksperanto::Import::Base
24
26
  private
25
27
 
26
28
  TRACKER_3_PATTERN = /^Tracker3 \{/
29
+ RECONCILE_PATTERN = /^Reconcile3D \{/
30
+ OUTPUT_PATTERN = /^output \{/
27
31
  TRACK_PATTERN = /^track(\d) \{/
28
32
  NODENAME = /^name ([^\n]+)/
29
33
 
34
+
35
+ # Scans a Reconcile3D node and returs it's output
36
+ def scan_reconcile_node(io)
37
+ t = Tracksperanto::Tracker.new
38
+ while line = io.gets_and_strip
39
+ if line =~ OUTPUT_PATTERN
40
+ t = extract_tracker(line)
41
+ elsif line =~ NODENAME
42
+ t.name = "Reconcile_#{$1}"
43
+ report_progress("Scavenging Reconcile3D node #{t.name}")
44
+ return [t] # Klunky
45
+ end
46
+ end
47
+ end
48
+
30
49
  # Scans a tracker node and return all tracks within that node (no more than 4)
31
50
  def scan_tracker_node(io)
32
51
  tracks_in_tracker = []
@@ -56,11 +75,10 @@ class Tracksperanto::Import::NukeScript < Tracksperanto::Import::Base
56
75
  def extract_tracker(line)
57
76
  tuples = scan_track(line)
58
77
  return nil unless (tuples && tuples.any?)
59
-
60
- Tracksperanto::Tracker.new(
61
- :keyframes => tuples.map do | (f, x, y) |
62
- Tracksperanto::Keyframe.new(:frame => f -1, :abs_x => x, :abs_y => y)
78
+ Tracksperanto::Tracker.new do | t |
79
+ tuples.each do | (f, x, y) |
80
+ t.keyframe!(:frame => (f -1), :abs_x => x, :abs_y => y)
63
81
  end
64
- )
82
+ end
65
83
  end
66
84
  end
@@ -1,4 +1,6 @@
1
1
  # -*- encoding : utf-8 -*-
2
+ require "forwardable"
3
+
2
4
  # The base middleware class works just like a Tracksperanto::Export::Base, but it only wraps another exporting object and does not get registered on it's own
3
5
  # as an export format. Middleware can be used to massage the tracks being exported in various interesting ways - like moving the coordinates, clipping the keyframes,
4
6
  # scaling the whole export or even reversing the trackers to go backwards
@@ -7,6 +9,10 @@ class Tracksperanto::Middleware::Base
7
9
  include Tracksperanto::BlockInit
8
10
  include Tracksperanto::ConstName
9
11
  include Tracksperanto::SimpleExport
12
+ include Tracksperanto::Parameters
13
+
14
+ extend Forwardable
15
+ def_delegators :@exporter, :start_export, :start_tracker_segment, :end_tracker_segment, :export_point, :end_export
10
16
 
11
17
  # Used to automatically register your middleware in Tracksperanto.middlewares
12
18
  # Normally you wouldn't need to override this
@@ -15,15 +21,16 @@ class Tracksperanto::Middleware::Base
15
21
  super
16
22
  end
17
23
 
18
- # Constructor accepts the exporter that will be wrapped
24
+ # Returns the human name of the action that the middleware will perform. The action is
25
+ # the in infinitive form, like "Remove all the invalid keyframes", "Crop the image" and so on
26
+ def self.action_description
27
+ "Base middleware class"
28
+ end
29
+
30
+ # Constructor accepts the exporter that will be wrapped, followed by the optional options hash
31
+ # and the optional block that yields self
19
32
  def initialize(*exporter_and_args_for_block_init)
20
33
  @exporter = exporter_and_args_for_block_init.shift
21
34
  super
22
35
  end
23
-
24
- %w( start_export start_tracker_segment end_tracker_segment
25
- export_point end_export).each do | m |
26
- define_method(m){|*a| @exporter.send(m, *a)}
27
- end
28
-
29
36
  end
@@ -1,8 +1,15 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  # Does the same as the Pad middleware but with absolute pixel values instead of fractionals
3
3
  class Tracksperanto::Middleware::Crop < Tracksperanto::Middleware::Base
4
- attr_accessor :top, :left, :right, :bottom
5
- cast_to_int :top, :left, :right, :bottom
4
+
5
+ parameter :top, :cast => :int, :desc => "Top crop amount in px"
6
+ parameter :left, :cast => :int, :desc => "Left crop amount in px"
7
+ parameter :right, :cast => :int, :desc => "Right crop amount in px"
8
+ parameter :bottom, :cast => :int, :desc => "Bottom crop amount in px"
9
+
10
+ def self.action_description
11
+ "Crop or pad the image by a specified number of pixels"
12
+ end
6
13
 
7
14
  def start_export(w, h)
8
15
  left_pad, right_pad, top_pad, bottom_pad = (left / w.to_f), (right / w.to_f), (top / h.to_f), (bottom / h.to_f)
@@ -1,11 +1,13 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  # Flips the comp being exported horizontally
3
3
  class Tracksperanto::Middleware::Flip < Tracksperanto::Middleware::Base
4
-
5
- attr_accessor :enabled
4
+
5
+ def self.action_description
6
+ "Mirrors all the tracker paths horizontally"
7
+ end
6
8
 
7
9
  def start_export(w, h)
8
- factor = enabled ? -1 : 1
10
+ factor = -1
9
11
  @exporter = Tracksperanto::Middleware::Scaler.new(@exporter, :x_factor => factor)
10
12
  super
11
13
  end
@@ -2,10 +2,12 @@
2
2
  # Flips the comp being exported vertically
3
3
  class Tracksperanto::Middleware::Flop < Tracksperanto::Middleware::Base
4
4
 
5
- attr_accessor :enabled
5
+ def self.action_description
6
+ "Mirror all the tracker paths vertically"
7
+ end
6
8
 
7
9
  def start_export(w, h)
8
- factor = enabled ? -1 : 1
10
+ factor = -1
9
11
  @exporter = Tracksperanto::Middleware::Scaler.new(@exporter, :y_factor => factor)
10
12
  super
11
13
  end
@@ -1,10 +1,13 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  # This middleware marks all trackers as being 100% accurate
3
3
  class Tracksperanto::Middleware::Golden < Tracksperanto::Middleware::Base
4
- attr_accessor :enabled
4
+
5
+ def self.action_description
6
+ "Reset residual of all the trackers to zero"
7
+ end
5
8
 
6
9
  def export_point(frame, float_x, float_y, float_residual)
7
- super(frame, float_x, float_y, (enabled ? 0.0 : float_residual))
10
+ super(frame, float_x, float_y, 0.0)
8
11
  end
9
12
 
10
13
  end
@@ -2,8 +2,12 @@
2
2
  # This middleware removes trackers that contain less than min_length keyframes
3
3
  # from the exported batch
4
4
  class Tracksperanto::Middleware::LengthCutoff < Tracksperanto::Middleware::Base
5
- attr_accessor :min_length
6
- cast_to_int :min_length
5
+
6
+ parameter :min_length, :cast => :int, :desc => "The minimum number of keyframes for the item to contain", :default => 100
7
+
8
+ def self.action_description
9
+ "Remove trackers that have less than the specified number of keyframes"
10
+ end
7
11
 
8
12
  def start_tracker_segment(name)
9
13
  @tracker = Tracksperanto::Tracker.new(:name => name)
@@ -1,7 +1,10 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  # This middleware adds linearly interpolated keyframes BETWEEN the keyframes passing through the exporter
3
3
  class Tracksperanto::Middleware::Lerp < Tracksperanto::Middleware::Base
4
- attr_accessor :enabled
4
+
5
+ def self.action_description
6
+ "Interpolate missing keyframes of all the trackers"
7
+ end
5
8
 
6
9
  def end_tracker_segment
7
10
  @last_f, @last_x, @last_y, @last_res = nil, nil, nil, nil
@@ -10,7 +13,7 @@ class Tracksperanto::Middleware::Lerp < Tracksperanto::Middleware::Base
10
13
 
11
14
  def export_point(frame, float_x, float_y, float_residual)
12
15
 
13
- if @enabled && @last_f && (frame - @last_f > 1) # Interpolate!
16
+ if @last_f && (frame - @last_f > 1) # Interpolate!
14
17
  interpolated_frames = []
15
18
  interpolated_x = []
16
19
  lerp(@last_f, @last_x, frame, float_x) do | interp_f, interp_x |
@@ -1,6 +1,11 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  # Prevents you from exporting invalid trackers
3
3
  class Tracksperanto::Middleware::Lint < Tracksperanto::Middleware::Base
4
+
5
+ def self.action_description
6
+ "Verify all the exported trackers and check for errors"
7
+ end
8
+
4
9
  class NoTrackersExportedError < RuntimeError
5
10
  def message
6
11
  "There were no trackers exported"
@@ -0,0 +1,50 @@
1
+ # -*- encoding : utf-8 -*-
2
+ # Sometimes your tracked sequence has been loaded from say frame 73282381, but you want to import into an application
3
+ # that expects the trackers to start at frame 1. This middleware autoslips everything so that your trackers start at frame 1.
4
+ class Tracksperanto::Middleware::MoveToFirst < Tracksperanto::Middleware::Base
5
+
6
+ def self.action_description
7
+ "Move all the keyframes in time so that the first frame is the first animated keyframe"
8
+ end
9
+
10
+ def start_export(width, height)
11
+ @width, @height = width, height
12
+ @start_frames = []
13
+ @buf = Obuf.new
14
+ @registered = false
15
+ end
16
+
17
+ def start_tracker_segment(tracker_name)
18
+ @current = Tracksperanto::Tracker.new(:name => tracker_name)
19
+ end
20
+
21
+ def end_tracker_segment
22
+ @buf.push(@current)
23
+ @registered = false
24
+ end
25
+
26
+ def export_point(frame, float_x, float_y, float_residual)
27
+ @current.keyframe!(:frame => frame, :abs_x => float_x, :abs_y => float_y, :residual => float_residual)
28
+ return if @registered
29
+
30
+ # Note where this tracker starts
31
+ @start_frames.push(frame)
32
+ @registered = true
33
+ end
34
+
35
+ def end_export
36
+ actual_start = @start_frames.sort.shift
37
+
38
+ @exporter.start_export(@width, @height)
39
+ @buf.each do | tracker |
40
+ @exporter.start_tracker_segment(tracker.name)
41
+ tracker.each do | kf |
42
+ @exporter.export_point(kf.frame - actual_start, kf.abs_x, kf.abs_y, kf.residual)
43
+ end
44
+ @exporter.end_tracker_segment
45
+ end
46
+ @exporter.end_export
47
+
48
+ @buf.clear
49
+ end
50
+ end
@@ -3,9 +3,15 @@
3
3
  # some fucked-up telecine transfers. The padding is in fractional units of the total width
4
4
  # and height
5
5
  class Tracksperanto::Middleware::Pad < Tracksperanto::Middleware::Base
6
- attr_accessor :left_pad, :right_pad, :top_pad, :bottom_pad
7
6
 
8
- cast_to_float :left_pad, :right_pad, :top_pad, :bottom_pad
7
+ parameter :top_pad, :cast => :float, :desc => "Top padding (fraction of original size)"
8
+ parameter :left_pad, :cast => :float, :desc => "Left padding (fraction of original size)"
9
+ parameter :right_pad, :cast => :float, :desc => "Right padding (fraction of original size)"
10
+ parameter :bottom_pad, :cast => :float, :desc => "Bottom padding (fraction of original size)"
11
+
12
+ def self.action_description
13
+ "Pad or crop the image by a fraction of it's original size"
14
+ end
9
15
 
10
16
  def start_export(w, h)
11
17
  @shift_left, @shift_bottom = w * left_pad, h * bottom_pad