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

I seem to be having a problem with Image::Magick in Mason. The following code works great at a CGI script:

#!/usr/bin/perl use strict; use Image::Magick; $| = 1; my $image = Image::Magick->new; $image->Set (size => '500x750'); $image->Read ('xc:black'); print "Content-Type: image/png\n\n"; binmode STDOUT; $image->Write ('png:-'); exit 0;

Notice that I'm turning off buffering ($| = 1) and using the Write() routine to go to STDOUT.

Now, when I do this in Mason:

<%perl> use Image::Magick; $| = 1; my $image = Image::Magick->new; $image->Set (size => '500 x 750'); $image->Read ('xc:black'); $m->clear_buffer; $r->content_type ('image/png'); $image->Write ('png:-'); $m->abort; </%perl>

I get nothing sent to the browser but the header. I'm assuming that the Write() that Image::Magick is using is somehow bypassing the Mason mechanisms here. I've tried sprinkling $m->flush_buffer around too, but to no effect.

How is Mason handling STDOUT and how is Image::Magick? I'd like to see if I could get Mason working with it. Otherwise, I should be able to create a temporary .PNG and then feed it out to STDOUT manually (although I've yet to be successful creating a .PNG from Mason using Image::Magick either). But I assume that's some sort of file security problem.

THANKS for any and all hints and tips that you can provide. I know we're all very busy so it's TRULY appreciated!

Replies are listed 'Best First'.
Re: Image::Magick in Mason and STDOUT
by Anonymous Monk on Feb 02, 2011 at 08:22 UTC
Re: Image::Magick in Mason and STDOUT
by nif (Sexton) on Feb 02, 2011 at 20:14 UTC

    You are right with your guess that instead of writing to the "STDOUT" of the Mason component, your $image->Write('png:-') call writes the image somewhere else.

    I suppose that this is a mod_perl limitation. Are you running Mason under mod_perl?
    In a terminal program or with CGI both commands "print $header_templ" and "system('cat /my/templates/header.html')" will write to the same "STDOUT", but under mod_perl this is not so.

    You have two options

    1. Use Mason handler as CGI Script, in this case the following code works
      <%flags> inherit => undef </%flags> <%init> use Image::Magick; my $image = Image::Magick->new; $image->Set(size => '500 x 750'); $image->Read('xc:black'); STDOUT->autoflush(1); $r->content_type('image/png'); $r->send_http_header; $image->Write("png:-"); </%init>
    2. Unfortunately Image::Magick can't write to scalar or filehandle. So let Image::Magick to write the image to some tempfile, then open this tempfile again, read it into a scalar and print to STDOUT, or use the "$r->sendfile" method from mod_perl like this.
      <%flags> inherit => undef </%flags> <%init> use Image::Magick; use File::Temp; my $image = Image::Magick->new; $image->Set(size => '500 x 750'); $image->Read('xc:green'); my $temp = File::Temp->new( DIR => '/tmp', UNLINK => 1); my $temp_file_name = $temp->filename; $image->Write("png:$temp_file_name"); $r->content_type('image/png'); $r->sendfile($temp_file_name); # File::Slurp and print could be used instead of $r->sendfile # #use File::Slurp; #print read_file($temp_file_name); </%init>

      Thanks very much for all the replies! Yes, I am using mod_perl and so it looks like in my case using a temporary file is the best approach. I just needed confirmation that I wasn't missing something.

      Thanks also for pointing me to "sendfile()". Somehow I had not seen that before. On a previous web site I read the file chunk by chunk and wrote it out manually in a loop. sendfile() or Slurp looks much easier. These files are only small images so no need to do anything else. On the other site I did, they were downloading files that could be over 100MB!

      Thanks again...

Re: Image::Magick in Mason and STDOUT
by Anonymous Monk on Feb 02, 2011 at 08:05 UTC
    What is your handler?