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

Dear Monks,

I'm trying to use Imager to scale an Image, which I get from a Catalyst upload request. Then I want to store the original image, an image of medium quality and a thumbnail via DBIx::Class::InflateColumn::Fs on the Filesystem.

The following code works perfect (just storing the original image without using Imager):

my $fh = $c->req->upload('original')->fh; $self->form->item->original($fh); $self->form->item->update; # The DBIx::Class row object comes from FormHandler, # but thats not important here

Now I try to use Imager to get my thumbnail and medium image. This is probably pretty naive:

my $fh = $c->req->upload('original')->fh; binmode $fh; my $img = Imager->new(fh => $fh) or die "Cannot read $fh ", $img->errstr; my $medium = $img->scale(xpixels => 640, ypixels => 640, type => 'min' +); my $thumb = $img->scale(xpixels => 200, ypixels => 200, type => 'min') +; $self->form->item->medium_pfad($medium); $self->form->item->thumb_pfad($thumb); $self->form->item->original($fh); $self->form->item->update;

Everything seems to go fine, but the generated images are corrupted, even the original. I've tried numerous variants...

The only way I could get this to work was writing the files to disk first an reading them in again:

$img->write(file => 'a.jpg'); $medium->write(file => 'b.jpg'); $thumb->write(file => 'c.jpg'); $fho = new IO::File "> a.jpg"; $fhm = new IO::File "> b.jpg"; $fht = new IO::File "> c.jpg"; # Then use these filehandles...

But this is obviously stupid. I'm sure that I just don't understand how filehandles work in Perl. Any help would be greatly appreciated.

Replies are listed 'Best First'.
Re: Imager - Problem with Filehandle (Catalyst, DBIx::Class::InflateColumn::FS)
by tonyc (Friar) on Oct 21, 2009 at 00:44 UTC

    For medium_pfad and thumb_pfad you appear to be supplying Imager objects to something expecting file handles. That can't work.

    For the original file, when you read the file via a fh into an Imager image, Imager will read to the end of the image, so unless you seek back to the beginning, only the remnant of the file will be copied (usually nothing) to the file referenced by original.

    Fixing this for original is simple enough, just seek back to the beginning of the file.

    For medium_pfad and thumb_pfad you could write the images to scalars ($im->write(data => \$data, ...)) and open those using open my $fh, \$data to provide a file handle to D::C::IC:FS)

    # something like this my $medium_data; # write to an in-memory file requires a file format $medium->write(type => "png", data => \$data) or die; open my $medium_fh, "<", \$data or die; $self->form->item->medium_pfad($medium_fh);

      Thank you very much for your help.
      I was able to fix the problem as far as the original file is concerned.
      Neverthless, this doesn't work for me:

      my $data; $thumb->write( type => 'png', data => \$data ) or die; open my $thumb_fh, "<", \$data or die; $self->form->item->thumb_pfad($thumb_fh);

      The resulting file is still corrupted

        Finally I got this to work using IO::String:

        my $data; $thumb->write( type => 'png', data => \$data ) or die; my $thumb_fh = IO::String->new( \$data ) or die; $self->form->item->thumb_pfad($thumb_fh);

        Thanks again for your help


        KvW