Class: MiniMagick::Image

Inherits:
Object
  • Object
show all
Defined in:
lib/mini_magick.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(input_path, tempfile = nil) ⇒ Image

Instance Methods




52
53
54
55
56
57
58
# File 'lib/mini_magick.rb', line 52

def initialize(input_path, tempfile=nil)
  @path = input_path
  @tempfile = tempfile # ensures that the tempfile will stick around until this image is garbage collected.

  # Ensure that the file is an image
  run_command("identify", @path)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(symbol, *args) ⇒ Object

If an unknown method is called then it is sent through the morgrify program Look here to find all the commands (www.imagemagick.org/script/mogrify.php)



141
142
143
144
145
146
147
148
149
150
151
# File 'lib/mini_magick.rb', line 141

def method_missing(symbol, *args)
  guessed_command_name = symbol.to_s.gsub('_','-')

  if MOGRIFY_COMMANDS.include?(guessed_command_name)
    args.push(@path) # push the path onto the end
    run_command("mogrify", "-#{guessed_command_name}", *args)
    self
  else
    super(symbol, *args)
  end
end

Instance Attribute Details

#outputObject (readonly)

Returns the value of attribute output.



24
25
26
# File 'lib/mini_magick.rb', line 24

def output
  @output
end

#pathObject (readonly)

Returns the value of attribute path.



22
23
24
# File 'lib/mini_magick.rb', line 22

def path
  @path
end

#tempfileObject (readonly)

Returns the value of attribute tempfile.



23
24
25
# File 'lib/mini_magick.rb', line 23

def tempfile
  @tempfile
end

Class Method Details

.from_blob(blob, ext = nil) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
# File 'lib/mini_magick.rb', line 29

def from_blob(blob, ext = nil)
  begin
    tempfile = Tempfile.new(['mini_magick', ext.to_s])
    tempfile.binmode
    tempfile.write(blob)
  ensure
    tempfile.close if tempfile
  end

  return self.new(tempfile.path, tempfile)
end

.open(image_path) ⇒ Object Also known as: from_file

Use this if you don’t want to overwrite the image file



42
43
44
45
46
# File 'lib/mini_magick.rb', line 42

def open(image_path)
  File.open(image_path, "rb") do |f|
    self.from_blob(f.read, File.extname(image_path))
  end
end

Instance Method Details

#<<(*args) ⇒ Object

Sends raw commands to imagemagick’s mogrify command. The image path is automatically appended to the command



90
91
92
# File 'lib/mini_magick.rb', line 90

def <<(*args)
  run_command("mogrify", *args << @path)
end

#[](value) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/mini_magick.rb', line 61

def [](value)
  # Why do I go to the trouble of putting in newlines? Because otherwise animated gifs screw everything up
  case value.to_s
  when "format"
    run_command("identify", "-format", format_option("%m"), @path).split("\n")[0]
  when "height"
    run_command("identify", "-format", format_option("%h"), @path).split("\n")[0].to_i
  when "width"
    run_command("identify", "-format", format_option("%w"), @path).split("\n")[0].to_i
  when "dimensions"
    run_command("identify", "-format", format_option("%w %h"), @path).split("\n")[0].split.map{|v|v.to_i}
  when "size"
    File.size(@path) # Do this because calling identify -format "%b" on an animated gif fails!
  when "original_at"
    # Get the EXIF original capture as a Time object
    Time.local(*self["EXIF:DateTimeOriginal"].split(/:|\s+/)) rescue nil
  when /^EXIF\:/i
    result = run_command('identify', '-format', "\"%[#{value}]\"", @path).chop
    if result.include?(",")
      read_character_data(result)
    else
      result
    end
  else
    run_command('identify', '-format', "\"#{value}\"", @path).split("\n")[0]
  end
end

#collapse!Object

Collapse images with sequences to the first frame (ie. animated gifs) and preserve quality



120
121
122
# File 'lib/mini_magick.rb', line 120

def collapse!
  run_command("mogrify", "-quality", "100", "#{path}[0]")
end

#combine_options(&block) ⇒ Object

You can use multiple commands together using this method



154
155
156
157
158
# File 'lib/mini_magick.rb', line 154

def combine_options(&block)
  c = CommandBuilder.new
  block.call c
  run_command("mogrify", *c.args << @path)
end

#destroy!Object



208
209
210
211
212
# File 'lib/mini_magick.rb', line 208

def destroy!
  return if tempfile.nil?
  File.unlink(tempfile.path)
  @tempfile = nil
end

#format(format, page = 0) ⇒ Object

This is a ‘special’ command because it needs to change @path to reflect the new extension Formatting an animation into a non-animated type will result in ImageMagick creating multiple pages (starting with 0). You can choose which page you want to manipulate. We default to the first page.



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/mini_magick.rb', line 98

def format(format, page=0)
  run_command("mogrify", "-format", format, @path)

  old_path = @path.dup
  @path.sub!(/(\.\w*)?$/, ".#{format}")
  File.delete(old_path) unless old_path == @path

  unless File.exists?(@path)
    begin
      FileUtils.copy_file(@path.sub(".#{format}", "-#{page}.#{format}"), @path)
    rescue => ex
      raise MiniMagickError, "Unable to format to #{format}; #{ex}" unless File.exist?(@path)
    end
  end
ensure
  Dir[@path.sub(/(\.\w+)?$/, "-[0-9]*.#{format}")].each do |fname|
    File.unlink(fname)
  end
end

#format_option(format) ⇒ Object

Outputs a carriage-return delimited format string for Unix and Windows



166
167
168
# File 'lib/mini_magick.rb', line 166

def format_option(format)
  windows? ? "#{format}\\n" : "#{format}\\\\n"
end

#run_command(command, *args) ⇒ Object



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/mini_magick.rb', line 170

def run_command(command, *args)
  args.collect! do |arg|        
    # args can contain characters like '>' so we must escape them, but don't quote switches
    if arg !~ /^[\+\-]/
      "\"#{arg}\""
    else
      arg.to_s
    end
  end

  command = "#{MiniMagick.processor} #{command} #{args.join(' ')}".strip

  if ::MiniMagick.use_subexec
    sub = Subexec.run(command, :timeout => MiniMagick.timeout)
    exit_status = sub.exitstatus
    output = sub.output
  else
    output = `#{command} 2>&1`
    exit_status = $?.exitstatus
  end

  if exit_status != 0
    # Clean up after ourselves in case of an error
    destroy!
    
    # Raise the appropriate error
    if output =~ /no decode delegate/i || output =~ /did not return an image/i
      raise Invalid, output
    else
      # TODO: should we do something different if the command times out ...?
      # its definitely better for logging.. otherwise we dont really know
      raise Error, "Command (#{command.inspect}) failed: #{{:status_code => exit_status, :output => output}.inspect}"
    end
  else
    output
  end
end

#to_blobObject

Give you raw data back



131
132
133
134
135
136
137
# File 'lib/mini_magick.rb', line 131

def to_blob
  f = File.new @path
  f.binmode
  f.read
ensure
  f.close if f
end

#windows?Boolean

Check to see if we are running on win32 – we need to escape things differently

Returns:

  • (Boolean)


161
162
163
# File 'lib/mini_magick.rb', line 161

def windows?
  !(RUBY_PLATFORM =~ /win32/).nil?
end

#write(output_path) ⇒ Object

Writes the temporary image that we are using for processing to the output path



125
126
127
128
# File 'lib/mini_magick.rb', line 125

def write(output_path)
  FileUtils.copy_file @path, output_path
  run_command "identify", output_path # Verify that we have a good image
end