bradcathey has asked for the wisdom of the Perl Monks concerning the following question:

Is there anyway to make thumbnails on the fly from full-size jpgs (either while uploading images or from those already on the server) without Image::Magick? My host does not support IM and tells me others that have installed it have gotten unreliable results.

Replies are listed 'Best First'.
Re: Making jpg thumbnails
by CombatSquirrel (Hermit) on Aug 26, 2003 at 14:30 UTC
    I fiddled a bit around with GD and came up with the following code (it is untested, since ActiveState does not have GD):
    #!perl use strict; use warnings; use GD; my $filename = '/path/to/img/img.jpg'; my $outfilename = '/path/to/img/thumb/img.jpg'; my $image = new GD::Image $filename or die "Could not open '$filename' +: $!\n"; my ($width, $height) = $image->getBounds; my ($newwidth, $newheight); if (($width > 300) || ($height > 300)) { if ($width > $height) { ($newwidth, $newheight) = (300, int((300 * $height) / $width)); } else { ($newwidth, $newheight) = (int((300 * $width) / $height), 300); } } else { ($newwidth, $newheight) = ($width, $height); } my $newimg = $image->copyResized( $image, # source image 0, 0, # destination position 0, 0, # original position $newwidth, $newheight, $width, $height ); $newimg->(); open OUTFILE, '>', $outfilename or die "Failed to open '$outfilename' +for output: $!\n"; print OUTFILE $newimg->jpeg; close OUTFILE;
    I hope it works and suits your needs.
    Cheers, CombatSquirrel.

    Update: For files not supplied by ActiveState, have a look at PPM::Repositories, thanks to PodMaster.
    Entropy is the tendency of everything going to hell.
      When the constructor new doesn't work, you might want to try something like
      my $image = newFromJpeg GD::Image( $filename );
      (I know I had problems when trying to use new, but probably I was just too dumb.)

      daniel.
      Many thanks to CombatSquirrel for getting me on the right path. Got it to work with the following edits, just in case anybody else stumbles across this thread and wants to try it:
      #!perl use strict; use warnings; use GD; my $filename = '/path/to/img/img.jpg'; my $outfilename = '/path/to/img/thumb/img.jpg'; my $image = new GD::Image->newFromJpeg($filename); #edited my ($width, $height) = $image->getBounds; my ($newwidth, $newheight); if (($width > 300) || ($height > 300)) { if ($width > $height) { ($newwidth, $newheight) = (150, int((150 * $height) / $width)); } else { ($newwidth, $newheight) = (int((150 * $width) / $height), 150); } } else { ($newwidth, $newheight) = ($width, $height); } my $newimg = new GD::Image($newwidth, $newheight); #edited $newimg->copyResized( $image, # source image 0, 0, # destination position 0, 0, # original position $newwidth, $newheight, $width, $height ); open (OUTFILE, ">$outfilename") or die "Failed to open '$outfilename' +for output: $!\n"; binmode(OUTFILE); #edited print OUTFILE $newimg->jpeg(100); #edited close OUTFILE;
      bradcathey
Re: Making jpg thumbnails
by RMGir (Prior) on Aug 26, 2003 at 14:19 UTC
    A similar question has been asked here before, although "no IM" makes it a bit more interesting.

    Check out Super Search, and you'll probably find interesting results.

    If that fails, merlyn has a written column about that... (Anyone else think that "merlyn wrote a column about that" nodes should be auto-generated for SOPW? :) )
    --
    Mike

