image_genie 0.2.0 → 0.3.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/Manifest +3 -0
- data/README +0 -0
- data/Rakefile +1 -1
- data/image_genie.gemspec +4 -4
- data/lib/image_genie.rb +1 -1
- data/lib/image_genie/base.rb +4 -3
- data/lib/image_genie/command.rb +83 -1
- data/lib/image_genie/convert.rb +18 -23
- data/lib/image_genie/identify.rb +13 -24
- data/lib/image_genie/montage.rb +22 -33
- data/lib/image_genie/test.rb +43 -0
- data/lib/image_genie/verify.rb +12 -17
- metadata +9 -5
data/Manifest
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
Manifest
|
2
|
+
README
|
2
3
|
README.rdoc
|
3
4
|
Rakefile
|
5
|
+
image_genie.gemspec
|
4
6
|
lib/image_genie.rb
|
5
7
|
lib/image_genie/base.rb
|
6
8
|
lib/image_genie/command.rb
|
7
9
|
lib/image_genie/convert.rb
|
8
10
|
lib/image_genie/identify.rb
|
9
11
|
lib/image_genie/montage.rb
|
12
|
+
lib/image_genie/test.rb
|
10
13
|
lib/image_genie/verify.rb
|
11
14
|
test/test_helper.rb
|
12
15
|
test/unit/base_test.rb
|
data/README
ADDED
File without changes
|
data/Rakefile
CHANGED
@@ -3,7 +3,7 @@ require 'rake'
|
|
3
3
|
require 'echoe'
|
4
4
|
require 'rake/testtask'
|
5
5
|
|
6
|
-
Echoe.new('image_genie', '0.
|
6
|
+
Echoe.new('image_genie', '0.3.0') do |p|
|
7
7
|
p.description = "ImageGenie - Simple Wrapper for command line ImageMagick"
|
8
8
|
p.url = "https://github.com/bkimble"
|
9
9
|
p.author = "Billy Kimble"
|
data/image_genie.gemspec
CHANGED
@@ -2,15 +2,15 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{image_genie}
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.3.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Billy Kimble"]
|
9
|
-
s.date = %q{2011-02-
|
9
|
+
s.date = %q{2011-02-09}
|
10
10
|
s.description = %q{ImageGenie - Simple Wrapper for command line ImageMagick}
|
11
11
|
s.email = %q{basslines@gmail.com}
|
12
|
-
s.extra_rdoc_files = ["README.rdoc", "lib/image_genie.rb", "lib/image_genie/base.rb", "lib/image_genie/command.rb", "lib/image_genie/convert.rb", "lib/image_genie/identify.rb", "lib/image_genie/montage.rb", "lib/image_genie/verify.rb"]
|
13
|
-
s.files = ["Manifest", "README.rdoc", "Rakefile", "lib/image_genie.rb", "lib/image_genie/base.rb", "lib/image_genie/command.rb", "lib/image_genie/convert.rb", "lib/image_genie/identify.rb", "lib/image_genie/montage.rb", "lib/image_genie/verify.rb", "test/test_helper.rb", "test/unit/base_test.rb"
|
12
|
+
s.extra_rdoc_files = ["README", "README.rdoc", "lib/image_genie.rb", "lib/image_genie/base.rb", "lib/image_genie/command.rb", "lib/image_genie/convert.rb", "lib/image_genie/identify.rb", "lib/image_genie/montage.rb", "lib/image_genie/test.rb", "lib/image_genie/verify.rb"]
|
13
|
+
s.files = ["Manifest", "README", "README.rdoc", "Rakefile", "image_genie.gemspec", "lib/image_genie.rb", "lib/image_genie/base.rb", "lib/image_genie/command.rb", "lib/image_genie/convert.rb", "lib/image_genie/identify.rb", "lib/image_genie/montage.rb", "lib/image_genie/test.rb", "lib/image_genie/verify.rb", "test/test_helper.rb", "test/unit/base_test.rb"]
|
14
14
|
s.homepage = %q{https://github.com/bkimble}
|
15
15
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Image_genie", "--main", "README"]
|
16
16
|
s.require_paths = ["lib"]
|
data/lib/image_genie.rb
CHANGED
@@ -33,7 +33,7 @@ module ImageGenie
|
|
33
33
|
|
34
34
|
module ClassMethods
|
35
35
|
# Make helper methods
|
36
|
-
[:convert,:montage,:identify,:verify].each do |method|
|
36
|
+
[:convert,:montage,:identify,:verify,:test].each do |method|
|
37
37
|
define_method(method) do |*splat|
|
38
38
|
module_name = "#{self.name}::#{method.to_s.capitalize}"
|
39
39
|
target = module_name.constantize
|
data/lib/image_genie/base.rb
CHANGED
@@ -15,7 +15,6 @@ module ImageGenie
|
|
15
15
|
@paths
|
16
16
|
end
|
17
17
|
|
18
|
-
# Eventually I want this method to accept a model that encapsulates its command execution logic.
|
19
18
|
def self.execute(command)
|
20
19
|
logger.info("Executing #{command}")
|
21
20
|
pid, stdin, stdout, stderr = Open4::popen4(command)
|
@@ -24,7 +23,7 @@ module ImageGenie
|
|
24
23
|
|
25
24
|
def self.path_for(program)
|
26
25
|
paths[program.to_sym]
|
27
|
-
end
|
26
|
+
end
|
28
27
|
|
29
28
|
def self.make_command(command,*args)
|
30
29
|
command.strip!
|
@@ -39,19 +38,21 @@ module ImageGenie
|
|
39
38
|
components.compact.join(' ')
|
40
39
|
end
|
41
40
|
|
41
|
+
|
42
42
|
def self.make_args(args)
|
43
43
|
args = [args] if !args.is_a?(Array)
|
44
44
|
return nil if args.empty?
|
45
45
|
args.join(' ')
|
46
46
|
end
|
47
47
|
|
48
|
+
|
48
49
|
# There is probably a better library to handle creation of command line flags,
|
49
50
|
# but this works for now.
|
50
51
|
def self.make_flags(options={})
|
51
52
|
return nil if options.empty?
|
52
53
|
options.collect{|k,v| "-#{k} #{v}"}.join(' ')
|
53
54
|
end
|
54
|
-
|
55
|
+
|
55
56
|
def self.logger
|
56
57
|
@log ||= TimestampedBufferedLogger.new(Rails.root.join('log','image_genie.log'))
|
57
58
|
end
|
data/lib/image_genie/command.rb
CHANGED
@@ -1,5 +1,35 @@
|
|
1
1
|
module ImageGenie
|
2
2
|
class Command < Base
|
3
|
+
attr_accessor :stdin,:stdout,:stderr,:pid,:status
|
4
|
+
attr_accessor :exception_class,:caller_obj
|
5
|
+
attr_accessor :output_buffer
|
6
|
+
|
7
|
+
def has_error?
|
8
|
+
!self.status.zero?
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(obj)
|
12
|
+
self.output_buffer = ''
|
13
|
+
self.caller_obj = obj
|
14
|
+
end
|
15
|
+
|
16
|
+
def execute(command)
|
17
|
+
begin
|
18
|
+
caller_obj.pid, caller_obj.stdin, caller_obj.stdout, caller_obj.stderr = Open4::popen4(command)
|
19
|
+
caller_obj.input if caller_obj.respond_to?(:input)
|
20
|
+
caller_obj.output if caller_obj.respond_to?(:output)
|
21
|
+
puts "Waiting"
|
22
|
+
ignored, status = Process::waitpid2 caller_obj.pid
|
23
|
+
self.status = status.exitstatus
|
24
|
+
puts "checking for error now"
|
25
|
+
caller_obj.error if caller_obj.respond_to?(:error)
|
26
|
+
rescue Exception => e
|
27
|
+
raise
|
28
|
+
ensure
|
29
|
+
caller_obj.cleanup if caller_obj.respond_to?(:cleanup)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
3
33
|
def self.handle_errors(stderr,status,exception)
|
4
34
|
unless status.exitstatus.zero?
|
5
35
|
errors = stderr.read.strip
|
@@ -7,5 +37,57 @@ module ImageGenie
|
|
7
37
|
raise(exception, errors)
|
8
38
|
end
|
9
39
|
end
|
40
|
+
|
41
|
+
def path_for(program)
|
42
|
+
self.class.paths[program.to_sym]
|
43
|
+
end
|
44
|
+
|
45
|
+
def make_command(command,*args)
|
46
|
+
command.strip!
|
47
|
+
components = [command]
|
48
|
+
args.each do |component|
|
49
|
+
components << case (component.class.name)
|
50
|
+
when 'Hash': make_flags(component)
|
51
|
+
when 'Array': make_args(component)
|
52
|
+
else " #{component}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
components.compact.join(' ')
|
56
|
+
end
|
57
|
+
|
58
|
+
def make_args(args)
|
59
|
+
args = [args] if !args.is_a?(Array)
|
60
|
+
return nil if args.empty?
|
61
|
+
args.join(' ')
|
62
|
+
end
|
63
|
+
|
64
|
+
# There is probably a better library to handle creation of command line flags,
|
65
|
+
# but this works for now.
|
66
|
+
def make_flags(options={})
|
67
|
+
return nil if options.empty?
|
68
|
+
options.collect{|k,v| "-#{k} #{v}"}.join(' ')
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
# define generic error/input/output handlers
|
73
|
+
def error
|
74
|
+
if has_error?
|
75
|
+
errors = stderr.read.strip
|
76
|
+
logger.error("#{caller_obj.class.name} #{errors}")
|
77
|
+
raise(caller_obj.exception_class, errors)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def output
|
82
|
+
# Generic output processing -- just read it and store it in a buffer. We may want to restrict the amount of data
|
83
|
+
# in here via a configuration directive so we don't eat up all of the available system memory.
|
84
|
+
while !stdout.eof?
|
85
|
+
self.output_buffer += stdout.readline
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
10
89
|
end
|
11
|
-
end
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
|
data/lib/image_genie/convert.rb
CHANGED
@@ -1,33 +1,28 @@
|
|
1
1
|
module ImageGenie
|
2
2
|
class ConvertError < StandardError; end;
|
3
3
|
class Convert < Command
|
4
|
-
|
5
|
-
raise(UnableToLocateBinaryError, 'convert') if path_for(:convert).blank?
|
4
|
+
attr_accessor :src, :temp_image_file, :options, :src_format
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
raise Errno::ENOENT,"#{src.path}" unless File.exists?(src.path)
|
11
|
-
rescue Errno::ENOENT => e
|
12
|
-
logger.error("#{self.name} #{e.message}")
|
13
|
-
raise
|
6
|
+
def output
|
7
|
+
while line = stdout.gets
|
8
|
+
temp_image_file.puts line
|
14
9
|
end
|
10
|
+
temp_image_file.rewind
|
11
|
+
end
|
15
12
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
ignored, status = Process::waitpid2 pid
|
26
|
-
handle_errors(stderr,status,ConvertError)
|
27
|
-
end
|
13
|
+
def initialize(src,options={})
|
14
|
+
self.src = src
|
15
|
+
self.options = options
|
16
|
+
self.src_format = File.extname(src.path).downcase.gsub(/\.|\?/,'')
|
17
|
+
logger.info("#{self.class.name} Attempting to convert #{src.path}")
|
18
|
+
raise Errno::ENOENT,"#{src.path}" unless File.exists?(src.path)
|
19
|
+
self.temp_image_file = Tempfile.new([src.original_filename,".#{src_format}"])
|
20
|
+
super(self)
|
21
|
+
end
|
28
22
|
|
29
|
-
|
30
|
-
|
23
|
+
def run
|
24
|
+
execute("#{path_for(:convert)} #{make_flags(options)} #{src_format}:#{src.path} #{src_format}:-")
|
25
|
+
temp_image_file
|
31
26
|
end
|
32
27
|
end
|
33
28
|
end
|
data/lib/image_genie/identify.rb
CHANGED
@@ -2,32 +2,21 @@
|
|
2
2
|
module ImageGenie
|
3
3
|
class IdentifyError < StandardError; end;
|
4
4
|
class Identify < Command
|
5
|
-
|
5
|
+
attr_accessor :filename
|
6
|
+
|
7
|
+
def initialize(filename, options={})
|
8
|
+
self.exception_class = IdentifyError
|
6
9
|
raise(UnableToLocateBinaryError, 'identify') if path_for(:identify).blank?
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end
|
14
|
-
|
10
|
+
self.filename = filename
|
11
|
+
raise Errno::ENOENT,"#{filename}" unless File.exists?(filename)
|
12
|
+
super(self)
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
15
16
|
command = "#{path_for(:identify)} #{filename}"
|
16
|
-
|
17
|
-
|
18
|
-
# We test for STDERR content
|
19
|
-
execute(command) do |pid,stdin,stdout,stderr|
|
20
|
-
while !stdout.eof?
|
21
|
-
output += stdout.readline
|
22
|
-
end
|
23
|
-
|
24
|
-
ignored, status = Process::waitpid2 pid
|
25
|
-
handle_errors(stderr,status,IdentifyError)
|
26
|
-
end
|
27
|
-
|
17
|
+
execute(command)
|
28
18
|
fields = [:filename,:format,:dimensions,:geometry,:bit,:image_class,:colors,:filesize,:usertime,:identify_time]
|
29
|
-
return Hash[fields.zip(
|
19
|
+
return Hash[fields.zip(output_buffer.split(' '))]
|
30
20
|
end
|
31
21
|
end
|
32
|
-
end
|
33
|
-
|
22
|
+
end
|
data/lib/image_genie/montage.rb
CHANGED
@@ -1,52 +1,41 @@
|
|
1
1
|
module ImageGenie
|
2
2
|
class MontageError < StandardError; end;
|
3
3
|
class Montage < Command
|
4
|
-
attr_accessor :filenames
|
4
|
+
attr_accessor :filenames, :options, :temp_image_file, :temp_image_list_file
|
5
5
|
|
6
|
-
def
|
7
|
-
|
8
|
-
|
6
|
+
def output
|
7
|
+
while !stdout.eof?
|
8
|
+
temp_image_file.puts stdout.readline
|
9
|
+
end
|
10
|
+
temp_image_file.rewind
|
11
|
+
end
|
12
|
+
|
13
|
+
def cleanup
|
14
|
+
logger.info("#{self.class.name} Cleaning up files")
|
15
|
+
temp_image_list_file.close
|
9
16
|
end
|
10
17
|
|
11
|
-
|
12
|
-
|
18
|
+
def initialize(filenames,options={})
|
19
|
+
logger.info("#{self.class.name} Attempting to make montage of #{filenames.count} files")
|
20
|
+
self.filenames = filenames
|
21
|
+
self.exception_class = MontageError
|
13
22
|
raise(UnableToLocateBinaryError, 'montage') if path_for(:montage).blank?
|
23
|
+
self.options = options
|
14
24
|
# Montage hates when you attempt to give it files with a path in it, so we
|
15
25
|
# need to change to the system specified temp directory to do our work.
|
16
26
|
Dir.chdir(Dir::tmpdir)
|
27
|
+
self.temp_image_file = Tempfile.new(['montage','.jpg'])
|
28
|
+
self.temp_image_list_file = Tempfile.new(['montage_image_filenames','.txt'])
|
17
29
|
# Create a temp file that will be all component files of this montage
|
18
|
-
temp_image_file = Tempfile.new(['montage','.jpg'])
|
19
|
-
temp_image_list_file = Tempfile.new(['montage_image_filenames','.txt'])
|
20
30
|
temp_image_list_file.puts filenames.join("\n")
|
21
31
|
temp_image_list_file.rewind
|
32
|
+
super(self)
|
33
|
+
end
|
22
34
|
|
23
|
-
|
24
|
-
|
35
|
+
def run
|
25
36
|
command = make_command(path_for(:montage), "@\"#{File.basename(temp_image_list_file.path)}\"", options, "jpeg:-")
|
26
|
-
|
27
|
-
begin
|
28
|
-
execute(command) do |pid,stdin,stdout,stderr|
|
29
|
-
while !stdout.eof?
|
30
|
-
temp_image_file.puts stdout.readline
|
31
|
-
end
|
32
|
-
temp_image_file.rewind
|
33
|
-
|
34
|
-
# Still foggy on if we need to wait until we read from STDOUT before waiting, or if
|
35
|
-
# we wait until we read STDOUT and STDERR.
|
36
|
-
ignored, status = Process::waitpid2 pid
|
37
|
-
handle_errors(stderr,status,MontageError)
|
38
|
-
end
|
39
|
-
rescue Exception => e
|
40
|
-
# Close the tempfile before raising
|
41
|
-
temp_image_file.close
|
42
|
-
raise
|
43
|
-
ensure
|
44
|
-
logger.info("#{self.name} Cleaning up files")
|
45
|
-
temp_image_list_file.close
|
46
|
-
end
|
47
|
-
|
37
|
+
execute(command)
|
48
38
|
return temp_image_file
|
49
|
-
|
50
39
|
end
|
51
40
|
end
|
52
41
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module ImageGenie
|
2
|
+
class TestError < StandardError; end;
|
3
|
+
class Test < Command
|
4
|
+
attr_accessor :temp_image_file, :temp_image_list_file
|
5
|
+
|
6
|
+
def input
|
7
|
+
end
|
8
|
+
|
9
|
+
def output
|
10
|
+
while !stdout.eof?
|
11
|
+
puts stdout.readline
|
12
|
+
# self.temp_image_file.puts stdout.readline
|
13
|
+
end
|
14
|
+
# temp_image_file.rewind
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def error
|
19
|
+
if has_error?
|
20
|
+
errors = stderr.read.strip
|
21
|
+
# logger.error("#{self.name} #{errors}")
|
22
|
+
raise(exception_class, errors)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(options={})
|
27
|
+
self.exception_class = TestError
|
28
|
+
# Dir.chdir(Dir::tmpdir)
|
29
|
+
# # Create a temp file that will be all component files of this montage
|
30
|
+
# self.temp_image_file = Tempfile.new(['montage','.jpg'])
|
31
|
+
# self.temp_image_list_file = Tempfile.new(['montage_image_filenames','.txt'])
|
32
|
+
end
|
33
|
+
|
34
|
+
def run
|
35
|
+
execute("ls WERIOWEK",self)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
|
data/lib/image_genie/verify.rb
CHANGED
@@ -4,24 +4,19 @@ module ImageGenie
|
|
4
4
|
class VerifyError < StandardError; end;
|
5
5
|
class Verify < Command
|
6
6
|
|
7
|
-
|
8
|
-
raise(UnableToLocateBinaryError, 'identify') if path_for(:identify).blank?
|
9
|
-
|
10
|
-
begin
|
11
|
-
raise Errno::ENOENT,"#{filename}" unless File.exists?(filename)
|
12
|
-
rescue Errno::ENOENT => e
|
13
|
-
logger.error("#{self.name} #{e.message}")
|
14
|
-
raise
|
15
|
-
end
|
7
|
+
attr_accessor :filename
|
16
8
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
return true
|
9
|
+
def initialize(filename, options={})
|
10
|
+
self.exception_class = VerifyError
|
11
|
+
raise(UnableToLocateBinaryError, 'identify') if path_for(:identify).blank?
|
12
|
+
self.filename = filename
|
13
|
+
raise Errno::ENOENT,"#{filename}" unless File.exists?(filename)
|
14
|
+
super(self)
|
25
15
|
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
execute("#{path_for(:identify)} #{filename}")
|
19
|
+
return true
|
20
|
+
end
|
26
21
|
end
|
27
22
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: image_genie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 3
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Billy Kimble
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-02-
|
18
|
+
date: 2011-02-09 00:00:00 -08:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -39,6 +39,7 @@ executables: []
|
|
39
39
|
extensions: []
|
40
40
|
|
41
41
|
extra_rdoc_files:
|
42
|
+
- README
|
42
43
|
- README.rdoc
|
43
44
|
- lib/image_genie.rb
|
44
45
|
- lib/image_genie/base.rb
|
@@ -46,21 +47,24 @@ extra_rdoc_files:
|
|
46
47
|
- lib/image_genie/convert.rb
|
47
48
|
- lib/image_genie/identify.rb
|
48
49
|
- lib/image_genie/montage.rb
|
50
|
+
- lib/image_genie/test.rb
|
49
51
|
- lib/image_genie/verify.rb
|
50
52
|
files:
|
51
53
|
- Manifest
|
54
|
+
- README
|
52
55
|
- README.rdoc
|
53
56
|
- Rakefile
|
57
|
+
- image_genie.gemspec
|
54
58
|
- lib/image_genie.rb
|
55
59
|
- lib/image_genie/base.rb
|
56
60
|
- lib/image_genie/command.rb
|
57
61
|
- lib/image_genie/convert.rb
|
58
62
|
- lib/image_genie/identify.rb
|
59
63
|
- lib/image_genie/montage.rb
|
64
|
+
- lib/image_genie/test.rb
|
60
65
|
- lib/image_genie/verify.rb
|
61
66
|
- test/test_helper.rb
|
62
67
|
- test/unit/base_test.rb
|
63
|
-
- image_genie.gemspec
|
64
68
|
has_rdoc: true
|
65
69
|
homepage: https://github.com/bkimble
|
66
70
|
licenses: []
|