(Dies ist mein Spickzettel für den Vortrag auf der UbuCon 2014 in Katlenburg. Das meiste wird sich als Live-Demo abspielen, vorgeführt am Notebook direkt, projeziert auf die Beamer-Leinwand; ich werde meine vorbereiteten Folien nicht zeigen. Einige Links zu vertiefenden Materialien befinden sich am Ende dieses Dokuments.)


1 Aufgabenstellungen

Im Rahmen dieses Vortrages werde ich anhand mehrerer relativ einfachen Beispiele vorführen, wie man mit ImageMagick-Kommandos Aufgaben der eigenen Bildbearbeitung bewältigt. Dazu gehören:

  1. PNG nach GIF konvertieren
  2. Eigenschaften eines Bildes feststellen
  3. Rahmen um ein Bild zeichnen
  4. Halb-durchsichtige Beschriftung einer Abbildung
  5. Illustration beschneiden
  6. Aus mehreren Bildern ein animiertes GIF erzeugen
  7. Zwei Bilder vergleichen
  8. Abbildung dehnen oder stauchen
  9. Grafik anders verzerren, z.B. “perspektivisch”
  10. Bild-Größen ändern – auf unterschiedliche Weise!

Diese Beispiele dienen dann zugleich als Aufhänger dafür, einige komplexere Funktionen von ImageMagick zu zeigen.

2 PNG nach GIF konvertieren

Zunächst Herstellung eines PNG:

 convert rose: rose.png

Was ist rose: ?!??

Ein ‘eingebautes’ Bild. Fest in ImageMagick integriert. Zweck: man kann Kommandos schonmal testen, ohne sich erstmal Bilder beschaffen zu müssen.

Es gibt noch andere eingebaute Bilder: netscape:, wizard:, logo: und granite:

 for i in netscape wizard logo granite ; do 
    convert ${i}: ${i}.png
 done
In ImageMagick eingebaute Test-Bilder: wizard:, logo:, netscape:, granite: und rose:

In ImageMagick ‘eingebaute’ Test-Bilder: wizard:, logo:, netscape:, granite: und rose:

Woran erkennt ImageMagick, was das Zielformat der Konvertierung sein soll? An der Datei-Endung.

Funktionieren bei JPEGs auch .jpeg, .jpg, .JPG, JPEG oder gar .jPeG ??! Ja.

 for i in jpg JpEG; do
   convert wizard: wizard.${i}
 done
 
 md5sum wizard.* | sort

Ach so, wir wollten ja eigentlich ein PNG nach GIF konvertieren! So geht’s:

 convert wizard.png wizard.gif

Aber auch das geht:

 convert wizard.png gif:name-ohne-datei-endung
 convert wizard.png gif:name-mit-irrefuehrender-datei-endung.txt
 convert wizard.png gif:name-mit-irrefuehrender-datei-endung.jpeg

ImageMagick erkennt normalerweise an der Datei-Endung, welches Ziel-Format man wünscht. Falls Namen ohne Endung (oder mit falscher Endung) im Spiel sind, dann kann [BEZEICHNER]: vor dem Namen erzwingen, dass ImageMagick das entsprechende Format verwendet.

3 Eigenschaften eines Bildes feststellen

Kommando identify:

 identify rose.png

Ergebnis:

 rose.png PNG 70x46 70x46+0+0 8-bit sRGB 6.97KB 0.000u 0:00.000

Man kann auch mehrere Dateien auf einmal “identifizieren”:

 identify rose*.*

Ergebnis:

 rose.gif     GIF  70x46 70x46+0+0 8-bit sRGB 256c 4.11KB 0.000u 0:00.000
 rose.png[1]  PNG  70x46 70x46+0+0 8-bit sRGB      6.97KB 0.000u 0:00.000
 rose.jpg[2]  JPEG 70x46 70x46+0+0 8-bit sRGB      2.07KB 0.000u 0:00.009
 rose.JPG[3]  JPEG 70x46 70x46+0+0 8-bit sRGB      2.07KB 0.000u 0:00.000
 rose.jpeg[4] JPEG 70x46 70x46+0+0 8-bit sRGB      2.15KB 0.000u 0:00.000
 rose.jpg[5]  JPEG 70x46 70x46+0+0 8-bit sRGB      2.07KB 0.000u 0:00.000

Oder die Dateien aus dem vorhergehenden Abschnitt:

 identify name-{mit,ohne}-*

   name-mit-irrefuehrender-datei-endung.jpeg   GIF 480x640 480x640+0+0 8-bit sRGB 256c 99.7KB 0.000u 0:00.000
   name-mit-irrefuehrender-datei-endung.txt[1] GIF 480x640 480x640+0+0 8-bit sRGB 256c 99.7KB 0.010u 0:00.000
   name-ohne-datei-endung[2]                   GIF 480x640 480x640+0+0 8-bit sRGB 256c 99.7KB 0.000u 0:00.000

