Just before my last trip I have finally decided to issue daily reports. Not to forget the impressions as well as to share my experiences with friends. The scenario I foresaw was: all the day I make photos, then reach a hotel with Wifi internet, pick out a dozen of best views and publish.
It’s worth to mention that I have chosen a jekyll successor, the ruhoh publishing system. I only needed a handy script to quickly produce a new blog entry by the directory with today photos. Plus I wanted a collage to be put as a post preview.
There is an ImageMagick wrapper for Ruby: RMagick. The only problem remained: I still needed to produce the collage by hands. So, I decided to monkeypatch the library. Below goes the code of the patch:
require 'RMagick'
module Magick
class ImageList
def self.preview files, options={}
options = {
:columns => 5, # number of columns in collage
:scale_range => 0.1, # ± to the thumb width
:thumb_width => 120, # the width of thumbnail
:rotate_angle => 20, # maximal rotate angle
:background => 'white', # background of the collage
:border => 'gray20' # border color
}.merge(options)
# Produce collage from all the files in directory
files = "#{files}/*" if File.directory?(files)
imgs = ImageList.new
# The placeholder for collage borders
imgnull = Image.new(options[:thumb_width],options[:thumb_width]) {
self.background_color = 'transparent'
}
# Top row
(options[:columns]+2).times { imgs << imgnull.dup }
Dir.glob("#{files}") { |f|
Image::read(f).each { |i|
scale = (1.0 + options[:scale_range]*Random::rand(-1.0..1.0))*options[:thumb_width]/[i.columns, i.rows].max
# Placeholder if that’s the first column
imgs << imgnull.dup if (imgs.size % (options[:columns]+2)).zero?
imgs << i.auto_orient.thumbnail(scale).polaroid(
Random::rand(-options[:rotate_angle]..options[:rotate_angle])
)
# Placeholder if that’s the last columns
imgs << imgnull.dup if (imgs.size % (options[:columns]+2)) == options[:columns]+1
} rescue puts "Skipping error: #{$!}" # simply skip non-image files
}
# Fill the last row
(2*options[:columns]+4-(imgs.size % (options[:columns]+2))).times { imgs << imgnull.dup }
imgs.montage {
self.tile = Magick::Geometry.new(options[:columns]+2)
self.geometry = "-#{options[:thumb_width]/5}-#{options[:thumb_width]/4}"
self.background_color = options[:background]
}.trim(true).border(10,10,options[:background]).border(1,1,options[:border])
end
end
end
The only noticable piece of code here is the stuff with imgnull
. Since I rotate the thumbnails, I need to
preserve a sufficient place around the resulting montaged image. The function may be called with:
Magick::ImageList::preview(IMGS_DIR, :thumb_width=>200).write COLLAGE.jpg
Resulting in smth like: