开发者

Saving Raphaël image as PNG on Internet Explorer

开发者 https://www.devze.com 2023-01-24 02:06 出处:网络
I have some nice graphics done using Raphaël (a JavaScript library), and I want to add a feature to save it as a PNG file.

I have some nice graphics done using Raphaël (a JavaScript library), and I want to add a feature to save it as a PNG file.

This is simple on every browser except Internet Explorer, because on non-Internet Explorer browsers I get SVG as an output from Raphaël, and then I can convert it to canvas (using cansvg library) and canvas has a toDataURL() method. But on Internet Explorer, Raphaël outputs VML. I can't use the Chrome frame plugin. Why?

Users of my application开发者_StackOverflow中文版 choose Internet Explorer just because it is preinstalled on Windows, and they don't have permission to install anything else. So they can't install this plugin. So my second idea was to get an SVG string on Internet Explorer, pass it to cansvg to get a canvas and then use flashCanvas.

I tried to trick Raphaël to think it's running on a non-Internet Explorer browser and get SVG as output, but I failed, as Raphaël use some JavaScript functions that are absent in Internet Explorer to produce SVG.

So how do I accomplish this task under Internet Explorer?


RaphaelJS does not use canvas. It uses VML in IE, but SVG in all other browsers.

As the OP said, you can grab the raw SVG (as it's a whole SVG doc) and download that, he is looking for some similar functionality with VML.

The only way I could think to do it, is get IE to send the VML data (if that is even possible) back to a server which does the conversion to PNG and downloads it.

However, as you want a PNG, you are probably better going for canvas from the start as you likely don't need the vector side of the graphics if you are then converting to bitmap. Checkout canvas and the google IE canvas script to see if you can use that instead.

As for "Browser support for generating graphics is still pretty limited", it isn't. Check out RaphaelJS.com demos, it's perfectly feasible and a good solution. The only problem is IE <9 which hasn't adopted any modern technologies like HTML5, CSS3 or SVG.

Anything which supports Canvas or the google IEcanvas can also produce decent results.


Raphaël uses VML in Internet Explorer and SVG in all other browsers. Canvas has built-in ability to export as an image, where as such feature is not built in VML. You can use server-side code to achieve the same for non-supported browsers.

An alternative solution is to use ActiveX solutions for Internet Explorer that can generate an image from VML. One such solution is HTML Snapshot ActiveX Component.

Generally, it is not recommend to implement ActiveX solutions unless it is an absolute necessary.


PHP & JavaScript solution (no need for ImageMagick, Apache Batik Rasterizer, or Inkscape!):

Requirements

  1. PHP
  2. Flash Player 9+ (for Flashcanvas, correct me if I'm wrong)
  3. RaphaelJS
  4. Raphael Export
  5. CanVG
  6. FlashCanvas Free or Pro
  7. Canvas2PNG + save.php (included with FlashCanvas)

Overview

  1. Initiate an empty canvas
  2. Draw some VML with Raphael
  3. Use Raphael Export to convert paper from VML to SVG
  4. Initialise Flashcanvas on the empty canvas
  5. Send the SVG string from Raphael Export to canvg
  6. Once canvg has generated the SVG data onto the FlashCanvas initiated canvas, call Flashcanvas' canvas2png function
  7. Paper is saved as a PNG! $$$

Breakdown

  1. Initiate an empty canvas

    <canvas id="myCanvas"></canvas>
    
  2. Draw some VML with Raphael

    //Basic Example
    var paper = Raphael(10, 50, 320, 200);
    var circle = paper.circle(50, 40, 10);
    circle.attr("fill", "#f00");
    circle.attr("stroke", "#fff");
    
  3. Use Raphael Export to convert paper from VML to SVG.

    var svg = paper.toSVG();
    
  4. Initialise Flashcanvas on the empty canvas

    var canvas = document.getElementById('export');
    if (typeof FlashCanvas != "undefined") {
      FlashCanvas.initElement(canvas); //initiate Flashcanvas on our canvas
    }
    
  5. Send the SVG string from Raphael Export to canvg

    canvg(canvas, svg, {
      ignoreMouse: true, //I needed these options so Internet Explorer wouldn't clear the canvas
      ignoreAnimation: true,
      ignoreClear: true,
      renderCallback: function() {
        setTimeout(function() {
          canvas2png(canvas);
        }, 1000);
      }
    });
    
  6. Once canvg has generated the SVG data onto the canvas, call Flashcanvas' canvas2png function

    //This is called within the renderCallback canvg function above:
    renderCallback: function() {
      setTimeout(function() {
        canvas2png(canvas);
      }, 1000);
    }
    
  7. Paper is saved as a PNG! $$$

Notes/Findings

  • DON'T INCLUDE/USE EXCANVAS with FLASHCANVAS, this one line of mistake I had that almost caused me to give up on FlashCanvas on numerous occasions.
  • Flashcanvas should be included as early as possible in the <head>, for some reason I had issues when including flashcanvas.js later.
  • Canvas2png.js by default will prompt the user to save the .png file. Alternatively you can write the .png to your server by editing the Flashcanvas save.php file from:

    readfile('php://input');
    

    To:

    //Comment these out so that the download is not forced
    //header('Content-Type: application/octet-stream');
    //header('Content-Disposition: attachment; filename="canvas.png"');
    
    $putdata = fopen("php://input", "r");
    $fp = fopen("path/to/image_name.png", "w");
    while ($data = fread($putdata, 1024)) {
      fwrite($fp, $data);
    }
    fclose($fp);
    fclose($putdata);
    
  • Following the last note: if you opted to save the image to the server instead, by default you'll be forwarded to a blank save.php when you call canvas2png() (save.php is not run by AJAX!) and thus you'll lose your current Raphael drawing session.

Therefore, if you want to invoke this method without losing your current Raphael session, the way I solved this was to keep the Raphael Paper on one page, and the <canvas> page on another.

The general idea is that you keep your Raphael drawing activity on your main page, and when you're ready to export/save an image, you could open a new window that contains the empty canvas, and send the SVG data to that new temporary page. From there on you could follow the steps again exactly where we left off except in the new window, and at the end of the save.php file when the image has been generated and saved, you can use a javascript call: self.close() to close that new window.

We need this new window to pop up so that the canvas can be processed properly with the SVG data.

  • canvg with Internet Explorer 8 (Chrome/Firefox worked) was unable to read images that were generated from a .php URL, to fix this I had to use PHP to save the "php url image contents" as a temporary image on the server and use that temporary image as a reference for the SVG data by replacing its original xlink:href.

  • canvas2png.js has a fall back in case your browser does support toDataURL, making this solution cross browser compatible

  • As a final note, I thought I'd include the quick method to export images if you're using a browser that supports toDataURL, which I would infer that the browser also supports SVG, and so the process to save an image is much easier (without the need of Flashcanvas hassle):

    1. Initiate an empty canvas
    2. Draw some SVG with Raphael
    3. Export the SVG string using Raphael Export
    4. Use canvg to parse the SVG data into the empty canvas
    5. Use canvas.toDataURL()


You might want to look into generating your images on the server-side. Browser support for generating graphics is still pretty limited.

Node Canvas just came out and I've used ImageMagick in the past with great success.

0

精彩评论

暂无评论...
验证码 换一张
取 消