Dave Cross: Still Munging Data With Perl: Online event - Mar 17 Learn more

# -----------------------------------------------------------------------------
=encoding utf8
=head1 NAME
Quiq::File::Image - Informationen über Bild-Datei
=head1 BASE CLASS
L<Quiq::Hash>
=cut
# -----------------------------------------------------------------------------
use base qw/Quiq::Hash/;
use v5.10;
use strict;
our $VERSION = '1.224';
use Encode ();
use Image::Size ();
# -----------------------------------------------------------------------------
=head1 METHODS
=head2 Konstruktor
=head3 new() - Instantiiere Bild-Datei-Objekt
=head4 Synopsis
$img = $class->new($path);
=head4 Description
Instantiiere ein Bild-Datei-Objekt und liefere eine Referenz auf
dieses Objekt zurück.
=cut
# -----------------------------------------------------------------------------
sub new {
my ($class,$path) = @_;
if (!-e Encode::encode('utf-8',$path)) {
$class->throw(
'IMAGE-00001: File not found',
Path => $path,
);
}
# Objekt instantiieren
return $class->SUPER::new(
# Eigenschaften
path => $path,
filename => undef,
basename => undef,
extension => undef,
width => undef,
height => undef,
created => undef,
type => undef,
# Properties
propertyH => Quiq::Hash->new->unlockKeys,
);
}
# -----------------------------------------------------------------------------
=head2 Eigenschaften
=head3 path() - Datei-Pfad
=head4 Synopsis
$path = $img->path;
=head4 Description
Liefere den Dateinamen einschl. Pfad der Bild-Datei.
=head3 filename() - Datei-Name ohne Verzeichnisanteil
=head4 Synopsis
$filename = $img->filename;
=head4 Description
Liefere den Dateinamen ohne Verzeichnisanteil, aber mit Extension,
z.B. '000456.jpg'.
=cut
# -----------------------------------------------------------------------------
sub filename {
my $self = shift;
return $self->memoize('filename',sub {
my ($self,$key) = @_;
$self->path =~ m|/([^/]+)$|;
return $1;
});
}
# -----------------------------------------------------------------------------
=head3 basename() - Datei-Name ohne Verzeichnis und Extension
=head4 Synopsis
$basename = $img->basename;
=head4 Description
Liefere den Dateinamen ohne Verzeichnis und Extension, z.B. '000456'.
=cut
# -----------------------------------------------------------------------------
sub basename {
my $self = shift;
return $self->memoize('basename',sub {
my ($self,$key) = @_;
$self->filename =~ m|([^.]+)|;
return $1;
});
}
# -----------------------------------------------------------------------------
=head3 extension() - Datei-Extension
=head4 Synopsis
$ext = $img->extension;
=head4 Description
Liefere die Extentsion der Datei, z.B. 'png'.
=cut
# -----------------------------------------------------------------------------
sub extension {
my $self = shift;
return $self->memoize('extension',sub {
my ($self,$key) = @_;
return Quiq::Path->extension($self->path);
});
}
# -----------------------------------------------------------------------------
=head3 mtime() - Letzte Änderung
=head4 Synopsis
$mtime = $img->mtime;
=head4 Description
Liefere den Zeitpunkt (Unix Epoch), an dem die Bilddatei
das letzte Mal geändert wurde.
=cut
# -----------------------------------------------------------------------------
sub mtime {
return (stat(shift->path))[9];
}
# -----------------------------------------------------------------------------
=head3 type() - Bild-Typ
=head4 Synopsis
$type = $img->type;
=head4 Description
Liefere den Datei-Typ des Bildes, z.B. 'jpg'.
=cut
# -----------------------------------------------------------------------------
sub type {
my $self = shift;
return $self->memoize('type',sub {
my ($self,$key) = @_;
my $type = Quiq::Image->type($self->path);
if ($type eq 'jpeg') {
$type = 'jpg';
}
return $type;
});
}
# -----------------------------------------------------------------------------
=head3 width() - Breite
=head4 Synopsis
$width = $img->width;
=head4 Description
Liefere die Breite des Bildes in Pixeln, z.B. 1920.
=cut
# -----------------------------------------------------------------------------
sub width {
my $self = shift;
return $self->memoize('width',sub {
my ($self,$key) = @_;
$self->analyzeFile;
return $self->get($key);
});
}
# -----------------------------------------------------------------------------
=head3 height() - Höhe
=head4 Synopsis
$height = $img->height;
=head4 Description
Liefere die Höhe des Bildes in Pixeln, z.B. 1080.
=cut
# -----------------------------------------------------------------------------
sub height {
my $self = shift;
return $self->memoize('height',sub {
my ($self,$key) = @_;
$self->analyzeFile;
return $self->get($key);
});
}
# -----------------------------------------------------------------------------
=head3 created() - Aufnahmezeitpunkt
=head4 Synopsis
$created = $img->created;
=head4 Description
Liefere den Aufnahmezeitpunkt des Bildes, z.B. '2024-11-11 22:22:06'.
=cut
# -----------------------------------------------------------------------------
sub created {
my $self = shift;
return $self->memoize('created',sub {
my ($self,$key) = @_;
$self->analyzeFile;
return $self->get($key);
});
}
# -----------------------------------------------------------------------------
=head3 size() - Breite und Höhe
=head4 Synopsis
$size = $img->size;
($width,$height) = $img->size;
=head4 Description
Liefere die Breite und Höhe des Bildes in Pixeln. Im Skalarkontext
werden die Breite und Höhe in einem String zusammengefasst geliefert:
'WIDTHxHEIGHT'
=head4 Examples
List-Kontext:
$img->size;
=>
(1920,1080)
Skalar-Kontext:
$img->size;
=>
'1920x1080'
=cut
# -----------------------------------------------------------------------------
sub size {
my $self = shift;
my $width = $self->width;
my $height = $self->height;
return wantarray? ($width,$height): $width.'x'.$height;
}
# -----------------------------------------------------------------------------
=head3 scaleFactor() - Skalierungsfaktor für andere Breite, Höhe
=head4 Synopsis
$scale = $img->scaleFactor($width,$height);
=head4 Description
Liefere den Skalierungsfaktor, wenn das Bild auf die Breite $width
und die Höhe $height skaliert werden soll. Werden nicht-proportionale
Werte für $width und $height angegeben, dass also für die Breite
und die Höhe unterschiedliche Skalierungsfakoren berechnet werden,
liefere von beiden den kleineren Wert.
=head4 Example
Das Bild hat die Größe 249 x 249 und soll skaliert werden auf
die Größe 83 x 83:
$scale = $img->scaleFactor(83,83);
# 0.333333333333333
=cut
# -----------------------------------------------------------------------------
sub scaleFactor {
my ($self,$width,$height) = @_;
return Quiq::Array->min([$width/$self->width,$height/$self->height]);
}
# -----------------------------------------------------------------------------
=head3 aspectRatio() - Seitenverhältnis
=head4 Synopsis
$aspectRatio = $img->aspectRatio;
=head4 Description
Liefere das Seitenverhältnis des Bildes, z.B. '16:9'.
=cut
# -----------------------------------------------------------------------------
sub aspectRatio {
my $self = shift;
return Quiq::Image->aspectRatio($self->width,$self->height);
}
# -----------------------------------------------------------------------------
=head2 Properties
=head3 property() - Liefere Property-Hash
=head4 Synopsis
$h = $img->property;
$h = $img->property(\%hash);
=head4 Description
Liefere eine Referenz auf den Property-Hash des Bildes. Der
Property-Hash speichert zusätzliche Eigenschaften des
Bild-Datei-Objektes, die z.B. im Zuge einer Bild-Bearbeitung
verwendet werden.
Der Property-Hash ist ein Quiq::Hash-Objekt, dessen Schlüssel
nicht gelockt sind. Nach der Objekt-Instantiierung ist der
Property-Hash leer.
=head4 Examples
Setze Eigenschaft:
$img->property->set(sizeFill=>[1440,1080]);
Eigenschaft abfragen:
($width,$height) = $img->property->getArray('sizeFill');
=cut
# -----------------------------------------------------------------------------
sub property {
my $self = shift;
# @_: \%hash
if (@_) {
return $self->{'propertyH'} = shift;
}
return $self->{'propertyH'};
}
# -----------------------------------------------------------------------------
=head2 Interne Methoden
=head3 analyzeFile() - Analysiere Bild-Datei
=head4 Synopsis
$img->analyzeFile;
=head4 Description
Analysiere die Bild-Datei und weise die ermittelten
Eigenschaften an die Attribute des Objektes zu.
=cut
# -----------------------------------------------------------------------------
our $xft = Image::ExifTool->new; # nur einmal instantiieren
sub analyzeFile {
my $self = shift;
if (!defined $self->get('width')) {
my ($width,$height) = Image::Size::imgsize($self->path);
$self->set(width=>$width);
$self->set(height=>$height);
my $h = $xft->ImageInfo($self->path);
my $created = $h->{'CreateDate'} || $h->{'DateTimeOriginal'} || '';
if ($created) {
my @arr = split /[^\d]+/,$created;
$created = sprintf '%04d-%02d-%02d %02d:%02d:%02d',@arr;
}
$self->set(created=>$created);
}
return;
}
# -----------------------------------------------------------------------------
=head1 VERSION
1.224
=head1 AUTHOR
Frank Seitz, L<http://fseitz.de/>
=head1 COPYRIGHT
Copyright (C) 2025 Frank Seitz
=head1 LICENSE
This code is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
=cut
# -----------------------------------------------------------------------------
1;
# eof