Generating HTML Canvas image data server-side?

后端 未结 1 502
挽巷
挽巷 2021-02-01 18:24

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

1条回答
  •  无人及你
    2021-02-01 19:05

    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/perl
    
    use 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 web
    use 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 text
    my $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|
    
    
    
        
        
        
    
        
        
    
        
    View as jpg |; #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 serverside if ($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 etc my ($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 files print $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 path system($FindBin::Bin.'\\phantomjs', $phantom_doc_filename, $phantom_graph_filename, $image_filename) == 0 or die "system failed: $?"; #read the entire image file my $img = slurp_file($image_filename); print "Content-Type: image/jpeg\nPragma: no-cache\n\n".$img; #The temp files are no more needed unlink $phantom_doc_filename, $phantom_graph_filename, $image_filename; } else { # just render client side print "Content-Type: text/html\nPragma: no-cache\n\n".$graph_html; } #slurp is not always std perl sub slurp_file{ my $filename = shift; my $string; local $/ = undef; open FILE, $filename or die "Couldn't open file: $!"; binmode FILE; $string = ; close FILE; return $string; }

    0 讨论(0)
提交回复
热议问题