Re: Making jpg thumbnails
by duct_tape (Hermit) on Aug 26, 2003 at 19:54 UTC

    Perhaps use the Imager module since you can not use Image::Magick. It doesn't look like anyone else has recommended that yet.

    Here is some sample code for resizing a JPEG with Imager.

    #!/usr/bin/perl -w use Imager; use strict; my $file = "something.jpg"; my $thumb_file = "something_thumb.jpg"; my $image = Imager->new() or die "Can't create Imager object"; $image->open(file => $file) or die $image->errstr; # You could also pass qtype => 'preview' to scale() to # supposedly make a smaller thumbnail (filesize wise) my $thumbnail = $image->scale(ypixels => 100) or die $image->errstr; # You could pass fd => fileno(STDOUT), instead of the file # parameter if you need to print to STDOUT. If you do so # make sure to binmode STDOUT, and disable buffering ($|++) $thumbnail->write(file => $thumb_file, type => 'jpeg') or die $thumbnail->errstr;

    Also, as other people have said, if you need to generate the thumbnails on the fly, at least do some caching of them. Check if a thumbnail exists and perhaps even compare the timestamps of the thumbnail and the actual image so that you only have to generate the thumbnail when it is absolutely necessary.

    When I was originally playing around with Imager I found it to be a bit slower than Image::Magick. Unfortunately I do not have any benchmarks... but it is something to keep in mind.

    Hope that helps. Good luck with your application.

Re: Making jpg thumbnails
by wirrwarr (Monk) on Aug 26, 2003 at 14:19 UTC
    Can you use GD, then? It has the method copyResized() which can scale an image. But you have to do the size calculations yourself.

    daniel.
Re: Making jpg thumbnails
by DrHyde (Prior) on Aug 26, 2003 at 15:22 UTC
    Making thumbnails on the fly is generally a bad idea, make them once and cache 'em. I don't use perl for making mine. I use a shell script and djpeg/cjpeg. This only allows me to scale images by 1/2, 1/4 or 1/8, but that's good enough for me.
      DrHyde: I agree with the "on the fly," that wasn't my real intent. However, can you tell me more about "shell script and djpeg/cjpeg?" Do you have any code you can send along. 1/8 would be perfect. The simpler the better. Thanks Brad
        From memory this will work to product thumbnails for all the .jpgs in the current directory:

        for i in *.jpg; do djpeg -dct float -scale 1/8 $i | cjpeg -dct float>$i.thumb.jpg; done

        djpeg and cjpeg are distributed with the JPEG group's libjpeg.

Re: Making jpg thumbnails
by skyknight (Hermit) on Aug 26, 2003 at 15:14 UTC

    Regardless of the solution on which you ultimately settle, you may want to avoid churning out thumbnails on the fly every time they are requested if you are in a heavy load environment. This could be as simple as reading in the timestamps on the original image and the corresponding thumbnail, checking to see whether the thumbnail is "fresh", and updating accordingly. This won't be a big deal to you if you've got CPU and disk access to burn, but if these resources are a potential bottleneck for your services, then you should definitely do this, assuming that disk space isn't something of which you are apt to be in short supply.

Re: Making jpg thumbnails
by glwtta (Hermit) on Aug 26, 2003 at 22:04 UTC
    A great alternative to IM and GD is Imager - it's much, much nicer for resizing than GD (can't speak for IM since I've never actually gotten the library to install).

    Two problems with it - one, it doesn't seem to be maintained anymore (anyone have any info on this?);

    and two, it seems (at least to me, maybe I am missing something?) that you can't scale the axes independently, in other words, it will always constraing the proportions for your thumbnails (I've been using it for over a year before I came across this limitation, but when I did, I couldn't get around it in Imager and had to use something else).

Re: Making jpg thumbnails
by CombatSquirrel (Hermit) on Aug 28, 2003 at 09:08 UTC
    I just found it now, but there is actually a module called Image::GD::Thumbnail on CPAN. Example code from the docs:
    use GD; use Image::GD::Thumbnail; # Load your source image open IN, 'E:/Images/test.jpg' or die "Could not open."; my $srcImage = GD::Image->newFromJpeg(*IN); close IN; # Create the thumbnail from it, where the biggest side is 50 px my ($thumb,$x,$y) = Image::GD::Thumbnail::create($srcImage,50); # Save your thumbnail open OUT, ">E:/Images/thumb_test.jpg" or die "Could not save "; binmode OUT; print OUT $thumb->jpeg; close OUT;
    Hope this helped.
    CombatSquirrel.
    Entropy is the tendency of everything going to hell.
A reply falls below the community's threshold of quality. You may see it by logging in.