thwomp 0.0.6 → 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.
- 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
|