Closed andrewray closed 10 years ago
It's difficult in your description to understand what doesn't work.
Did you try the minimal svg example ? This should output you an SVG file on stdout that you should be able to visualise with an SVG viewer (browsers included).
Yes I did - here's a test case;
andyman@woofer:~/dev/test$ more svg_test.ml
#use "topfind"
#require "vg.svg"
open Gg
open Vg
(* 1. Define your image *)
let aspect = 1.618
let size = Size2.v (aspect *. 100.) 100. (* mm *)
let view = Box2.v P2.o (Size2.v aspect 1.)
let image = I.const (Color.v_srgb 0.314 0.784 0.471)
(* 2. Render *)
let () =
let title = "Vgr_svg minimal example" in
let description = "Emerald Color" in
let xmp = Vgr.xmp ~title ~description () in
let warn w = Vgr.pp_warning Format.err_formatter w in
let r = Vgr.create ~warn (Vgr_svg.target ~xmp ()) (`Channel stdout) in
ignore (Vgr.render r (`Image (size, view, image)));
ignore (Vgr.render r `End)
Then
andyman@woofer:~/dev/test$ ocaml ./svg_test.ml > test.svg
When loading the image with gnome image viewer (3.8.2) nothing is displayed (or rather a checker board image which I think is its default background). I note it takes a few seconds to think about it as well. The toolbar says "573x354 pixels 962 bytes 99%".
OCaml is 4.01.0, opam 1.1, Vg 0.8.0
I tested in a linux vm and I confirm what you see. I suspect this to be a bug of eog
(svg is an insane standard so it's difficult to implement correctly) as the file displays fine in firefox
or inkscape
in that vm.
I can confirm that inkscape and loading the file directly into the browser works.
I guess my issue is more specific. I really want to make this work in the IOCaml notebook. I have copy/pasted the text output from the minimal example and tried to get it to render - it doesn't work. There is indeed a bunch of stuff going on behind the scenes to make this happen, though I still find it interesting that eog
and iocaml
seem to render the same thing for the pie-ambiguity example.
In summary, this doesn't work in the notbook;
x = '''<svg xmlns="http://www.w3.org/2000/svg" xmlns:l="http://www.w3.org/1999/xlink" version="1.1" width="161.8mm" height="100mm" viewBox="0 0 161.8 100" color-profile="auto" color-interpolation="linearRGB" color-interpolation-filters="linearRGB"><?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?><x:xmpmeta xmlns:x="adobe:ns:meta/"><r:RDF xmlns:r="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:d="http://purl.org/dc/elements/1.1/" xmlns:x="http://ns.adobe.com/xap/1.0/"><r:Description r:about=""><d:title><r:Alt><r:li xml:lang="x-default">Vgr_svg minimal example</r:li></r:Alt></d:title><d:description><r:Alt><r:li xml:lang="x-default">Emerald Color</r:li></r:Alt></d:description></r:Description></r:RDF></x:xmpmeta><?xpacket end="w"?><g fill="none" stroke-miterlimit="9.98123" transform="matrix(100 0 0 -100 -0 100)"><defs><path id="i1" d="M0 0L1.618 0L1.618 1L0 1Z"/></defs><use l:href="#i1" fill="#50C878"/></g></svg>
SVG(x)
While this example from the MSDN
x = '''<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="200px" height="200px">
<rect x="0" y="0" width="100%" height="100%" fill="none" stroke="black"/>
</svg>'''
SVG(x)
Does work. I'll look into this more - perhaps a XML version thing?
Ok, so for eog
it seems that the problem is that they use a non-conformant XML parser that looks for hard coded namespaces names, namely xlink
. In our example you replace the declaration:
xmlns:l="http://www.w3.org/1999/xlink"
by
xmlns:xlink="http://www.w3.org/1999/xlink"
And replace the l:
prefix accordingly in the document, it renders. This should be reported upstream.
I can have a look for IOCaml if you can point me to a web page somewhere for testing. This must be a different issue because if they inject the document directly in the DOM it should work (as it works in browsers when I do that in the Vg image database). Does maybe that SVG(x)
maybe do some pre-processing before injecting it in the DOM ? Where is that SVG(x) defined ?
Sorry I was being very confusing there. I put 2 code examples from the "python kernel for ipython" so the code is python. At that point I was testing with it to remove a possible point of failure.
Some equivalent ocaml code would be;
Iocaml.display "image/svg+xml" "<svg ...>..."
However, you would need to find a way to escape the svg string. There's an html example on-line here. You should be able to download the html page locally (some javascript stuff wont load but the svg declaration will be there).
Regarding the code it is writing the svg data to (mime : out_channel) then sending the svg to notebook with the 'send_mime' function.
Does maybe that SVG(x) maybe do some pre-processing before injecting it in the DOM ?
Yes, it certainly does some parsing as I have hacked away at some svg strings and got errors reported. I look further into that.
The w3c validator has quite a few things to say about that webpage. I don't remember the exact rules for direct inclusion of svg (vs injecting it in the DOM via js) in an html5 documents, I need to have a look at that but it seems for example it doesn't like namespace declarations.
That being said something you can already do is to suppress the xml declarations and the xmp metadata packet which generate xml processing instructions that an html5 document won't like anyways. More precisely when you create create the rendering target, use xml_decl:false
and don't specify the xmp
argument.
I have set xml_decl:false and updated the page. w3c validator is even less happy now!
Shouldn't be can you provide the link to the new document.
It should be at the same link. If its not showing up try adding ?create=1
to the end of the url.
From what I read from here (the bullets at the end of the post) HTML5's svg tag seems to be hack: your xml shall have no namespace prefixes, make no usage of namespaces, and hard code the xlink namespace name to xlink
.
So I think it's going hard to make it work with the current Vg. Here are a few possibilities if you want to make it work now:
object
tag (I don't know if this fits in the infrastructure provided by that notebook thing).The fact that the validator gives you more error is because it is now able to the parse the svg and gives you errors about these ones. Two things:
id
attributes have to be unique. Now since you repeatedetly output svg documents inline in the same document with different targets you get duplicated id
s. That one of the reasons why there are so many warnings/errors reported by the validator. So these svg documents need to be properly isolated. Note that the id
issue would also be an issue if Vg was able to generated the restricted form that html5 wants.
Of course we could give to the rendering target the first id it has to use and have a function to let us know the last one it used. But that would be a bloody hack and I won't do it as it wouldn't solve the problem in general for other svg (maybe non Vg generated) documents when you Iocaml.send_mime "image/svg+xml". If you really want to solve the problem in a clean way you have to do one of the following two things:
Iocaml.send_mime "image/svg+xml"
using an object
tag. Iocaml.send_mime "image/svg+xml"
to make it html5 compatible. This means removing xmlns declarations, replacing any xmlns namespace name that points on xlink by xlink
and uniquify all the ids (and of course modify their occurences) with respect to the current document being output. By hacking the svg output string data to use xlink it works as you suggest.
Switching to xhtml5 is not an option I have as I don't control the notebook interface code.
Generating external files is possible, however, they will not be embedded into the notebook so wouldn't work online. If there was a solution where I could encode the SVG data into the object tag itself that would be ideal but I am not sure it's possible.
Thanks for your help.
In case 2. you also need to the following:
Note that this is not as hard you may think and should be quite easy to perform with xmlm.
So I'm closing this, I hope you'll take path 2. it's the only clean and robust way to go. Feel free to continue the discussion in this issue if you need help.
This seems to work the way I want;
Iocaml.display
"text/html"
("<object data=\"data:image/svg+xml;base64," ^
base64 (string_of_svg (Size2.v 30. 30., Box2.unit, gray)) ^ "\"> </object>")
Interesting hack. Just note that the maximal size for data:
URIs is unspecified and left to implementers (see "Length limitations" on this page). So I'd rather call this a workaround...
Btw if the notebook interface has functions to inject SVG documents into a document (that SVG(x)
function ?). What I have described above should be done by that function so maybe you should report the problem upstream.
I think you're right - this is both a shocking hack and IPython itself should probably be doing a better job here. I will have a trawl though their forums and documentation to see what I can figure out.
In the mean time this seems like a good start. The latest version of the page has working svg images. I've also put in some code to pull apart the xml representation using ocaml-cow which I believe would provide a way to perform the transformations you were suggesting.
I have tried to follow the tutorials on the website but get no output when rendering in the web-browser, or with the (Ubuntu 13.10 64bit) gnome image viewer.
The only time I have seen anything at all is with the pie-ambiguity database image. You can just about see the text numbers but that's all.
This all being said the images in your demo website work fine in the browser until I download them.
Any idea what I am doing wrong? The fact your website works suggest it's something at my end.
Cheers, Andy