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.
@@ -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
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /vendor/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.2
4
+ before_install: gem install bundler -v 1.10.4
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in renchin.gemspec
4
+ gemspec
@@ -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.
@@ -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
+ ![timelapse](http://img.gifmagazine.net/gifmagazine/images/693433/original.gif)
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
+ ![reverse movie](http://img.gifmagazine.net/gifmagazine/images/496200/original.gif?1438912596)
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
+ ![cinemagraph](http://img.gifmagazine.net/gifmagazine/images/676045/original.gif)
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
+
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -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
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "renchin"
5
+
6
+ Renchin::CLI.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,11 @@
1
+ require "renchin/version"
2
+ require "renchin/cli"
3
+ require "renchin/client"
4
+
5
+ module Renchin
6
+ def self.options
7
+ @options ||= {
8
+ command_path: nil
9
+ }
10
+ end
11
+ end
@@ -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
@@ -0,0 +1,3 @@
1
+ module Renchin
2
+ VERSION = "0.1.0"
3
+ end
@@ -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: []