renchin 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +182 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/renchin +6 -0
- data/bin/setup +7 -0
- data/lib/renchin.rb +11 -0
- data/lib/renchin/cli.rb +143 -0
- data/lib/renchin/client.rb +177 -0
- data/lib/renchin/file_processor.rb +36 -0
- data/lib/renchin/version.rb +3 -0
- data/renchin.gemspec +26 -0
- metadata +118 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4656f49e6a3c5409d1d3d5def2c4adade4163db3
|
4
|
+
data.tar.gz: 3190c4b9880153a0de4e19c2ee3e4ed64a0236d9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 49c1e82589d035ad0a2803750dc5925d90b0df436423129541420a779e1597949a14ec8ef357becf90ef6a376aeffaac5cf0a16f4313e94589c356f54bc5446c
|
7
|
+
data.tar.gz: 312bd2efe6a6fad32551890783115fcb6477eaec744670f2323e75aedf968ec878f1245d2a218f611af2d7fb2c0727c00149a67d518281d940f7fdd9512a59e6
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 YuheiNakasaka
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,182 @@
|
|
1
|
+
# Renchin
|
2
|
+
|
3
|
+
Renchin is a convinient cli wrapper library to convert movie to image/movie/gif or convert image to image/movie/gif with imagemagick and ffmpeg.
|
4
|
+
|
5
|
+
## Requirements
|
6
|
+
|
7
|
+
### Ruby
|
8
|
+
|
9
|
+
Renchin is tested in Ruby version >= 2.0.0
|
10
|
+
|
11
|
+
### Image Processor
|
12
|
+
- FFmpeg
|
13
|
+
- Imagemagick
|
14
|
+
|
15
|
+
In default, Renchin use $PATH.
|
16
|
+
|
17
|
+
## Installation
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
gem 'renchin'
|
21
|
+
```
|
22
|
+
|
23
|
+
And then execute:
|
24
|
+
|
25
|
+
$ bundle
|
26
|
+
|
27
|
+
Or install it yourself as:
|
28
|
+
|
29
|
+
$ gem install renchin
|
30
|
+
|
31
|
+
## Usage
|
32
|
+
|
33
|
+
Each methods have client version and cli version.
|
34
|
+
|
35
|
+
### Options
|
36
|
+
|
37
|
+
- command_path
|
38
|
+
- set command line path
|
39
|
+
```
|
40
|
+
Renchin.options[:command_path] = '/usr/bin'
|
41
|
+
|
42
|
+
```
|
43
|
+
|
44
|
+
### Timelapse
|
45
|
+
|
46
|
+

|
47
|
+
|
48
|
+
```
|
49
|
+
renchin = Renchin.new
|
50
|
+
renchin.tlapse( "/tmp/zOx3LRvtz22XIfhE.mp4" , "/tmp/output.mp4")
|
51
|
+
```
|
52
|
+
|
53
|
+
#### CLI
|
54
|
+
|
55
|
+
```
|
56
|
+
renchin tlapse -i MOVIE_FILE_PATH -o OUTPUT_MOVIE_FILE_PATH
|
57
|
+
```
|
58
|
+
|
59
|
+
Options
|
60
|
+
|
61
|
+
- --ofps
|
62
|
+
- set output movie fps(default: 30)
|
63
|
+
- --iex
|
64
|
+
- set temporary image file extension(default: png)
|
65
|
+
|
66
|
+
example)
|
67
|
+
|
68
|
+
```
|
69
|
+
renchin tlapse -i /tmp/example.mp4 -o /tmp/renchin_output_tlapse.mp4
|
70
|
+
```
|
71
|
+
|
72
|
+
### Single sprite image from movie
|
73
|
+
|
74
|
+
It creates a single sprite image from movie.
|
75
|
+
|
76
|
+
The image is useful to create gif like animation with javascript in [this library](http://nbnote.github.io/flipbook/).
|
77
|
+
|
78
|
+
```
|
79
|
+
renchin = Renchin.new
|
80
|
+
renchin.sprite( "/tmp/zOx3LRvtz22XIfhE.mp4" , "/tmp/output.jpg")
|
81
|
+
```
|
82
|
+
|
83
|
+
#### CLI
|
84
|
+
|
85
|
+
```
|
86
|
+
renchin sprite -i MOVIE_FILE_PATH -o OUTPUT_FILE_PATH
|
87
|
+
```
|
88
|
+
|
89
|
+
Options
|
90
|
+
|
91
|
+
- --cfps
|
92
|
+
- captured frame per second
|
93
|
+
|
94
|
+
example)
|
95
|
+
|
96
|
+
```
|
97
|
+
renchin sprite -i /tmp/example.mp4 -o /tmp/renchin_output_sprite.jpg
|
98
|
+
```
|
99
|
+
|
100
|
+
### Reverse movie
|
101
|
+
|
102
|
+

|
103
|
+
|
104
|
+
```
|
105
|
+
renchin = Renchin.new
|
106
|
+
renchin.reverse( "/tmp/zOx3LRvtz22XIfhE.mp4" , "/tmp/output.mp4", {start: 0, end_sec: 10})
|
107
|
+
```
|
108
|
+
|
109
|
+
#### Options
|
110
|
+
|
111
|
+
- start
|
112
|
+
- start time
|
113
|
+
- _end
|
114
|
+
- end time
|
115
|
+
|
116
|
+
#### CLI
|
117
|
+
|
118
|
+
```
|
119
|
+
renchin reverse -i MOVIE_FILE_PATH -o OUTPUT_FILE_PATH -s START_TIME -e END_TIME
|
120
|
+
```
|
121
|
+
|
122
|
+
example)
|
123
|
+
|
124
|
+
```
|
125
|
+
renchin reverse -i /tmp/example.mp4 -o /tmp/renchin_output_reverse.mp4 -s 0 -e 40
|
126
|
+
```
|
127
|
+
|
128
|
+
The example, output movie starts from 40 second and finishes to 0 second.
|
129
|
+
|
130
|
+
### cinemagraph
|
131
|
+
|
132
|
+

|
133
|
+
|
134
|
+
create cinemagraph gif from gif animation
|
135
|
+
|
136
|
+
```
|
137
|
+
renchin = Renchin.new
|
138
|
+
renchin.cgraph( "/tmp/zOx3LRvtz22XIfhE.gif" , "/tmp/output.gif", {overlay_x: 320, overlay_y: 150, overlay_w: 411, overlay_h: 315, viewport_w: 411, viewport_h: 315})
|
139
|
+
```
|
140
|
+
|
141
|
+
#### Options
|
142
|
+
|
143
|
+
- overlay_x
|
144
|
+
- animated part x
|
145
|
+
- overlay_y
|
146
|
+
- animated part y
|
147
|
+
- overlay_w
|
148
|
+
- animated part width
|
149
|
+
- overlay_h
|
150
|
+
- animated part height
|
151
|
+
- viewport_w
|
152
|
+
- final output width
|
153
|
+
- viewport_h
|
154
|
+
- final output height
|
155
|
+
|
156
|
+
#### CLI
|
157
|
+
|
158
|
+
```
|
159
|
+
renchin cgraph -i GIF_FILE -o OUTPUT_GIF_FILE -x ANIMATED_POSITION_X -y ANIMATED_POSITION_Y -w ANIMATED_PART_WIDTH -h ANIMATED_PART_HEIGHT
|
160
|
+
```
|
161
|
+
|
162
|
+
example)
|
163
|
+
|
164
|
+
```
|
165
|
+
renchin cgraph -i /tmp/example.gif -o /tmp/output_gif_file.gif -x 250 -y 100 -w 50 -h 100
|
166
|
+
```
|
167
|
+
|
168
|
+
## Development
|
169
|
+
|
170
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
171
|
+
|
172
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
173
|
+
|
174
|
+
## Contributing
|
175
|
+
|
176
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/YuheiNakasaka/renchin.
|
177
|
+
|
178
|
+
|
179
|
+
## License
|
180
|
+
|
181
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
182
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "renchin"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/renchin
ADDED
data/bin/setup
ADDED
data/lib/renchin.rb
ADDED
data/lib/renchin/cli.rb
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
require "renchin"
|
2
|
+
require "thor"
|
3
|
+
require "renchin/file_processor"
|
4
|
+
require "open3"
|
5
|
+
|
6
|
+
module Renchin
|
7
|
+
class CLI < Thor
|
8
|
+
include Renchin::FileProcessor
|
9
|
+
|
10
|
+
desc "tlapse -i MOVIE_FILE -o OUTPUT_FILE_NAME", "Generate a timelapse movie"
|
11
|
+
method_option :input, aliases: "i", desc: "Input movie file path"
|
12
|
+
method_option :output, aliases: "o", desc: "Output result file name"
|
13
|
+
method_option :ofps, default: nil, desc: "Set output movie fps"
|
14
|
+
method_option :iex, default: 'png', desc: "frame image extension"
|
15
|
+
method_option :debug, default: 0, desc: "Print stdout"
|
16
|
+
method_option :overwrite, aliases: "y", default: 0, desc: "Force creation"
|
17
|
+
def tlapse
|
18
|
+
movie_file = options[:input]
|
19
|
+
result_file = options[:output]
|
20
|
+
output_fps = options[:ofps] || frame_per_second(60)
|
21
|
+
ext = options[:iex]
|
22
|
+
debug = options[:debug].to_i
|
23
|
+
overwrite = options[:overwrite].to_i == 1 ? '-y' : ''
|
24
|
+
|
25
|
+
image_directory_path = image_directory(__method__)
|
26
|
+
Dir.chdir("#{image_directory_path}")
|
27
|
+
|
28
|
+
# Split a movie to png images.
|
29
|
+
o1, e1, i1 = Open3.capture3("ffmpeg -i #{movie_file} -f image2 #{image_directory_path}/%7d.#{ext}")
|
30
|
+
# Generate timelapse movie from frame images.
|
31
|
+
o2, e2, i2 = Open3.capture3("ffmpeg #{overwrite} -f image2 -r #{output_fps} -i #{image_directory_path}/%7d.#{ext} -r #{output_fps} -an -vcodec libx264 -pix_fmt yuv420p #{result_file}")
|
32
|
+
|
33
|
+
if debug == 1
|
34
|
+
puts e1
|
35
|
+
puts e2
|
36
|
+
end
|
37
|
+
|
38
|
+
delete_directory(image_directory_path, "\.#{ext}")
|
39
|
+
say("Renchin generated timelapse! ~> #{result_file}", :green)
|
40
|
+
end
|
41
|
+
|
42
|
+
desc "sprite -i MOVIE_FILE -o IMAGE_FILE", "Generate a sprite image which movie frames are merged to"
|
43
|
+
method_option :input, aliases: "i", desc: "Input movie file path"
|
44
|
+
method_option :output, aliases: "o", desc: "Output result file"
|
45
|
+
method_option :cfps, default: '2', desc: "Frame per second to capture"
|
46
|
+
def sprite
|
47
|
+
movie_file = options[:input]
|
48
|
+
result_file = options[:output]
|
49
|
+
captured_frame_per_sec = options[:cfps]
|
50
|
+
|
51
|
+
image_directory_path = image_directory(__method__)
|
52
|
+
|
53
|
+
system("ffmpeg -i #{movie_file} -r #{captured_frame_per_sec} -s qvga -f image2 #{image_directory_path}/renchin-original-%3d.png")
|
54
|
+
system("convert #{image_directory_path}/renchin-original-*.png -quality 30 #{image_directory_path}/renchin-converted-%03d.jpg")
|
55
|
+
system("convert #{image_directory_path}/renchin-converted-*.jpg -append #{result_file}")
|
56
|
+
|
57
|
+
delete_directory(image_directory_path, "\.(jpg|png)")
|
58
|
+
say("Renchin generated sprite file! ~> #{result_file}", :green)
|
59
|
+
end
|
60
|
+
|
61
|
+
desc "reverse -i MOVIE_FILE -o MOVIE_FILE -start START_TIME -end END_TIME", "Generate a reverse playback movie"
|
62
|
+
method_option :input, aliases: "-i", desc: "Input movie file path"
|
63
|
+
method_option :output, aliases: "-o", desc: "Output result file"
|
64
|
+
method_option :start, aliases: "-s", default: 0, desc: "Movie start time"
|
65
|
+
method_option :end, aliases: "-e", default: 10, desc: "Movie end time"
|
66
|
+
def reverse
|
67
|
+
movie_file = options[:input]
|
68
|
+
result_file = options[:output]
|
69
|
+
start_sec = options[:start]
|
70
|
+
end_sec = options[:end]
|
71
|
+
|
72
|
+
image_directory_path = image_directory(__method__)
|
73
|
+
|
74
|
+
system("ffmpeg -i #{movie_file} -vf trim=#{start_sec}:#{end_sec},reverse,setpts=PTS-STARTPTS -an #{result_file}")
|
75
|
+
|
76
|
+
say("Renchin generated reverse movie! ~> #{result_file}", :green)
|
77
|
+
end
|
78
|
+
|
79
|
+
desc "cgraph -i GIF_FILE -o OUTPUT_GIF_FILE", "Generate a cinemagraph from gifs"
|
80
|
+
method_option :input, aliases: "i", desc: "Input gif file path"
|
81
|
+
method_option :output, aliases: "o", desc: "Output result file"
|
82
|
+
method_option :frame_start, default: 1, desc: "which frame to pick as starting frame from inputfile?"
|
83
|
+
method_option :frame_end, default: 10, desc: "which frame to stop?"
|
84
|
+
method_option :frame_bg, default: 1, desc: "which frame should function as background 'still' ?"
|
85
|
+
method_option :overlay_x, aliases: 'x', default: 0, desc: "which part should be animated?"
|
86
|
+
method_option :overlay_y, aliases: 'y', default: 0, desc: "which part should be animated?"
|
87
|
+
method_option :overlay_w, aliases: 'w', default: 50, desc: "which part should be animated?"
|
88
|
+
method_option :overlay_h, aliases: 'h', default: 50, desc: "which part should be animated?"
|
89
|
+
method_option :viewport_x, default: 0, desc: "crop final output"
|
90
|
+
method_option :viewport_y, default: 0, desc: "crop final output"
|
91
|
+
method_option :viewport_w, desc: "crop final output"
|
92
|
+
method_option :viewport_h, desc: "crop final output"
|
93
|
+
method_option :duration, aliases: 'd', default: 4, desc: "duration"
|
94
|
+
def cgraph
|
95
|
+
gif_file = options[:input]
|
96
|
+
result_file = options[:output]
|
97
|
+
gif_configs = (`identify ~/Downloads/notch_belt.gif`).split("\n")
|
98
|
+
pingpong = 0 # comment this if you dont want a pingpong loop
|
99
|
+
frame_start = options[:frame_start]
|
100
|
+
frame_stop = options[:frame_end]
|
101
|
+
frame_bg = options[:frame_bg]
|
102
|
+
overlay_x = options[:overlay_x]
|
103
|
+
overlay_y = options[:overlay_y]
|
104
|
+
overlay_w = options[:overlay_w]
|
105
|
+
overlay_h = options[:overlay_h]
|
106
|
+
viewport_x = options[:viewport_x]
|
107
|
+
viewport_y = options[:viewport_y]
|
108
|
+
viewport_w = options[:viewport_w] || gif_configs[0].split(" ")[2].split("x")[0]
|
109
|
+
viewport_h = options[:viewport_h] || gif_configs[0].split(" ")[2].split("x")[1]
|
110
|
+
speed_current = options[:duration]
|
111
|
+
frames = ""
|
112
|
+
offset = 0
|
113
|
+
|
114
|
+
image_directory_path = image_directory(__method__)
|
115
|
+
|
116
|
+
# movie_to_frame
|
117
|
+
system("convert #{gif_file}[#{frame_bg}] #{image_directory_path}/bg.png")
|
118
|
+
system("convert #{gif_file} -repage 0x0 -crop #{overlay_w}x#{overlay_h}+#{overlay_x}+#{overlay_y} +repage #{image_directory_path}/frame.png")
|
119
|
+
|
120
|
+
# frames_to_gif && iterate_frames
|
121
|
+
frame_stop = (`identify #{gif_file} | wc -l`).chomp.gsub(/\s/,'').to_i
|
122
|
+
for i in frame_start...frame_stop do
|
123
|
+
frames = "#{frames} -delay #{speed_current} #{image_directory_path}/frame-out-#{offset}.png"
|
124
|
+
system("convert #{image_directory_path}/bg.png #{image_directory_path}/frame-#{i}.png -geometry +#{overlay_x}+#{overlay_y} -compose over -composite #{image_directory_path}/frame-out-#{offset}.png")
|
125
|
+
offset += 1
|
126
|
+
end
|
127
|
+
system("convert #{frames} -loop 0 -crop #{viewport_w}x#{viewport_h}+#{viewport_x}+#{viewport_y} -layers Optimize #{result_file}")
|
128
|
+
|
129
|
+
|
130
|
+
delete_directory(image_directory_path, "\.(jpg|png)")
|
131
|
+
say("Renchin generated sprite file! ~> #{result_file}", :green)
|
132
|
+
end
|
133
|
+
|
134
|
+
private
|
135
|
+
def frame_count(expr)
|
136
|
+
Dir.glob(expr).count
|
137
|
+
end
|
138
|
+
|
139
|
+
def frame_per_second(ext)
|
140
|
+
frame_count("*\.#{ext}") > 10 ? frame_count("*\.#{ext}") / 10 : 1
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
require "open3"
|
2
|
+
module Renchin
|
3
|
+
class Client
|
4
|
+
include Renchin::FileProcessor
|
5
|
+
def tlapse(input, output, options={})
|
6
|
+
# validate params
|
7
|
+
return false unless exists?(input)
|
8
|
+
|
9
|
+
opts = {
|
10
|
+
ofps: nil,
|
11
|
+
iex: 'png',
|
12
|
+
debug: 0,
|
13
|
+
force: ''
|
14
|
+
}.merge(options)
|
15
|
+
command_path = Renchin.options[:command_path].nil? ? '' : Renchin.options[:command_path]+'/'
|
16
|
+
movie_file = input
|
17
|
+
result_file = output
|
18
|
+
output_fps = opts[:ofps] || frame_per_second(60)
|
19
|
+
ext = opts[:iex]
|
20
|
+
|
21
|
+
# create dir for output file
|
22
|
+
init_file(result_file)
|
23
|
+
|
24
|
+
image_directory_path = image_directory(__method__)
|
25
|
+
Dir.chdir("#{image_directory_path}")
|
26
|
+
|
27
|
+
# Split a movie to png images.
|
28
|
+
o1, e1, i1 = Open3.capture3("#{command_path}ffmpeg -i #{movie_file} -f image2 #{image_directory_path}/%7d.#{ext}")
|
29
|
+
# Generate timelapse movie from frame images.
|
30
|
+
o2, e2, i2 = Open3.capture3("#{command_path}ffmpeg #{opts[:force]} -f image2 -r #{output_fps} -i #{image_directory_path}/%7d.#{ext} -r #{output_fps} -an -vcodec libx264 -pix_fmt yuv420p #{result_file}")
|
31
|
+
|
32
|
+
if opts[:debug] == 1
|
33
|
+
puts e1, e2
|
34
|
+
end
|
35
|
+
|
36
|
+
delete_directory(image_directory_path, "\.#{ext}")
|
37
|
+
result_file
|
38
|
+
end
|
39
|
+
|
40
|
+
def sprite(input, output, options={})
|
41
|
+
# validate params
|
42
|
+
return false unless exists?(input)
|
43
|
+
|
44
|
+
opts = {
|
45
|
+
cfps: 2,
|
46
|
+
debug: 0
|
47
|
+
}.merge(options)
|
48
|
+
command_path = Renchin.options[:command_path].nil? ? '' : Renchin.options[:command_path]+'/'
|
49
|
+
movie_file = input
|
50
|
+
result_file = output
|
51
|
+
captured_frame_per_sec = opts[:cfps]
|
52
|
+
|
53
|
+
# create dir for output file
|
54
|
+
init_file(result_file)
|
55
|
+
|
56
|
+
image_directory_path = image_directory(__method__)
|
57
|
+
Dir.chdir("#{image_directory_path}")
|
58
|
+
|
59
|
+
o1, e1, i1 = Open3.capture3("#{command_path}ffmpeg -i #{movie_file} -r #{captured_frame_per_sec} -s qvga -f image2 #{image_directory_path}/renchin-original-%3d.png")
|
60
|
+
o2, e2, i2 = Open3.capture3("#{command_path}convert #{image_directory_path}/renchin-original-*.png -quality 30 #{image_directory_path}/renchin-converted-%03d.jpg")
|
61
|
+
o3, e3, i3 = Open3.capture3("#{command_path}convert #{image_directory_path}/renchin-converted-*.jpg -append #{result_file}") # if overwrite, use mogrify
|
62
|
+
|
63
|
+
if opts[:debug] == 1
|
64
|
+
puts e1, e2, e3
|
65
|
+
end
|
66
|
+
|
67
|
+
delete_directory(image_directory_path, "\.(jpg|png)")
|
68
|
+
result_file
|
69
|
+
end
|
70
|
+
|
71
|
+
def reverse(input, output, options={})
|
72
|
+
# validate params
|
73
|
+
return false unless exists?(input)
|
74
|
+
|
75
|
+
opts = {
|
76
|
+
start: 0,
|
77
|
+
_end: 0,
|
78
|
+
debug: 0,
|
79
|
+
force: ""
|
80
|
+
}.merge(options)
|
81
|
+
command_path = Renchin.options[:command_path].nil? ? '' : Renchin.options[:command_path]+'/'
|
82
|
+
movie_file = input
|
83
|
+
result_file = output
|
84
|
+
start_sec = opts[:start]
|
85
|
+
end_sec = opts[:_end]
|
86
|
+
|
87
|
+
# create dir for output file
|
88
|
+
init_file(result_file)
|
89
|
+
|
90
|
+
image_directory_path = image_directory(__method__)
|
91
|
+
Dir.chdir("#{image_directory_path}")
|
92
|
+
|
93
|
+
o1, e1, i1 = Open3.capture3("#{command_path}ffmpeg #{opts[:force]} -i #{movie_file} -vf trim=#{start_sec}:#{end_sec},reverse,setpts=PTS-STARTPTS -an #{result_file}")
|
94
|
+
|
95
|
+
if opts[:debug] == 1
|
96
|
+
puts e1
|
97
|
+
end
|
98
|
+
|
99
|
+
Dir::rmdir(image_directory_path)
|
100
|
+
result_file
|
101
|
+
end
|
102
|
+
|
103
|
+
def cgraph(input, output, options={})
|
104
|
+
# validate input params
|
105
|
+
return false unless exists?(input)
|
106
|
+
|
107
|
+
opts = {
|
108
|
+
viewport_w: 100,
|
109
|
+
viewport_h: 100,
|
110
|
+
duration: 4,
|
111
|
+
frame_start: 1,
|
112
|
+
frame_end: 10,
|
113
|
+
frame_bg: 1,
|
114
|
+
overlay_x: nil,
|
115
|
+
overlay_y: nil,
|
116
|
+
overlay_w: 50,
|
117
|
+
overlay_h: 50,
|
118
|
+
viewport_x: 0,
|
119
|
+
viewport_y: 0,
|
120
|
+
debug: 0
|
121
|
+
}.merge(options)
|
122
|
+
command_path = Renchin.options[:command_path].nil? ? '' : Renchin.options[:command_path]+'/'
|
123
|
+
gif_file = input
|
124
|
+
result_file = output
|
125
|
+
gif_configs = (`identify #{gif_file}`).split("\n")
|
126
|
+
viewport_w = opts[:viewport_w] || gif_configs[0].split(" ")[2].split("x")[0]
|
127
|
+
viewport_h = opts[:viewport_h] || gif_configs[0].split(" ")[2].split("x")[1]
|
128
|
+
speed_current = opts[:duration]
|
129
|
+
frame_start = opts[:frame_start]
|
130
|
+
frame_stop = opts[:frame_end]
|
131
|
+
frame_bg = opts[:frame_bg]
|
132
|
+
overlay_x = opts[:overlay_x]
|
133
|
+
overlay_y = opts[:overlay_y]
|
134
|
+
overlay_w = opts[:overlay_w]
|
135
|
+
overlay_h = opts[:overlay_h]
|
136
|
+
viewport_x = opts[:viewport_x]
|
137
|
+
viewport_y = opts[:viewport_y]
|
138
|
+
frames = ""
|
139
|
+
offset = 0
|
140
|
+
|
141
|
+
# create dir for output file
|
142
|
+
init_file(result_file)
|
143
|
+
|
144
|
+
image_directory_path = image_directory(__method__)
|
145
|
+
Dir.chdir("#{image_directory_path}")
|
146
|
+
|
147
|
+
# movie_to_frame
|
148
|
+
o1, e1, i1 = Open3.capture3("#{command_path}convert #{gif_file}[#{frame_bg}] #{image_directory_path}/bg.png")
|
149
|
+
o2, e2, i2 = Open3.capture3("#{command_path}convert #{gif_file} -repage 0x0 -crop #{overlay_w}x#{overlay_h}+#{overlay_x}+#{overlay_y} +repage #{image_directory_path}/frame.png")
|
150
|
+
|
151
|
+
# frames_to_gif && iterate_frames
|
152
|
+
frame_stop = (`identify #{gif_file} | wc -l`).chomp.gsub(/\s/,'').to_i
|
153
|
+
for i in frame_start...frame_stop do
|
154
|
+
frames = "#{frames} -delay #{speed_current} #{image_directory_path}/frame-out-#{offset}.png"
|
155
|
+
o3, e3, i3 = Open3.capture3("#{command_path}convert #{image_directory_path}/bg.png #{image_directory_path}/frame-#{i}.png -geometry +#{overlay_x}+#{overlay_y} -compose over -composite #{image_directory_path}/frame-out-#{offset}.png")
|
156
|
+
offset += 1
|
157
|
+
end
|
158
|
+
o4, e4, i4 = Open3.capture3("#{command_path}convert #{frames} -loop 0 -crop #{viewport_w}x#{viewport_h}+#{viewport_x}+#{viewport_y} -layers Optimize #{result_file}")
|
159
|
+
|
160
|
+
if opts[:debug] == 1
|
161
|
+
puts e1, e2, e3, e4
|
162
|
+
end
|
163
|
+
|
164
|
+
delete_directory(image_directory_path, "\.(jpg|png)")
|
165
|
+
result_file
|
166
|
+
end
|
167
|
+
|
168
|
+
private
|
169
|
+
def frame_count(expr)
|
170
|
+
Dir.glob(expr).count
|
171
|
+
end
|
172
|
+
|
173
|
+
def frame_per_second(ext)
|
174
|
+
frame_count("*\.#{ext}") > 10 ? frame_count("*\.#{ext}") / 10 : 1
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
module Renchin
|
3
|
+
module FileProcessor
|
4
|
+
# create temporary directory for frame images
|
5
|
+
def image_directory(method_name)
|
6
|
+
timestamp_image_dir = "/tmp/renchin_#{method_name}_#{Time.now.to_i}"
|
7
|
+
Dir::mkdir(timestamp_image_dir,0777)
|
8
|
+
timestamp_image_dir
|
9
|
+
end
|
10
|
+
|
11
|
+
# delete all files in directory
|
12
|
+
def delete_directory(image_directory_path,expr)
|
13
|
+
if exists?(image_directory_path)
|
14
|
+
Dir::foreach(image_directory_path) do |file|
|
15
|
+
File.delete(image_directory_path + '/' + file) if (/#{expr}$/ =~ file)
|
16
|
+
end
|
17
|
+
Dir::rmdir(image_directory_path)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def exists?(filename)
|
22
|
+
File.exist?(filename)
|
23
|
+
end
|
24
|
+
|
25
|
+
def init_file(filename)
|
26
|
+
unless File.exist?(filename)
|
27
|
+
dir = File.dirname(filename)
|
28
|
+
unless File.exist?(dir)
|
29
|
+
FileUtils.mkdir_p(dir)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
true
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
data/renchin.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'renchin/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "renchin"
|
8
|
+
spec.version = Renchin::VERSION
|
9
|
+
spec.authors = ["YuheiNakasaka"]
|
10
|
+
spec.email = ["yuhei.nakasaka@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Renchin is a convinient cli wrapper library to convert movie to image/movie/gif or convert image to image/movie/gif}
|
13
|
+
spec.description = %q{Renchin is a convinient cli wrapper library to convert movie to image/movie/gif or convert image to image/movie/gif}
|
14
|
+
spec.homepage = "https://github.com/YuheiNakasaka/renchin"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = "exe"
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
23
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
+
spec.add_development_dependency "rspec"
|
25
|
+
spec.add_development_dependency "thor"
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: renchin
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- YuheiNakasaka
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-12-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.10'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.10'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: thor
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Renchin is a convinient cli wrapper library to convert movie to image/movie/gif
|
70
|
+
or convert image to image/movie/gif
|
71
|
+
email:
|
72
|
+
- yuhei.nakasaka@gmail.com
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".gitignore"
|
78
|
+
- ".rspec"
|
79
|
+
- ".travis.yml"
|
80
|
+
- Gemfile
|
81
|
+
- LICENSE.txt
|
82
|
+
- README.md
|
83
|
+
- Rakefile
|
84
|
+
- bin/console
|
85
|
+
- bin/renchin
|
86
|
+
- bin/setup
|
87
|
+
- lib/renchin.rb
|
88
|
+
- lib/renchin/cli.rb
|
89
|
+
- lib/renchin/client.rb
|
90
|
+
- lib/renchin/file_processor.rb
|
91
|
+
- lib/renchin/version.rb
|
92
|
+
- renchin.gemspec
|
93
|
+
homepage: https://github.com/YuheiNakasaka/renchin
|
94
|
+
licenses:
|
95
|
+
- MIT
|
96
|
+
metadata: {}
|
97
|
+
post_install_message:
|
98
|
+
rdoc_options: []
|
99
|
+
require_paths:
|
100
|
+
- lib
|
101
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
requirements: []
|
112
|
+
rubyforge_project:
|
113
|
+
rubygems_version: 2.4.5
|
114
|
+
signing_key:
|
115
|
+
specification_version: 4
|
116
|
+
summary: Renchin is a convinient cli wrapper library to convert movie to image/movie/gif
|
117
|
+
or convert image to image/movie/gif
|
118
|
+
test_files: []
|