Saving Raphaël image as PNG on Internet Explorer
Asked Answered
T

4

11

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 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?

Tyus answered 7/11, 2010 at 14:26 Comment(3)
I'm not posting this as an answer, because I haven't tried it myself, but you may have some success "tricking" Raphael to use svg-web, which has decent support for the SVG DOM API. The techniques you're using in other browsers would then be the same. I think it's very conceivable that this could work, but you may have to hack into the raphaeljs code a bit. Note that I have never read about anyone attempting to use raphaeljs with svg-web, svg-web with canvg, or canvg with flashcanvas, so if you get it all to work, it will be an epic hack, and you should definitely write about it. Good luck :)Scudder
As I said - i made it working on every browser except IE. I can attach aptana project if you want to try it.Tyus
Now something about tricking raphael. These are methods used in raphael that are not supported in IE: getNumberOfChars(), getExtentOfChar(), createElementNS() and there were some other issues as wellTyus
V
2

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.

Verse answered 2/12, 2010 at 14:4 Comment(0)
M
2

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.

Monition answered 7/12, 2010 at 19:38 Comment(2)
Excanvas pretty much sucks, Raphael is far better. That being said, I've just started trying to save Raphael drawings as images in IE :).Europeanize
I haven't used it, but this sourceforge.net/projects/vectorconverter now exists and may be modified to do what you needMonition
M
2

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()
Molest answered 21/8, 2013 at 20:0 Comment(0)
D
0

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.

Dissolute answered 12/11, 2010 at 19:28 Comment(2)
"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." This sums up my point of view pretty well.Europeanize
@Alex His problem is exactly that . . . He needs to support older browsers. Why wouldn't it be a good solution to just generate the images on the back-end and then load them via AJAX?Dissolute

© 2022 - 2024 — McMap. All rights reserved.