Dashboard > Public Content > ... > Perl > A Simple Web Service To Resize Images
  Public Content Log In   View a printable version of the current page.  
  A Simple Web Service To Resize Images
Added by James Richardson, last edited by James Richardson on May 15, 2007  (view change)
Labels: 
(None)

What it does

I wanted a little stand alone web service that could resize, crop, and convert to black and white a library of images, on demand.

The requester will know the exact filename of the source image, but wanted the resultant image returned as the content of the http request, along with size information of the resized image.

I put together this, which seemed to work for what I wanted. Its not going to win any prizes for elegance, but it works quite reliably.

How to use

curl http://localhost:5300?file=/data/imagedata/A/M/A/B/3087&x=100&y=100&crop=1&filetype=TIFF'

Parameters

  • file Filename (as seen by the server!) of the image to scale
  • x Width of Required Image
  • y Height of Required Image
  • crop=1 Crop the image after resizing
  • bw=1 Convert image to greyscale
  • dull=n Reduce contrast of image n times
  • filetype=x Make output filetype x (see list at: http://www.imagemagick.org/script/formats.php)

If you don't specify one of x or y then the image will be resized keeping its proportions.

The crop parameter works by reducing the size of the image in proportion to either the width or the height, then crops the image along the other dimension. This allows for making square thumbnails from either portrait or landscape images. It crops from the top or left.

#!/usr/bin/perl

# resize.pl - (C) James Richardson 2001-2007 
# Licensed under the GPL v2 or your choice of a later version.
# If you use this / find it helpful please send me an email to let me know.

use HTTP::Daemon;
use HTTP::Response;
use HTTP::Headers;

use Image::Magick;

use FileHandle;

use Data::Dumper;

use strict;

my $FILTER = "Cubic";
my $BLUR = 0.125;

$SIG{CHLD} = sub { 
  my $pid = wait;
  print "Child $pid exited\n";
};

sub Log {
  print join(":", @_ );
  print "\n";
}

sub Info { Log ( "Info", @_ ); }

sub ratio {
    my ( $image ) = @_;

    my $currentx = $image->Get("width");
    my $currenty = $image->Get("height");
    my $ratio = $currenty / $currentx;

    Info ("Current file is $currentx x $currenty, Ratio = $ratio");

    return $ratio;
}

sub resize_without_crop {
    my ($image, $wantedx, $wantedy) = @_;

    my $ratio = ratio($image);

    if ( $wantedx && $wantedy ) {

    }
    elsif ( $wantedx ) {
	$wantedy = $wantedx * $ratio;
    }
    elsif ( $wantedy ) {
	$wantedx = $wantedy / $ratio;
    }

    $image->Resize(filter=>$FILTER, blur=>$BLUR, width=>$wantedx, height=>$wantedy);
}

sub resize_with_crop {
    my ( $image, $wantedx, $wantedy ) = @_;

    if ( ! ( $wantedx && $wantedy )) {
	die "Need both x and y sizes for cropping";
    }

    my $ratio = ratio($image);

    if ( $ratio >= 1 ) {
	# Portrait (or square) Image
	# Resize using the given width and then crop to the height
	resize_without_crop($image, $wantedx, undef);
    }
    else {
	# Landscape Image
	resize_without_crop($image, undef, $wantedy);
    }

    $image->Crop(width=>$wantedx, height=>$wantedy, x=>0, y=>0);
}
 
sub resize {
  my ( $filename, $filetype, $wantedx, $wantedy, $allowcrop, $tobw, $dull ) = @_;

  my $quality = 95;

  my $image = Image::Magick->new();

  $image->Read(filename=>$filename);


  if ( $allowcrop ) {
      resize_with_crop($image, $wantedx, $wantedy);
  }
  else {
      resize_without_crop($image, $wantedx, $wantedy);
  }

  if ( $tobw ) {
      Info("Converting to B/W");
      $image->Set(colorspace=>"gray");
      $image->Quantize();
  }

  if ( $dull ) {
      for ( my $i = 0 ; $i < $dull ; $i++ ) {
	  Info("Dulling");
	  $image->Contrast(sharpen=>"False");
      }
  }

  my $outputx = $image->Get("width");
  my $outputy = $image->Get("height");

  $image->Set(quality=>$quality);

  Info ( "Returned image is: Width = $outputx, Height = $outputy, Format = $filetype" );
  
  my @bytes = $image->ImageToBlob(magick=>$filetype);

  my $buffer = $bytes[0];

  return $outputx, $outputy, $buffer;

}

#################################################################
#
# Main Program
# 
#################################################################

my $listenport = 5300;

my $daemon = HTTP::Daemon->new ( LocalPort => $listenport, Reuse=>1 );

if ( !defined ( $daemon ) ) {
  Info ( "Can't listen on listenport $listenport: $!" );
  exit;
}

Info ( "Listening on port $listenport" );

while ( 1 ) {

  while ( my $client = $daemon->accept() ) {

    my $pid = fork();

    if ( $pid == 0 ) {
      # This is the client

      my $request = $client->get_request();

      my $uri = $request->uri();

      my %q = $uri->query_form();

      my $file = $q{file};
      my $x = $q{x};
      my $y = $q{y};
      my $filetype = $q{filetype};
      my $crop = exists $q{crop} ? 1 : 0;
      my $bw = exists $q{bw} ? 1 : 0;
      my $dull = $q{dull};
      
      Info ( "File is $file, $filetype, X=$x,Y=$y, Crop=$crop, B/W=$bw" );

      my ( $width, $height, $image ) = resize ( $file, $filetype, $x, $y, $crop, $bw, $dull );

      if ( defined ( $image ) ) {
	my $header = new HTTP::Headers ( "Content-Type" => "image/jpeg",
				       "X-Image-Width" => $width,
				       "X-Image-Height" => $height );
					 
	$client->send_response ( new HTTP::Response ( 200, "OK", $header, $image ) );

	exit;
      }
    }
    elsif ( $pid > 0 ) {
      # This is the parent
    }
    else {
      print "fork() failed $!\n";
    }
  }
}
Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.5.1 Build:#806 May 06, 2007) - Bug/feature request - Contact Administrators