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

Howdy Y'all,
I'm trying to create a graphical plot image on the fly to be incorporated in a webpage Perl program. The Perl program creates Apache statistics using a CGI object. My question is how do I output the graph image inbetween calls to the CGI object? I can't seem to find documentation that details doing this. This is the page I'm outputting:
sub cgiOut { print $q->header( "text/html" ), $q->start_html( -title=>"Apache Stats for $hostname", -bgcolor=>"#383838", -text=>"#FFFFFF", -link=>"#FFFFFF", -alink=>"#FFFFFF", -vlink=>"#FFFFFF"), $q->h2( "Apache Stats for $hostname" ), $q->start_form( -method=>"POST", -action=>"/cgi-bin/logrep"), $q->popup_menu( -name=>'filename', , -values=>[ '/var/log/apache/access_log', '/var/log/apache/access_log.1', '/var/log/apache/access_log.2', '/var/log/apache/access_log.3', '/var/log/apache/access_log.4', '/var/log/apache/access_log.5', '/var/log/apache/access_log.6', '/var/log/apache/access_log.7', '/var/log/apache/mega',], -defaults=>'', -labels=>"Label"); print "&nbsp;&nbsp;"; print $q->submit( -value=>"Query" ); print "&nbsp;&nbsp;"; print $q->reset, $q->end_form, $q->a( { href=>$q->url() }, "Refresh" ); print "&nbsp;&nbsp;"; print $q->a( { href=>"/lug" }, "Home" ), $q->hr, $q->br; &tableOut(1, $q, 'Host Client', 'Hits', %host); print $q->br; my @data = ( ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], [ 1203, 3500, 3973, 2859, 3012, 3423, 1230] ); my $graph = new GD::Graph::lines3d( 400, 300 ); $graph->set( x_label => 'Day of the week', y_label => 'Number of hits', title => 'Daily Summary of Web Site', ); my $gd = $graph->plot( \@data ); # ---> HOW DO I PRINT THIS $gd object, create another CGI object p +erhaps?? &tableOut(0, $q, 'Referring Site', 'Ref\'d', %ref); print $q->br; &tableOut(0, $q, , 'Page Requested', 'Hits', %page); print $q->br, $q->hr; print $q->p( "Created by <a href=\"mailto:pararox\@host61.g\">Pararox</a>" ); print $q->end_html; 1; }
That graph is just a temp, ripped directly from the GD::Grap3d documentation. How would I go about printing that to the webpage after the initial &tableOut()?

Thanks, hope the weekend has been restful to ya!,

"There is more in heaven and earth
than is dreamt of in your philosophy"

Replies are listed 'Best First'.
•Re: Incorporating On-The-Fly Graphics In CGI output
by merlyn (Sage) on Mar 30, 2003 at 20:36 UTC
      I think you use that as a conversation piece don't you? Its like Eistein in conversation, "Yeah! Well I rewrote the enitre laws of physics." I wish I could do that. :)
Re: Incorporating On-The-Fly Graphics In CGI output
by The Mad Hatter (Priest) on Mar 30, 2003 at 20:14 UTC
    I don't think it is possible to directly embed image information in HTML. You'd probably have to output something like <img src="name-of-cgi.cgi?op=displayimage" /> and have the script output the image when the field op equals displayimage. See this for how to correctly return an image.
Re: Incorporating On-The-Fly Graphics In CGI output
by benn (Vicar) on Mar 30, 2003 at 20:20 UTC
    You can't incorporate binary graphic data directly into a HTML web page, which is what your CGI object is producing. You'll need to incorporate an <img> tag which then requests the picture data.

    One way would be to write the image to a temporary file, then use this filename for your image tag.
    Another way would be to separate out the graph-plot into a separate script or a re-entry into the existing script, then call it from your image tag... <img src='graph.cgi?drawpic=1'> or something, printing the binary data directly with the correct MIME-type header.

    Hope this helps.
Re: Incorporating On-The-Fly Graphics In CGI output
by Dr. Mu (Hermit) on Mar 31, 2003 at 06:19 UTC
    The foregoing comments are mostly true, but not entirely. There is the data: URI, but not all browsers support it. It allows image data to be embedded directly in the HTML, and there is even a Perl module that makes it easy to use in a CGI environment. The following code will generate some text and an image consisting of a red square with a blue-outline square inside of it:
    #!/usr/bin/perl use strict; use URI; use GD; my $img = GD::Image->new(100,100); my $red = $img->colorAllocate(255,0,0); my $blue = $img->colorAllocate(0,0,255); $img->rectangle(40,40,59,59,$blue); my $uri = URI->new("data:"); $uri->media_type("image/png"); $uri->data($img->png); print "Content-type:text/html\n\n"; print "<html>\n"; print "<h3>Testing inline image data</h3>"; print qq(<img src="$uri" alt="Didn't work."></html>\n);
    This is a CGI script, even though I didn't actually use CGI, as it didn't help to illustrate the point. Anyway, the code produces this output:
    Content-type:text/html <html> <h3>Testing inline image data</h3><img src="data:image/png;base64,iVBO +Rw0KGgoAAAANSUhEUgAAAGQAAABkAQMAAABKLAcXAAAABlBMVEX/AAAAAP9sof2OAAAAI +UlEQVR4nGNgGAWjgFTw//8HJF4Dg8CI5aGGxCgYBcQBAMULD/2Zt2wmAAAAAElFTkSuQm +CC" alt="Didn't work."></html>
    Netscape 4.7 on Linux showed the image without any problems. Opera did not. So results may vary.

    Also, there is apparently some restriction on the maximum size of such an embedded image, but so far I've not been able to determine what that is. Maybe someone else will know.

    One would think that something could be done with the multipart/mixed MIME type. This is how mixed content is included in email messages, but so far my efforts to make this work with a browser have come up dry. I'm with you, though. It seems idiotic to require a separate request for data that could just as easily be included with the main document.

    Update: Since images don't seem to be permitted in the SOPW nodes, I've included a sample similar to the above on my home node: Dr. Mu

      I apologize for the apparently superfluous reply, but I really have to say that this is very cool. I've never seen this before, and am especially glad I read this node because of it. :)

Re: Incorporating On-The-Fly Graphics In CGI output
by CountZero (Bishop) on Mar 30, 2003 at 21:01 UTC

    I had some success with Apache::GD::Graph.

    It works only on Apache servers and you must of course have the possibility to install this mod-perl Apache module, as well as making some changes to the config-file.

    To use it you include an <img>tag with the datapoints, labels, type of graph, ... as parameters of the URL pointing to the virtual location of this module.

    It's quite fast and it caches your graphs so it will not recalculate the graph if it is not necessary.


    "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

Re: Incorporating On-The-Fly Graphics In CGI output
by dpuu (Chaplain) on Mar 30, 2003 at 20:30 UTC
    As others have said, you can't directly embed an image from GD. But if you take a step back, your problem is to embed a graph within an html stream. If you are able to construct that graph using SVG, then this can be inlined in the html stream. The problem with this approach is that many (most?) browsers don't support it. --Dave
Re: Incorporating On-The-Fly Graphics In CGI output
by lacertus (Monk) on Mar 31, 2003 at 07:42 UTC
    Thanks for taking the time to post that example image Dr. Mu; thanks to everyone else (Mr. Schwartz, that article is fantastic), you've definitely given me a good foundation with which I can begin to implement this hairy piece of code.


    "There is more in heaven and earth
    than is dreamt of in your philosophy"
Re: Incorporating On-The-Fly Graphics In CGI output
by aquarium (Curate) on Mar 31, 2003 at 10:54 UTC
    You can use HTML 4.0 <OBJECT> tag, image data inline via object's DATA attribute. Chris
Re: Incorporating On-The-Fly Graphics In CGI output
by SysApe9000 (Acolyte) on Mar 31, 2003 at 17:28 UTC
    This is an excellent question and although I thought I knew the answer (there isn't any way to do it!) I was surprised to find out there are in fact several ways to do it, or at least make it easier. I'll have to re-visit some of the scripts I've written.

    I've hit this problem in the past and it always made me mad that I had to develop a CGI interface to something that I already had a Perl interface for, especially since I was writing a Perl program!

    It's too bad I ran out of votes for this thread's poster and responders....