Class: Giftrim::Image

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

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(input_path, tempfile = nil) ⇒ Image

TODO:

Allow this to accept a block that can pass off to Image#combine_options

Modified from MiniMagick, see License_MiniMagick Create a new MiniMagick::Image object

DANGER: The file location passed in here is the *working copy*. That is, it gets modified. you can either copy it yourself or use the MiniMagick::Image.open(path) method which creates a temporary file for you and protects your original!

Parameters:

  • input_path (String)

    The location of an image file



121
122
123
124
# File 'lib/giftrim.rb', line 121

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

Instance Attribute Details

#pathString

Returns The location of the current working file.

Returns:

  • (String)

    The location of the current working file



20
21
22
# File 'lib/giftrim.rb', line 20

def path
  @path
end

Class Method Details

.create(ext = nil, validate = true) {|IOStream| ... } ⇒ Image

Modified from MiniMagick, see License_MiniMagick Used to create a new Image object data-copy. Not used to “paint” or that kind of thing.

Takes an extension in a block and can be used to build a new Image object. Used by both #open and #read to create a new object! Ensures we have a good tempfile!

Parameters:

  • ext (String) (defaults to: nil)

    Specify the extension you want to read it as

  • validate (Boolean) (defaults to: true)

    If false, skips validation of the created image. Defaults to true.

Yields:

  • (IOStream)

    You can #write bits to this object to create the new Image

Returns:

  • (Image)

    The created image



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/giftrim.rb', line 92

def create(ext = nil, validate = true, &block)
  begin
    tempfile = Tempfile.new(['giftrim_', ext.to_s.downcase])
    tempfile.binmode
    block.call(tempfile)
    tempfile.close

    image = self.new(tempfile.path, tempfile)

    if validate and !image.valid?
      raise Giftrim::Invalid
    end
    return image
  ensure
    tempfile.close if tempfile
  end
end

.open(file_or_url, ext = nil) ⇒ Image

Modified from MiniMagick, see License_MiniMagick Opens a specific image file either on the local file system or at a URI.

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

Extension is either guessed from the path or you can specify it as a second parameter.

If you pass in what looks like a URL, we require ‘open-uri’ before opening it.

Parameters:

  • file_or_url (String)

    Either a local file path or a URL that open-uri can read

  • ext (String) (defaults to: nil)

    Specify the extension you want to read it as

Returns:

  • (Image)

    The loaded image



68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/giftrim.rb', line 68

def open(file_or_url, ext = nil)
  file_or_url = file_or_url.to_s # Force it to be a String... hell or highwater
  if file_or_url.include?("://")
    require 'open-uri'
    ext ||= File.extname(URI.parse(file_or_url).path)
    self.read(Kernel::open(file_or_url), ext)
  else
    ext ||= File.extname(file_or_url)
    File.open(file_or_url, "rb") do |f|
      self.read(f, ext)
    end
  end
end

.read(stream, ext = nil) ⇒ Image

Modified from MiniMagick, see License_MiniMagick This is the primary loading method used by all of the other class methods.

Use this to pass in a stream object. Must respond to Object#read(size) or be a binary string object (BLOBBBB)

As a change from the old API, please try and use IOStream objects. They are much, much better and more efficient!

Probably easier to use the #open method if you want to open a file or a URL.

Parameters:

  • stream (IOStream, String)

    Some kind of stream object that needs to be read or is a binary String blob!

  • ext (String) (defaults to: nil)

    A manual extension to use for reading the file. Not required, but if you are having issues, give this a try.

Returns:



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/giftrim.rb', line 36

def read(stream, ext = nil)
  if stream.is_a?(String)
    stream = StringIO.new(stream)
  elsif stream.is_a?(StringIO)
    # Do nothing, we want a StringIO-object
  elsif stream.respond_to? :path
    if File.respond_to?(:binread)
      stream = StringIO.new File.binread(stream.path.to_s)
    else
      stream = StringIO.new File.open(stream.path.to_s,"rb") { |f| f.read }
    end
  end

  create(ext) do |f|
    while chunk = stream.read(8192)
      f.write(chunk)
    end
  end
end

Instance Method Details

#number_of_framesObject



163
164
165
166
167
168
169
170
171
# File 'lib/giftrim.rb', line 163

def number_of_frames
  command = "#{Giftrim.processor} --info #{@path}"
  output = run_command command
  if output
    first_line = output.lines.first
    number_of_frames = first_line.scan(/\d+[ \t]*images/).first.to_i
  end
  number_of_frames
end

#run_command(command) ⇒ Object



132
133
134
135
136
137
138
139
# File 'lib/giftrim.rb', line 132

def run_command command
  sub = Subexec.run(command, :timeout => Giftrim.timeout)
  if sub.exitstatus == 0
    sub.output
  else
    raise Error, "Command (#{command.inspect.gsub("\\", "")}) failed: #{{:status_code => sub.exitstatus, :output => sub.output}.inspect}"
  end
end

#trimObject



173
174
175
176
177
178
179
180
181
182
# File 'lib/giftrim.rb', line 173

def trim
  @outfile = Tempfile.new('giftrim_')
  @outfile.binmode
  @outfile.close

  frames = Giftrim::frame_number_wanted self.number_of_frames, 10
  frames_formatted = frames.map{|frame| "\"##{frame}\""}.join " "
  command = "#{Giftrim.processor} --unoptimize -O2 --no-comments --no-names --delay 20 --same-loopcount --no-warnings --resize-fit '300x300' #{@path} #{frames_formatted} > #{@outfile.path}"
  trim_run_command command
end

#trim_with_target_frame_number(frame_number) ⇒ Object



184
185
186
187
188
189
190
191
192
193
# File 'lib/giftrim.rb', line 184

def trim_with_target_frame_number frame_number
  @outfile = Tempfile.new('giftrim_')
  @outfile.binmode
  @outfile.close

  frames = Giftrim::frame_number_wanted self.number_of_frames, 10
  frames_formatted = frames.map{|frame| "\"##{frame}\""}.join " "
  command = "#{Giftrim.processor} --unoptimize -O2 --no-comments --no-names --delay 20 --same-loopcount --no-warnings #{@path} #{frames_formatted} > #{@outfile.path}"
  trim_run_command command
end

#valid?Boolean

Returns:

  • (Boolean)


127
128
129
130
# File 'lib/giftrim.rb', line 127

def valid?
  # TODO
  true
end

#write(output_to) ⇒ IOStream, Boolean

Modified from MiniMagick, see License_MiniMagick Writes the temporary file out to either a file location (by passing in a String) or by passing in a Stream that you can #write(chunk) to repeatedly

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

Parameters:

  • output_to (IOStream, String)

    Some kind of stream object that needs to be read or a file path as a String

Returns:

  • (IOStream, Boolean)

    If you pass in a file location [String] then you get a success boolean. If its a stream, you get it back.



148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/giftrim.rb', line 148

def write(output_to)
  if output_to.kind_of?(String) || !output_to.respond_to?(:write)
    FileUtils.copy_file @path, output_to
    run_command "identify #{output_to}" # Verify that we have a good image
  else # stream
    File.open(@path, "rb") do |f|
      f.binmode
      while chunk = f.read(8192)
        output_to.write(chunk)
      end
    end
    output_to
  end
end