Skip to content

Instantly share code, notes, and snippets.

@mikehoward
Created March 10, 2012 18:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • 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.

@robertjwhitney
Copy link

This is really interesting and about what I was hoping we could do. I'm not confident I have enough experience to do it just right on my own but would definitely be interested in pursuing it as a collaboration.

@mikehoward
Copy link
Author

After thinking some more, I think depending on Tempfile is the right way to go for temporary files. We should maintain an open file descriptor and add a finalizer to close the file - if experimentation shows it's needed. That should keep temp files around as long as needed - i.e. as long as the Image instance exists.

Add a trap in the 'path=' accessor to create a 'real' file and maybe a copy method - both of which do a full copy of the temp file content into a specified directory [to avoid losing files if /tmp is a ram disk]. .copy should probably return an Image object, whereas 'path=' just de-temp-ifies the Image.

@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