Aus Linux-Magazin 12/2003

Bildbearbeitung mit dem Java-API von Image Magick

Das Java-SDK bietet in der aktuellen Version einige Möglichkeiten für die Bildbearbeitung. Einfacher und performanter geht es aber mit JMagick, dem Java-API für das bekannte Image-Magick-Toolkit.

Mit Image Magick mag schon manch einer gearbeitet haben, ohne es zu wissen. Viele Tools verwenden in bester Unix-Manier unter der Haube die Sammlung der Image-Magick-Programme zur Bildbearbeitung. Seine Stärken spielt das Toolkit besonders dann aus, wenn es um die Massenverabeitung oder komplexe Automation von Bildbearbeitungsvorgängen geht.

In C geschrieben bietet es eine Reihe einfach zu bedienender Kommandozeilenprogramme an, zum Beispiel »mogrify« und »convert« für die Umwandlung zwischen Grafikformaten beziehungsweise das Skalieren von Bildern oder »display« für die Anzeige. Mit »man ImageMagick« erhält man eine Übersicht über alle Programme und darüber, was sie können. Die Kommandozeilenprogramme sind Frontends für das eigentliche Image-Magick-API[2]. Für das C-API gibt es zudem verschiedene Wrapper, unter anderem auch für Perl und eben Java.

Dreischritt mit Hindernissen

Der Quellcode des Java-API, JMagick genannt, steht auf der Website des Autors der Software[3] oder auf[4] bereit. Abhängig von der installierten Version von Image Magick wählt man sich die geeignete Version aus. Für diesen Coffee-Shop ist es die JMagick-Version 5.5.1 im Zusammenspiel mit Image Magick 5.5.4. Für Java-Pakete eher unüblich ist das Build-System mit »autoconf« erstellt. Der übliche Dreischritt »configure;make all;su -c “make install”« erzeugt aber zunächst mal eine Menge Fehlermeldungen.

Zuerst mahnt das Configure-Skript zu Recht die fehlenden Image-Magick- Headerdateien an – hier muss also zusätzlich das Image-Magick-Devel-Paket installiert sein. Außerdem ist »configure« der Aufenthaltsort der »libMagick«-Bibliotheken explizit mitzuteilen (obwohl diese ganz normal unter »/usr/lib« installiert sind). Die dynamische »libMagick« – zumindest in der hier verwendeten Version – ist zudem von Hand zu linken. Ein erneuter Versuch, der diese Vorgaben berücksichtigt, führt schließlich zum Erfolg:

./configure --with-magick-lib-dir =/usr/lib
make all
gcc -shared -o
lib/.libs/libJMagick.so.5.0.510 obj/magick/*.lo -lMagick
su -c"make install"

Knappe, aber ausreichende Dokumentation

Die Programme (ein Jar und eine dynamische Bibliothek) landen in »/usr/ local/lib«. Ein »make javadoc« generiert und installiert die Dokumentation des Java-API unter »/usr/local/doc/javadoc«. Sie enthält im Wesentlichen eine Übersicht darüber, welche Methoden mit welchen Parametern aufgerufen werden müssen. Viel mehr ist auch nicht erforderlich, da das API sauber und einfach strukturiert und wenig mehr als ein Wrapper für verschiedene Structs und Funktionen auf C-Ebene ist. Ein Blick in die C-API[2], meist auch als Teil von Image Magick lokal installiert, klärt eventuell offene Fragen.

Drei kleine Beispiele sollen zeigen, wie einfach JMagick anzuwenden ist: für die Ausgabe von Bildinformationen, das Anzeigen sowie das Bearbeiten von Bildern. Die volle Mächtigkeit des Toolkits erschließt ein Blick in »man ImageMagick«. Was dort beschrieben ist, sollte auch mit Java funktionieren. Das erste Beispielprogramm (Listing 1) gibt zu allen als Argumente übergebenen Dateien verschiedene Informationen aus (siehe Abbildung 1).

Abbildung 1: Deskriptive Informationen zur Grafikdatei, ausgegeben mit JMagick (Listing 1).

Abbildung 1: Deskriptive Informationen zur Grafikdatei, ausgegeben mit JMagick (Listing 1).

Was bin ich?

Wichtig für die Nutzung von JMagick sind zwei Zeilen: In Zeile 52 erzeugt das Programm ein »ImageInfo«-Objekt und in der nächsten Zeile ein »MagickImage«-Objekt. Ersteres kapselt die »ImageInfo«-Struktur aus dem C-API, Letztere die Image-Struktur (der Name »MagickImage« wurde gewählt, um eine Verwechslung mit »java.awt.Image« zu vermeiden).

Die Methoden der »MagickImage«-Klasse bilden das zentrale API von JMagick. Die Main-Methode der Klasse »Identify« aus Listing 1 nutzt hier verschiedene »get XXX()«-Methoden, um Informationen zu den Bilddateien auszugeben. Nicht jede Information ist notwendigerweise im Bild enthalten. Für die Ausführung ist es notwendig, neben dem »java.library.path« (wie in Abbildung 1 zu sehen) auch den »CLASSPATH« zu setzten, entweder über einen Export-Befehl oder mittels:

> java -Djava.library.path=/usr/local/lib 
-cp .:/usr/local/lib/jmagick.jar Identify hiking_tux.jpg

Für die Anzeige von Bildern gibt es die Utility-Klasse »magick.util.MagickViewer«, sie ist eine Subklasse von »java .awt.ScrollPane«. Die beiden Zeilen 58 und 84 in Listing 2 demonstrieren ihre Verwendung. Der Konstruktor fügt das »MagickViewer«-Objekt in sein Border-Layout ein (Zeile 58). Die »setImage«-Methode bestimmt das »MagickImage«, das der »MagickViewer« anzeigen soll (Zeile 84).

Anzeige leicht gemacht

Das Ergebnis ist in Abbildung 2 zu sehen: Auch wenn beim Erscheinen dieses Linux-Magazins schon langsam die Punschzeit angebrochen ist, entstand der Artikel noch in den letzten Tagen des Oktoberfests und die Pinguine waren entsprechend zünftig unterwegs (das Bild ist das Logo der jährlichen “Linux-Bierwanderung”[6]).

Wie oben schon erwähnt bilden die Methoden der »MagickImage«-Klasse den Kern des JMagick-API. Das gilt natürlich gerade für alle Standardumformungen wie Rotationen, Skalierungen, Weichzeichnungen und so weiter. Die Methoden folgen dabei stets dem Namensschema » xxxImage(…)«, zum Beispiel »rotateImage()«, »blurImage()« oder »scaleImage()«. Sie verhalten sich leider nicht objektorientiert, das heißt, sie lassen das aktuelle »MagickImage«-Objekt unverändert und geben stets ein verändertes Objekt zurück.

Vielfältige Manipulationsmöglichkeiten

Die Anwendung der Weichzeichnung zeigt das Listing 3. Das Wichtige passiert in den Zeilen 60 bis 62. Zuerst wird ein verändertes »ImageMagick«-Objekt erzeugt, dann der neue Dateiname gesetzt, zuletzt das Bild geschrieben. Das Ergebnis zeigt Abbildung 3 (einige Biere haben dieselbe Wirkung. ;-)

finally{}

Die kompletten Listings zusammen mit einer Reihe weiterer kleiner Beispiele sind wie üblich auf dem Listing-Server des Linux-Magazins verfügbar. Mit wenig Aufwand ließe sich mit Java-Mitteln auch ein kleines GUI entwickeln – um endlich das ultimative Bildbearbeitungstool zu schaffen. Alternativ dazu bietet es sich aber an, die sehr gute Titelstrecke zum Thema Bildbearbeitung im unlängst erschienenen “LinuxUser”[5] zu lesen – hier findet sich für jeden Geschmack etwas.

JMagick ist sicher nicht dafür geeignet, die schon sehr guten Kommandozeilenprogramme von Image Magick oder vorhandene GUI-Lösungen zu ersetzen. Aber immer dort, wo es schon Java-basierte automatisierte Abläufe gibt (etwa auf Web-Applikationsservern), ist JMagick eine gute Alternative zur Bildbearbeitung mit nativen Java-Mitteln, etwa dem Image I/O Framework oder den Java2D-APIs. (uwo)

Abbildung 2 und 3: Pinguin auf dem Weg zum Oktoberfest, angezeigt mit JMagick. Pinguin auf dem Weg vom Oktoberfest (rechts), der verschwommene Eindruck kommt nicht vom Bier, sondern vom Filter in Listing 3.

Abbildung 2 und 3: Pinguin auf dem Weg zum Oktoberfest, angezeigt mit JMagick. Pinguin auf dem Weg vom Oktoberfest (rechts), der verschwommene Eindruck kommt nicht vom Bier, sondern vom Filter in Listing 3.

Abbildung 2 und 3: Pinguin auf dem Weg zum Oktoberfest, angezeigt mit JMagick. Pinguin auf dem Weg vom Oktoberfest (rechts), der verschwommene Eindruck kommt nicht vom Bier, sondern vom Filter in Listing 3.

Abbildung 2 und 3: Pinguin auf dem Weg zum Oktoberfest, angezeigt mit JMagick. Pinguin auf dem Weg vom Oktoberfest (rechts), der verschwommene Eindruck kommt nicht vom Bier, sondern vom Filter in Listing 3.

 

Listing 1: »Identify.java«

23: import magick.*;
24: import java.awt.*;
25:
34: public class Identify {
35:
45:   public static void main(String[] args) {
46:     if (args.length < 1 )
47:       usage();
49:     try {
50:       for (int i=0; i<args.length; ++i) {
51:
52:         ImageInfo info = new ImageInfo(args[i]);
53:         MagickImage image = new MagickImage(info);
54:
55:         System.out.println("Filename: " + image.getFileName());
56:         System.out.println("  Type: " + image.getMagick());
57:         Dimension dim = image.getDimension();
58:         System.out.println("  Width: " + dim.getWidth());
59:         System.out.println("  Height: " + dim.getHeight());
60:         System.out.println("  Resolution units: " + image.getUnits());
61:         System.out.println("  X resolution: " + image.getXResolution());
62:         System.out.println("  Y resolution: " + image.getYResolution());
63:         System.out.println("  Size blob: " + image.sizeBlob());
64:         System.out.println("  Colors: " + image.getNumberColors());
65:         System.out.println("  Depth: " + image.getDepth());
66:         System.out.println("  Colorspace: " + image.getColorspace());
67:         try {
68:           image.getColormap();
69:           System.out.println("  Colors in colormap: " + image.getColors());
70:         } catch (MagickException e) {
71:         }
72:       }
73:     } catch (MagickException ex) {
74:       System.err.println("MagickException: " + ex);
75:     }
76:   }
77: }

 

Listing 2: »Display.java«

023: import magick.*;
024: import magick.util.*;
025: import java.awt.*;
026: import java.awt.event.*;
027:
036: public class Display extends Frame {
037:
038:   MagickImage iImage;
039:   MagickViewer iViewer;
040:
048:   //////////////////////////////////////
049:
050:   public Display() {
051:     setResizable(true);
052:     addWindowListener(new WindowAdapter() {
053:       public void windowClosing(WindowEvent event) {
054:         System.exit(0);
055:       }
056:     });
057:     iViewer = new MagickViewer();
058:     add(iViewer, "Center");
059:   }
060:
061:   //////////////////////////////////////
062:
063:   public Dimension getPreferredSize() {
064:     return getMinimumSize();
065:   }
066:
067:   //////////////////////////////////////
068:
069:   public Dimension getMinimumSize() {
070:     try {
071:       if (iImage == null)
072:         return new Dimension(300, 200);
073:       else
074:         return iImage.getDimension();
075:     } catch (MagickException e) {
076:       return new Dimension(300, 200);
077:     }
078:   }
079:
080:   //////////////////////////////////////
081:
082:   public void setImage(MagickImage image) {
083:     iImage = image;
084:     iViewer.setImage(image);
085:   }
086:
087:   //////////////////////////////////////
088:
089:   public static void main(String[] args) {
090:     if (args.length != 1)
091:       usage();
092:
093:     try {
094:       ImageInfo   info  = new ImageInfo(args[0]);
095:       MagickImage image = new MagickImage(info);
096:       Display     d     = new Display();
097:       d.setImage(image);
098:       d.setTitle(image.getFileName());
099:       d.pack();
100:       d.show();
101:     } catch (MagickException ex) {
102:       System.err.println("MagickException: " + ex);
103:     }
104:   }
105: }

 

Listing 3: »Blur.java«

23: import magick.*;
24: import java.awt.*;
25:
34: public class Blur {
35:
45:   public static void main(String[] args) {
46:     if (args.length < 1)
47:       usage();
49:     try {
50:       for (int i=0; i<args.length; ++i) {
51:         String filename = args[i];
52:         ImageInfo info = new ImageInfo(filename);
53:         MagickImage image = new MagickImage(info);
54:
55:         int ext = filename.lastIndexOf(".",filename.length());
56:         if (ext == -1)
57:           ext = filename.length();
58:         filename = filename.substring(0,ext)+"_blur"+
59:                             filename.substring(ext);
60:         MagickImage bluredImage = image.blurImage(0.0,4.0);
61:         bluredImage.setFileName(filename);
62:         bluredImage.writeImage(info);
63:       }
64:     } catch (MagickException ex) {
65:       System.err.println("MagickException: " + ex);
66:     }
67:   }
69: }

 

Infos

[1] Homepage von Image Magick: [http://www.imagemagick.com]

[2] Image-Magick-C-API: [http://www.imagemagick.com/www/api.html]

[3] Homepage von JMagick: [http://www.yeo.nu/jmagick]

[4] Download von Image Magick und JMagick: [ftp://ftp.imagemagick.org/pub/ImageMagick]

[5] Professionelle Bildbearbeitung: Linux User 10/03, ab Seite 24

[6] Hiking Tux: [www.linuxbierwanderung.org]

[7] Coffee-Shop, “Java2D – Nicht nur für Bunte Bilder”: Linux-Magazin 03/00, S. 154 (auch online verfügbar)

 

Der Autor

Bernhard Bablok arbeitet bei der Allianz Versicherungs AG im Bereich Data-Warehouse-Systeme. Wenn er nicht Musik hört, mit dem Radl oder zu Fuß unterwegs ist, beschäftigt er sich mit Themen rund um Objektorientierung. Er ist unter [mailto:coffee-shop@bablokb.de] zu erreichen.

LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben