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


A friend and I are struggling to get this little segment of code to work. Basically all we are doing is generating some graphics on the fly from a MySQL database and displaying them on a webpage.

The problem is that this section of code does NOT display the generated image - but if we set the img src to a previously generated image it will happily display that.

The image itself is generated fine - but why can't we get the new one to display?

if(param("submit")) { $start=param("start"); $finish=param("finish"); if(!defined($child_pid=fork())) { die "cannot fork $!"; } elsif($child_pid==0) { my $query= "/usr/apache/cgi-bin/order/ldasdump.pl -png + -d dicty chr5.1:$s tart,$finish --user xxxx --pass xxxxxxxxx > /usr/apache/htdocs/nob24.p +ng"; exec($query); } else { waitpid($child_pid,0); print img({src=>"../../nob24.png",align=>'LEFT'});

Bukowski - aka Dan (dcs@black.hole-in-the.net)
"Coffee for the mind, Pizza for the body, Sushi for the soul" -Userfriendly

Replies are listed 'Best First'.
Re: Images built on the fly do not display
by FamousLongAgo (Friar) on Jan 07, 2003 at 17:41 UTC
    I had a similar problem with a script to generate a JPEG image on the fly, and eventually realized that I was failing to provide the right HTTP header. Have you made sure to print an appropriate content-type header in your script?

Re: Images built on the fly do not display
by dws (Chancellor) on Jan 07, 2003 at 18:26 UTC
    FamousLongAgo touches on the problem: unless you let the browser know the MIME type of the server's response ("image/png" in this case), it won't know what to display.

    Scanning over your snippet, the other thing that jumped out is that you're using the single-argument form of exec(), which has a hidden performance penalty. (See perlfunc, and read carefully.)

    But do you really need a fork()/exec() here? Wouldn't using system() give you the same effect with less hassle? Note, though, that system() has the same hidden overhead as exec() when called with a single argument.

Re: Images built on the fly do not display
by nedals (Deacon) on Jan 07, 2003 at 20:04 UTC
    This may be your problem. Difficult to tell from your writeup. If the image you are building has the same name as an image already in the browser cache, it will not download. If this is the case, here's a workaround I picked up from another forum and it worked for me.

    Create an image tag for your html that looks something like this.

    <img src="imagename.ext?randomcode"......
    Where the random code changes with each new image. This will force the browser to update the cache.
Re: Images built on the fly do not display
by bart (Canon) on Jan 08, 2003 at 00:23 UTC
    So you're saving an image to a file which then you expect the webserver to pass on to the browser... You could have a problem with webserver side caching. The fact that the image filename is always the same, could have a lot to do with it.

    You could try to make sure the image name is always different. Use a counter to increment a number, and use that as part of an image name. To delete old files, you could use a cron job; or you can have the parent do that, while it's waiting for the child to finish. You'll never have too many old files, that way. I hope. :-)

    But my preference would be to invoke the image creating script directly from a separate CGI script (or equivalent), and send the image data directly to the browser instead of saving it to a file first. You do need to provide the appropriate content-type header, as others already have suggested, and then simply print out the image data. The parameters you now use on the command line, can be passed as part of the image URL, after a question mark, using the familiar GET URL syntax.

      The image is saved to file and although this snippet doesn't show it, the image filename was manually changed each time the script was run, so the caching problem shouldn't really apply.

      We did try to give the give the process ID as the filename.

      Yes, I can see how it would be a good idea to send the image directly to the browser but I am curious to know why the current effort doesn't work Here is the full code:

      #!/usr/bin/perl -w $|=1; use strict; use CGI::Carp "fatalsToBrowser"; use CGI ":all"; use DBI; print header,start_html(-title=>'Bright', -bgcolor=>'#BDBDB0'); print h1(font{-face=>'Futura Lt BT'}, "Genome view"); print font{-size=>'3', -color=>'#800000', -face=>'Futura Lt BT'}; my($tth,$sth,$dbh,@position,$start,$finish,@row,$i,$child_pid,@accessi +on,$SQLstr,$imagename); if(!param) { $dbh = DBI->connect("DBI:mysql:database=dicty;host=localhost", "** +**", "****"); $sth=$dbh->prepare("select min(fstart),max(fstop) from fdata"); $sth->execute; while(@row=$sth->fetchrow_array) { $position[0]=$row[0]; $position[1]=$row[1]; } $dbh->disconnect; print start_form; print textfield(-name=>'start',-value=>$position[0],-size=>15),br, textfield(-name=>'finish',-value=>$position[1],-size=>15); print submit(-name=>'submit'),end_form; } if(param("submit")) { $imagename=$$; $start=param("start"); $finish=param("finish"); if(!defined($child_pid=fork())) { die "cannot fork $!"; } elsif($child_pid==0) { my $query= "/usr/apache/cgi-bin/order/ldasdump.pl -png -d dict +y chr5.1:$start,$finish --user root --pass mysqladmin > /usr/apache/h +tdocs/imagename.png"; exec($query); } else { waitpid($child_pid,0); print img({src=>"../../imagename.png",align=>'LEFT'}); } }
        I am curious to know why the current effort doesn't work

        The problems start with this line   print header,start_html(-title=>'Bright', -bgcolor=>'#BDBDB0'); which sends a MIME type of "text/html" back to the browser, then starts an HTML page. At this point, it's a bit late to start printing image bits and expect the browser to display an image.

        Read the description of header() in the CGI.pm POD, and note how to override the MIME type (aka Content-type). You want to send "image/png".

        I should have given up and gone to bed hours ago.

        Is it possible that there's something in $start or $finish that is fouling up the shell meta-character expansion that happens when you use the single-argument form of exec(), preventing the command from generating an image?

        Try using the list form of exec(), which doesn't trigger shell meta-character expansion.