Skip to content

Instantly share code, notes, and snippets.

@mikehoward
Created March 10, 2012 18:22
Show Gist options
  • Save mikehoward/2012377 to your computer and use it in GitHub Desktop.
Save mikehoward/2012377 to your computer and use it in GitHub Desktop.
re-write of MiniMagick

This is a rough outline rewrite the internals of MiniMagick - a ruby gem for using ImageMagick and GraphicsMagick from ruby scripts. MiniMagick's most prominent feature is creating appropriate shell commands which are run as subprocesses - thereby making the gem less fragile w.r.t. the graphics libraries and changes to the *Magick routines.

the Image Class.

The MiniMagick image class does too much. I propose that the Image class should be responsible for the image files only and not be involved in running *Magick commands.

Image#new(path = nil)

If path is nil, creates a temporary file using 

I think we can avoid issues with Tempfile for temporary files by creating our own files and creating a finalizer (via ObjectSpace#define_finalizer(image, proc)) which removes the file upon reference count exhaustion. We also need to 'write(path)' method which:

  • if Image is temporary, does a move and calls ObjectSpace#undefine_finalizer on self.
  • if Image is not a temporary image, then does a copy to the new path.

Attributes should track the stuff which comes from 'identify'. It's reasonable to lazy load them, but it's a tradeoff. The most reliable values should come from parsing the 'identify' return string from querying the image file. We probably should do some sort of simple modification time checking to see if the image has been updated since updates are out of programatic control.

Command Builder.

MiniMagick::CommandBuilder is pretty good, but rather than being used by the Image class 'run' method, it should work better the other way around.

I propose:

class CommandBuilder

which is pretty much the class defined in MiniMagick except that is should have a 'call' (or 'run') method which raises an exception of it is called.

All the descendents of CommandBuilder will take an optional block as an argument can be used to initialize the command stack

for example:

Morgify#new [&block] - will create a Mogify instance and assemble any
commands passed in the block.

class Morgify < CommandBuilder

which runs the 'morgify' command. It will delegate command building to CommandBuilder.

Morgify#call(image-file-or-path)

will run the assembled commands. Returns the modified Image object.

class MorgifyCopy < Morgify

same as Morgify, except that the call method creates a copy of the passed in image.

class Identify < CommandBuilder -

Identify#call(image-file-or-path)

returns an Image object which can be queried for image parameters

class Convert < CommandBuilder

Convert#call(input-file-or-Image = nil[, output-path-or-Image = nil])

converts input to output. Returns an Image object. If input-file-or-Image is nil, then creates image w/o input. If output-path-or-Image is nil, the returned Image is a temporary object.

class Composite < CommandBuilder

Composite#call(*input-files-or-Images-mixed[, :output_path = nil)

composites the input and returns an Image object. If output path is nil or not specified, the returned object is temporary.

@phrozen
Copy link

phrozen commented Dec 4, 2012

Is there a code example on how to use this? I want to be able to produce images of caption text in a color background using convert command.

convert -size 400x400 -background #cccccc -font "SomeFont.ttf" -pointsize 50 -fill #666666 -gravity Center caption:"My Text" caption.jpg

Maybe without the need of a temp file, if I can do it in memory it would be nice also, but the very least I want to be able to create an image using mini magick, which as far as i know does not support image creation. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment