Wie klassifiziere ich Bilder mit ImageMagick? identify -verbose?
Name
imid.pl
Aufgabe
(English summary below) Beispiel, wie sich
ImageMagicks? "identify" mit der "-verbose"-Option
aus Perl aufrufen und die Ausgabe auswerten laesst. Das Skript versucht Bilddateien
nach folgenden Kriterien zu klassifizieren:
- Farbtyp (Palette oder linear)
- Farbmodell (Gray, RGB, CMYK)
- Transparenz (wenn ja: Tiefe des Alphakanals in Bits)
- Animated (ja, nein)
- Zahl der Farben: wenn Palette, absolute Zahl; wenn linear, Tiefe in Bits (z.B. 24 oder 32)
Ich finde zwei Elemente des -verbose-Protokolls widerspruechlich:
- Bilder koennen gleichzeitig als "Class: DirectClass?" und "Type: Palette" markiert werden. Ersteres steht ja fuer "lineare Farben", zweiteres fuer eine Palette à la GIF.
- Bilder koennen als "Typ ohne Matte" markiert sein, aber trotzdem einen Alphakanal haben. Aber Transparenz erfordert doch eine Matte -- oder???
Das Skript versucht, diese Widersprueche aufzuloesen. Fuer Rueckmeldungen waer ich dankbar!
(English speakers: A script demonstrating the extraction of image data from
ImageMagick?'s
identify -verbose. You'll find a short version of the above discussion at the head of the
script.)
Aufruf mit Parametern
perl ./imid.pl # will process all images in the current directory
Skript
#!/usr/bin/perl
# Experimental Perlscript to classify Images, using "identify -verbose",
# into
# - animated vs. still
# - palette vs. linear colours
# - gray vs. rgb vs. cmyk
# - # of colors per palette or total colour resoution in bits
# - opaque vs. transparent (plus # of transparency bits)
#
# Usage:
# Call from any image directory without arguments, will analyze all images
# in the directory and report to STDOUT.
# Will not write or alter files.
#
# johannes 10/2006
# get list of image files and loop over it
@images = grep /\.(png|gif|jpg|tif|bmp|psd|xcf)/,`ls ./*`;
foreach (@images) {
chomp;
@id = identify($_); # identify -verbose $_
%img = classify($_,@id);
pretty(%img);
}
1;
sub pretty {
my %img = @_;
print substr($img{'name'}."--------------------------------------------------",0,50),"\n";
print "Animated: $img{animated} Type: $img{type} Transparency, bits: $img{transparent}\n";
print "Color model: $img{model} Color depth, ".($img{type} eq 'linear'?'bits':'size').": $img{colors}\n";
print "\n";
}
sub classify {
my ($filename,@id) = @_;
my %res;
$res{'name'} = $filename;
# parse id output and gather necessary data
my $tagclass;
my $tagtype;
my %channels;
my $tagcolors;
my $i; my $state=''; for ($i=1; exists($id[$i]); $i++) {
# lines preceding Image: tag
# animated gifs have more than one lines preceding the "Image:" line
if ($state eq '') {
if ($id[$i] =~ /^Image:/) {
$res{'animated'} = '';
$state = 'waitChannels';
}
else {
$res{'animated'} += 1; # every line is one frame of a movie
}
}
else { # states waitChannels, inChannels, waitEnd
# color depth per channel: look for it immediately after "Channel depth: " line
if ($state eq 'inChannels') {
if ($id[$i] =~ /^\s*(Gray|Red|Green|Blue|Cyan|Magenta|Yellow|Black|Alpha): (\d+)/i) {
$channels{lc($1)} = $2;
next;
}
else {
$state = 'waitEnd';
}
}
# image format: any string composed of non-blanks and non-brackets
# (typically, the line looks line "Format: PNG (Portable Network Graphics)")
if ($id[$i] =~ /^\s*Format: ([^ (]+)/) { $res{'format'} = $1 }
elsif ($id[$i] =~ /^\s*Geometry: (\d+)x(\d+)/) { $res{'width'} = $1; $res{'height'} = $2; }
elsif ($id[$i] =~ /^\s*Class: /) { $tagclass = $' }
elsif ($id[$i] =~ /^\s*Type: /) { $tagtype = $' }
elsif ($id[$i] =~ /^\s*Colors: /) { $tagcolors = $' }
elsif ($state eq 'waitChannels') {
($id[$i] =~ /^\s*Channel depth:/) && ($state = 'inChannels');
}
elsif ($state eq 'waitEnd') {
($id[$i] =~ /^Image: /) and last;
}
}
}
# the color model is taken from the following, mutually dependent attributes:
#
# Attribute Name Possible Values Meaning
# -------------- --------------- -------
# Class: PseudoClass Image has a color palette
# DirectClass Linear colors, no color palette*
# Type: Grayscale No transparency, usually 8 bits
# GrayscaleMatte Has transparency, usually 8 bits
# TrueColor May have transparency
# TrueColorMatte May have transparency
# Palette May be 24Bt (seen with BMP, TIF) or gray
# PaletteMatte
# ColorSeparation CMYK, no transparency???
# *For DirectClass Images. "Channel depth" has valid info on # of channels, transparency
#
# Colorspace: (ignore) (look at channels instead)
# Channel depth:
# Gray: 1-bits, 8-bits, 16-bits (for linear images, add channel
# Red: depths to get the total colour
# Green: resolution, i.e., 8, 24 or 32 bits.
# Blue:
# Cyan:
# Magenta: For linear color images, the
# Yellow: Alpha: depth seems to be the only
# Black: secure indicator for presence
# Alpha: or absence of transparency.)
#
# Colors: Any # of colors for palette images
if ($tagclass =~ /Pseudo/) {
$res{'type'} = 'palette';
# gray / rgb? look at Channel hash, not Type: (Type: Palette may be gray)
($channels{'gray'}) && ($res{'model'} = 'gray') || ($res{'model'} = 'rgb');
($tagtype =~ /Matte/) && ($res{'transparent'} = 1) || ($res{'transparent'} = '');
$res{'colors'} = 'i'.$tagcolors;
}
else {
$res{'type'} = 'linear';
if ($channels{'gray'}) {
$res{'model'} = 'gray';
$res{'colors'} = $channels{'gray'};
}
elsif ($channels{'cyan'} or $channels{'magenta'} or
$channels{'yellow'} or $channels{'black'}) {
$res{'model'} = 'cmyk';
$res{'colors'} = $channels{'cyan'}+$channels{'magenta'}+
$channels{'yellow'}+$channels{'black'};
}
else { # default: rgb
$res{'model'} = 'rgb';
$res{'colors'} = $channels{'red'}+$channels{'green'}+$channels{'blue'};
}
$res{'transparent'} = ($channels{'alpha'}>0?$channels{'alpha'}:'');
}
return %res;
}
sub identify {
my $imgname = shift;
# call imagemagick identify with verbose option , return its result
return `identify -verbose $imgname`;
# for testing, i used precalculated identify protocols
# open INF,"<$imgname";
# my @id = <INF>;
# close INF;
# return @id;
}
Ergänzungen, Kommentare
Kommentare werden am besten in folgender Form vorgenommen, damit
sie im Inhaltsverzeichnis angezeigt werden (natürlich ohne das <verbatim>):
---### Main.??? - 14 Jul 2003 - Betreff