thwomp 0.0.6 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.ruby-version +1 -0
- data/.travis.yml +10 -0
- data/Gemfile +3 -0
- data/README.rdoc +14 -11
- data/Rakefile +3 -0
- data/bin/install_gnash_osx +3 -3
- data/lib/thwomp.rb +17 -1
- data/lib/thwomp/animation_preview.rb +13 -44
- data/lib/thwomp/color_counter.rb +10 -2
- data/lib/thwomp/command.rb +11 -0
- data/lib/thwomp/renderer.rb +7 -88
- data/lib/thwomp/renderers/ffmpeg.rb +31 -0
- data/lib/thwomp/renderers/helper.rb +21 -0
- data/lib/thwomp/renderers/swf.rb +63 -0
- data/lib/thwomp/thumbnail.rb +13 -40
- data/lib/thwomp/thumbnail_picker.rb +16 -0
- data/lib/thwomp/version.rb +1 -1
- data/spec/animation_preview_spec.rb +15 -5
- data/spec/renderer_spec.rb +16 -17
- data/spec/renderers/ffmpeg_spec.rb +23 -0
- data/spec/renderers/swf_spec.rb +22 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/thumbnail_spec.rb +2 -24
- metadata +73 -78
- data/lib/thwomp/raw_renderer.rb +0 -40
- data/lib/thwomp/suitable_thumbnail.rb +0 -52
- data/spec/suitable_thumbnail_spec.rb +0 -11
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.9.3
|
data/.travis.yml
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 1.9.3
|
4
|
+
|
5
|
+
before_install:
|
6
|
+
- sudo apt-get update -qq
|
7
|
+
- sudo apt-get install -qq gnash libagg-dev automake autoconf libtool libltdl-dev libjpeg-dev libgif-dev libboost-dev libboost-thread-dev libboost-program-options-dev libfontconfig1-dev libfreetype6-dev ffmpeg libpng-dev libspeex-dev libsdl-dev libspeexdsp-dev imagemagick
|
8
|
+
|
9
|
+
script:
|
10
|
+
- rspec spec
|
data/Gemfile
ADDED
data/README.rdoc
CHANGED
@@ -63,7 +63,7 @@ Option 1: Install from source
|
|
63
63
|
make
|
64
64
|
sudo make install
|
65
65
|
|
66
|
-
Option 2: Install from
|
66
|
+
Option 2: Install from tarball from the intertubes:
|
67
67
|
cd /tmp/
|
68
68
|
wget ftp://ftp.mirror.nl/pub/mirror/gnu/gnash/0.8.9/gnash-0.8.9.tar.gz
|
69
69
|
tar -xzf gnash-0.8.9.tar.gz
|
@@ -76,24 +76,27 @@ Don't forget to add sudo before gnash.
|
|
76
76
|
|
77
77
|
=== Ubuntu
|
78
78
|
|
79
|
-
|
79
|
+
git clone git://git.sv.gnu.org/gnash.git
|
80
|
+
cd gnash
|
81
|
+
sudo apt-get install -y libagg-dev automake autoconf libtool libltdl-dev libjpeg-dev libgif-dev libboost-dev libboost-thread-dev libboost-program-options-dev libfontconfig1-dev libfreetype6-dev ffmpeg libpng-dev libspeex-dev libsdl-dev libspeexdsp-dev imagemagick
|
82
|
+
./autogen.sh
|
83
|
+
./configure --prefix=/usr/local/gnash-dump --enable-renderer=agg --enable-gui=dump --enable-media=no --disable-menus
|
84
|
+
make
|
85
|
+
sudo make install
|
80
86
|
|
81
87
|
== Installing the thwomp gem
|
82
88
|
gem install thwomp
|
83
89
|
|
84
90
|
== Usage
|
85
91
|
|
86
|
-
<b>
|
87
|
-
|
88
|
-
data = renderer.png_data(2)
|
92
|
+
<b>Finding the most suitable thumbnail for a swf movie:</b>
|
93
|
+
thumbnail_path = Thwomp.pick("http://www.example.com/flash.swf")
|
89
94
|
|
90
|
-
|
91
|
-
|
92
|
-
data = Thwomp::Thumbnail.new(renderer).png_data(2)
|
95
|
+
This picks the right renderer based on file extension. If that doesn't work
|
96
|
+
for you, you can instantiate the right renderer yourself. Like this;
|
93
97
|
|
94
|
-
|
95
|
-
|
96
|
-
data = Thwomp::SuitableThumbnail.new(renderer).png_data
|
98
|
+
renderer = Thwomp::Renderers::SWF.new("http://www.example.com/flash.swf")
|
99
|
+
thumbnail_path = ThumbnailPicker.pick(renderer.frames)
|
97
100
|
|
98
101
|
<b>Creating a GIF animation from a swf movie:</b>
|
99
102
|
renderer = Thwomp::Renderer.new("http://www.example.com/flash.swf")
|
data/Rakefile
CHANGED
data/bin/install_gnash_osx
CHANGED
@@ -9,7 +9,7 @@ end
|
|
9
9
|
|
10
10
|
if ask('Install required libs with homebrew? [y/n]') =~ /^[Yy]$/
|
11
11
|
puts 'Installing required libs with homebrew'
|
12
|
-
`brew update && brew install giflib boost libagg`
|
12
|
+
`brew update && brew install libtool giflib boost libagg gconf`
|
13
13
|
end
|
14
14
|
|
15
15
|
if ask('Install gnash? This may take a while! [y/n]') =~ /^[Yy]$/
|
@@ -21,8 +21,8 @@ if ask('Install gnash? This may take a while! [y/n]') =~ /^[Yy]$/
|
|
21
21
|
rm -fr gnash
|
22
22
|
git clone git://git.sv.gnu.org/gnash.git
|
23
23
|
cd gnash
|
24
|
-
./autogen
|
25
|
-
./configure --prefix=/usr/local/gnash-dump --enable-renderer=agg --enable-gui=dump --enable-media=no --disable-kparts --disable-nsapi --disable-menus
|
24
|
+
./autogen.sh
|
25
|
+
./configure --prefix=/usr/local/gnash-dump --enable-renderer=agg --enable-gui=dump --enable-media=no --disable-kparts --disable-nsapi --disable-menus
|
26
26
|
make
|
27
27
|
sudo make install`
|
28
28
|
end
|
data/lib/thwomp.rb
CHANGED
@@ -1,10 +1,26 @@
|
|
1
1
|
require 'thwomp/version'
|
2
2
|
require 'thwomp/renderer'
|
3
|
+
require 'thwomp/renderers/helper'
|
4
|
+
require 'thwomp/renderers/swf'
|
5
|
+
require 'thwomp/renderers/ffmpeg'
|
3
6
|
require 'thwomp/color_counter'
|
4
7
|
require 'thwomp/downloader'
|
8
|
+
require 'thwomp/thumbnail_picker'
|
5
9
|
require 'thwomp/thumbnail'
|
6
|
-
require 'thwomp/suitable_thumbnail'
|
7
10
|
require 'thwomp/animation_preview'
|
11
|
+
require 'thwomp/command'
|
8
12
|
|
9
13
|
module Thwomp
|
14
|
+
|
15
|
+
class << self
|
16
|
+
|
17
|
+
attr_accessor :gnash_path, :ffmpeg_path
|
18
|
+
|
19
|
+
def pick(url)
|
20
|
+
renderer = Renderer.new(url)
|
21
|
+
ThumbnailPicker.pick(renderer.frames.reverse)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
10
26
|
end
|
@@ -1,58 +1,27 @@
|
|
1
1
|
require 'tmpdir'
|
2
2
|
|
3
3
|
module Thwomp
|
4
|
-
class AnimationPreview
|
4
|
+
class AnimationPreview
|
5
5
|
|
6
|
-
|
6
|
+
# TODO: (optional) use Thumbnail class to make png's from the
|
7
|
+
# rendered frames, instead of passing the frames directly to 'convert'
|
7
8
|
|
8
|
-
|
9
|
-
:max_height => 128,
|
10
|
-
:max_frames => 10 }
|
9
|
+
attr_reader :frames
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
#
|
15
|
-
# Options
|
16
|
-
# :max_width Maximum width of GIF
|
17
|
-
# :max_height Maximum height of GIF
|
18
|
-
#
|
19
|
-
def initialize(renderer, options = {})
|
20
|
-
DEFAULT_OPTIONS.merge(options).each { |k,v| send(:"#{k}=", v) if v }
|
21
|
-
@renderer = renderer
|
11
|
+
def initialize(frames)
|
12
|
+
@frames = frames
|
22
13
|
end
|
23
14
|
|
24
|
-
|
25
|
-
def gif_data
|
26
|
-
File.open(filename, 'rb') { |f| f.read }
|
27
|
-
end
|
28
|
-
|
29
|
-
# returns temp filename of generated animation
|
30
|
-
def filename
|
31
|
-
@filename ||= generate_gif!
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
|
36
|
-
def thumbnail
|
37
|
-
@thumbnail ||= Thumbnail.new(renderer, :max_width => max_width, :max_height => max_height)
|
38
|
-
end
|
39
|
-
|
40
|
-
# returns all filenames of the seperate frames in the flash animation
|
41
|
-
def frame_filenames
|
42
|
-
unless @frame_filenames
|
43
|
-
frames = (0..max_frames).to_a + ['last']
|
44
|
-
renderer.render_batch!(frames)
|
45
|
-
@frame_filenames = frames.map { |frame| thumbnail.filename(frame) }.compact
|
46
|
-
end
|
47
|
-
|
48
|
-
@frame_filenames
|
49
|
-
end
|
50
|
-
|
51
|
-
def generate_gif!
|
15
|
+
def generate!
|
52
16
|
filename = "#{Dir.tmpdir}/animation_#{Time.now.to_i}.gif"
|
53
|
-
|
17
|
+
Command.exec("convert #{frames.join(' ')} #{filename}")
|
54
18
|
filename
|
55
19
|
end
|
56
20
|
|
21
|
+
# returns the gif binary data of generated animation
|
22
|
+
def gif_data
|
23
|
+
File.open(generate!, 'rb') { |f| f.read }
|
24
|
+
end
|
25
|
+
|
57
26
|
end
|
58
27
|
end
|
data/lib/thwomp/color_counter.rb
CHANGED
@@ -22,10 +22,18 @@ module Thwomp
|
|
22
22
|
!empty?
|
23
23
|
end
|
24
24
|
|
25
|
+
def valid_png?
|
26
|
+
!!png
|
27
|
+
end
|
28
|
+
|
25
29
|
private
|
26
30
|
|
27
31
|
def png
|
28
|
-
@png ||=
|
32
|
+
@png ||= begin
|
33
|
+
ChunkyPNG::Image.from_file(image_filename)
|
34
|
+
rescue Errno::ENOENT, ChunkyPNG::Exception, RangeError, NoMethodError
|
35
|
+
false
|
36
|
+
end
|
29
37
|
end
|
30
38
|
|
31
39
|
def width
|
@@ -72,7 +80,7 @@ module Thwomp
|
|
72
80
|
|
73
81
|
# returns the color at pixel X,Y
|
74
82
|
def color_at(x,y)
|
75
|
-
png[
|
83
|
+
png[x, y]
|
76
84
|
end
|
77
85
|
|
78
86
|
def flattened_color_at(x,y)
|
data/lib/thwomp/renderer.rb
CHANGED
@@ -1,98 +1,17 @@
|
|
1
|
-
require 'tmpdir'
|
2
|
-
|
3
1
|
module Thwomp
|
4
2
|
|
5
|
-
# Renders SWF files
|
6
3
|
class Renderer
|
7
4
|
|
8
|
-
|
9
|
-
|
10
|
-
DEFAULT_OPTIONS = { :max_width => 500,
|
11
|
-
:max_height => 500,
|
12
|
-
:max_frames => 10 }
|
13
|
-
|
14
|
-
# Initializer the Thwomp renderer
|
15
|
-
#
|
16
|
-
# Options:
|
17
|
-
# :max_width Maximum width of renderer
|
18
|
-
# :max_height Maximum height of renderer
|
19
|
-
# :max_frames Maximum number of frames the renderer can handle
|
20
|
-
def initialize(url, options = {})
|
21
|
-
DEFAULT_OPTIONS.merge(options).each { |k,v| send(:"#{k}=", v) if v }
|
22
|
-
@url = url
|
23
|
-
end
|
24
|
-
|
25
|
-
# returns filename of frame
|
26
|
-
def frame_filename(frame)
|
27
|
-
frame_exists?(frame) ? @frame_filename[frame] : nil
|
28
|
-
end
|
29
|
-
|
30
|
-
# returns PNG data from given frame
|
31
|
-
def png_data(frame)
|
32
|
-
frame_exists?(frame) ? frame_data(frame) : nil
|
33
|
-
end
|
34
|
-
|
35
|
-
# renders a batch of frames
|
36
|
-
def render_batch!(frames)
|
37
|
-
@frame_filename ||= {}
|
5
|
+
def self.new(*args)
|
6
|
+
url = args.first
|
38
7
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
frames.each do |frame|
|
45
|
-
@frame_filename[frame] = file_mask.gsub('%f', frame.to_s)
|
8
|
+
if url.match(/\.swf$/)
|
9
|
+
Renderers::SWF.new(*args)
|
10
|
+
else
|
11
|
+
Renderers::FFMPEG.new(*args)
|
46
12
|
end
|
47
13
|
end
|
48
14
|
|
49
|
-
def frame_exists?(frame)
|
50
|
-
render_frame!(frame)
|
51
|
-
File.exists?(@frame_filename[frame])
|
52
|
-
end
|
53
|
-
|
54
|
-
# returns the current set gnash binary
|
55
|
-
def self.gnash_binary
|
56
|
-
@gnash_binary ||= 'gnash-dump'
|
57
|
-
end
|
58
|
-
|
59
|
-
# sets the path to the gnash binary
|
60
|
-
def self.gnash_binary=(binary)
|
61
|
-
@gnash_binary = binary
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
|
-
|
66
|
-
def frame_data(frame)
|
67
|
-
File.open(@frame_filename[frame], 'rb') { |f| f.read }
|
68
|
-
end
|
69
|
-
|
70
|
-
# renders all the frames from the SWF file and dump them to a RAW file
|
71
|
-
def render_frame!(frame)
|
72
|
-
@frame_filename ||= {}
|
73
|
-
|
74
|
-
unless @frame_filename[frame]
|
75
|
-
@frame_filename[frame] = frame_output_filename(frame)
|
76
|
-
|
77
|
-
`#{self.class.gnash_binary} -s1 --screenshot=#{frame} --screenshot-file #{@frame_filename[frame]} -1 -r1 --timeout 200 #{filename} -j #{max_width} -k #{max_height}`
|
78
|
-
end
|
79
|
-
|
80
|
-
@frame_filename[frame]
|
81
|
-
end
|
82
|
-
|
83
|
-
def filename
|
84
|
-
downloader.filename
|
85
|
-
end
|
86
|
-
|
87
|
-
# returns the downloader
|
88
|
-
def downloader
|
89
|
-
@downloader ||= Downloader.new(url)
|
90
|
-
end
|
91
|
-
|
92
|
-
# returns temp filename for given frame no.
|
93
|
-
def frame_output_filename(frame)
|
94
|
-
"#{Dir.tmpdir}/frame_#{Time.now.to_i}_#{frame}.png"
|
95
|
-
end
|
96
|
-
|
97
15
|
end
|
16
|
+
|
98
17
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Thwomp
|
2
|
+
|
3
|
+
module Renderers
|
4
|
+
|
5
|
+
class FFMPEG
|
6
|
+
include Renderers::Helper
|
7
|
+
|
8
|
+
attr_reader :filename
|
9
|
+
|
10
|
+
def initialize(url)
|
11
|
+
@filename = Downloader.new(url).filename
|
12
|
+
end
|
13
|
+
|
14
|
+
def frames
|
15
|
+
timestamp = Time.now.to_i
|
16
|
+
output_file_name = "#{Dir.tmpdir}/frame_#{timestamp}_%d.png"
|
17
|
+
|
18
|
+
Command.exec("#{executable} -i #{filename} -f image2 -r 1 -vf scale=128:-1 #{output_file_name} &> /dev/null")
|
19
|
+
|
20
|
+
sort Dir.glob("#{Dir.tmpdir}/frame_#{timestamp}_*.png")
|
21
|
+
end
|
22
|
+
|
23
|
+
def executable
|
24
|
+
Thwomp.ffmpeg_path || "ffmpeg"
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Thwomp
|
2
|
+
|
3
|
+
module Renderers
|
4
|
+
|
5
|
+
module Helper
|
6
|
+
|
7
|
+
def sort(frames)
|
8
|
+
frames.sort do |a, b|
|
9
|
+
frame_number(File.basename(a)) <=> frame_number(File.basename(b))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def frame_number(file_name)
|
14
|
+
file_name.scan(/\d+/).last.to_i
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'tmpdir'
|
2
|
+
|
3
|
+
module Thwomp
|
4
|
+
|
5
|
+
# Renders SWF files
|
6
|
+
module Renderers
|
7
|
+
|
8
|
+
class SWF
|
9
|
+
|
10
|
+
include Renderers::Helper
|
11
|
+
|
12
|
+
attr_reader :filename, :frame_count, :width, :height
|
13
|
+
|
14
|
+
def initialize(url, options={})
|
15
|
+
@filename = Downloader.new(url).filename
|
16
|
+
@frame_count = options.fetch(:frame_count) { 10 }
|
17
|
+
@width = options.fetch(:width) { 500 }
|
18
|
+
@height = options.fetch(:height) { 500 }
|
19
|
+
end
|
20
|
+
|
21
|
+
def frames
|
22
|
+
timestamp = Time.now.to_i
|
23
|
+
|
24
|
+
Command.exec(
|
25
|
+
"#{executable} -s1 --screenshot=#{frame_batch}" \
|
26
|
+
" --screenshot-file=#{output_file(timestamp)}" \
|
27
|
+
" -1 -r1 --timeout 200 #{filename} -j #{width}" \
|
28
|
+
" -k #{height} > /dev/null 2>&1"
|
29
|
+
)
|
30
|
+
|
31
|
+
sort Dir.glob("#{Dir.tmpdir}/frame_#{timestamp}_*.png")
|
32
|
+
end
|
33
|
+
|
34
|
+
def frame(number)
|
35
|
+
timestamp = Time.now.to_i
|
36
|
+
|
37
|
+
Command.exec(
|
38
|
+
"#{executable} -s1 --screenshot=#{number}" \
|
39
|
+
" --screenshot-file=#{output_file(timestamp)}" \
|
40
|
+
" -1 -r1 --timeout 200 #{filename} -j #{width}" \
|
41
|
+
" -k #{height} > /dev/null 2>&1"
|
42
|
+
)
|
43
|
+
|
44
|
+
"#{Dir.tmpdir}/frame_#{timestamp}_#{number}.png"
|
45
|
+
end
|
46
|
+
|
47
|
+
def frame_batch
|
48
|
+
batch = ['last'] + (0..frame_count).to_a.reverse
|
49
|
+
batch.join(',')
|
50
|
+
end
|
51
|
+
|
52
|
+
def output_file(timestamp)
|
53
|
+
"#{Dir.tmpdir}/frame_#{timestamp}_%f.png"
|
54
|
+
end
|
55
|
+
|
56
|
+
def executable
|
57
|
+
Thwomp.gnash_path || "gnash-dump"
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
data/lib/thwomp/thumbnail.rb
CHANGED
@@ -3,52 +3,25 @@ require 'oily_png'
|
|
3
3
|
|
4
4
|
module Thwomp
|
5
5
|
|
6
|
-
# Creates thumbnail of SWF movies
|
7
6
|
class Thumbnail
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
:max_height => 128 }
|
13
|
-
|
14
|
-
#
|
15
|
-
# Intializes thumbnail renderer
|
16
|
-
#
|
17
|
-
# Options
|
18
|
-
# :max_width Maximum width of thumbnail
|
19
|
-
# :max_height Maximum height of thumbnail
|
20
|
-
#
|
21
|
-
def initialize(renderer, options = {})
|
22
|
-
DEFAULT_OPTIONS.merge(options).each { |k,v| send(:"#{k}=", v) if v }
|
23
|
-
@renderer = renderer
|
24
|
-
end
|
25
|
-
|
26
|
-
# returns the png binary data of the generated thumbnail
|
27
|
-
def png_data(frame)
|
28
|
-
File.open(filename(frame), 'rb') { |f| f.read } if renderer.frame_exists?(frame)
|
29
|
-
end
|
30
|
-
|
31
|
-
# returns the temp filename of the generated thumbnail
|
32
|
-
def filename(frame)
|
33
|
-
@filename ||= {}
|
34
|
-
@filename[frame] ||= generate_thumbnail!(frame) if renderer.frame_exists?(frame)
|
35
|
-
end
|
8
|
+
def self.generate!(path, options={})
|
9
|
+
width = options.fetch(:width, 128)
|
10
|
+
height = options.fetch(:height, 128)
|
36
11
|
|
37
|
-
|
12
|
+
filename = path.gsub(/frame/, 'thumbnail')
|
38
13
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
def generate_thumbnail!(frame)
|
44
|
-
filename = "#{Dir.tmpdir}/thumbnail_#{Time.now.to_i}_#{frame}.png"
|
14
|
+
begin
|
15
|
+
thumbnail = ChunkyPNG::Image.from_file(path)
|
16
|
+
thumbnail.resample_bilinear!(width, height)
|
17
|
+
thumbnail.save(filename)
|
45
18
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
filename
|
19
|
+
filename
|
20
|
+
rescue ChunkyPNG::Exception, RangeError, NoMethodError
|
21
|
+
false
|
22
|
+
end
|
51
23
|
end
|
52
24
|
|
53
25
|
end
|
26
|
+
|
54
27
|
end
|
data/lib/thwomp/version.rb
CHANGED
@@ -1,12 +1,22 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
|
3
|
+
module Thwomp
|
4
4
|
|
5
|
-
|
5
|
+
describe AnimationPreview do
|
6
|
+
|
7
|
+
it "shells out to 'convert' to create an animated gif" do
|
8
|
+
frames = %w(a.png b.png c.png)
|
9
|
+
now = Time.now
|
10
|
+
output_file = "#{Dir.tmpdir}/animation_#{now.to_i}.gif"
|
11
|
+
|
12
|
+
cmd = "convert #{frames.join(' ')} #{output_file}"
|
13
|
+
Command.should_receive(:exec).with(cmd)
|
14
|
+
|
15
|
+
Time.stub(:now).and_return(now)
|
16
|
+
preview = AnimationPreview.new(frames)
|
17
|
+
preview.generate!.should == output_file
|
18
|
+
end
|
6
19
|
|
7
|
-
it 'generates a gif animation' do
|
8
|
-
animation = Thwomp::AnimationPreview.new(renderer, :max_width => 60, :max_height => 60)
|
9
|
-
animation.gif_data.should == get_contents("#{File.dirname(__FILE__)}/fixtures/frames.gif")
|
10
20
|
end
|
11
21
|
|
12
22
|
end
|
data/spec/renderer_spec.rb
CHANGED
@@ -1,30 +1,29 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'thwomp'
|
3
3
|
|
4
|
-
|
5
|
-
describe 'extracting frames from flash' do
|
4
|
+
module Thwomp
|
6
5
|
|
7
|
-
|
6
|
+
describe Renderer do
|
8
7
|
|
9
|
-
it
|
10
|
-
|
8
|
+
it "instantiates the ffmpeg renderer for flv" do
|
9
|
+
path = "/some/path/test.flv"
|
10
|
+
Renderers::FFMPEG.should_receive(:new).with(path)
|
11
|
+
renderer = Renderer.new(path)
|
11
12
|
end
|
12
13
|
|
13
|
-
it
|
14
|
-
|
14
|
+
it "instantiates the gnash renderer for swf" do
|
15
|
+
path = "/some/path/test.swf"
|
16
|
+
Renderers::SWF.should_receive(:new).with(path)
|
17
|
+
renderer = Renderer.new(path)
|
15
18
|
end
|
16
19
|
|
17
|
-
it
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
subject.png_data(3).should == get_contents("#{File.dirname(__FILE__)}/fixtures/frame3.png")
|
23
|
-
end
|
24
|
-
|
25
|
-
it 'extracts frame 5' do
|
26
|
-
subject.png_data(4).should == get_contents("#{File.dirname(__FILE__)}/fixtures/frame4.png")
|
20
|
+
it "passes all arguments to the renderer" do
|
21
|
+
path = "/some/path/test.swf"
|
22
|
+
options = { :width => 200, :height => 200 }
|
23
|
+
Renderers::SWF.should_receive(:new).with(path, options)
|
24
|
+
renderer = Renderer.new(path, options)
|
27
25
|
end
|
28
26
|
|
29
27
|
end
|
28
|
+
|
30
29
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'thwomp'
|
3
|
+
|
4
|
+
module Thwomp
|
5
|
+
|
6
|
+
describe Renderers::FFMPEG do
|
7
|
+
|
8
|
+
let(:path) { File.expand_path("./spec/fixtures/test.flv") }
|
9
|
+
|
10
|
+
it "creates a screenshot every second" do
|
11
|
+
renderer = Renderers::FFMPEG.new(path)
|
12
|
+
now = Time.now
|
13
|
+
output_file = "#{Dir.tmpdir}/frame_#{now.to_i}_%d.png"
|
14
|
+
cmd = "ffmpeg -i #{path} -f image2 -r 1 -vf scale=128:-1 #{output_file} &> /dev/null"
|
15
|
+
|
16
|
+
Time.stub(:now).and_return(now)
|
17
|
+
Command.should_receive(:exec).with(cmd)
|
18
|
+
renderer.frames
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'thwomp'
|
3
|
+
|
4
|
+
module Thwomp
|
5
|
+
|
6
|
+
describe Renderers::SWF do
|
7
|
+
|
8
|
+
let(:input) { "./some/path/to/test.swf" }
|
9
|
+
|
10
|
+
it "shells out to 'gnash' to extract frames from an SWF movie" do
|
11
|
+
renderer = Renderers::SWF.new(input)
|
12
|
+
now = Time.now
|
13
|
+
Time.stub(:now).and_return(now)
|
14
|
+
output_file = "#{Dir.tmpdir}/frame_#{now.to_i}_%f.png"
|
15
|
+
cmd = "gnash-dump -s1 --screenshot=last,10,9,8,7,6,5,4,3,2,1,0 --screenshot-file=#{output_file} -1 -r1 --timeout 200 #{input} -j 500 -k 500 > /dev/null 2>&1"
|
16
|
+
Command.should_receive(:exec).with(cmd)
|
17
|
+
renderer.frames
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/thumbnail_spec.rb
CHANGED
@@ -2,30 +2,8 @@ require 'spec_helper'
|
|
2
2
|
require 'thwomp'
|
3
3
|
|
4
4
|
describe Thwomp::Thumbnail do
|
5
|
-
describe 'creating thumbnails from frames' do
|
6
|
-
|
7
|
-
let(:renderer) { Thwomp::Renderer.new("#{File.dirname(__FILE__)}/fixtures/test.swf") }
|
8
|
-
subject { Thwomp::Thumbnail.new(renderer, :max_width => 128, :max_height => 128) }
|
9
|
-
|
10
|
-
it 'creates thumbnail from frame 1' do
|
11
|
-
subject.png_data(0).should == get_contents("#{File.dirname(__FILE__)}/fixtures/frame0_thumbnail.png")
|
12
|
-
end
|
13
|
-
|
14
|
-
it 'creates thumbnail from frame 2' do
|
15
|
-
subject.png_data(1).should == get_contents("#{File.dirname(__FILE__)}/fixtures/frame1_thumbnail.png")
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'creates thumbnail from frame 3' do
|
19
|
-
subject.png_data(2).should == get_contents("#{File.dirname(__FILE__)}/fixtures/frame2_thumbnail.png")
|
20
|
-
end
|
21
|
-
|
22
|
-
it 'creates thumbnail from frame 4' do
|
23
|
-
subject.png_data(3).should == get_contents("#{File.dirname(__FILE__)}/fixtures/frame3_thumbnail.png")
|
24
|
-
end
|
25
|
-
|
26
|
-
it 'creates thumbnail from frame 5' do
|
27
|
-
subject.png_data(4).should == get_contents("#{File.dirname(__FILE__)}/fixtures/frame4_thumbnail.png")
|
28
|
-
end
|
29
5
|
|
6
|
+
describe 'creating thumbnails from frames' do
|
7
|
+
pending
|
30
8
|
end
|
31
9
|
end
|
metadata
CHANGED
@@ -1,77 +1,77 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: thwomp
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 0
|
9
|
-
- 6
|
10
|
-
version: 0.0.6
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Altovista
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
dependencies:
|
21
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2013-08-27 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
22
15
|
name: rspec
|
23
|
-
|
24
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
25
17
|
none: false
|
26
|
-
requirements:
|
27
|
-
- -
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
|
30
|
-
segments:
|
31
|
-
- 0
|
32
|
-
version: "0"
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
33
22
|
type: :development
|
34
|
-
version_requirements: *id001
|
35
|
-
- !ruby/object:Gem::Dependency
|
36
|
-
name: oily_png
|
37
23
|
prerelease: false
|
38
|
-
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
25
|
none: false
|
40
|
-
requirements:
|
41
|
-
- -
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: oily_png
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
47
38
|
type: :runtime
|
48
|
-
version_requirements: *id002
|
49
|
-
- !ruby/object:Gem::Dependency
|
50
|
-
name: highline
|
51
39
|
prerelease: false
|
52
|
-
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
41
|
none: false
|
54
|
-
requirements:
|
55
|
-
- -
|
56
|
-
- !ruby/object:Gem::Version
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: highline
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
61
54
|
type: :runtime
|
62
|
-
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
63
62
|
description: Creates thumbnails or gif animations using Gnash as SWF renderer
|
64
|
-
email:
|
63
|
+
email:
|
65
64
|
- webmaster@altovista.nl
|
66
|
-
executables:
|
65
|
+
executables:
|
67
66
|
- install_gnash_osx
|
68
67
|
- install_gnash_ubuntu
|
69
68
|
extensions: []
|
70
|
-
|
71
69
|
extra_rdoc_files: []
|
72
|
-
|
73
|
-
files:
|
70
|
+
files:
|
74
71
|
- .gitignore
|
72
|
+
- .ruby-version
|
73
|
+
- .travis.yml
|
74
|
+
- Gemfile
|
75
75
|
- README.rdoc
|
76
76
|
- Rakefile
|
77
77
|
- bin/install_gnash_osx
|
@@ -79,11 +79,14 @@ files:
|
|
79
79
|
- lib/thwomp.rb
|
80
80
|
- lib/thwomp/animation_preview.rb
|
81
81
|
- lib/thwomp/color_counter.rb
|
82
|
+
- lib/thwomp/command.rb
|
82
83
|
- lib/thwomp/downloader.rb
|
83
|
-
- lib/thwomp/raw_renderer.rb
|
84
84
|
- lib/thwomp/renderer.rb
|
85
|
-
- lib/thwomp/
|
85
|
+
- lib/thwomp/renderers/ffmpeg.rb
|
86
|
+
- lib/thwomp/renderers/helper.rb
|
87
|
+
- lib/thwomp/renderers/swf.rb
|
86
88
|
- lib/thwomp/thumbnail.rb
|
89
|
+
- lib/thwomp/thumbnail_picker.rb
|
87
90
|
- lib/thwomp/version.rb
|
88
91
|
- spec/animation_preview_spec.rb
|
89
92
|
- spec/color_counter_spec.rb
|
@@ -102,45 +105,36 @@ files:
|
|
102
105
|
- spec/fixtures/insignificant.png
|
103
106
|
- spec/fixtures/significant.png
|
104
107
|
- spec/renderer_spec.rb
|
108
|
+
- spec/renderers/ffmpeg_spec.rb
|
109
|
+
- spec/renderers/swf_spec.rb
|
105
110
|
- spec/spec_helper.rb
|
106
|
-
- spec/suitable_thumbnail_spec.rb
|
107
111
|
- spec/thumbnail_spec.rb
|
108
112
|
- thwomp.gemspec
|
109
|
-
has_rdoc: true
|
110
113
|
homepage: http://www.altovista.nl
|
111
114
|
licenses: []
|
112
|
-
|
113
115
|
post_install_message:
|
114
116
|
rdoc_options: []
|
115
|
-
|
116
|
-
require_paths:
|
117
|
+
require_paths:
|
117
118
|
- lib
|
118
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
119
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
119
120
|
none: false
|
120
|
-
requirements:
|
121
|
-
- -
|
122
|
-
- !ruby/object:Gem::Version
|
123
|
-
|
124
|
-
|
125
|
-
- 0
|
126
|
-
version: "0"
|
127
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ! '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
128
126
|
none: false
|
129
|
-
requirements:
|
130
|
-
- -
|
131
|
-
- !ruby/object:Gem::Version
|
132
|
-
|
133
|
-
segments:
|
134
|
-
- 0
|
135
|
-
version: "0"
|
127
|
+
requirements:
|
128
|
+
- - ! '>='
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
136
131
|
requirements: []
|
137
|
-
|
138
132
|
rubyforge_project: thwomp
|
139
|
-
rubygems_version: 1.
|
133
|
+
rubygems_version: 1.8.24
|
140
134
|
signing_key:
|
141
135
|
specification_version: 3
|
142
136
|
summary: Create thumbnails or gif animations from SWF files
|
143
|
-
test_files:
|
137
|
+
test_files:
|
144
138
|
- spec/animation_preview_spec.rb
|
145
139
|
- spec/color_counter_spec.rb
|
146
140
|
- spec/fixtures/frame0.png
|
@@ -158,6 +152,7 @@ test_files:
|
|
158
152
|
- spec/fixtures/insignificant.png
|
159
153
|
- spec/fixtures/significant.png
|
160
154
|
- spec/renderer_spec.rb
|
155
|
+
- spec/renderers/ffmpeg_spec.rb
|
156
|
+
- spec/renderers/swf_spec.rb
|
161
157
|
- spec/spec_helper.rb
|
162
|
-
- spec/suitable_thumbnail_spec.rb
|
163
158
|
- spec/thumbnail_spec.rb
|
data/lib/thwomp/raw_renderer.rb
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
require 'tmpdir'
|
2
|
-
|
3
|
-
# TODO maybe nice to use RAW files instead of screenshot files
|
4
|
-
module Thwomp
|
5
|
-
# Renders SWF files
|
6
|
-
class RawRenderer < Renderer
|
7
|
-
|
8
|
-
attr_accessor :max_advances
|
9
|
-
|
10
|
-
private
|
11
|
-
|
12
|
-
# calculates offset of given frame
|
13
|
-
def frame_offset(frame)
|
14
|
-
frame_size * frame
|
15
|
-
end
|
16
|
-
|
17
|
-
# calculates size of frame
|
18
|
-
def frame_size
|
19
|
-
max_width * max_height * 4
|
20
|
-
end
|
21
|
-
|
22
|
-
# maximum number of captures frames
|
23
|
-
def max_advances
|
24
|
-
@max_advances ||= 100
|
25
|
-
end
|
26
|
-
|
27
|
-
# extracts one frame from dump and returns the raw data
|
28
|
-
def extract_frame_from_raw(frame)
|
29
|
-
#@render_frames ||= `#{gnash_binary} #{downloader.filename} -D #{raw_filename} --max-advances #{max_advances} 1 -j 500 -k 500`
|
30
|
-
render_frame!(frame)
|
31
|
-
|
32
|
-
File.open('rb', raw_filename) do |file|
|
33
|
-
file.seek(frame_offset(frame))
|
34
|
-
file.read(frame_size)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
@@ -1,52 +0,0 @@
|
|
1
|
-
module Thwomp
|
2
|
-
|
3
|
-
# Creates thumbnail of SWF movie and finds the most interesting frame in the movie
|
4
|
-
class SuitableThumbnail < Thumbnail
|
5
|
-
|
6
|
-
# returns the png binary data of the generated thumbnail
|
7
|
-
def png_data
|
8
|
-
File.open(filename, 'rb') { |f| f.read }
|
9
|
-
end
|
10
|
-
|
11
|
-
# returns the temp filename of the generated thumbnail
|
12
|
-
def filename
|
13
|
-
@filename ||= generate_thumbnail!
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
# loop till we find the most suitable frame
|
19
|
-
def suitable_frame
|
20
|
-
unless @suitable_frame
|
21
|
-
frames = ['last'] + (0..renderer.max_frames).to_a.reverse
|
22
|
-
|
23
|
-
# render a batch of frames to speed up the process
|
24
|
-
renderer.render_batch!(frames)
|
25
|
-
|
26
|
-
frames.each do |frame|
|
27
|
-
@suitable_frame = frame if !@suitable_frame && suitable_frame?(frame)
|
28
|
-
end
|
29
|
-
|
30
|
-
@suitable_frame ||= 'last'
|
31
|
-
end
|
32
|
-
|
33
|
-
@suitable_frame
|
34
|
-
end
|
35
|
-
|
36
|
-
# tests if the given frame no. is suitable for a thumbnail
|
37
|
-
# tests if the frame doesn't contain a too high concentration of one color
|
38
|
-
def suitable_frame?(frame)
|
39
|
-
renderer.frame_exists?(frame) && ColorCounter.new(renderer.frame_filename(frame)).present?
|
40
|
-
end
|
41
|
-
|
42
|
-
def suitable_frame_filename
|
43
|
-
@suitable_frame_filename ||= renderer.frame_filename(suitable_frame)
|
44
|
-
end
|
45
|
-
|
46
|
-
def generate_thumbnail!
|
47
|
-
super(suitable_frame)
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
51
|
-
|
52
|
-
end
|
@@ -1,11 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'thwomp'
|
3
|
-
|
4
|
-
describe Thwomp::SuitableThumbnail do
|
5
|
-
it 'finds a suitable preview image' do
|
6
|
-
renderer = Thwomp::Renderer.new("#{File.dirname(__FILE__)}/fixtures/test.swf")
|
7
|
-
subject = Thwomp::SuitableThumbnail.new(renderer, :max_width => 128, :max_height => 128)
|
8
|
-
|
9
|
-
subject.png_data.should == get_contents("#{File.dirname(__FILE__)}/fixtures/frame5_thumbnail.png")
|
10
|
-
end
|
11
|
-
end
|