Skip to content Skip to sidebar Skip to footer

Generating Html Canvas Image Data Server-side?

The title of this question may be slightly misleading, but I'm not sure what the best title would be (since I can't guess at a solution yet). Basically the system I am developing r

Solution 1:

I used phantomJs (like node.js but different) serverside to run exactly the same code as client side, and get the same result. all you need is one single exe-file (like a webkit stand alone web brower)

The following program (in Perl, but should be feasible to translate to you favourite language) takes some data, inserts into a web-page (could be ajax'ed) and either sends that web page to the client, or stores it as a temporary file, and starts PhantomJs on the same page. Then ask PhantomJs to generate a jpg, that is then picked up (and in this case sendt to the client).

#!/usr/bin/perluse strict;
use File::Temp;
$|=1;
#this script returns a graph, either as html +js web page to render client side,#or renders the same page server side, and returns the jpg image.#files needed:#.\phantom_srv_client.pl  #this script#.\phantomjs.exe          #the webkit runtime stand alone file, from http://phantomjs.org/#.\Scripts\excanvas.min.js #canvas simulator for IE8-#.\Scripts\jquery.min.js   #jQuery as we know it#.\Scripts\jquery.jqplot.min.js #graph library on top of jQuery from http://www.jqplot.com/ (Flot or any can be used)#do we want client side rendering (html + js), or server side rendering (jpg)#jpg seems to render nicer than png on some pages?use CGI;
my $show_as_jpg = CGI::param("jpg");

#path to javascript libraries (jQuery etc). #Must be absolute file location for server rendering, relative for webuse FindBin;
my $script_path = $show_as_jpg 
    ? $FindBin::Bin."/Scripts" 
    : './Scripts';


#data to send to graph (two sets)my $data = [[2,5,4], [6,4,5]];

#use json to get this as a javascript textmy $json_data;
eval {require JSON; $json_data=JSON::to_json($data)};
#in case JSON is not installed, get the json/javascript data manually (just for demo)
$json_data ||= "[[2,5,4], [6,4,9]]"; #here 9 at the end to see a difference#The following is the web page that renders the graph, client or server side #(links to scripts must be abolute to work serverside, as temp-files may go anywhere, $script_path keeps track of that)#$json_data is the Perl data structure converted to JSON (aka javascript, but not)my $graph_html =qq|
<!DOCTYPE html>
<html>
<head>
    <!--[if lt IE 9]><script language="javascript" type="text/javascript" src="$script_path/excanvas.min.js"></script><![endif]-->
    <script class="include" type="text/javascript" src="$script_path/jquery.min.js"></script>
    <script class="include" type="text/javascript" src="$script_path/jquery.jqplot.min.js"></script>

    <script class="code" type="text/javascript" language="javascript">
        jQuery(document).ready(function(){
            /*data from perl (\$json_data) inserted here */
            var data = $json_data;
            jQuery.jqplot("chart1", data );
        });
    </script>
    </head>
<body>
    <div id="chart1" style="width:600px; height:400px;"></div>
    <a href='?jpg=1'>View as jpg</a>
</body>
</html>
|;


#this is the javascript that tells PhantomJs what to do (ie open a doc and render it to bitmap)my $phantom_doc_js =qq|
    var system = require('system');
    //read from commandline which files to open, and write to
    var open_doc = system.args[1];
    var return_doc = system.args[2];
    var page = require('webpage').create();
    page.open(open_doc, function () {
        page.render(return_doc);
        phantom.exit();
    });
|;

#see if we shall render this page serversideif ($show_as_jpg) {
    #get temporary filenames with related file handlers#where to put phantomjs script (generic so could be a static file)my ($phantom_doc_filehandler, $phantom_doc_filename) = File::Temp::tempfile(  SUFFIX =>'.js', TMPDIR =>1);
    #where to put web page with data to render and ref to javascripts etcmy ($phantom_graph_filehandler, $phantom_graph_filename) = File::Temp::tempfile(SUFFIX =>'.html', TMPDIR =>1);
    #also get a filename with no handler, so phantomjs can return the jpg file. Extention must be .jpg!my (undef, $image_filename) = File::Temp::tempfile( SUFFIX =>'.jpg',TMPDIR =>1, OPEN =>0);

    #store file content and close filesprint $phantom_doc_filehandler $phantom_doc_js; close $phantom_doc_filehandler;
    print $phantom_graph_filehandler $graph_html;   close $phantom_graph_filehandler;

    #now call PhantomJs with filenames to read from and write to.#Next version should support piping, which would simplify a lot#use absolute path to phantomjs.exe in case web-server does not use current pathsystem($FindBin::Bin.'\\phantomjs', $phantom_doc_filename, $phantom_graph_filename, $image_filename) == 0ordie"system failed: $?";

    #read the entire image filemy $img = slurp_file($image_filename);
    print"Content-Type: image/jpeg\nPragma: no-cache\n\n".$img;

    #The temp files are no more neededunlink $phantom_doc_filename, $phantom_graph_filename, $image_filename;

} else { # just render client sideprint"Content-Type: text/html\nPragma: no-cache\n\n".$graph_html;
}

#slurp is not always std perl   subslurp_file{
  my $filename = shift;
  my $string;
  local $/ = undef;
  open FILE, $filename ordie"Couldn't open file: $!";
  binmode FILE;
  $string = <FILE>;
  close FILE;
  return $string;
}

Post a Comment for "Generating Html Canvas Image Data Server-side?"