perlmagick and image size

R

rossz

I've been trying to use the perlmagick module to do the following, but
haven't been having much luck.

I need to adjust an image to a minimum size, but without distoring it,
so I basically want to add space evenly around the existing image.
Using Resize is out since that will distort the image, so I gave
"Composite" a shot, though there doesn't seem to much in the way of docs
for this. My attempt results in this error message:

"Exception 410: reference is not my type `Image::Magick' at ./img.pl
line 23."

That's the "Composite" line.

Any suggestions on how to get this done would be appreciated. I have a
few thousand images I need to process so I would rather avoid doing this
manually. Useless and broken code follows (simplified). Both
ImageMagick and PerlMagick are the latest (afaik).

#!/usr/bin/perl


use Image::Magick;

$img = new Image::Magick;

$img->Read('test1.jpg');
($width,$height) = $img->Get('width','height');

$w = 100; # minimum sizes
$h = 100;

$w = $width if $w < $width; # if the axis is larger than the minimum,
leave it as is
$h = $height if $h < $height;

$x = int(($w-$width)/2); # position adjustment to keep it centered
$y = int(($h-$height)/2);

$geometry = $w."x".$h; # e.g "100x100"
$new = new Image::Magick(size=>$geometry);
$new->ReadImage('xc:white');
$z = $new->Composite(image=>$p, compose=>atop, gravity=>"SouthEast",
x=>$x, y=>$y);
print "$z\n" if "$z";
$new->Write('x.jpg'); # never gets this far
 
G

gnari

[ problem resizing image to fixed size without distortion]
"Exception 410: reference is not my type `Image::Magick' at ./img.pl
line 23."

[ snip code ]
$z = $new->Composite(image=>$p, compose=>atop, gravity=>"SouthEast",
x=>$x, y=>$y);

what is this image=>$p ?
should there not be $img there ?

also, you still need to resize the image.

you should:
a) determine needed scaling factor
$sf=$min/max($width,$height);
b) resize image to $width*$sf,$height*$sf
c) create blank image size $min,$min
d) calculate offsets, as you did
e) paint resized image into new image at
appropriate offsets. (can't be bothered
to look at the docs to see if Composite()
is the correct method, but it sounds familiar)

gnari
 
R

Rossz

gnari said:
[ problem resizing image to fixed size without distortion]

"Exception 410: reference is not my type `Image::Magick' at ./img.pl
line 23."


[ snip code ]
$z = $new->Composite(image=>$p, compose=>atop, gravity=>"SouthEast",
x=>$x, y=>$y);


what is this image=>$p ?
should there not be $img there ?

Oops, that should have been:

$z = $new->Composite(image=>$img, compose=>atop, gravity=>"SouthEast",
x=>$x, y=>$y);

The (limited) docs say it should be the image handle.

I'll see what I can do with your suggestions.
 
R

Rossz

gnari said:
[ problem resizing image to fixed size without distortion]

"Exception 410: reference is not my type `Image::Magick' at ./img.pl
line 23."


[ snip code ]
$z = $new->Composite(image=>$p, compose=>atop, gravity=>"SouthEast",
x=>$x, y=>$y);


what is this image=>$p ?
should there not be $img there ?

also, you still need to resize the image.

you should:
a) determine needed scaling factor
$sf=$min/max($width,$height);
b) resize image to $width*$sf,$height*$sf
c) create blank image size $min,$min
d) calculate offsets, as you did
e) paint resized image into new image at
appropriate offsets. (can't be bothered
to look at the docs to see if Composite()
is the correct method, but it sounds familiar)

The error message has gone away, but the image is distored, so I guess
I'm not handling the resize and scaling properly. Is resizing necessary
since I'm going to copy the image onto another, anyway?

Also, the "gravity" doesn't seem to be working, either. The image is
stuck at 0x0 instead of the offset. Am I misunderstanding the purpose
of gravity?

Here's the situation. Images tend to be ABOUT 100x100, but some are
less and some are more. If the image is <100 on an axis, increase the
axis size to 100. If it is more than 100, leave ias is. All without
modifying the actual image (we're just adding padding). So a 75x75
becomes 100x100. A 50x150 becomes 100x150, etc.

I've searched everywhere for some kind of howto on perlmagick, but what
I've found has been of very limited use.

I don't really understand your use of the scaling factor. Where do you
get $min, and why are we choosing the larger of $width and $height?

Sorry if I'm being dense.
 
G

gnari

Rossz said:
Never mind, I got it working. Thanks for your suggestions, it did the
job.

that's good, I didn't relish the thought of installing imagemagick
just for this.

gnari
 
M

Martien Verbruggen

I've been trying to use the perlmagick module to do the following, but
haven't been having much luck.

I need to adjust an image to a minimum size, but without distoring it,
so I basically want to add space evenly around the existing image.
Using Resize is out since that will distort the image, so I gave
"Composite" a shot, though there doesn't seem to much in the way of docs
for this. My attempt results in this error message:

"Exception 410: reference is not my type `Image::Magick' at ./img.pl
line 23."

That's the "Composite" line.

Any suggestions on how to get this done would be appreciated. I have a
few thousand images I need to process so I would rather avoid doing this
manually. Useless and broken code follows (simplified). Both
ImageMagick and PerlMagick are the latest (afaik).

#!/usr/bin/perl

You really, really need

use warnings;
use strict;

It would have caught your problem.
use Image::Magick;

$img = new Image::Magick;

$img->Read('test1.jpg');

You should store this somewhere, presumably in $p.
You should also check for errors.

[snip]
$z = $new->Composite(image=>$p, compose=>atop, gravity=>"SouthEast",
x=>$x, y=>$y);

Where did $p come from?

Try the following:


use Image::Magick;
use strict;
use warnings;

my $im = Image::Magick->new();
my $bg = Image::Magick->new(size => "200x400");

my $rc = $bg->Read("xc:white");

$rc = $im->Read($ARGV[0]);
die $rc if $rc;

$rc = $im->Resize("200x400");
warn $rc if $rc;

$rc = $bg->Composite(gravity => "Center", image => $im);
warn $rc if $rc;

$rc = $bg->Write("foo.png");
die $rc if $rc;

Martien
 
D

dan baker

rossz said:
I need to adjust an image to a minimum size, but without distoring it,
so I basically want to add space evenly around the existing image.
----------------------

a while back I wrote some tools to resize and build thumbnails for a
photo gallery site (http://www.NormsGallery.com) and I thought I'd
post the sub that does most of the image sizing for you to look at.
Its probably not the most glamorous way to do it, and perhaps Martin
will suggest some improvements. ;)

d
--------------

sub SizeAndThumb { my ( $FileNameIn ) = @_ ;

=head1 Purpose

This sub examines the current size of image passed in, and re-samples
so that it fits within the maximum allowable area defined by
$cMaxFullimgX , $cMaxFullimgY . If $cAnnotateText is defined, it will
also add the annotation.

Resampling is always done, even if the image is already the right
size
so that it get save with the right compression quality. Image might
have
been uploaded at higher quality with larger filesize.

Then, a thumbnail image is created with the name
$FileNameIn_$cMaxThumbimgX .

=head1 Input

$FileNameIn = relative path to a single image file to process

=head1 Output

- overwrites $FileNameIn, and creates a thumbnail image in the same
folders with a name based on $FileNameIn_$cMaxThumbimgX
- returns a 0 for success, or an error message string

=head1 Notes and Usage

# Note that subConfig.pl MUST be required in main:: because it uses
parameters:
#
( $cMaxFullimgX , $cMaxFullimgY ) = (600,400);
( $cMaxThumbimgX , $cMaxThumbimgY ) = (100,100);
$cImageQuality = 75 ; # value 10-90
$cAnnotateFont = '@Comic.ttf' ;
$cAnnotatePointsize = 11 ;
$cAnnotateText = '(c)2000 www.NormsGallery.com' ; # set undef to skip
annotation
$cLowSRCText = '(c)2000 www.NormsGallery.com' ; # set undef to image
label

$ErrorMsg = &SizeAndThumb( $FileNameIn ); # returns 0 for success,
# $ErrorMsg for failure

This sub does NOT die on error, but does return an error message, so
the calling script can decide to die or continue.

=head1 History
written 10/18/2000 - Dan Baker, dan_at_dtbakerprojects.com
revised 12/3/2000 - changed to use Scale() instead of Sample()
- recoded Annotate() section for light outline

=cut
# ------------------------------------------------------------------------------
# declarations

use lib "./lib/perl5/site_perl/5.005/i386-linux" ;
use Image::Magick;

# local var declarations

my $tempString = "";
my $ErrMsg = "";
my $DoSample = "true" ;

# ------------------------------------------------------------------------------
# -------------------------------- executable ---------------

# read $FileNameIn to new object
# -----
my $image = Image::Magick->new;
$ErrMsg = $image->Read( $FileNameIn ) ;

if ($ErrMsg ) {
return( "$ErrMsg : Image-Magick could not read $FileNameIn " );
} elsif ( $cDEBUG ) {
print DEBUG_LOG "read $FileNameIn into ImageMagick object. \n" ;
}

# re-size
# -----
$ErrMsg = $image->Scale( geometry=>"${cMaxFullimgX}x${cMaxFullimgY}"
);

if ($ErrMsg ) {
return( "$ErrMsg : Image-Magick could not re-size $FileNameIn " );
} elsif ( $cDEBUG ) {
print DEBUG_LOG "resized $FileNameIn to ${MaxFullimgX}x${MaxFullimgY}
\n" ;
}

# annotate if text is defined
# -----
my $DidAnnotate = 0;
if ( $cAnnotateText ) { # only annotate if a text string is defined

print DEBUG_LOG "\t attempting to annotate. \n" if $cDEBUG ;

# we cant trust gravity=>'South' or 'North
# so figure offset manually
# -----
# get actual scaled size
my ( $imgX , $imgY ) = $image->Get('columns', 'rows');
my ( $Xoffset , $Yoffset ) = (0 , 0) ;
my $AnnotateOutline = 'LightGrey' ;
my $AnnotatePen = 'Black' ;

# figure out $Xoffset
# -----
$Xoffset = int( $imgX/2 -
(length($cAnnotateText)*($cAnnotatePointsize/1.5))/2 ) ;

# set up for differences between v4.2.9 and 5.2.4
# -----
if ( $^O =~ m/mswin32/i ) { # calculations for v4.2.9 on win98
# use $cAnnotatePointsize from config file
$Yoffset = int($imgY*.90) ;

} else { # calculations for v5.2.4 on LINUX

$cAnnotatePointsize += 3 ; # has to be set bigger to match
$Yoffset = int($imgY*.93) ;
}

# insert 8 instances of annotation in outline positions and color,
# 1 pixel offset in all directions

$image->Annotate( text=>$cAnnotateText ,
font=> $cAnnotateFont ,
pointsize=> $cAnnotatePointsize ,
pen=> $AnnotateOutline ,
x=> $Xoffset -1 ,
y=> $Yoffset -1 ,
);

$image->Annotate( text=>$cAnnotateText ,
font=> $cAnnotateFont ,
pointsize=> $cAnnotatePointsize ,
pen=> $AnnotateOutline ,
x=> $Xoffset -1 ,
y=> $Yoffset ,
);

$image->Annotate( text=>$cAnnotateText ,
font=> $cAnnotateFont ,
pointsize=> $cAnnotatePointsize ,
pen=> $AnnotateOutline ,
x=> $Xoffset -1 ,
y=> $Yoffset +1 ,
);

$image->Annotate( text=>$cAnnotateText ,
font=> $cAnnotateFont ,
pointsize=> $cAnnotatePointsize ,
pen=> $AnnotateOutline ,
x=> $Xoffset ,
y=> $Yoffset +1 ,
);

$image->Annotate( text=>$cAnnotateText ,
font=> $cAnnotateFont ,
pointsize=> $cAnnotatePointsize ,
pen=> $AnnotateOutline ,
x=> $Xoffset +1 ,
y=> $Yoffset +1 ,
);

$image->Annotate( text=>$cAnnotateText ,
font=> $cAnnotateFont ,
pointsize=> $cAnnotatePointsize ,
pen=> $AnnotateOutline ,
x=> $Xoffset +1 ,
y=> $Yoffset +0 ,
);

$image->Annotate( text=>$cAnnotateText ,
font=> $cAnnotateFont ,
pointsize=> $cAnnotatePointsize ,
pen=> $AnnotateOutline ,
x=> $Xoffset +1 ,
y=> $Yoffset -1 ,
);

$image->Annotate( text=>$cAnnotateText ,
font=> $cAnnotateFont ,
pointsize=> $cAnnotatePointsize ,
pen=> $AnnotateOutline ,
x=> $Xoffset ,
y=> $Yoffset -1 ,
);

# insert annotation on top of outline

$ErrMsg =
$image->Annotate( text=>$cAnnotateText ,
font=> $cAnnotateFont ,
pointsize=> $cAnnotatePointsize ,
pen=> $AnnotatePen ,
x=> $Xoffset ,
y=> $Yoffset ,
);

if ( $ErrMsg ) {

$tempString = "\t $ErrMsg : Image-Magick failed to annotate
$FileNameIn \n" ;
print DEBUG_LOG $tempString if $cDEBUG ;
return( $tempString );
} else {
print DEBUG_LOG "\t ...annotated \n" if $cDEBUG ;
$DidAnnotate = 'true' ;
}
}

# save the sized image
# ------
if ( $DidAnnotate or $DoSample ) {
$ErrMsg = $image->Write( filename=>$FileNameIn ,
quality=>$cImageQuality );

if ( $ErrMsg ) {
return( "$ErrMsg : Image-Magick failed to overwrite ".
"$FileNameIn with resampled image" );
} elsif ( $cDEBUG ) {
print DEBUG_LOG "\t ...saved \n"
}
}

# re-sample for thumbnail
# -----
$ErrMsg = $image->Scale( geometry=>"${cMaxThumbimgX}x${cMaxThumbimgY}"
);

if ($ErrMsg ) {
return( "$ErrMsg : Image-Magick failed to resample $FileNameIn to ".
"thumbnail ${cMaxThumimgX}x${cMaxThumimgY} " ) ;
} elsif ( $cDEBUG ) { print DEBUG_LOG "\t thumbnailed ok... \n" }

# figure out name and write thumbnail image
# -----
my $FileNameThum = $FileNameIn ;
$FileNameThum =~ s/(.*)\.(.+)$/$1/ ; # grab base filename and
extension
$FileNameThum = "$1_$cMaxThumbimgX.$2" ; # insert the thumb X to
filename

$ErrMsg = $image->Write( filename=>$FileNameThum ,
quality=>$cImageQuality );

if ( $ErrMsg ) {
return( "$ErrMsg : Image-Magick failed to write $FileNameThum
thumbnail image" ) ;
} elsif ( $cDEBUG ) { print DEBUG_LOG "\t ...saved thumbnail to
$FileNameThum \n" }

undef $image; # release object memory

print DEBUG_LOG scalar(localtime).
"finished SizeAndThumb for $FileNameIn and $FileNameThum \n" if
$cDEBUG;

# ------------------------------------------------------------------------------
return (0) ; # return success, no error message
}
1 ; # done.....
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,228
Members
46,818
Latest member
SapanaCarpetStudio

Latest Threads

Top