We are a software consultancy based in Berlin, Germany. We deliver
high quality web apps in short timespans.

Upstream Agile GmbH

Bild-im-Bild und Text-im-Bild mit Rails, file_column und RMagick

May 09, 2007 by alex

Update: Teil 2 ist fertig.

Gerade haben wir bei autoki Badges eingeführt - kleine Banner, die sich auf Blogs, Foren etc. einbinden lassen, und auf denen neben dem jeweiligen Auto des Mitglieds die URL zu seinem oder ihrem Profil zu sehen ist:

MINI Cooper S

Im folgenden Posting werde ich erklären, wie wir das ganze umgesetzt haben. Ziel war es, einfach einzubindende Grafiken zu generieren. Eine Alternative wäre Flash gewesen, jedoch lässt sich Flash an vielen Stellen (vor allem als Signatur in Foren) nicht einbinden.

Wir brauchten also eine Lösung, die uns für jedes Auto mehrere Banner mit jeweils einem Foto und Text darauf automatisch erstellt. Für die Skalierung der Bilder benutzen wir das file_column-Plugin für Rails, das auf RMagick , den Ruby-Bindings für ImageMagick, aufsetzt,. Damit lassen sich sehr einfach skalierte und beschnittene Versionen einer Grafik erzeugen, indem man in einem Rails-Model, nennen wir es mal Auto, ein Attribut als file_column-Attribute markiert:

class Auto
  file_column :photo
end

Um die verschiedenen Bildgrößen zu erzeugen, genügt es, mittels :version die gewünschten Größen anzugeben:

file_column :photo, :magick => { :versions =>
  {
	:large => "480x480",
	:thumb => "238x"
  }
}

Dieser Code erzeugt zwei Versionen: :large passt unter Beibehaltung der Seitenverhältnisse in einen Rahmen von 480x480 Pixeln, :thumb hat eine Breite von 238 Pixeln und eine daran angepaste Höhe.

Alles ganz schön und nett, aber um damit Banner zu produzieren, kommen wir nicht umhin, file_column ein wenig zu hacken erweitern. Unser Problem lässt sich in 3 Schritte aufteilen:

  1. das Autobild herunterskalieren, so dass es auf den Banner passt,
  2. das verkleinerte Bild in ein Banner-Template-Bild kopieren,
  3. die URL des Autoprofils in das Bild schreiben

Schritt eins können wir bereits lösen:

file_column :photo, :magick => { :versions =>
  {
	:badge_1_online => {:crop => "52:46", :size => "52x46!", :name => "badge_1_online"}
  }
}

Mit Hilfe von :crop wird das Bild zusätzlich beschnitten, damit es garantiert 52x46 Pixel groß ist.

Um nun das Bild in das Banner-Template zu platzieren, verwenden wir folgende Syntax:

file_column :photo, :magick => { :versions =>
  {
	:badge_1_online => {:crop => "52:46", :size => "52x46!", :name => "badge_1_online",
  :composite => {:x => 3, :y => 3, :file => 'badge_1.gif'}
  }
}

Soll heißen: Das Autobild wird an der Stelle 3/2 in das Bild badge_1.gif kopiert. Wie schon erwähnt, funktioniert das so erstmal nicht. Nachdem wir die Methode transform_image in der Datei magick_file_column.rb des file_column-Plugins folgendermaßen angepasst haben, aber schon:

if img_options[:size]
 ...
end
if img_options[:composite]
					composite = ::Magick::Image.read("#{RAILS_ROOT}/public/composites/#{img_options[:composite][:file]}")[0]
					img = composite.composite!(img, img_options[:composite][:x]+1, img_options[:composite][:y]+1, ::Magick::OverCompositeOp)
				end

Diese Modifikation setzt voraus, dass unser Banner-Template badge_1.gif in public/composites/liegt. Mittels der RMagick-composite-Methode wird das Auto mit zwei Zeilen Code in den Banner kopiert.

Sieht doch schonmal ganz nett aus oder? Und wie das mit dem Text funktioniert, erkläre ich im nächten Post :) Das ist nämlich etwas komplizierter….