ImageMagick lässt sich beim Input also nicht von falschen Datei-Endungen an der Nase herumführen. Es verwendet seine eigene ‘Magie’ um das ihm vor die Nase gesetzte Format zu bestimmen.

 identify JPEG:name-mit-irrefuehrender-datei-endung.jpeg

    identify: Not a JPEG file: starts with 0x47 0x49 
              `name-mit-irrefuehrender-datei-endung.jpeg' @ error/jpeg.c/JPEGErrorHandler/322.

Der Vorgabe eines Formats zur Erzwingen einer entsprechenden Behandlung der Datei (per [FORMAT]:-Vorsilbe) klappt also ebenfalls nicht, da ImageMagick seine eigene Prüfung unabhängig davon durchführt.

identify — ich möchte mehr wissen! Geht’s vielleicht etwas detaillierter? – Na klar! Kuckstdu:

 identify -verbose rose.png

Ergebnis:

 Image: rose.png
  Format: PNG (Portable Network Graphics)
  Mime type: image/png
  Class: DirectClass
  Geometry: 70x46+0+0
  Units: Undefined
  Type: TrueColor
  Endianess: Undefined
  Colorspace: sRGB
  Depth: 8-bit
  Channel depth:
    red: 8-bit
    green: 8-bit
    blue: 8-bit
  Channel statistics:
    Pixels: 3220
    Red:
      min: 35 (0.137255)
      max: 255 (1)
      mean: 145.712 (0.57142)
      standard deviation: 69.2953 (0.271746)
      kurtosis: -1.385
      skewness: 0.14637
    Green:
      min: 22 (0.0862745)
      max: 255 (1)
      mean: 89.2602 (0.35004)
      standard deviation: 52.4698 (0.205764)
      kurtosis: 2.63898
      skewness: 1.81893
    Blue:
      min: 24 (0.0941176)
      max: 255 (1)
      mean: 80.4683 (0.315562)
      standard deviation: 55.1114 (0.216123)
      kurtosis: 3.01818
      skewness: 1.9795
  Image statistics:
    Overall:
      min: 22 (0.0862745)
      max: 255 (1)
      mean: 105.147 (0.412341)
      standard deviation: 59.4199 (0.233019)
      kurtosis: 1.2733
      skewness: 1.45983
  Rendering intent: Perceptual
  Gamma: 0.45455
  Chromaticity:
    red primary: (0.64,0.33)
    green primary: (0.3,0.6)
    blue primary: (0.15,0.06)
    white point: (0.3127,0.329)
  Background color: white
  Border color: srgb(223,223,223)
  Matte color: grey74
  Transparent color: black
  Interlace: None
  Intensity: Undefined
  Compose: Over
  Page geometry: 70x46+0+0
  Dispose: Undefined
  Iterations: 0
  Compression: Zip
  Orientation: Undefined
  Properties:
    date:create: 2014-10-17T22:37:50+02:00
    date:modify: 2014-10-17T22:11:32+02:00
    png:bKGD: chunk was found (see Background color, above)
    png:cHRM: chunk was found (see Chromaticity, above)
    png:gAMA: gamma=0.45454544 (See Gamma, above)
    png:IHDR.bit-depth-orig: 8
    png:IHDR.bit_depth: 8
    png:IHDR.color-type-orig: 2
    png:IHDR.color_type: 2 (Truecolor)
    png:IHDR.interlace_method: 0 (Not interlaced)
    png:IHDR.width,height: 70, 46
    png:sRGB: intent=0 (Perceptual Intent)
    png:text: 2 tEXt/zTXt/iTXt chunks were found
    signature: a698f2fe0c6c31f83d19554a6ec02bac79c961dd9a87e7ed217752e75eb615d7
  Artifacts:
    filename: quarry-pit/rose.png
    verbose: true
  Tainted: False
  Filesize: 6.97KB
  Number pixels: 3.22K
  Pixels per second: 3.22EB
  User time: 0.000u
  Elapsed time: 0:01.000
  Version: ImageMagick 6.8.9-8 Q16 x86_64 2014-10-03 http://www.imagemagick.org

3.1 ImageMagick ‘escapes’

Es gibt eine Reihe von ‘Escapes’, die ImageMagick verwendet, um bestimmte Eigenschaften von Dateien anzusprechen. %W entspricht z.B. der Bild-Breite, %H der Bild-Höhe. Diese kann man u.a. verwenden, um per identify -format "%W x %H" die Breite und die Höhe eines Bildes auszugeben.

Vollständige Liste:

   \n   newline
   \r   carriage return
   <    less-than character.
   >    greater-than character.
   &    ampersand character.
   %%   a percent sign
   %b   file size of image read in
   %c   comment meta-data property
   %d   directory component of path
   %e   filename extension or suffix
   %f   filename (including suffix)
   %g   layer canvas page geometry   (equivalent to "%Wx%H%X%Y")
   %h   current image height in pixels
   %i   image filename (note: becomes output filename for "info:")
   %k   CALCULATED: number of unique colors
   %l   label meta-data property
   %m   image file format (file magic)
   %n   number of images in current image sequence
   %o   output filename  (used for delegates)
   %p   index of image in current image list
   %q   quantum depth (compile-time constant)
   %r   image class and colorspace
   %s   scene number (from input unless re-assigned)
   %t   filename without directory or extension (suffix)
   %u   unique temporary filename (used for delegates)
   %w   current width in pixels
   %x   x resolution (density)
   %y   y resolution (density)
   %z   image depth (as read in unless modified, image save depth)
   %A   image transparency channel enabled (true/false)
   %C   image compression type
   %D   image GIF dispose method
   %G   original image size (%wx%h; before any resizes)
   %H   page (canvas) height
   %M   Magick filename (original file exactly as given,  including read mods)
   %O   page (canvas) offset ( = %X%Y )
   %P   page (canvas) size ( = %Wx%H )
   %Q   image compression quality ( 0 = default )
   %S   ?? scenes ??
   %T   image time delay (in centi-seconds)
   %U   image resolution units
   %W   page (canvas) width
   %X   page (canvas) x offset (including sign)
   %Y   page (canvas) y offset (including sign)
   %Z   unique filename (used for delegates)
   %@   CALCULATED: trim bounding box (without actually trimming)
   %#   CALCULATED: 'signature' hash of image values

3.2 Farbwert jedes einzelnen Pixels

Das Spezial-Ausgabeformat .txt schreibt zeilenweise für jeden einzelnen Pixel seine Koordinate und seinen Farbwert in eine einfache (u.U. sehr große!) Textdatei:

 convert rose: rose.txt

oder auch

 convert rose: txt:- | head -n 10

Ergebnis:

 # ImageMagick pixel enumeration: 70,46,255,srgb
 0,0: (48,47,45)  #302F2D  srgb(48,47,45)
 1,0: (50,48,46)  #32302E  srgb(50,48,46)
 2,0: (54,50,47)  #36322F  srgb(54,50,47)
 3,0: (56,51,46)  #38332E  srgb(56,51,46)
 4,0: (58,51,45)  #3A332D  srgb(58,51,45)
 5,0: (57,50,45)  #39322D  srgb(57,50,45)
 6,0: (56,48,45)  #38302D  srgb(56,48,45)
 7,0: (57,49,46)  #39312E  srgb(57,49,46)
 8,0: (56,48,45)  #38302D  srgb(56,48,45)

Diese Textdatei kann man selbstverständlich editieren, oder per sed-Kommando, Perl-Skript oder programmatisch anderweitig manipulieren. Und ImageMagick kann diese modifizierte Textdatei wieder als Input verwenden, um daraus ein “echtes” Bild zu erzeugen:

 convert rose.txt nelkenstrauss.png

(Übrigens sind bei diesem speziellen Text-Datei-Format nicht alle 4 Spalten erforderlich. Die erste Spalte mit den Pixel-Koordinaten ist selbstverständlich zwingend; von den anderen dreien reicht eine alleine aus – sie drücken ja jeweils denselben Farbwert auf unterschiedliche Weise aus…)

4 Metadaten der ImageMagick-Installation feststellen

 convert -version

Ergebnis (z.B.):

 Version: ImageMagick 6.8.9-8 Q16 x86_64 2014-10-03 http://www.imagemagick.org
 Copyright: Copyright (C) 1999-2014 ImageMagick Studio LLC
 Features: DPC Modules
 Delegates: bzlib cairo djvu fftw fontconfig freetype gslib gvc jbig jng jp2 jpeg lcms lqr ltdl lzma openexr \
            pangocairo png ps rsvg tiff webp wmf x xml zlib
 convert -list configure

Ergebnis:

 Path: /opt/local/lib/ImageMagick-6.8.9//config-Q16/configure.xml
 
 Name           Value
 -------------------------------------------------------------------------------
 CC             /usr/bin/clang
 CFLAGS         -I/opt/local/include/lqr-1 -I/opt/local/include/glib-2.0 \
                   -I/opt/local/lib/glib-2.0/include -I/opt/local/include \
                   -I/opt/local/include/freetype2 -I/opt/local/include \
                   -I/opt/local/include/libpng16 -pipe -Os -arch x86_64 -Wall \
                   -march=corei7-avx -fexceptions -D_FORTIFY_SOURCE=0 -D_THREAD_SAFE \
                   -pthread -DMAGICKCORE_HDRI_ENABLE=0 -DMAGICKCORE_QUANTUM_DEPTH=16
 CODER_PATH     /opt/local/lib/ImageMagick-6.8.9/modules-Q16/coders
 CONFIGURE      ./configure  '--prefix=/opt/local' '--enable-shared' '--enable-static' \
                   '--disable-ltdl-install' '--disable-silent-rules' '--with-frozenpaths' \
                   '--with-openexr' '--disable-hdri' '--with-dps' '--with-bzlib' '--with-djvu' \
                   '--with-fontconfig' '--with-gslib' '--with-jbig' '--with-jpeg' '--with-lcms' \
                   '--with-openjp2' '--with-png' '--with-tiff' '--with-webp' '--with-zlib' \
                   '--with-modules' '--with-xml' '--without-perl' '--without-fpx' '--with-wmf' \
                   '--with-gvc' '--with-rsvg' '--with-lqr' '--with-pango' '--with-x' \
                   '--with-gs-font-dir=/opt/local/share/fonts/urw-fonts' 'CC=/usr/bin/clang' \
                   'CFLAGS=-pipe -Os -arch x86_64' \
                   'LDFLAGS=-L/opt/local/lib -Wl,-headerpad_max_install_names -arch x86_64' \
                   'CPPFLAGS=-I/opt/local/include' 'CXX=/usr/bin/clang++' 'CXXFLAGS=-pipe -Os \
                   -arch x86_64 -stdlib=libc++'
 CONFIGURE_PATH /opt/local/etc/ImageMagick-6/
 COPYRIGHT      Copyright (C) 1999-2014 ImageMagick Studio LLC
 CPPFLAGS       -I/opt/local/include/ImageMagick-6
 CXX            /usr/bin/clang++
 CXXFLAGS       -pipe -Os -arch x86_64 -stdlib=libc++ -D_THREAD_SAFE -pthread
 DEFS           -DHAVE_CONFIG_H
 DELEGATES      bzlib djvu mpeg fftw fontconfig freetype gslib jbig jng jpeg lcms lqr lzma \
                   openexr openjp2 pango png ps rsvg tiff webp wmf x xml zlib
 DISTCHECK_CONFIG_FLAGS 'CC=/usr/bin/clang' 'CFLAGS=-pipe -Os -arch x86_64' \
                   'CPPFLAGS=-I/opt/local/include' 'CXX=/usr/bin/clang++' \
                   'LDFLAGS=-L/opt/local/lib -Wl,-headerpad_max_install_names -arch x86_64' \
                   --disable-deprecated --with-quantum-depth=16 --with-umem=no \
                   --with-autotrace=no --with-fpx=no --with-fontpath= \
                   --with-gs-font-dir=/opt/local/share/fonts/urw-fonts --with-perl=no
 DOCUMENTATION_PATH /opt/local/share/doc/ImageMagick-6
 EXEC-PREFIX    /opt/local
 EXECUTABLE_PATH /opt/local/bin
 FEATURES       DPC Modules
 FILTER_PATH    /opt/local/lib/ImageMagick-6.8.9/modules-Q16/filters
 HOST           x86_64-apple-darwin13.4.0
 INCLUDE_PATH   /opt/local/include/ImageMagick-6
 LDFLAGS        -L/opt/local/lib -L/opt/local/lib -Wl,-headerpad_max_install_names -arch x86_64 \
                   -L/opt/local/lib
 LIB_VERSION    0x689
 LIB_VERSION_NUMBER 6,8,9,8
 LIBRARY_PATH   /opt/local/lib/ImageMagick-6.8.9
 LIBS           -llcms2 -L/opt/local/lib -lfreetype -L/opt/local/lib -llqr-1 -lglib-2.0 -lintl \
                   -lfftw3 -L/opt/local/lib -lfontconfig -lfreetype -lXext -lSM -lICE -lX11 \
                   -lXt -L/opt/local/lib -llzma -lbz2 -lz -lltdl -lm
 NAME           ImageMagick
 PCFLAGS        -DMAGICKCORE_HDRI_ENABLE=0 -DMAGICKCORE_QUANTUM_DEPTH=16
 PREFIX         /opt/local
 QuantumDepth   16
 RELEASE_DATE   2014-10-03
 SHARE_PATH     /opt/local/share/ImageMagick-6
 SHAREARCH_PATH /opt/local/lib/ImageMagick-6.8.9/config-Q16
 SVN_REVISION   16502
 TARGET_CPU     x86_64
 TARGET_OS      darwin13.4.0
 TARGET_VENDOR  apple
 VERSION        6.8.9
 WEBSITE        http://www.imagemagick.org
 
 Path: [built-in]
 
 Name           Value
 -------------------------------------------------------------------------------
 FEATURES       
 NAME           ImageMagick
 QuantumDepth   16

Ich möchte noch mehr wissen! Geht das?

 convert -list list

Ergebnis:

 [....]
 Coder
 Color
 Colorspace
 Command
 Complex
 Compose
 Compress
 Configure
 DataType
 Debug
 Decoration
 Delegate
 Direction
 Dispose
 Distort
 [....]

Besonders interessant:

 convert -list color
 convert -list colorspace
 convert -list command
 convert -list delegate
 convert -list font
 convert -list magic
 convert -list mime 
 convert -list style

Am besten: selbst rumschmökern!

Ergebnis (Beispiel):

 convert -list delegate
  
  Path: /opt/local/etc/ImageMagick-6/delegates.xml
  
  Delegate                Command
  -------------------------------------------------------------------------------
      blender =>          "blender" -b "%i" -F PNG -o "%o""\n"/opt/local/bin/convert" \
                            -concatenate "%o*.png" "%o"
          bmp<= jxr       "mv "%i" "%i.bmp"; "JxrEncApp" -i "%i.bmp" -o "%o.jxr"; mv "%i.bmp" \
                            "%i"; mv "%o.jxr" "%o"
          bmp<= wdp       "mv "%i" "%i.bmp"; "JxrEncApp" -i "%i.bmp" -o "%o.jxr"; mv "%i.bmp" \
                            "%i"; mv "%o.jxr" "%o"
          cdr =>          "uniconvertor" "%i" "%o.svg"; mv "%o.svg" "%o"
          cgm =>          "uniconvertor" "%i" "%o.svg"; mv "%o.svg" "%o"
   dng:decode =>          "/opt/local/bin/ufraw-batch" --silent --create-id=also --out-type=png \
                            --out-depth=16 "--output=%u.png" "%i"
          doc =>          "soffice" --headless --convert-to pdf --outdir `dirname "%i"` \
                            "%i" 2> "%Z"; mv "%i.pdf" "%o"
         docx =>          "soffice" --headless --convert-to pdf --outdir `dirname "%i"` \
                            "%i" 2> "%Z"; mv "%i.pdf" "%o"
          dot =>          "/opt/local/bin/dot" -Tsvg "%i" -o "%o"
          dvi =>          "/opt/local/bin/dvips" -q -o "%o" "%i"
          dxf =>          "uniconvertor" "%i" "%o.svg"; mv "%o.svg" "%o"
          eps<=>pdf       "/opt/local/bin/gsx" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT \
                            -dMaxBitmap=500000000 "-sDEVICE=pdfwrite" "-sOutputFile=%o" "-f%i"
          eps<=>ps        "/opt/local/bin/gsx" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT \
                            -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 \
                            "-sDEVICE=ps2write" "-sOutputFile=%o" "-f%i"
          fig =>          "uniconvertor" "%i" "%o.svg"; mv "%o.svg" "%o"
          hpg =>          "hp2xx" -q -m eps -f `basename "%o"` "%i";     mv -f `basename "%o"` "%o"
         hpgl =>          "hp2xx" -q -m eps -f `basename "%o"` "%i";     mv -f `basename "%o"` "%o"
          htm =>          "/opt/local/bin/html2ps" -U -o "%o" "%i"
         html =>          "/opt/local/bin/html2ps" -U -o "%o" "%i"
        https =>          "/opt/local/bin/curl" -s -k -L -o "%o" "https:%M"
         ilbm =>          "/opt/local/bin/ilbmtoppm" "%i" > "%o"
          jxr =>          "mv "%i" "%i.jxr"; "JxrDecApp" -i "%i.jxr" -o "%o.bmp" -c 0; \
                            mv "%i.jxr" "%i"; mv "%o.bmp" "%o"
          man =>          "/opt/local/bin/groff" -man -Tps "%i" > "%o"
         miff<= show      "/opt/local/bin/display" -delay 0 -window-group %[group] \
                            -title "%l " "ephemeral:%i"
  mpeg:decode =>          "avconv" -v -1 -i "%i" -vframes %S -vcodec pam -an -f rawvideo \
                            -y "%u.pam" 2> "%Z"
          odt =>          "soffice" --headless --convert-to pdf --outdir `dirname "%i"` \
                            "%i" 2> "%Z"; mv "%i.pdf" "%o"
          pdf<=>eps       "/opt/local/bin/gsx" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT \
                            -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 \
                            "-sDEVICE=epswrite" "-sOutputFile=%o" "-f%i"
          pdf<=>ps        "/opt/local/bin/gsx" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT \
                            -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 \
                            "-sDEVICE=ps2write" "-sOutputFile=%o" "-f%i"
          plt =>          "/bin/echo" "set size 1.25,0.62; set terminal postscript portrait color \
                            solid; set output \'%o\'; load \'%i\'" > "%u";"/opt/local/bin/gnuplot" \
                            "%u"
          png<= webp      "/opt/local/bin/cwebp" -quiet -q %Q "%i" -o "%o"
          pnm<= ilbm      "/opt/local/bin/ppmtoilbm" -24if "%i" > "%o"
          pov =>          "povray" "+i%i" -D0 "+o%o" +fn%q +w%w +h%h +a -q9 "-kfi%s" "-kff%n";\
                            "/opt/local/bin/convert" -concatenate "%o*.png" "%o"
          ppt =>          "soffice" --headless --convert-to pdf --outdir `dirname "%i"` \
                            "%i" 2> "%Z"; mv "%i.pdf" "%o"
         pptx =>          "soffice" --headless --convert-to pdf --outdir `dirname "%i"` \
                            "%i" 2> "%Z"; mv "%i.pdf" "%o"
           ps<=>eps       "/opt/local/bin/gsx" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT \
                            -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 \
                            "-sDEVICE=epswrite" "-sOutputFile=%o" "-f%i"
           ps<=>pdf       "/opt/local/bin/gsx" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT \
                            -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 \
                            "-sDEVICE=pdfwrite" "-sOutputFile=%o" "-f%i"
           ps<= print     "lpr "%i"
         rgba<= rle       "rawtorle" -o "%o" -v "%i"
         scan =>          "/opt/local/bin/scanimage" -d "%i" > "%o"
        scanx =>          "/opt/local/bin/scanimage" > "%o"
        shtml =>          "/opt/local/bin/html2ps" -U -o "%o" "%i"
          sid =>          "mrsidgeodecode" -if sid -i "%i" -of tif -o "%o" > "%u"
          svg =>          "/opt/local/bin/rsvg-convert" -o "%o" "%i"
         tiff<= launch    "/opt/local/bin/gimp" "%i"
          txt<=>ps        "/opt/local/bin/enscript" -o "%o" "%i"
          wdp =>          "mv "%i" "%i.jxr"; "JxrDecApp" -i "%i.jxr" -o "%o.bmp"; mv "%i.jxr" "%i"; \
                            mv "%o.bmp" "%o"
         webp =>          "/opt/local/bin/dwebp" -pam "%i" -o "%o"
          wmf =>          "/opt/local/bin/wmf2eps" -o "%o" "%i"
          xls =>          "soffice" --headless --convert-to pdf --outdir `dirname "%i"` "%i" 2> "%Z"; \
                            mv "%i.pdf" "%o"
         xlsx =>          "soffice" --headless --convert-to pdf --outdir `dirname "%i"` "%i" 2> "%Z"; \
                            mv "%i.pdf" "%o"
  
  Path: /Users/kurtpfeifle/.magick/delegates.xml
  
  Delegate                Command
  -------------------------------------------------------------------------------
         flip =>          "convert '%i' -flip 'miff:%o"

5 Rahmen um ein Bild zeichnen

5 Pixel dicker Rahmen:

 convert logo: -frame 5 logo-framed.png
Logo mit -frame 5…

Logo mit -frame 5

Aber die Farbe? Ich will rot!

 convert logo: -mattecolor red -frame 5 logo-framed.png
Logo mit -mattecolor red -frame 5…

Logo mit -mattecolor red -frame 5

Aber rechts und links soll er dicker sein als oben und unten!

 convert logo: -mattecolor red -frame 20x1 logo-framed.png
Logo mit -mattecolor red -frame 20x1…

Logo mit -mattecolor red -frame 20x1

6 Anatomie der ImageMagick-Kommandozeilen

6.1 Allereinfachstes Beispiel

 convert a.jpg a.png

Unschwer zu erraten, was dieses Kommando bewirkt, oder?

Beim nächsten Kommando wird’s erheblich schwerer:

6.2 Komplexes Beispiel

 convert                  \
        label.gif         \
        +matte            \
                          \
        \(                \
           +clone         \
           -shade 110x90  \
           -normalize     \
           -negate        \
           +clone         \
           -compose Plus  \
           -composite     \
        \)                \
                          \
        \( -clone 0       \
           -shade 110x50  \
           -normalize     \
           -channel BG    \
           -fx 0          \
           +channel       \
           -matte         \
        \)                \
                          \
        -delete 0         \
        +swap             \
        -compose Multiply \
        -composite        \
         button.gif

Bei diesem Kommando das Ergebnis erraten? Ziemlich unmöglich…

6.3 Details zur Kommandozeile

Ein ImageMagick-Kommando besteht aus…

  1. …genau einer Kommando-Bezeichnung,
  2. …plus mindestens einem Dateinamen für ein Input-Dat(ei)en,
  3. …plus keinem, einer oder mehreren image settings,
  4. …plus keinem, einem oder mehreren image operators,
  5. …plus keinem, einem oder mehreren image sequence operators,
  6. …plus keinem oder einem image geometry setting,
  7. …plus keinem, einem oder mehreren image stacks,
  8. …plus keinem oder einem Dateinamen für die Ausgabe-Dat(ei)en (nicht erforderlich für stream, mogrify, animate oder display)

6.4 Kommando-Bezeichnung

Möglich sind: convert, composite, montage, compare, import, stream, animate, mogrify, display oder conjure

6.5 Input-Dateinamen

Für Input-Dateien sind folgende Konzepte möglich:

6.5.1 Platzhalter und Wildcards

Beispiel:

 convert *.jpg output.gif

6.5.2 Explizite Angabe eines Bild-Formats

Beispiel:

 convert -size 640x480 -depth 8 rgb:bilddateiname image.png

6.5.3 Eingebautes Beispiel-Bild oder -Muster

Beispiel:

 convert pattern:checkerboard output.png
 convert pattern:hexagons     output.gif

6.5.4 STDIN, STDOUT und Datei-Deskriptoren

Beispiele:

 convert logo: gif:-    | display             gif:-
 convert logo: gif:fd:1 | display -resize 50% gif:fd:0

 # Es gilt: STDIN  == fd:0
 #          STDOUT == fd:1
 #          STDERR == fd:2
 #
 # Dateien mit Deskriptor-Nummern N>2 ansprechen mit fd:N

6.5.5 Auswahl von ‘frames’ oder Seiten

Beispiele:

 convert 'multipage.tiff[4]' output.pdf
 convert 'document.pdf[1]'   output.jpeg
 convert 'images.gif[3-7]'   output.mng
  
 # Benutzen von einfachen Anführungszeichen, damit die Shell nix falsch macht mit den eckigen Klammern
 # ACHTUNG: Zählung fängt bei '0' an. Seite 1 eines PDFs also per `[0]`, Frame 3 eines animierten GIFs also per `[4]`!

6.5.6 Auswahl bestimmter Regionen

Beispiele:

 convert -size 6000x4000 -depth 8 'rgb:bilddateiname[500x500+2750+1750]' output.png

6.5.7 Erzwingen einer Inline-Bildgrößen-Änderung

Beispiele:

 convert '*.jpg' -resize 96x96 symbolbild-%03d.png
 convert '*.jpg[96x96]'        symbolbild-%03d.png    # ist äquivalent

6.5.8 Erzwingen einer Inline-Bild-Beschneidung

Beispiele:

 convert '*.jpg' -crop 120x120+10+5 thumbnail%03d.png
 convert '*.jpg[120x120+10+5]'      thumbnail%03d.png   # ist äquivalent

6.5.9 Benutzung von Dateinamens-Referenzen

Beispiele:

 convert @meine-bilder.txt mein-filmchen.gif

 # wobei z.B.:
 cat meine-bilder.txt
 bild-001.jpg
 bild-002.jpg
 bild-003.jpg

oder:

 convert bild-%04d.png[3-5] ...

 # versucht die folgenden Bild-Dateinamen zu lesen:
 bild-0003.png
 bild-0004.png
 bild-0005.png

6.6 Image Settings

Dazu gehören:
-adjoin • -affine • -alpha • -antialias • -authenticate • -background • -bias • -black-point-compensation • -blue-primary • -bordercolor • -caption • -channel • -comment • -compress • -debug • -define • -delay • -density • -depth • -direction • -display • -dispose • -dither • -encoding • -endian • -extract • -family • -fill • -filter • -font • -format • -fuzz • -geometry • -gravity • -green-primary • -interlace • -intent • -interpolate • -label • -limit • -linewidth • -log • -loop • -mask • -mattecolor • -monitor • -orient • -page • -pointsize • -preview • -quality • -quiet • -red-primary • -region • -render • -repage • -sampling-factor • -scene • -seed • -size • -stretch • -stroke • -strokewidth • -style • -texture • -tile • -transparent-color • -treedepth • -type • -undercolor • -units • -verbose • -virtual-pixel • -weight


Image Settings gelten…

Image Settings können wirken auf…

6.7 Image Operators

Dazu gehören:
-annotate • -black-threshold • -blur • -border • -charcoal • -chop • -clip • -clip-path • -clip-mask • -colors • -colorize • -colorspace • -compose • -contrast • -convolve • -crop • -cycle • -despeckle • -draw • -edge • -emboss • -enhance • -equalize • -evaluate • -extent • -flip • -flop • -floodfill • -frame • -gamma • -gaussian-blur • -implode • -lat • -level • -map • -median • -modulate • -monochrome • -negate • -noise • -normalize • -opaque • -ordered-dither • -paint • -posterize • -raise • -profile • -radial-blur • -raise • -random-threshold • -resample • -resize • -roll • -rotate • -sample • -scale • -sepia-tone • -segment • -shade • -shadow • -sharpen • -shave • -shear • -sigmoidal-contrast • -solarize • -splice • -spread • -strip • -swirl • -threshold • -transparent • -thumbnail • -tint • -transform • -trim • -unsharp • -version • -wave • -white-point • -white-threshold


6.8 Image Sequence Operators

Dazu gehören:
-append • -affinity • -average • -clut • -coalesce • -combine • -compare • -complex • -composite • -crop • -debug • -deconstruct • -delete • -evaluate-sequence • -fft • -flatten • -fx • -hald-clut • -ift • -identify • -insert • -layers • -limit • -map • -maximum • -minimum • -morph • -mosaic • -optimize • -print • -process • -quiet • -separate • -swap • -write


Image Sequence Operators unterscheiden sich von Image Settings:

Image Operators unterscheiden sich von Image Settings. Sie wirken…

Alle Kommandozeilen-Optionen, die…

…sind Image Operators.


6.9 Image Geometry Settings

Dazu gehören:
-adaptive-resize • -border • -borderwidth • -chop • -crop • -density • -extent • -extract • -frame • -geometry • -iconGeometry • -liquid-rescale • -page • -region • -repage • -resize • -sample • -scale • -shave • -splice • -thumbnail • -window


Generelle Syntax für das Setzen von Werten der Image Geometry Settings:

{dimension}{offset} Allgemeine Syntax zur Angabe von Werten für die Geometrie-Einstellungen. Innerhalb der Werte darf nirgendwo ein Leerzeichen vorkommen.
{offset} Angabe von {offset} ist optional. Erfolgt in der Form ±x±y. Voreinstellung ist +0+0. Werte in Pixeln. Bedeutung: +x bewirkt Verschiebung nach rechts; -x bewirkt Verschiebung nach links; +y verschiebt nach unten; -y verschiebt nach oben; Vorzeichen für beide Angaben sind erforderlich.
{dimension} {dimension} gibt die Abmessungen oft in Form von {breite}x{hoehe} an. (Ausnahme bei Angabe von Z% oder X%xY% als prozentuale Skalierung.) Details zu {dimension}-Angaben in der nächsten Tabelle.

Generelle Syntax für {dimension}-Angaben zur Image Geometry (1):

Z% Skaliert Breite und Höhe gleichermaßen um den genannten Prozentsatz. Bewahrt das Seitenverhältnis.
X%xY% Skaliert die Breite um X%, die Höhe um Y%. (Nur ein einziges %-Symbol ist erforderlich. Es sind demnach gleichbedeutend: *X%xY*, *XxY%* und *X%xY%*.)
{Breite}x Skaliert die Breite auf die angegebene Anzahl von Pixeln. Höhe wird automatisch so berechnet, dass das Seitenverhältnis bewahrt bleibt.
x{Hoehe} Skaliert die Höhe auf die angegebene Anzahl von Pixeln. Breite wird automatisch so berechnet, dass das Seitenverhältnis bewahrt bleibt.

Generelle Syntax für {dimension}-Angaben zur Image Geometry (2):

{Breite}x{Hoehe} Die maximale Anzahl von Pixeln für die Breite beträgt {Breite}. Die maximale Anzahl von Pixeln für die Höhe beträgt {Hoehe}. Die Skalierung erfolgt so, dass das Seitenverhältnis bewahrt bleibt. ({Breite}x{Hoehe} bildet also ein Rechteck, in welches das Bild komplett reinpasst.)
{Breite}x{Hoehe}^ Das ^-Zeichen am Ende ist signifikant. Die minimale Anzahl von Pixeln für die Breite beträgt {Breite}. Die minimale Anzahl von Pixeln für die Höhe beträgt {Hoehe}. Die Skalierung erfolgt so, dass das Seitenverhältnis bewahrt bleibt. ({Breite}x{Hoehe} bildet also ein Rechteck, welches in das Bild komplett reinpasst.)

Generelle Syntax für {dimension}-Angaben zur Image Geometry (3):

{Breite}x{Hoehe}! Das !-Zeichen am Ende ist signifikant. Die exakte Anzahl von Pixeln für die Breite beträgt {Breite}. Die exakte Anzahl von Pixeln für die Höhe beträgt {Hoehe}. Die Skalierung erfolgt so, dass das Seitenverhältnis gegebenenfalls völlig ignoriert wird.. ({Breite}x{Hoehe} bildet also ein Rechteck, welches das Bild komplett ausfüllt, gegebenenfalls mit entsprechender Verzerrung [Dehnung oder Stauchung in eine oder zwei Richtungen].)
{Breite}x{Hoehe}> Das >-Zeichen am Ende ist signifikant. Verkleinert ein Bild, falls es in einer oder beiden Dimensionen größer ist als die entsprechende Angabe(n).

Generelle Syntax für {dimension}-Angaben zur Image Geometry (4):

{Breite}x{Hoehe}< Das <-Zeichen am Ende ist signifikant. Vergrößert ein Bild, falls es in einer oder beiden Dimensionen kleiner ist als die entsprechende Angabe(n).
{Gebiet}@ Größen-Veränderung des Bildes auf das spezifizierte Gebiet. Seitenverhältnis bleibt erhalten.

Folgende Parameter erfordern die Übergabe von geometry-Werten, meist in der Form WxH±x±y:

  -density geometry               #  horizontal and vertical density of the image
  -page geometry                  #  size and location of an image canvas (setting)
  -sampling-factor geometry
  -size geometry                  #  width and height of image
  -tile-offset geometry
  -adaptive-blur geometry
  -adaptive-resize geometry
  -adaptive-sharpen geometry
  -annotate geometry              #  text
  -blur geometry                  #  reduce image noise and reduce detail levels
  -border geometry                #  surround image with a border of color
  -brightness-contrast geometry   # 
  -canny geometry                 #  detect edges in the image
  -chop geometry                  #  remove pixels from the image interior
  -contrast-stretch geometry
  -extent geometry                #  set the image size
  -extract geometry               #  extract area from image
  -floodfill geometry             #  color
  -frame geometry                 #  surround image with an ornamental border
  -gaussian-blur geometry
  -geometry geometry              #  preferred size or location of the image
  -hough-lines geometry
  -interpolative-resize geometry
  -lat geometry                   #  local adaptive thresholding
  -linear-stretch geometry
  -liquid-rescale geometry
  -mean-shift geometry            #  delineate arbitrarily shaped clusters in the image
  -median geometry                #  apply a median filter to the image
  -mode geometry                  #  make each pixel the 'predominant color' of the
  -motion-blur geometry
  -noise geometry                 #  add or reduce noise in an image
  -region geometry                #  apply options to a portion of the image
  -repage geometry                #  size and location of an image canvas
  -resample geometry              #  change the resolution of an image
  -resize geometry                #  resize the image
  -roll geometry                  #  roll an image vertically or horizontally
  -sample geometry                #  scale image with pixel sampling
  -scale geometry                 #  scale the image
  -selective-blur geometry
  -shadow geometry                #  simulate an image shadow
  -sharpen geometry               #  sharpen the image
  -shave geometry                 #  shave pixels from the image edges
  -shear geometry                 #  slide one edge of the image along the X or Y axis
  -sigmoidal-contrast geometry
  -sketch geometry                #  simulate a pencil sketch
  -splice geometry                #  splice the background color into the image
  -statistic type geometry
  -thumbnail geometry             #  create a thumbnail of the image
  -unsharp geometry               #  sharpen the image
  -vignette geometry              #  soften the edges of the image in vignette style
  -wave geometry                  #  alter an image along a sine wave
  -crop geometry                  #  cut out a rectangular region of the image
  -smush geometry                 #  smush an image sequence together

6.10 Image Stacks

Ein Image Stack erlaubt es, ein einzelnes Bild (oder eine Bild-Sequenz) von der Haupt-Kommandozeile zu separieren und sozusagen erstmal ‘beiseite zu nehmen’, außerhalb der Haupt-Kommandozeile zu manipulieren, und dann das Ergebnis dieses Neben-Geleises wieder in die Haupt-Kommandozeile einzuspeisen.

Einen Image Stack umschließt man in runden Klammern, die man per Rückstrich/backslash escapen muss, und die (mindestens) ein zusätzliches Leerzeichen vom Image Stack trennt: \( ...image stack... )\


Beispiel: Kommando

 convert wand.png \( wizard.jpg -rotate 30 \) +append images.png                            
 ^       ^       ^^^^^           ^      ^ ^^^^ ^      ^                                     
 |       |       |||||           |      | |||| |      |                                     
 |       |       |||||           |      | |||| |      +----Ausgabe-Datei (Ergebnis)         
 |       |       |||||           |      | |||| |                                            
 |       |       |||||           |      | |||| +----Image Sequence Operator (hängt Ergebnis 
 |       |       |||||           |      | ||||      des Image Stacks an die Input-Datei)    
 |       |       |||||           |      | ||||                                              
 |       |       |||||           |      | |||+----zusätzliches Leerzeichen zur Abtrennung   
 |       |       |||||           |      | |||     des Image Stacks                          
 |       |       |||||           |      | ||+----runde Schließklammer zur Abtrennung des    
 |       |       |||||           |      | ||     Image Stacks                               
 |       |       |||||           |      | |+----Rückstrich zum Escapen der runden           
 |       |       |||||           |      | |     Schließklammer                              
 |       |       |||||           |      | +----zusätzliches Leerzeichen zur Abtrennung des  
 |       |       |||||           |      |      Image Stacks                                 
 |       |       |||||           |      +----Parameter für den Image Operator des           
 |       |       |||||           |           Image Stacks                                   
 |       |       |||||           +----Image Operator des Image Stacks: rotiert das Bild     
 |       |       |||||                des Image Stacks                                      
 |       |       ||||+----Input-Bild des Image Stacks                                       
 |       |       ||||                                                                       
 |       |       |||+----zusätzliches Leerzeichen zur Abtrennung des Image Stacks           
 |       |       |||                                                                        
 |       |       ||+----runde Öffnungsklammer zur Abtrennung des Image Stacks               
 |       |       ||                                                                         
 |       |       |+----Rückstrich zum Escapen der runden Öffungsklammer                     
 |       |       |                                                                          
 |       |       +----zusätzliches Leerzeichen zur Abtrennung des Image Stacks              
 |       |                                                                                  
 |       +----Input-Datei                                                                   
 |                                                                                          
 +----Kommando                                                                              

Beispiel: Ergebnis

Ergebnis von:   convert wizard: \( wizard: -resize 80% -rotate -30 \) +append -mattecolor red -frame 3x3 images.png

Ergebnis von:   convert wizard: \( wizard: -resize 80% -rotate -30 \) +append -mattecolor red -frame 3x3 images.png

6.11 Ausgabe-Dateinamen

ImageMagick kennt mehrere Konzepte, um die Ausgabe-Dateinamen zu spezifizieren::


6.11.1 Ausgabe-Format per Datei-Endung

 convert input.png OUT.JPEG
 convert input.png OUT.jpeg
 convert input.png OUT.JpgG
 convert input.png OUT.JpEg
 convert input.png OUT.png
 convert input.png OUT.TIFF
 convert input.png OUT.tIFF
 convert input.png OUT.TIf

6.11.2 Explizite Angabe des Datei-Formats

 convert input.png jpeg:OUT.data
 convert input.png Jpeg:OUT.dat
 convert input.png jpeg:OUT
 convert input.png jPEg:OUT.jpg
 convert input.png jpeg:OUT.png    # Auch hier entsteht ein JPEG!
 convert input.png  PNG:OUT
 convert input.png Tiff:OUT
 convert input.png  tif:OUT

6.11.3 Dateinamens-Referenz

Angenommen, in der Textdatei meine-bilder.txt stehen die Dateinamen verschiedener Bilder, durch Leerraum getrennt:

 erste.Tif  zweite.PNG    dritte.jpg
 "die vierte.jpeg"
 fuenf.gif
 rose:
 [...]

Dann kann ImageMagick alle in der Datei genannten Bilder wie folgt verwenden:

 convert @meine-bilder.txt output.gif
 convert @meine-bilder.txt *.png

6.11.4 Schreiben nach STDOUT

 convert input.png jpeg:-
 convert input.png Jpeg:fd:1

7 Nochmals: die drei verschiedenen Kategorien von Kommando-Parametern

Wiederholung: Es gibt drei grundsätzlich unterschiedliche Kategorien von Kommando-Parametern.

  1. Image Settings: werden gültig, sobald sie auf der Kommandozeile erscheinen. Bleibt gültig, bis es durch ein anderes, später auf der Kommandozeile vorkommendes Image Setting aufgehoben wird, oder bis das Kommando beendet ist.
  2. Image Operators: werden sofort wirksam auf das zuletzt geladene Bild, sobald sie auf der Kommandozeile vorkommen. (Ausnahme: falls ein Setting vorkommt, bevor ein Bild geladen ist, wirkt es erst, sobald das erste Bild geladen ist.) Nach Wirkung eines Operators wird er sofort “vergessen” und nicht mehr wirksam.
  3. Image Sequence Operators: wirken ähnlich wie Image Operators, mit dem Unterschied, dass sie nicht nur das letzte Einzel-Bild betreffen, sondern auf die komplette bereits geladene Bild-Sequenz wirken.

Alle diese Parameter gibt es (mindestens) in der Form -parameter .... Die meisten davon gibt es außerdem in der Abwandlung +parameter .... Die +-Form modifiziert die Bedeutung der --Form.

Nochmals: im Zweifel bitte die Ausgabe von convert -help konsultieren. Diese listet alle Parameter nach Kategorien getrennt auf.

8 Halb-durchsichtige Beschriftung einer Abbildung

…und zwar soll der Dateiname in die jeweilige Abbildung integriert werden.

Initiale Abbildung, erster Versuch:

 convert \
     nature-FbJDP.png \
    -gravity south \
    -annotate 0 '%f' \
     nature-output.jpg
Abbildung original (links) — mit fast unlesbarer Beschriftung (Mitte) — besser… (rechts)

Abbildung original (links) — mit fast unlesbarer Beschriftung (Mitte) — besser… (rechts)

Kommando:

 for img in *.png; do

   width=$(identify -format %W ${img})
   width=$(( ${width} * 9 / 10 ))

   convert                  \
     -background '#0008'    \
     -gravity center        \
     -fill yellow           \
     -size ${width}x100     \
      caption:"${img}"      \
      "${img}"              \
     +swap                  \
     -gravity south         \
     -composite             \
      "with-caption-${img}"

done

Noch mehr Text… Geht das auch?

 width=$(identify -format %W nature-FbJDP.png)

 convert                  \
   -background '#0008'    \
   -gravity center        \
   -fill white            \
   -size ${width}x100     \
    caption:"This is a sample text to test \
 the automatic sizing of fonts by ImageMagick." \
    nature-FbJDP.png      \
  +swap                   \
  -gravity north          \
  -composite              \
   output1.png

 convert                  \
   -background '#0008'    \
   -gravity center        \
   -fill white            \
   -size ${width}x100     \
    caption:"This is a even longer sample text. \
 It also serves to test if automatic sizing of fonts \
 by ImageMagick works as expected: just don't specify \
 any fontsize, and let ImageMagick go for the best fit..." \
    nature-FbJDP.png      \
  +swap                   \
  -gravity north          \
  -composite              \
   output2.png
Abbildung original (links) — mit mehr Text (Mitte) — mit viiiieeel mehr Text… (rechts). Textbox-Größe war fix – ImageMagick passte die Font-Größe automatisch so an, dass der Text reinpasst.

Abbildung original (links) — mit mehr Text (Mitte) — mit viiiieeel mehr Text… (rechts). Textbox-Größe war fix – ImageMagick passte die Font-Größe automatisch so an, dass der Text reinpasst.

Übrigens kann man auch ganze Textseiten zu einem Bild konvertieren:

 man convert     \
  | \
    col -b       \
  | expand       \
  | \
    head -n 17   \
  | \
    convert -font       Source-Code-Pro  \
            -background lightblue        \
            -fill       blue             \
            -size       700x350          \
             text:-                      \
            -delete     1--1             \
            -trim                        \
             text_manpage.png

Ergebnis:

Man page für convert zu einem GIF der Größe 700x350 gewandelt…

Man page für convert zu einem GIF der Größe 700x350 gewandelt…

9 Illustration beschneiden

 convert logo: -crop 300x300+150+150 logo-cropped.png
logo-cropped.png

logo-cropped.png

10 Aus mehreren Bildern ein animiertes GIF erzeugen

Kommando:

 # Generierung von 121 PNGs:
 for i in {100..120}; do
   convert logo: -scale ${i}x logo-${i}-breit.png
 done

 # Kommando zum Erzeugen eines ersten GIFs:
 convert               \
    logo-1??-breit.png \
      \( \
         -clone 1--1   \
      \) \
    logo-animiert-1.gif

 # Kommando zum Erzeugen des zweiten GIFs:
 convert               \
    logo-1??-breit.png \
      \( \
         -clone 1--1   \
         -reverse      \
      \) \
    logo-animiert-2.gif

Ergebnis:

Lässt sich leider in PDF nicht animiert darstellen… Es sind zwei animierte GIFs entstanden. Der Unterschied, den der Zusatz-Parameter -reverse des 2. Kommandos ausmacht, ist beim Vergleich der Ergebnisse leicht zu erkennen.

Animiertes GIF Nr. 1 - Animation nur in HTML-Output aktiv… Animiertes GIF Nr. 2 - Animation nur in HTML-Output aktiv…

Kommentiertes Kommando:

 for i in {100..120}; do                           # Erstellt in einer Schleife insgesamt 121 PNGs
   convert logo: -scale ${i}x logo-${i}-breit.png  #+   mit Dateienamen 'logo-100-breit.png' bis
 done                                              #+   'logo-120-breit.png'. Deren Breite in Pixeln
                                                   #+   variiert von 100 bis 120 px.

 convert               \   # Startet die ImageMagick; bereitet es auf die Aufgabe "Konvertierung" vor.
    logo-1??-breit.png \   # Lädt alle zuvor erstellten 'logo-1xx-breit.png'-Bilder in aufsteigender Folge.
    \                      # ImageMagick hat jetzt 121 Bilder geladen.
      \( \                 # Startet einen neuen 'image stack' --- außerhalb des Haupt-Kommandos.
         -clone 1--1   \   # Klont die bisher geladenen Bilder von Index '1' bis Index '-1'.
    \                      # Im externen Stack befinden sich jetzt die Bilder 'logo-100*' bis 'logo-120*'.
         -reverse      \   # Kehrt die Reihenfolge aller Bilder im externen 'image stack' um.
    \                      # Im externen Stack befinden sich jetzt die Bilder 'logo-120*' bis 'logo-100*'.
      \) \                 # Beendet den 'image stack' und lädt alle Bilder darin ins Haupt-Kommando.
    \                      # Im Haupt-Stack befinden sich jetzt insgesamt 242 Bilder (die 121 ursprünglichen
    \                      #+    sowie die 121 ge-klonten in umgekehrter Reihenfolgen.
    logo-animiert.gif      # Erzeugt ein GIF aus den geladenen Bildern. Bei mehreren geladenen Bildern
                           #+    ist das Resultat automatisch ein animiertes GIF.

Geschwindigkeit der Animation, Wiederholung/Looping ist selbstverständlich über zusätzliche Parameter beinflußbar…

Auch: aus einem *.AVI ein animiertes *.GIF!

 convert -quiet -delay 1 some.avi some.gif

11 Mehrere Bilder vergleichen

Zuerst 2 oder mehr verschiedene (aber ähnliche!) Bilder herstellen:

 convert rose: rose.png
 convert rose: rose.jpg
 convert rose: rose.tif
 convert rose: rose.gif

Dann vergleichen mit dem compare-Kommando, dabei das Vergleichs-Ergebnis jeweils in eine Datei delta-....png schreiben:

 compare rose.png rose.png delta-png-png.png
 compare rose.png rose.jpg delta-png-jpg.png
 compare rose.png rose.tif delta-png-tif.png
 compare rose.png rose.gif delta-png-gif.png
 compare rose.jpg rose.tif delta-jpg-tif.png
 compare rose.jpg rose.gif delta-jpg-gif.png
 compare rose.tif rose.gif delta-tif-gif.png

Per Default ist in den “Delta”-Dateien im Hintergrund die zweite Vergleichsdatei (etwas ausgegraut) eingeblendet. Die Differenz-Pixel sind rot, die identischen Pixel sind weiß.

delta-png-png.png delta-png-jpg.png delta-png-tif.png delta-png-gif.png delta-jpg-tif.png delta-jpg-gif.png delta-tif-gif.png

Wie man sieht: die verlustfreien Formate PNG und TIFF zeigen überhaupt keine roten Pixel, also gar keine Unterschiede. . Zwischen diesen und den verlust-behafteten Formaten JPEG und GIF ist praktisch jeder einzelne Pixel verschieden – wenn auch eventuell nur mit leicht unterschiedlichen Farbwerten.

Wenn man über sehr kleine Unterschiede hinwegsehen möchte, kann man per -fuzz 3% z.B. alle Differenzen ausblenden, die kleiner als 3% sind. Mit den Zusatz-Optionen -highlight-color und -lowlight-color kann man statt der rot-weissen Darstellung der Unterschiede andere Farben erzwingen.

 compare rose.png rose.png -highlight-color blue  -fuzz 3% delta-png-png-fuzz-3pc.png
 compare rose.png rose.jpg -highlight-color blue  -fuzz 3% delta-png-jpg-fuzz-3pc.png
 compare rose.png rose.tif -highlight-color blue  -fuzz 3% delta-png-tif-fuzz-3pc.png
 compare rose.png rose.gif -highlight-color blue  -fuzz 3% delta-png-gif-fuzz-3pc.png
 compare rose.jpg rose.tif -highlight-color blue  -fuzz 3% delta-jpg-tif-fuzz-3pc.png
 compare rose.jpg rose.gif -highlight-color blue  -fuzz 3% delta-jpg-gif-fuzz-3pc.png
 compare rose.tif rose.gif -highlight-color blue  -fuzz 3% delta-tif-gif-fuzz-3pc.png

delta-png-png-fuzz-3pc.png delta-png-jpg-fuzz-3pc.png delta-png-tif-fuzz-3pc.png delta-png-gif-fuzz-3pc.png delta-jpg-tif-fuzz-3pc.png delta-jpg-gif-fuzz-3pc.png delta-tif-gif-fuzz-3pc.png

Das Beispiel rose: als Ausgangspunkt zur Demo des compare-Kommandos war evtl. nicht das best-geeignetste (es war die kleinste Beispiel-Datei, die gerade vorhanden war und sich zum Einbau in diese HTML-Seite eignet.)

compare arbeitet mit einer Voreinstellung von 72 PPI. Sehr häufig reicht das aus, um vorhandene Unterschiede grob zu visualisieren. Wer eine feinere Auflösung benötigt, kann per -density 200, -density 600 oder -density 345 eine beliebig höhere Auflösung wählen. Der Vergleichsvorgang dauert hier natürlich etwas länger und die erzeugte “Delta”-Datei wird größer!

Man kann compare auch verwenden, um feinste (oder auch gröbere) Unterschiede sichtbar zu machen z.B. zwischen zwei PDF-Seiten:

Erstellung zweier leicht unterschiedlicher PDFs mit Ghostscript

 gs -o pdf1.pdf \
    -sDEVICE=pdfwrite \
    -g3000x500 \
    -c "/Courier findfont 32 scalefont setfont \
        10.0 10.0 moveto \
        (Hello, UbuCon!) show \
        showpage"

 gs -o pdf2.pdf \
    -sDEVICE=pdfwrite \
    -g3000x500 \
    -c "/Courier findfont 32 scalefont setfont \
        10.1 10.1 moveto \
        (Hello, UbuCom!) show \
        showpage"

Vergleichen:

 compare pdf1.pdf pdf2.pdf delta-pdf.png
 compare -density 600 pdf1.pdf pdf2.pdf delta-pdf-600ppi.png
 compare -density 600 pdf1.pdf pdf2.pdf -compose src delta-pdf-600ppi-src.png

Wer den ausgegrauten Hintergrund der Referenz-Datei nicht sehen möchte, blendet ihn durch Hinzufügen von -compose src komplett aus. Übrig bleiben nur die roten und weißen Pixel.

delta-pdf.png delta-pdf-600ppi.png delta-pdf-600ppi-src.png

Bei genauem Hinschauen zeigt sich, dass die gröbere Auflösung von 72 PPI zwar ausreicht, um die unterschiedlichen Buchstaben n und m zu erfassen. Dass der Buchstabe l bei 72 PPI scheinbar sehr stark abweichend positioniert ist, alle anderen Buchstaben jedoch “perfekt”, liegt daran, …

Die systematische Verschiebung der Worte oben und links um jeweils einen Zehntel Punkt zu erkennen, gelang erst bei 600 PPI…

12 Abbildung dehnen oder stauchen

Kommando:

 convert logo: -resize '500x250!' resized-logo.png

Ergebnis:

Logo, gestaucht

Logo, gestaucht

13 Grafik anders verzerren, z.B. “perspektivisch”

Ausgangspunkt:

Perspektiven-Änderung: aus rotem Schief-Eck soll blaues Rechteck werden

Perspektiven-Änderung: aus rotem ‘Schief’-Eck soll blaues Rechteck werden

 convert                                                                     \
  -verbose                                                                   \
   http://i.stack.imgur.com/SN7sm.jpg                                        \
  -matte                                                                     \
  -virtual-pixel transparent                                                 \
  -distort perspective '7,40 4,30  4,124 4,123  85,122 100,123  85,2 100,30' \
   output.png

Ist Euch was aufgefallen? ImageMagick kann sich Input auch per HTTP (und per HTTPS ebenfalls) aus dem Web holen!

Operation:

Perspektiven-Änderung: alt (links) und neu (rechts)

Perspektiven-Änderung: alt (links) und neu (rechts)

Magick’s image operator war hier: -distort perspective.

Dieser operator nimmt als Argumente 8 verschiedene Pixel-Koordinaten:

Der rote Rahmen zeigt die 4 Original-Koordinaten. Der blaue Rahmen zeigt die 4 Ziel-Koordinaten.

14 Bild-Größen ändern – auf unterschiedliche Weise!

Bild-Dimensionen:

Frage stammt von Stackoverflow.com. Leider waren die Angaben nicht so ganz eindeutig.

Dies sind die Größen-Verhältnisse von Original-Bild und Ziel-Bild:

Original-Bild

Original-Bild

Vergleich der Dimensionen von Original-Bild und Zielbild zeigt, dass die Skalierung unter Beibehaltung des Seitenverhältnisses nicht möglich ist…

Vergleich der Dimensionen von Original-Bild und Zielbild zeigt, dass die Skalierung unter Beibehaltung des Seitenverhältnisses nicht möglich ist…

Es gibt also verschiedene Möglichkeiten, das Bild zu verkleinern. Sehen wir sie uns an…

14.1 Bild beschneiden

 convert WPTgp.jpg -gravity Center -crop 290x310+0+0 WPT-cropped.jpg
WPT-cropped.jpg

WPT-cropped.jpg

 identify -format "%W Pixel breit, %H Pixel hoch\n" WPT-cropped.jpg

   290 Pixel breit, 310 Pixel hoch

14.2 Bild-Höhe vorgeben

 convert WPTgp.jpg -resize x310 WPT-keep-height.jpg
WPT-keep-height.jpg

WPT-keep-height.jpg

 identify -format "%W Pixel breit, %H Pixel hoch\n" WPT-keep-height.jpg

   237 Pixel breit, 310 Pixel hoch

14.3 Bild-Breite vorgeben

 convert WPTgp.jpg -resize 290x WPT-keep-width.jpg
WPT-keep-width.jpg

WPT-keep-width.jpg

 identify -format "%W Pixel breit, %H Pixel hoch\n" WPT-keep-width.jpg

   290 Pixel breit, 380 Pixel hoch

14.4 Beide Maße erzwingen und Bild damit verzerren

 convert WPTgp.jpg -resize 290x310\! WPT-distorted.jpg
WPT-distorted.jpg

WPT-distorted.jpg

 identify -format "%W Pixel breit, %H Pixel hoch\n" WPT-distorted.jpg

  290 Pixel breit, 310 Pixel hoch

14.5 “Padding”

 convert WPTgp.jpg \
   -resize 290x310 \
   -gravity center \
   -background orange \
   -extent 290x310 \
    WPT-padded.jpg
WPT-padded.jpg

WPT-padded.jpg

 identify -format "%W Pixel breit, %H Pixel hoch\n" WPT-padded.jpg

   290 Pixel breit, 310 Pixel hoch

14.6 “Seam Carving” oder “Liquid Rescaling”

Wer die “Seam Carving”-Methode nicht kennt, sollte sich mal per Suchmaschine über diese Technologie erkundigen. Und da z.B. auf den folgenden Link stoßen:

Aber auf einmal (d.h. in einem einzigen Schritt) geht’s leider nicht! Dann geht’s schief, weil das Bild ja in zwei Dimensionen verändert werden soll, sowohl Breite, als auch Höhe:

 convert WPTgp.jpg -liquid-rescale 290x310\! WPT-liquid-gone-wrong.jpg
WPT-liquid-gone-wrong.jpg

WPT-liquid-gone-wrong.jpg

 identify -format "%W Pixel breit, %H Pixel hoch\n" WPT-liquid-gone-wrong.jpg

   290 Pixel breit, 310 Pixel hoch

Aber in 2 Schritten funktioniert’s:

 convert WPTgp.jpg -liquid-rescale 599x640\! -scale 290x310 WPT-liquid-1.jpg
 convert WPTgp.jpg -liquid-rescale 599x640\! -scale 48.4%   WPT-liquid-2.jpg
WPT-liquid-1.jpg

WPT-liquid-1.jpg

 identify -format "%W Pixel breit, %H Pixel hoch\n" WPT-liquid-{1,2}.jpg

   290 Pixel breit, 310 Pixel hoch
   290 Pixel breit, 310 Pixel hoch

Die Zeit ist jetzt leider um…


15 Mehr Info

15.1 Hinweise zu dieser HTML-Seite: