screenshot_generator 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dc45676b2096d9d1ac542d9e69c4a2491dae98ea
4
+ data.tar.gz: 90edf5253fffb6edaa668cc0824927dc68c29349
5
+ SHA512:
6
+ metadata.gz: 866854e0a4210f882315cdb4c6fa5f7fd92d73f771f7e5751b5d689dec888d4e01a0598dce3d0bb35edbcfdb3511fa185cc838e12369c10331ab9c527a040821
7
+ data.tar.gz: 59e420d241994def73a32944cda3dfc6178fe0c0ce534b2dfa99623480e826e9c05564bf64bf40bcd8ed2103e81b05516c79ef78a1a8365371b3f18ead7928f6
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,12 @@
1
+ DO WHAT THE FUCK YOU WANT TO + BEER/PIZZA PUBLIC LICENSE
2
+ Version 1, May 2011
3
+
4
+ Copyright (C) 2011 Tom Lea
5
+
6
+
7
+ DO WHAT THE FUCK YOU WANT TO + BEER/PIZZA PUBLIC LICENSE
8
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
9
+
10
+ 0. You just DO WHAT THE FUCK YOU WANT TO.
11
+ 1. If you make a substantial amount of money by exercising clause 0,
12
+ you should consider buying the author a beer or a pizza.
@@ -0,0 +1,32 @@
1
+ # ScreenshotGenerator
2
+
3
+ It makes pictures of your videos using ffmpg, and ruby.
4
+
5
+ ## Installation
6
+ ```bash
7
+ gem install screenshot_generator
8
+ ```
9
+
10
+ ## Usage
11
+ ```ruby
12
+ # Capture that lovely view from 3 hours into your 6 hour holiday video.
13
+ ScreenshotGenerator.extract_frame("holiday.mp4", 60*60*3, "the-car-park.jpg")
14
+
15
+ # Take 20 frames spread evenly around your holiday video, so you can sample the
16
+ # majesty of the same beach, from 20 different angles.
17
+ ScreenshotGenerator.extract_multi("holiday.mp4", "pictures-for-firends/", 20)
18
+
19
+ # Capture the three interesting bits of your holiday video.
20
+ vid = ScreenshotGenerator.new("holiday.mp4")
21
+ vid.extract_frame(60*60*2+8, "base-jumping.jpg")
22
+ vid.extract_frame(vid.length - 30, "end-credits.jpg")
23
+ ```
24
+
25
+ ## Additional usage
26
+ Although not thoroughly tested, it is theoretically possible that this library
27
+ could be used to take screen shots of videos that are neither holiday related,
28
+ nor dull.
29
+
30
+ ## Licence
31
+ WTFBPPL: http://tomlea.co.uk/WTFBPPL.txt
32
+
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+ RSpec::Core::RakeTask.new(:spec)
4
+ task :default => :spec
5
+
@@ -0,0 +1,77 @@
1
+ require "screenshot_generator/version"
2
+
3
+ class ScreenshotGenerator
4
+ # Helper method for fetching a single frame
5
+ def self.extract_frame(video, *args)
6
+ new(video).extract_frame(*args)
7
+ end
8
+
9
+ def self.extract_multi(video, *args)
10
+ new(video).extract_multi(*args)
11
+ end
12
+
13
+ def initialize(video, size: '640x400')
14
+ @video = video
15
+ @size = size
16
+ raise ArgumentError, "Video does not exist" unless File.exist? @video
17
+ end
18
+
19
+ attr_reader :video, :size
20
+
21
+ def extract_frame(offset, path)
22
+ raise ArgumentError, "File already exists" if File.exist? path
23
+ offset = format_offset(offset)
24
+ ffmpeg(
25
+ "-loglevel", "error",
26
+ "-ss", offset,
27
+ "-i", video,
28
+ "-frames:v", 1,
29
+ "-s", size,
30
+ path
31
+ )
32
+ end
33
+
34
+
35
+ def extract_multi(dir, count)
36
+ dir = Pathname.new(dir)
37
+ 0.upto(count) do |index|
38
+ path = dir + "#{index}.jpg"
39
+ segment_size = length / (count + 2)
40
+ offset = (index + 1) * segment_size
41
+ extract_frame(offset, path)
42
+ end
43
+ end
44
+
45
+ def length
46
+ @length ||= get_length
47
+ end
48
+
49
+ protected
50
+
51
+ def ffmpeg(*args)
52
+ options = [self.class.ffmpeg, *args].map(&:to_s)
53
+ options.push(:err=>[:child, :out])
54
+ IO.popen(options) {|io| return io.read }
55
+ raise "ffmpeg comamnd #{options.inspect} failed" unless $?.success?
56
+ end
57
+
58
+ def self.ffmpeg
59
+ @ffmpeg ||= `which ffmpeg`.chomp
60
+ end
61
+
62
+ def get_length
63
+ output = ffmpeg("-i", video, "-frames", 1)
64
+ if output =~ /Duration:\s*([0-9:.]+)/
65
+ h,m,s = $1.split(":").map(&:to_i)
66
+ h*60^2 + m*60 + s
67
+ else
68
+ 60
69
+ end
70
+ end
71
+
72
+ def format_offset(v)
73
+ m, s = v.divmod(60)
74
+ h, m = m.divmod(60)
75
+ "%02i:%02i:%02i" % [h, m, s]
76
+ end
77
+ end
@@ -0,0 +1,3 @@
1
+ class ScreenshotGenerator
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'screenshot_generator/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "screenshot_generator"
8
+ spec.version = ScreenshotGenerator::VERSION
9
+ spec.authors = ["Tom Lea"]
10
+ spec.email = ["commit@tomlea.co.uk"]
11
+ spec.summary = %q{A simple wrapper around FFMpeg for extracing screen shots}
12
+ spec.homepage = ""
13
+ spec.license = "WTFBPPL"
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.5"
21
+ spec.add_development_dependency "rake"
22
+ spec.add_development_dependency "rspec"
23
+ spec.add_development_dependency "chunky_png"
24
+ end
@@ -0,0 +1,101 @@
1
+ require "rubygems"
2
+ require "bundler"
3
+ Bundler.setup
4
+
5
+ require "screenshot_generator"
6
+ require "rspec"
7
+
8
+ require "chunky_png"
9
+
10
+ describe ScreenshotGenerator do
11
+ let(:test_video){ "spec/fixtures/test-video.mov" }
12
+ let(:tmpfile){ "tmp/test_frame.png" }
13
+
14
+ describe ".extract_frame" do
15
+ it "extracts a frame from the video" do
16
+ expect(color_for_frame(0)).to be :red
17
+ expect(color_for_frame(1)).to be :green
18
+ expect(color_for_frame(2)).to be :blue
19
+ end
20
+
21
+ it "raises an ArgumentError if the video does not exist" do
22
+ expect{
23
+ ScreenshotGenerator.extract_frame("/tmp/does-not-exist.mp4", 0, "/dev/null")
24
+ }.to raise_error ArgumentError
25
+ end
26
+
27
+ it "errors is the output file already exists" do
28
+ expect{
29
+ ScreenshotGenerator.extract_frame(test_video, 0, __FILE__)
30
+ }.to raise_error ArgumentError
31
+ end
32
+ end
33
+
34
+ describe "#length" do
35
+ it "knows how long the video is" do
36
+ expect(ScreenshotGenerator.new(test_video).length).to eq 18
37
+ end
38
+ end
39
+
40
+ describe ".extract_multi" do
41
+ it "calls extract_frame for each needed frame" do
42
+ in_a_temp_dir do |dir|
43
+ ScreenshotGenerator.extract_multi(test_video, dir, 5)
44
+ 0.upto(5) do |i|
45
+ %x{convert #{dir + "#{i}.jpg"} #{dir + "#{i}.png"}}
46
+ end
47
+ expect(color_for_image(dir + "0.png")).to be :blue
48
+ expect(color_for_image(dir + "1.png")).to be :black
49
+ expect(color_for_image(dir + "2.png")).to be :green
50
+ expect(color_for_image(dir + "3.png")).to be :white
51
+ expect(color_for_image(dir + "4.png")).to be :red
52
+ expect(color_for_image(dir + "5.png")).to be :blue
53
+ end
54
+ end
55
+ end
56
+
57
+ def color_for_image(path)
58
+ rgb(ChunkyPNG::Image.from_file(path)[50,50]).classify
59
+ end
60
+
61
+ def color_for_frame(i)
62
+ ScreenshotGenerator.extract_frame(test_video, i, tmpfile)
63
+ color_for_image(tmpfile)
64
+ ensure
65
+ File.unlink tmpfile if File.exists?(tmpfile)
66
+ end
67
+
68
+ def in_a_temp_dir
69
+ dir = Pathname.new("tmp/working")
70
+ FileUtils.mkdir_p dir
71
+ yield dir
72
+ ensure
73
+ FileUtils.rm_r dir
74
+ end
75
+
76
+ Color = Struct.new(:r, :g, :b) do
77
+ def classify
78
+ if r > 250 and g > 250 and b > 250
79
+ :white
80
+ elsif r < 5 and g > 250 and b < 5
81
+ :green
82
+ elsif r > 250 and g < 5 and b < 5
83
+ :red
84
+ elsif r < 5 and g < 5 and b > 250
85
+ :blue
86
+ elsif r < 5 and g < 5 and b < 5
87
+ :black
88
+ else
89
+ raise "I don't know the color #{self.inspect}"
90
+ end
91
+ end
92
+ end
93
+
94
+ def rgb(color)
95
+ Color.new(
96
+ ChunkyPNG::Color.r(color),
97
+ ChunkyPNG::Color.g(color),
98
+ ChunkyPNG::Color.b(color)
99
+ )
100
+ end
101
+ end
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: screenshot_generator
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Tom Lea
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-22 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.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '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: chunky_png
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:
70
+ email:
71
+ - commit@tomlea.co.uk
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - .gitignore
77
+ - Gemfile
78
+ - LICENSE.txt
79
+ - README.md
80
+ - Rakefile
81
+ - lib/screenshot_generator.rb
82
+ - lib/screenshot_generator/version.rb
83
+ - screenshot_generator.gemspec
84
+ - spec/features/image_generation_spec.rb
85
+ - spec/fixtures/test-video.mov
86
+ homepage: ''
87
+ licenses:
88
+ - WTFBPPL
89
+ metadata: {}
90
+ post_install_message:
91
+ rdoc_options: []
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubyforge_project:
106
+ rubygems_version: 2.0.14
107
+ signing_key:
108
+ specification_version: 4
109
+ summary: A simple wrapper around FFMpeg for extracing screen shots
110
+ test_files:
111
+ - spec/features/image_generation_spec.rb
112
+ - spec/fixtures/test-video.mov