tupalo-mini_magick 1.2.5

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ /pkg
data/MIT-LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2005 Corey Johnson probablycorey@gmail.com
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
data/README.rdoc ADDED
@@ -0,0 +1,72 @@
1
+ = MiniMagick
2
+
3
+ A ruby wrapper for ImageMagick command line.
4
+
5
+
6
+ == Why?
7
+
8
+ I was using RMagick and loving it, but it was eating up huge amounts
9
+ of memory. A simple script like this...
10
+
11
+ Magick::read("image.jpg") do |f|
12
+ f.write("manipulated.jpg")
13
+ end
14
+
15
+ ...would use over 100 Megs of Ram. On my local machine this wasn't a
16
+ problem, but on my hosting server the ruby apps would crash because of
17
+ their 100 Meg memory limit.
18
+
19
+
20
+ == Solution!
21
+
22
+ Using MiniMagick the ruby processes memory remains small (it spawns
23
+ ImageMagick's command line program mogrify which takes up some memory
24
+ as well, but is much smaller compared to RMagick)
25
+
26
+ MiniMagick gives you access to all the commandline options ImageMagick
27
+ has (Found here http://www.imagemagick.org/script/mogrify.php)
28
+
29
+
30
+ == Examples
31
+
32
+ Want to make a thumbnail from a file...
33
+
34
+ image = MiniMagick::Image.from_file("input.jpg")
35
+ image.resize "100x100"
36
+ image.write("output.jpg")
37
+
38
+ Want to make a thumbnail from a blob...
39
+
40
+ image = MiniMagick::Image.from_blob(blob)
41
+ image.resize "100x100"
42
+ image.write("output.jpg")
43
+
44
+ Need to combine several options?
45
+
46
+ image = MiniMagick::Image.from_file("input.jpg")
47
+ image.combine_options do |c|
48
+ c.sample "50%"
49
+ c.rotate "-90>"
50
+ end
51
+ image.write("output.jpg")
52
+
53
+ Want to manipulate an image at its source (You won't have to write it
54
+ out because the transformations are done on that file)
55
+
56
+ image = MiniMagick::Image.new("input.jpg")
57
+ image.resize "100x100"
58
+
59
+ Want to get some meta-information out?
60
+
61
+ image = MiniMagick::Image.from_file("input.jpg")
62
+ image[:width] # will get the width (you can also use :height and :format)
63
+ image["EXIF:BitsPerSample"] # It also can get all the EXIF tags
64
+ image["%m:%f %wx%h"] # Or you can use one of the many options of the format command
65
+
66
+ For more on the format command see
67
+ http://www.imagemagick.org/script/command-line-options.php#format
68
+
69
+
70
+ == Requirements
71
+
72
+ You must have ImageMagick installed.
data/Rakefile ADDED
@@ -0,0 +1,39 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ $:.unshift(File.dirname(__FILE__) + "/lib")
6
+ require 'mini_magick'
7
+
8
+ desc 'Default: run unit tests.'
9
+ task :default => :test
10
+
11
+ desc 'Test the mini_magick plugin.'
12
+ Rake::TestTask.new(:test) do |t|
13
+ t.libs << 'lib'
14
+ t.pattern = 'test/**/*_test.rb'
15
+ t.verbose = true
16
+ end
17
+
18
+ desc 'Generate documentation for the mini_magick plugin.'
19
+ Rake::RDocTask.new(:rdoc) do |rdoc|
20
+ rdoc.rdoc_dir = 'rdoc'
21
+ rdoc.title = 'MiniMagick'
22
+ rdoc.options << '--line-numbers'
23
+ rdoc.options << '--inline-source'
24
+ rdoc.rdoc_files.include('README.rdoc')
25
+ rdoc.rdoc_files.include('lib/**/*.rb')
26
+ end
27
+
28
+ begin
29
+ require 'jeweler'
30
+ Jeweler::Tasks.new do |gemspec|
31
+ gemspec.name = "mini_magick"
32
+ gemspec.summary = "Manipulate images with minimal use of memory."
33
+ gemspec.email = "probablycorey@gmail.com"
34
+ gemspec.homepage = "http://github.com/probablycorey/mini_magick"
35
+ gemspec.authors = ["Corey Johnson"]
36
+ end
37
+ rescue LoadError
38
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
39
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.2.5
@@ -0,0 +1,9 @@
1
+ require "tempfile"
2
+
3
+ module MiniMagick
4
+ class ImageTempFile < Tempfile
5
+ def make_tmpname(ext, n)
6
+ 'mini_magick%d-%d%s' % [$$, n, ext ? ".#{ext}" : '']
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,223 @@
1
+ require "open-uri"
2
+ require "stringio"
3
+ require "fileutils"
4
+ require "open3"
5
+
6
+ require File.join(File.dirname(__FILE__), '/image_temp_file')
7
+
8
+ module MiniMagick
9
+ class MiniMagickError < RuntimeError; end
10
+
11
+ class Image
12
+ attr :path
13
+ attr :tempfile
14
+ attr :output
15
+
16
+ # Class Methods
17
+ # -------------
18
+ class << self
19
+ def from_blob(blob, ext = nil)
20
+ begin
21
+ tempfile = ImageTempFile.new(ext)
22
+ tempfile.binmode
23
+ tempfile.write(blob)
24
+ ensure
25
+ tempfile.close if tempfile
26
+ end
27
+
28
+ return self.new(tempfile.path, tempfile)
29
+ end
30
+
31
+ # Use this if you don't want to overwrite the image file
32
+ def open(image_path)
33
+ File.open(image_path, "rb") do |f|
34
+ self.from_blob(f.read, File.extname(image_path))
35
+ end
36
+ end
37
+ alias_method :from_file, :open
38
+ end
39
+
40
+ # Instance Methods
41
+ # ----------------
42
+ def initialize(input_path, tempfile=nil)
43
+ @path = input_path
44
+ @tempfile = tempfile # ensures that the tempfile will stick around until this image is garbage collected.
45
+
46
+ # Ensure that the file is an image
47
+ run_command("identify", @path)
48
+ end
49
+
50
+ # For reference see http://www.imagemagick.org/script/command-line-options.php#format
51
+ def [](value)
52
+ # Why do I go to the trouble of putting in newlines? Because otherwise animated gifs screw everything up
53
+ case value.to_s
54
+ when "format"
55
+ run_command("identify", "-format", format_option("%m"), @path).split("\n")[0]
56
+ when "height"
57
+ run_command("identify", "-format", format_option("%h"), @path).split("\n")[0].to_i
58
+ when "width"
59
+ run_command("identify", "-format", format_option("%w"), @path).split("\n")[0].to_i
60
+ when "dimensions"
61
+ run_command("identify", "-format", format_option("%w %h"), @path).split("\n")[0].split.map{|v|v.to_i}
62
+ when "size"
63
+ File.size(@path) # Do this because calling identify -format "%b" on an animated gif fails!
64
+ when "original_at"
65
+ # Get the EXIF original capture as a Time object
66
+ Time.local(*self["EXIF:DateTimeOriginal"].split(/:|\s+/)) rescue nil
67
+ when /^EXIF\:/i
68
+ run_command('identify', '-format', "\"%[#{value}]\"", @path).chop
69
+ else
70
+ run_command('identify', '-format', "\"#{value}\"", @path).split("\n")[0]
71
+ end
72
+ end
73
+
74
+ # Sends raw commands to imagemagick's mogrify command. The image path is automatically appended to the command
75
+ def <<(*args)
76
+ run_command("mogrify", *args << @path)
77
+ end
78
+
79
+ # This is a 'special' command because it needs to change @path to reflect the new extension
80
+ # Formatting an animation into a non-animated type will result in ImageMagick creating multiple
81
+ # pages (starting with 0). You can choose which page you want to manipulate. We default to the
82
+ # first page.
83
+ def format(format, page=0)
84
+ run_command("mogrify", "-format", format, @path)
85
+
86
+ old_path = @path.dup
87
+ @path.sub!(/(\.\w+)?$/, ".#{format}")
88
+ File.delete(old_path) unless old_path == @path
89
+
90
+ unless File.exists?(@path)
91
+ begin
92
+ FileUtils.copy_file(@path.sub(".#{format}", "-#{page}.#{format}"), @path)
93
+ rescue e
94
+ raise MiniMagickError, "Unable to format to #{format}; #{e}" unless File.exist?(@path)
95
+ end
96
+ end
97
+ ensure
98
+ Dir[@path.sub(/(\.\w+)?$/, "-[0-9]*.#{format}")].each do |fname|
99
+ File.unlink(fname)
100
+ end
101
+ end
102
+
103
+ # Writes the temporary image that we are using for processing to the output path
104
+ def write(output_path)
105
+ FileUtils.copy_file @path, output_path
106
+ run_command "identify", output_path # Verify that we have a good image
107
+ end
108
+
109
+ # Give you raw data back
110
+ def to_blob
111
+ f = File.new @path
112
+ f.binmode
113
+ f.read
114
+ ensure
115
+ f.close if f
116
+ end
117
+
118
+ # If an unknown method is called then it is sent through the morgrify program
119
+ # Look here to find all the commands (http://www.imagemagick.org/script/mogrify.php)
120
+ def method_missing(symbol, *args)
121
+ args.push(@path) # push the path onto the end
122
+ run_command("mogrify", "-#{symbol}", *args)
123
+ self
124
+ end
125
+
126
+ # You can use multiple commands together using this method
127
+ def combine_options(&block)
128
+ c = CommandBuilder.new
129
+ block.call c
130
+ run_command("mogrify", *c.args << @path)
131
+ end
132
+
133
+ # Check to see if we are running on win32 -- we need to escape things differently
134
+ def windows?
135
+ !(RUBY_PLATFORM =~ /win32/).nil?
136
+ end
137
+
138
+ # Outputs a carriage-return delimited format string for Unix and Windows
139
+ def format_option(format)
140
+ windows? ? "#{format}\\n" : "#{format}\\\\n"
141
+ end
142
+
143
+ def run_command(command, *args)
144
+ args.collect! do |arg|
145
+ # args can contain characters like '>' so we must escape them, but don't quote switches
146
+ if arg !~ /^[\+\-]/
147
+ "\"#{arg}\""
148
+ else
149
+ arg.to_s
150
+ end
151
+ end
152
+
153
+ command = "#{command} #{args.join(' ')}"
154
+ output = `#{command} 2>&1`
155
+
156
+ if $?.exitstatus != 0
157
+ raise MiniMagickError, "ImageMagick command (#{command.inspect}) failed: #{{:status_code => $?, :output => output}.inspect}"
158
+ else
159
+ output
160
+ end
161
+ end
162
+ end
163
+
164
+ # Combines multiple images into a single montage via ImageMagick's montage script
165
+ class Montage
166
+ # Class Methods
167
+ # -------------
168
+
169
+ # To create a montage simply call Montage.new with the images you want combine,
170
+ # the path to the output file and any command line options you may want.
171
+ # You will be returned a MiniMagick::Image instance for the new montage:
172
+ #
173
+ # image1 = MiniMagick::Image.open('alice.png')
174
+ # image2 = MiniMagick::Image.open('bob.png')
175
+ # output_image = MiniMagick::Composite.new([image1, image2], 'jpg', :background => '#336699')
176
+ # output_image.write('montage.jpg')
177
+ #
178
+ # The above example would combine the two images into a new JPEG file using a background color of #336699.
179
+ # The the image is saved using the standard Image.save method.
180
+ #
181
+ # The 'montage' script has several options, see here: http://www.imagemagick.org/script/montage.php
182
+ def self.new(images, output_extension, options={})
183
+ begin
184
+ tempfile = ImageTempFile.new(output_extension)
185
+ tempfile.binmode
186
+ ensure
187
+ tempfile.close
188
+ end
189
+
190
+ args = options.collect { |key,value| "-#{key.to_s} #{value.to_s}" } # collect hash parts into arguments
191
+ images.each do |image|
192
+ args.push image.path
193
+ end
194
+ args.push(tempfile.path)
195
+
196
+ # This is a little hacky - cannikin's CommandeRunner would be a useful
197
+ # alternative (http://github.com/cannikin/mini_magick).
198
+ Image.new(images.first.path).run_command('montage', *args)
199
+ return Image.open(tempfile.path)
200
+ end
201
+
202
+ def run
203
+ end
204
+
205
+ end
206
+
207
+ class CommandBuilder
208
+ attr :args
209
+
210
+ def initialize
211
+ @args = []
212
+ end
213
+
214
+ def method_missing(symbol, *args)
215
+ @args << "-#{symbol}"
216
+ @args += args
217
+ end
218
+
219
+ def +(value)
220
+ @args << "+#{value}"
221
+ end
222
+ end
223
+ end
@@ -0,0 +1,55 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{tupalo-mini_magick}
5
+ s.version = "1.2.5"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Corey Johnson"]
9
+ s.date = %q{2009-05-27}
10
+ s.description = %q{This is a fork of peplins fork of the mini_magick gem. It includes support for the montage command.}
11
+ s.email = %q{thomas@tupalo.com}
12
+ s.extra_rdoc_files = [
13
+ "README.rdoc"
14
+ ]
15
+ s.files = [
16
+ ".gitignore",
17
+ "MIT-LICENSE",
18
+ "README.rdoc",
19
+ "Rakefile",
20
+ "VERSION",
21
+ "lib/image_temp_file.rb",
22
+ "lib/mini_magick.rb",
23
+ "mini_magick.gemspec",
24
+ "test/actually_a_gif.jpg",
25
+ "test/animation.gif",
26
+ "test/command_builder_test.rb",
27
+ "test/image_temp_file_test.rb",
28
+ "test/image_test.rb",
29
+ "test/leaves.tiff",
30
+ "test/not_an_image.php",
31
+ "test/simple.gif",
32
+ "test/trogdor.jpg"
33
+ ]
34
+ s.has_rdoc = true
35
+ s.homepage = %q{http://github.com/fadr/tupalo-mini_magick}
36
+ s.rdoc_options = ["--charset=UTF-8"]
37
+ s.require_paths = ["lib"]
38
+ s.rubygems_version = %q{1.3.1}
39
+ s.summary = %q{Manipulate images with minimal use of memory.}
40
+ s.test_files = [
41
+ "test/command_builder_test.rb",
42
+ "test/image_temp_file_test.rb",
43
+ "test/image_test.rb"
44
+ ]
45
+
46
+ if s.respond_to? :specification_version then
47
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
48
+ s.specification_version = 2
49
+
50
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
51
+ else
52
+ end
53
+ else
54
+ end
55
+ end
Binary file
Binary file
@@ -0,0 +1,20 @@
1
+ require 'test/unit'
2
+ require File.join(File.dirname(__FILE__), '../lib/mini_magick')
3
+
4
+ class CommandBuilderTest < Test::Unit::TestCase
5
+ include MiniMagick
6
+
7
+ def test_basic
8
+ c = CommandBuilder.new
9
+ c.resize "30x40"
10
+ assert_equal "-resize 30x40", c.args.join(" ")
11
+ end
12
+
13
+ def test_complicated
14
+ c = CommandBuilder.new
15
+ c.resize "30x40"
16
+ c.input 1, 3, 4
17
+ c.lingo "mome fingo"
18
+ assert_equal "-resize 30x40 -input 1 3 4 -lingo mome fingo", c.args.join(" ")
19
+ end
20
+ end