kelredd-pruview 0.1.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of kelredd-pruview might be problematic. Click here for more details.

data/README.rdoc ADDED
@@ -0,0 +1,62 @@
1
+ = Pruview
2
+
3
+ == Description
4
+
5
+ A gem to ease generating image previews (thumbnails) of various files
6
+
7
+ == Installation
8
+
9
+ # install image magick with whatever build dependencies you need for image handling, etc...)
10
+ # if you want to preview movie files
11
+ # => install ffmpeg with whatever build dependencies you need for video/audio handling, etc...)
12
+ # if you want to preview postscript files (PDFs, Adobe Illustrator, etc...)
13
+ # => install any postscript handling libs or dependencies for image magick
14
+
15
+ sudo gem install kelredd-pruview --source http://gems.github.com
16
+
17
+ == Dependencies
18
+
19
+ * image magick + any special file type handling dependencies
20
+ * ffmpeg + h264 encoder + any special file type handling dependencies (for video previewing)
21
+ # something like 'sudo port install ffmpeg +gpl +lame +x264 +xvid' on Mac OSX Leopard
22
+ * gawk
23
+ * Rubygems: mini_magick
24
+
25
+ == Usage
26
+
27
+ require 'pruview'
28
+
29
+ # Preview a document (using image magick)
30
+ document = Pruview::Document.new(<document_file_path>, <pruview_output_path>)
31
+ doc_image_thumb_path = document.to_jpg(<thumb_file_name>, <thumb_pixel_width>, <thumb_pixel_height)
32
+
33
+ # Preview a video (ffmpeg to get an image from movie, then image magick to resize that image)
34
+ video_image_path = Pruview::VideoImage.to_jpg(<video_file_path>, <pruview_output_path>, <video_image_file_name>)
35
+ document = Pruview::Document.new(video_image_path, <pruview_output_path>)
36
+ video_image_thumb_path = document.to_jpg(<thumb_file_name>, <thumb_pixel_width>, <thumb_pixel_height)
37
+
38
+
39
+ == License
40
+
41
+ Copyright (c) 2007-2009 Kelly Redding
42
+
43
+ Permission is hereby granted, free of charge, to any person
44
+ obtaining a copy of this software and associated documentation
45
+ files (the "Software"), to deal in the Software without
46
+ restriction, including without limitation the rights to use,
47
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
48
+ copies of the Software, and to permit persons to whom the
49
+ Software is furnished to do so, subject to the following
50
+ conditions:
51
+
52
+ The above copyright notice and this permission notice shall be
53
+ included in all copies or substantial portions of the Software.
54
+
55
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
56
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
57
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
58
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
59
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
60
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
61
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
62
+ OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,41 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'rake/testtask'
4
+
5
+ require 'lib/pruview/version'
6
+
7
+ task :default => :test
8
+
9
+ spec = Gem::Specification.new do |s|
10
+ s.name = 'pruview'
11
+ s.version = Pruview::Version.to_s
12
+ s.has_rdoc = true
13
+ s.extra_rdoc_files = %w(README.rdoc)
14
+ s.rdoc_options = %w(--main README.rdoc)
15
+ s.summary = "A gem to ease generating image previews (thumbnails) of various files"
16
+ s.author = 'Kelly Redding'
17
+ s.email = 'kelly@kelredd.com'
18
+ s.homepage = ''
19
+ s.files = %w(README.rdoc Rakefile) + Dir.glob("{features,lib,test}/**/*")
20
+ # s.executables = ['pruview']
21
+
22
+ s.add_dependency('mini_magick')
23
+ s.add_dependency('flvtool2')
24
+ end
25
+
26
+ Rake::GemPackageTask.new(spec) do |pkg|
27
+ pkg.gem_spec = spec
28
+ end
29
+
30
+ Rake::TestTask.new do |t|
31
+ t.libs << 'test'
32
+ t.test_files = FileList["test/**/*_test.rb"]
33
+ t.verbose = true
34
+ end
35
+
36
+ desc 'Generate the gemspec to serve this Gem from Github'
37
+ task :github do
38
+ file = File.dirname(__FILE__) + "/#{spec.name}.gemspec"
39
+ File.open(file, 'w') {|f| f << spec.to_ruby }
40
+ puts "Created gemspec: #{file}"
41
+ end
@@ -0,0 +1,21 @@
1
+ Feature: Document
2
+ In order have file thumbnails programmatically
3
+ As a user
4
+ I want create document file thumbnails
5
+
6
+ Scenario: Basic Image thumbnail
7
+ Given I have a basic image document
8
+ When I create a jpg version
9
+ Then I should have a jpg file
10
+
11
+ Scenario: Invalid source image
12
+ Given I have an invalid image document
13
+ Then Pruview should complain about an invalid source file
14
+
15
+ Scenario: Invalid output path
16
+ Given I have an invalid output path for documents
17
+ Then Pruview should complain about an invalid output path
18
+
19
+ Scenario: Invalid source format
20
+ Given I have an invalid format document
21
+ Then Pruview should complain about an invalid source file format
@@ -0,0 +1,32 @@
1
+ When /^I create a[n]* (.+) version$/ do |format|
2
+ @output = @file.send("to_#{format}", 'file', 50, 50)
3
+ end
4
+
5
+ Then /^I should have a[n]* (.+) file$/ do |format|
6
+ assert File.exists?(@output)
7
+ assert File.extname(@output), format
8
+ end
9
+
10
+ Then /^Pruview should complain about an invalid source file$/ do
11
+ assert @complaint
12
+ assert_kind_of Pruview::Exceptions::InvalidError, @complaint
13
+ assert_match /^Invalid source file/, @complaint.message
14
+ end
15
+
16
+ Then /^Pruview should complain about an invalid output path$/ do
17
+ assert @complaint
18
+ assert_kind_of Pruview::Exceptions::InvalidError, @complaint
19
+ assert_match /^Invalid target directory/, @complaint.message
20
+ end
21
+
22
+ Then /^Pruview should complain about an invalid source file format$/ do
23
+ assert @complaint
24
+ assert_kind_of Pruview::Exceptions::InvalidError, @complaint
25
+ assert_match /not supported - file extension: .poop/, @complaint.message
26
+ end
27
+
28
+ Then /^Pruview should complain about an error$/ do
29
+ assert @complaint
30
+ assert_kind_of Pruview::Exceptions::InvalidError, @complaint
31
+ assert_match /not supported - file extension: .poop/, @complaint.message
32
+ end
@@ -0,0 +1,16 @@
1
+ Given /^I have a[n]* (.+) document$/ do |file_type|
2
+ begin
3
+ @file = Pruview::Document.new(FILES[file_type], OUTPUT_PATH)
4
+ rescue Exception => err
5
+ @complaint = err
6
+ end
7
+ end
8
+
9
+ Given /^I have an invalid output path for documents$/ do
10
+ begin
11
+ @file = Pruview::Document.new(FILES['basic image'], INVALID_OUTPUT_PATH)
12
+ rescue Exception => err
13
+ @complaint = err
14
+ end
15
+ end
16
+
@@ -0,0 +1,20 @@
1
+ require 'test/unit/assertions'
2
+ World(Test::Unit::Assertions)
3
+
4
+ require File.dirname(__FILE__) + '/../../../lib/pruview'
5
+
6
+ FILES_PATH = "./test/files"
7
+ OUTPUT_PATH = "./test_output"
8
+ INVALID_OUTPUT_PATH = "./test_output/invalid"
9
+ FILES = {
10
+ 'basic image' => "./test/files/basic.jpg",
11
+ 'invalid image' => "./test/files/invalid.jpg",
12
+ 'error image' => "./test/files/error.jpg",
13
+ 'basic video' => "./test/files/basic.mpg",
14
+ 'invalid video' => "./test/files/invalid.mov",
15
+ 'error video' => "./test/files/error.mov",
16
+ 'invalid format' => "./test/files/invalid_format.poop"
17
+ }
18
+
19
+ FileUtils.mkdir_p File.expand_path(FILES_PATH) unless File.exists? File.expand_path(FILES_PATH)
20
+ FileUtils.mkdir_p File.expand_path(OUTPUT_PATH) unless File.exists? File.expand_path(OUTPUT_PATH)
@@ -0,0 +1,5 @@
1
+ module PruviewFeature
2
+ module Helpers
3
+
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ Given /^I have a[n]* (.+) video image (.+)$/ do |file_type, format|
2
+ begin
3
+ @output = Pruview::VideoImage.send("to_#{format}", FILES[file_type], OUTPUT_PATH, 'file')
4
+ rescue Exception => err
5
+ @complaint = err
6
+ end
7
+ end
8
+
9
+ Given /^I have an invalid output path for video images$/ do
10
+ begin
11
+ @output = Pruview::VideoImage.to_jpg(FILES['basic video'], INVALID_OUTPUT_PATH, 'file')
12
+ rescue Exception => err
13
+ @complaint = err
14
+ end
15
+ end
16
+
@@ -0,0 +1,16 @@
1
+ Given /^I have a[n]* (.+) file$/ do |file_type|
2
+ begin
3
+ @file = Pruview::Video.new(FILES[file_type], OUTPUT_PATH)
4
+ rescue Exception => err
5
+ @complaint = err
6
+ end
7
+ end
8
+
9
+ Given /^I have an invalid output path for videos$/ do
10
+ begin
11
+ @file = Pruview::Video.new(FILES['basic video'], INVALID_OUTPUT_PATH)
12
+ rescue Exception => err
13
+ @complaint = err
14
+ end
15
+ end
16
+
@@ -0,0 +1,26 @@
1
+ Feature: Video
2
+ In order to use video in more universal ways
3
+ As a user
4
+ I want convert video to other formats for viewing
5
+
6
+ Scenario: Basic video to FLV
7
+ Given I have a basic video file
8
+ When I create an flv version
9
+ Then I should have an flv file
10
+
11
+ Scenario: Basic video to MOV
12
+ Given I have a basic video file
13
+ When I create an mov version
14
+ Then I should have an mov file
15
+
16
+ Scenario: Invalid source video
17
+ Given I have an invalid video file
18
+ Then Pruview should complain about an invalid source file
19
+
20
+ Scenario: Invalid output path
21
+ Given I have an invalid output path for videos
22
+ Then Pruview should complain about an invalid output path
23
+
24
+ Scenario: Invalid source format
25
+ Given I have an invalid format file
26
+ Then Pruview should complain about an invalid source file format
@@ -0,0 +1,20 @@
1
+ Feature: Video Image
2
+ In order have video image thumbnails programmatically
3
+ As a user
4
+ I want create video image file thumbnails
5
+
6
+ Scenario: Basic Image thumbnail
7
+ Given I have a basic video video image jpg
8
+ Then I should have a jpg file
9
+
10
+ Scenario: Invalid source image
11
+ Given I have an invalid video video image jpg
12
+ Then Pruview should complain about an invalid source file
13
+
14
+ Scenario: Invalid output path
15
+ Given I have an invalid output path for video images
16
+ Then Pruview should complain about an invalid output path
17
+
18
+ Scenario: Invalid source format
19
+ Given I have an invalid format video image jpg
20
+ Then Pruview should complain about an invalid source file format
data/lib/pruview.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'mini_magick'
3
+ require 'yaml'
4
+
5
+ require File.join(File.dirname(__FILE__), 'pruview', 'exceptions.rb')
6
+ require File.join(File.dirname(__FILE__), 'pruview', 'document.rb')
7
+ require File.join(File.dirname(__FILE__), 'pruview', 'video.rb')
8
+ require File.join(File.dirname(__FILE__), 'pruview', 'video_image.rb')
Binary file
@@ -0,0 +1,138 @@
1
+ module Pruview
2
+
3
+ class Document
4
+
5
+ def initialize(source, target_dir)
6
+ raise Pruview::Exceptions::InvalidError, "Invalid source file: #{source.to_s}" if !File.file?(source)
7
+ raise Pruview::Exceptions::InvalidError, "Invalid target directory: #{target_dir.to_s}" if !File.directory?(target_dir)
8
+ raise Pruview::Exceptions::InvalidError, "Document not supported - file extension: " + file_extension(source) if !format_supported?(source)
9
+ @source = source
10
+ @target_dir = target_dir
11
+ @image = process_image(get_image(source))
12
+ @tempfile = nil
13
+ end
14
+
15
+ def to_jpg(name, width, height, crop = false)
16
+ scale_img = scale_image(width, height, crop)
17
+ scale_img.combine_options do |img|
18
+ img.format 'jpg'
19
+ img.quality '90'
20
+ img.interlace 'plane'
21
+ end
22
+ target = File.join(@target_dir, name.to_s + '.jpg')
23
+ scale_img.write(target)
24
+ return target
25
+ end
26
+
27
+ protected
28
+
29
+ def format_supported?(source)
30
+ file_ext = file_extension(source)
31
+ #return true if file_ext == PSD_EXT # don't support photoshop for now
32
+ POSTSCRIPT_EXT.each { |extension| return true if file_ext == extension }
33
+ IMAGE_EXT.each { |extension| return true if file_ext == extension }
34
+ return false
35
+ end
36
+
37
+ def format_postscript?(source)
38
+ file_ext = file_extension(source)
39
+ POSTSCRIPT_EXT.each { |extension| return true if file_ext == extension }
40
+ return false
41
+ end
42
+
43
+ def file_extension(source_file)
44
+ File.extname(source_file).downcase.chomp
45
+ end
46
+
47
+ def get_image(source)
48
+ source = get_postscript_source(source) if format_postscript?(source)
49
+ begin
50
+ return MiniMagick::Image.from_file(source)
51
+ rescue Exception => err
52
+ raise "Error reading source image: #{err.message}"
53
+ end
54
+ end
55
+
56
+ def get_postscript_source(source)
57
+ begin
58
+ @tempfile = MiniMagick::ImageTempFile.new("pruview.jpg")
59
+ @tempfile.binmode
60
+ ensure
61
+ @tempfile.close
62
+ end
63
+ run_system_command("convert -format jpg \"#{source}[0]\" \"#{@tempfile.path}\"", "Error processing postscript document")
64
+ return @tempfile.path
65
+ end
66
+
67
+ def process_image(image)
68
+ image.format PROCESS_FORMAT
69
+ set_RGB_colorspace(image)
70
+ image.strip
71
+ return image
72
+ end
73
+
74
+ def set_RGB_colorspace(image)
75
+ colorspace = run_system_command("identify -format \"%r\" #{image.path}", "Error reading document colorspace")
76
+ puts "Colorspace: #{colorspace}"
77
+ if colorspace =~ /CMYK/
78
+ image.combine_options do |img|
79
+ img.profile File.join(File.dirname(__FILE__), 'USWebCoatedSWOP.icc')
80
+ img.profile File.join(File.dirname(__FILE__), 'sRGB.icm')
81
+ img.colorspace 'sRGB'
82
+ end
83
+ end
84
+ end
85
+
86
+ def scale_image(width, height, crop = false)
87
+ begin
88
+ image = MiniMagick::Image.from_file(@image.path)
89
+ crop_image(image, crop)
90
+ image.resize "#{width}x#{height}" if crop || @image[:width].to_i > width || @image[:height] > height
91
+ return image
92
+ rescue Exception => err
93
+ raise "Error scaling image: #{err.message}"
94
+ end
95
+ end
96
+
97
+ def crop_image(image, ratio)
98
+ if ratio.kind_of?(Array) && ratio.length == 2
99
+ ratio_width, ratio_height = ratio
100
+ puts "image orig size: #{image[:width].to_i}x#{image[:height].to_i}"
101
+ puts "ratio_width: #{ratio_width}, ratio_height: #{ratio_height}"
102
+ if ratio_width > ratio_height || (ratio_width == ratio_height && image[:height].to_i > image[:width].to_i)
103
+ # calc ratio height from width
104
+ rheight = (image[:width].to_i*(ratio_height.to_f / ratio_width.to_f)).round
105
+ puts "rheight: #{rheight}"
106
+ # shave off height
107
+ shave_off = ((image[:height].to_i - rheight)/2).round
108
+ puts "shave off height: #{image[:height].to_i - rheight}"
109
+ image.shave("0x#{shave_off}")
110
+ puts "image crop size: #{image[:width].to_i}x#{image[:height].to_i}"
111
+ elsif ratio_height > ratio_width || (ratio_width == ratio_height && image[:width].to_i > image[:height].to_i)
112
+ # calc ratio width from height
113
+ rwidth = (image[:height].to_i*(ratio_width.to_f / ratio_height.to_f)).round
114
+ # shave off width
115
+ shave_off = ((image[:width].to_i - rwidth).to_f / 2.to_f).round
116
+ image.shave("#{shave_off}x0")
117
+ end
118
+ end
119
+ return image
120
+ end
121
+
122
+ def run_system_command(command, error_message)
123
+ output = `#{command}`
124
+ raise "#{error_message}: error given #{$?}\n#{output}" if $? != 0
125
+ return output
126
+ end
127
+
128
+ end
129
+
130
+ # Configurations
131
+ Document::PROCESS_FORMAT = 'jpg'
132
+
133
+ Document::PSD_EXT = '.psd'
134
+ Document::POSTSCRIPT_EXT = ['.pdf', '.eps', '.ai']
135
+ Document::IMAGE_EXT = ['.bmp', '.gif', '.jpg', '.jpeg', '.png', '.tga']
136
+
137
+ end
138
+
@@ -0,0 +1,8 @@
1
+ module Pruview
2
+ module Exceptions
3
+
4
+ class InvalidError < ::StandardError
5
+ end
6
+
7
+ end
8
+ end
Binary file
@@ -0,0 +1,13 @@
1
+ module Pruview
2
+ module Version
3
+
4
+ MAJOR = 0
5
+ MINOR = 1
6
+ TINY = 1
7
+
8
+ def self.to_s # :nodoc:
9
+ [MAJOR, MINOR, TINY].join('.')
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,130 @@
1
+ module Pruview
2
+
3
+ class Video
4
+
5
+ # this class assumes you have 'ffmpeg' and 'flvtool2' installed and in your path
6
+
7
+ def initialize(source, target_dir, bitrate_mult = 1)
8
+ raise Pruview::Exceptions::InvalidError, "Invalid source file:: #{source.to_s}" if !File.file?(source)
9
+ raise Pruview::Exceptions::InvalidError, "Invalid target directory: #{target_dir.to_s}" if !File.directory?(target_dir)
10
+ raise Pruview::Exceptions::InvalidError, "Video not supported - file extension: " + file_extension(source) if !format_supported?(source)
11
+ @source = source
12
+ @target_dir = target_dir
13
+ @bitrate_multiplier = bitrate_mult
14
+ end
15
+
16
+ def to_flv(name, width, height, scale_static = false)
17
+ target = to_base(name, width, height, '.flv', scale_static)
18
+ run("#{FLVTOOL} -U #{target}", "Unable to add meta-data for #{target}.")
19
+ return target
20
+ end
21
+
22
+ def to_mov(name, width, height, scale_static = false)
23
+ target = to_base(name, width, height, '.mov', scale_static)
24
+ # TODO: run qt-faststart
25
+ return target
26
+ end
27
+
28
+ protected
29
+
30
+ def to_base(name, width, height, extension, scale_static)
31
+ target = File.join(@target_dir, name.to_s + extension)
32
+ info_yml = File.join(@target_dir, name.to_s + '_info.yml')
33
+ run(build_command(@source, target, width, height, get_info(info_yml), scale_static), "Unable to convert #{@source} to #{target}.")
34
+ return target
35
+ end
36
+
37
+ def format_supported?(source)
38
+ file_ext = file_extension(source)
39
+ EXT.each { |extension| return true if file_ext == extension }
40
+ return false
41
+ end
42
+
43
+ def file_extension(source_file)
44
+ File.extname(source_file).downcase.chomp
45
+ end
46
+
47
+ def get_info(yml)
48
+ run("#{FFYML} #{@source} #{yml}", "Unable to get video info")
49
+ YAML.load_file(yml)
50
+ end
51
+
52
+ def build_command(source, target, width, height, info, scale_static)
53
+ command = "#{FFMPEG} -i #{source}"
54
+ command += get_scale_command(info['width'], info['height'], width, height, scale_static)
55
+ scale_factor = get_scale_factor(info['width'], info['height'], width, height)
56
+ if file_extension(target) != '.flv' # use h264 codec with lower bitrate scaling factor
57
+ command += " -vcodec libx264"
58
+ scale_factor /= 2.0
59
+ end
60
+ puts "scale factor: #{scale_factor.to_s}"
61
+ if !info['bitrate'].zero?
62
+ command += " -b #{(info['bitrate']*@bitrate_multiplier*scale_factor).to_s}"
63
+ else
64
+ command += " -sameq"
65
+ end
66
+ command += " -ab #{AUDIO_BITRATE}"
67
+ command += " -ar #{AUDIO_SAMPLING}"
68
+ command += " -y #{target}"
69
+ end
70
+
71
+ def get_scale_factor(source_width, source_height, scale_width, scale_height)
72
+ if source_width > source_height
73
+ return (scale_width.to_f / source_width.to_f)
74
+ else
75
+ return (scale_height.to_f / source_height.to_f)
76
+ end
77
+ end
78
+
79
+ def get_scale_command(source_width, source_height, scale_width, scale_height, static)
80
+ # this type of scaling assumes a static overall resolution with black padding added appropriately
81
+ # to keep the meaningful video area at the source aspect ratio
82
+ scale_params = get_scaling_params(source_width, source_height, scale_width, scale_height)
83
+ scale_command = " -s #{scale_params[:width].to_s}x#{scale_params[:height].to_s}"
84
+ if static == true
85
+ scale_command += " -padcolor #{PAD_COLOR}"
86
+ scale_command += " -padleft #{scale_params[:left]}" if scale_params[:left] > 0
87
+ scale_command += " -padtop #{scale_params[:top]}" if scale_params[:top] > 0
88
+ scale_command += " -padright #{scale_params[:right]}" if scale_params[:right] > 0
89
+ scale_command += " -padbottom #{scale_params[:bottom]}" if scale_params[:bottom] > 0
90
+ end
91
+ scale_command
92
+ end
93
+
94
+ def get_scaling_params(source_width, source_height, scale_width, scale_height)
95
+ params = {}
96
+ params[:left],params[:top],params[:right],params[:bottom] = 0,0,0,0
97
+ params[:width],params[:height] = scale_width, scale_height
98
+ scale_aspect = scale_width.to_f / scale_height.to_f
99
+ source_aspect = source_width.to_f / source_height.to_f
100
+ if(source_aspect > scale_aspect)
101
+ params[:height] = (scale_width.to_f / source_aspect).to_i
102
+ params[:height] += 1 if params[:height] % 2 != 0
103
+ params[:top] = params[:bottom] = ((scale_height - params[:height]).to_f / 2).to_i
104
+ params[:top] = params[:bottom] += 1 if params[:top] % 2 != 0
105
+ elsif(source_aspect < scale_aspect)
106
+ params[:width] = (scale_height.to_f * source_aspect).to_i
107
+ params[:width] += 1 if params[:width] % 2 != 0
108
+ params[:left] = params[:right] = ((scale_width - params[:width]).to_f / 2).to_i
109
+ params[:left] = params[:right] += 1 if params[:left] % 2 != 0
110
+ end
111
+ return params
112
+ end
113
+
114
+ def run(command, error_message = "Unknown error.")
115
+ raise "Ffmpeg error: " + error_message + " - command: '#{command}'" if !system(command)
116
+ end
117
+
118
+ # Configurations
119
+ Video::FFYML = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'bin', 'ffyml'))
120
+ Video::FFMPEG = 'ffmpeg'
121
+ Video::FLVTOOL = 'flvtool2'
122
+ Video::PAD_COLOR = "000000"
123
+ Video::AUDIO_BITRATE = '128' # kbps
124
+ Video::AUDIO_SAMPLING = '44100'
125
+
126
+ Video::EXT = ['.avi', '.flv', '.mov', '.mpg', '.mp4']
127
+
128
+ end
129
+ end
130
+
@@ -0,0 +1,40 @@
1
+ module Pruview
2
+ class VideoImage
3
+
4
+ # this class assumes you have 'ffmpeg' installed and in your path
5
+
6
+ def self.to_jpg(source, target_dir, name)
7
+ raise Pruview::Exceptions::InvalidError, "Invalid source file:: #{source.to_s}" if !File.file?(source)
8
+ raise Pruview::Exceptions::InvalidError, "Invalid target directory: #{target_dir.to_s}" if !File.directory?(target_dir)
9
+ raise Pruview::Exceptions::InvalidError, "Video not supported - file extension: " + file_extension(source) if !format_supported?(source)
10
+ target = File.join(target_dir, name.to_s + '.jpg')
11
+ run(build_command(source, '-ss 00:00:00.2', 'mjpeg', target), "Unable to get preview image for #{target}")
12
+ # TODO: analyze image - create better
13
+ return target
14
+ end
15
+
16
+ protected
17
+
18
+ def self.format_supported?(source)
19
+ file_ext = file_extension(source)
20
+ Video::EXT.each { |extension| return true if file_ext == extension }
21
+ return false
22
+ end
23
+
24
+ def self.file_extension(source_file)
25
+ File.extname(source_file).downcase.chomp
26
+ end
27
+
28
+ def self.build_command(source, time_str, format, target)
29
+ command = "#{Video::FFMPEG} -i #{source}"
30
+ command += " #{time_str}"
31
+ command += " -f #{format}" if !format.empty?
32
+ command += " -an -y #{target}"
33
+ end
34
+
35
+ def self.run(command, error_message = "Unknown error.")
36
+ raise "Ffmpeg error: " + error_message + " - command: '#{command}'" if !system(command)
37
+ end
38
+
39
+ end
40
+ end
Binary file
Binary file
File without changes
File without changes
File without changes
@@ -0,0 +1,10 @@
1
+ # http://sneaq.net/textmate-wtf
2
+ $:.reject! { |e| e.include? 'TextMate' }
3
+
4
+ require 'rubygems'
5
+ require 'test/unit'
6
+ require 'matchy'
7
+ require 'context'
8
+ require 'mocha'
9
+
10
+ require File.dirname(__FILE__) + '/../lib/pruview'
@@ -0,0 +1,13 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class PruviewTest < Test::Unit::TestCase
4
+
5
+ describe "An instance of the Pruview class" do
6
+
7
+ it "should flunk" do
8
+ flunk "Please provide some tests"
9
+ end
10
+
11
+ end
12
+
13
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kelredd-pruview
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Kelly Redding
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-07-22 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: mini_magick
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: flvtool2
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ description:
36
+ email: kelly@kelredd.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - README.rdoc
43
+ files:
44
+ - README.rdoc
45
+ - Rakefile
46
+ - features/document.feature
47
+ - features/step_definitions
48
+ - features/step_definitions/common_steps.rb
49
+ - features/step_definitions/document_steps.rb
50
+ - features/step_definitions/support
51
+ - features/step_definitions/support/env.rb
52
+ - features/step_definitions/support/helpers.rb
53
+ - features/step_definitions/video_image_steps.rb
54
+ - features/step_definitions/video_steps.rb
55
+ - features/video.feature
56
+ - features/video_image.feature
57
+ - lib/pruview
58
+ - lib/pruview/document.rb
59
+ - lib/pruview/exceptions.rb
60
+ - lib/pruview/sRGB.icm
61
+ - lib/pruview/USWebCoatedSWOP.icc
62
+ - lib/pruview/version.rb
63
+ - lib/pruview/video.rb
64
+ - lib/pruview/video_image.rb
65
+ - lib/pruview.rb
66
+ - test/files
67
+ - test/files/basic.jpg
68
+ - test/files/basic.mpg
69
+ - test/files/error.jpg
70
+ - test/files/error.mov
71
+ - test/files/invalid_format.poop
72
+ - test/test_helper.rb
73
+ - test/unit
74
+ - test/unit/pruview_test.rb
75
+ has_rdoc: true
76
+ homepage: ""
77
+ post_install_message:
78
+ rdoc_options:
79
+ - --main
80
+ - README.rdoc
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: "0"
88
+ version:
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: "0"
94
+ version:
95
+ requirements: []
96
+
97
+ rubyforge_project:
98
+ rubygems_version: 1.2.0
99
+ signing_key:
100
+ specification_version: 2
101
+ summary: A gem to ease generating image previews (thumbnails) of various files
102
+ test_files: []
103
+