inline SVG fallback - browsers processing all switch elements - html

I have just started using inline SVG to display images on a resource heavy website. However, I also have a fallback using switch and foreignobject tags so that older browsers should just display a png image in its place.
Here is the bare bones - there are more details at inline svg in html - how to degrade gracefully?
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xml:space='preserve'
width="100" height="100">
<switch>
<g>
<!-- the svg goes here -->
</g>
<foreignObject width="100" height="100">
<img src="/some_image.png"/>
</foreignObject>
</switch>
</svg>
I thought that this would lighten the load on the server - e.g. for a page with 4 images, the browser gets everything in one hit, rather than making 5 trips to the server, 1 for the page and 1 for each img tag.
However, now that I have deployed this solution, I have discovered (by examining the server logs) that browsers are actually processing the img requests inside the foreignobject tag, regardless of whether they can handle SVG.
In other words, it's increasing the load on the server since the page is much bigger (full of SVG) and the images are downloaded anyway, even though they are never displayed.
This seems crazy - I thought the idea of a switch was that the browser should process the first tag it understands (in my example, the g tag) and ignore the rest (the foreignobject in my example).
I have tested this in Firefox 17.0.1, Chrome 23.0.1271.95, Safari 5.1.7 and Opera 12.10 and they all do it.
Is there any way I can persuade the browsers that they really really don't need to download the images?
Thanks
Chris

You can still make reference to the content of a <switch> child that isn't directly displayed by using it in a <use> <filter> or <clipPath>. It's only direct rendering of switch children that is suppressed.
The only way to stop downloading would be not to set the src attribute on the image unless you need it. You could check for SVG support using javascript e.g.
document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Shape", "1.0")
and then set the src attributes if that returns true.

Related

Stop auto image smoothing inside an SVGZ

I'm using SVGZ images on HTML pages for their resizability. These SVGZ images contain PNGs that have been enlarged in specific ways that I want to preserve, pixelation and all. Firefox is displaying this correctly (the way I designed it in Inkscape):
while Chrome is "helpfully" autosmoothing everything:
I'm teaching a course, and I'm trying to show how image data is being created over successive passes. I want the pixelation, because that's what the data is. In fact, the PNGs inside the SVGZ contain the property style="image-rendering:optimizeSpeed". I was hoping that Chrome would recognize that and respect it.
(Please note that I've already tried the CSS image-rendering: pixelated; trick. I'm sure that would work perfectly well if I were showing PNGs directly, but that's not what I'm doing.)
Works for me in Chrome:
<svg width="100" height="100">
<image xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFElEQVQIHWP4z8DwHwyBNJDN8B8AQNEG+t5Ik2kAAAAASUVORK5CYII=" width="100px" height="100px"/>
</svg>
<svg width="100" height="100">
<image xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFElEQVQIHWP4z8DwHwyBNJDN8B8AQNEG+t5Ik2kAAAAASUVORK5CYII=" width="100px" height="100px" style="image-rendering: pixelated"/>
</svg>
I found an answer that builds on what Paul said above.
It looks like the way to do this in Chrome is to make sure that the PNG inside the SVG/SVGZ has the property style="image-rendering: pixelated", which makes sense. However,
This doesn't work with Firefox.
This isn't an option within Inkscape, so if you want it you have to edit the SVG code manually.
Both Firefox and Inkscape seem to prefer style="image-rendering: optimizeSpeed". So I ended up adding both to my SVGZ file: style="image-rendering:optimizeSpeed;image-rendering:pixelated". This seems to make both browsers happy, though again it means modifying the SVG code of the image file manually, since Inkscape doesn't let you do it directly.
I'm going to add an Inkscape tag if I can, since this seems to involve that program as much as anything.

HTML-only fallback for MathML

MathML is a web standard for writing mathematics in a way that can be easily zoomed without pixellating (just like SVG), copied and pasted, and read by screen readers.
Chrome are refusing to implement it on the basis that a JavaScript polyfill exists. (I kid you not.) Edge's support is 'Not currently planned'. Thus, it's just Safari and Firefox (and some EPub readers) that support MathML.
Given that implementation is so spotty, fallback content is 100% necessary. The usual solution for this is MathJax; but this doesn't work for users who have JavaScript disabled or, more likely, broken.
We live in an age where HTML easily allows fallback content without JavaScript (see the <picture>, <audio> and <video> tags). Is there some way to do so for MathML?
As far as I am aware, there is no HTML-only way to detect support for MathML.
However, there is an SVG way.
The <switch> SVG element renders the first direct child of itself where certain boolean attributes on that child are either missing or evaluate to true. One such attribute is the requiredExtensions attribute, which mandates that the user agent has to support a particular extension to render the indicated element.
So, if you have an SVG <foreignObject> element (used to embed non-SVG elements in SVG) with requiredExtensions="http://www.w3.org/1998/Math/MathML" set on it, and then put that <foreignObject> inside a <switch> element, the <math> element will be rendered if MathML is supported, and the next element will be if MathML isn't.
So, for a basic MathML example: <math xmlns="http://www.w3.org/1998/Math/MathML"><mn>1</mn><mo>+</mo><mn>1</mn><mo>=</mo><mn>2</mn></math> is MathML for 1 + 1 = 2.
A basic SVG fallback for this would be <svg xmlns="http://www.w3.org/2000/svg" width="65" height="23"><text y="15" font-size="16">1 + 1 = 2</text></svg> (more complicated fallbacks could be generated with Mathjax-Node).
So the completed MathML expression with fallback would be:
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="40">
<switch>
<foreignObject requiredExtensions="http://www.w3.org/1998/Math/MathML" width="120" height="40">
<math xmlns="http://www.w3.org/1998/Math/MathML">
<mn>1</mn><mo>+</mo><mn>1</mn><mo>=</mo><mn>2</mn><mtext>MathML</mtext>
</math>
</foreignObject>
<text y="15" font-size="16">1 + 1 = 2 (SVG)</text>
</switch>
</svg>
I have tested the above in Firefox (renders MathML), Edge, IE11 and Chrome (renders SVG). I have not tested Safari, as I don't own a Mac.
EDIT: Safari 9 renders the MathML.
But I want to support IE8!
Why?
BECAUSE!
Fine.
If you want to keep the ability to copy + past your math, you can't use an <picture> tag to embed your SVG/MathML hybrid - use <object> instead:
(I'm using a DataUrl here, but you could just as easily save the SVG as an external file):
<object typemustmatch type="image/svg+xml" data="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMTIwIiBoZWlnaHQ9IjQwIj4NCiAgPHN3aXRjaD4NCiAgICA8Zm9yZWlnbk9iamVjdCByZXF1aXJlZEV4dGVuc2lvbnM9Imh0dHA6Ly93d3cudzMub3JnLzE5OTgvTWF0aC9NYXRoTUwiIHdpZHRoPSIxMjAiIGhlaWdodD0iNDAiPg0KICAgICAgPG1hdGggeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzE5OTgvTWF0aC9NYXRoTUwiPg0KICAgICAgICA8bW4+MTwvbW4+PG1vPis8L21vPjxtbj4xPC9tbj48bW8+PTwvbW8+PG1uPjI8L21uPjxtdGV4dD5NYXRoTUw8L210ZXh0Pg0KICAgICAgPC9tYXRoPg0KICAgIDwvZm9yZWlnbk9iamVjdD4NCiAgICA8dGV4dCB5PSIxNSIgZm9udC1zaXplPSIxNiI+MSArIDEgPSAyIChTVkcpPC90ZXh0Pg0KICA8L3N3aXRjaD4NCjwvc3ZnPg==">
1 + 1 = 2 (You don't support SVG)
</object>
(You could render the SVG as a PNG using CloudConvert or similar and put in inside the object if you really wanted.)
So there you go. A little pre-rendering, and you have a MathML fallback that requires no JavaScript or CSS - just HTML.
EDIT: I have made an NPM package to automate the creation of the MathML, SVG, and PNG. It can be found here.
I was not aware of this at the time of my first answer, but you can in fact use the <object> tag to display MathML directly - the MIME type of MathML is application/mathml+xml.
So you can have one <object> tag that points to a mml file, with whatever fallback content you want inside of it (I'd suggest a SVG representation of your equation, possibly in its own <object> for a PNG fallback).
I have tested and confirmed this works in Firefox (MathML is displayed), Edge, Internet Explorer 11 and Chrome (SVG is displayed).
EDIT: Safari shows the SVG, not the MathML. (Even through it supports MathML.)

Firefox issues when displaying SVG (Firefox 55.0.3)

Firefox won't display the SVG book covers properly ...
http://new.images.hindawi.org/kalimat/covers/svg/270x360/c/24972860.svg
Compare the link above in Firefox and Chrome.
It used to be displayed just fine in Firefox, but I think something went wrong with the latest update.
If any one know a solution to this issue it would be great.
Thanks.
If you check your browser inspector, than you will see an error:
There is an SVG reference chain which is too long in this
document, which will prevent the document rendering correctly.
Inside your SVG image there are many of them, looking like:
<path clip-path="url(#SVGID_68_)" fill="#FFFFFF" d="..." />
Either create less accurate SVG (less details), or create it some other way.
Since it is rendered well in webkit browsers, than maybe you can use wkhtmltoimage to convert it server side to PNG or JPG.

How is my HTML <image> element being interpreted as an <img> element? [duplicate]

I am writing an introductory HTML course. I remember discovering 9 years ago as I was learning HTML that both <img> and <image> worked as the tag for displaying images, at least in IE. Indeed, <image> still works in the latest versions of the 5 top browsers.
I realize that <image> is incorrect and will not validate with http://validator.w3.org. However, is anyone aware of a browser that will not display an image if <image> is used instead of <img>?
Furthermore, I assume the modern browsers display images created with the <image> tag simply because it is a common mistake that beginners make. Is this assumption correct?
Yes and no. As you point out <image> has been a synonym for <img> for a long time. I believe it was an early Netscape browser that first did this, possibly to compensate for user error, or possibly because there was dispute at the time whether the element should actually be called <image> or <img>.
Anyway, as pst points out, once it was implemented in a browser that dominated the market of the time, web pages came to rely on it. Its persistence is then down to commercial pressure on the browser manufacturers. If all the major browsers support it, then Browser A decides that although it supported it in Version V, it won't support it in version V+1, as soon as version V+1 is released, they get lots of messages saying "Site S is broken in your latest browser. You browser is rubbish. I'm going to switch to browser B".
The HTML5 parsing spec requires that the <image> tag is mapped to the img element at the tree construction stage, so there can never be any justification for using it.
I would be less concerned about browsers, than other HTML consumers, such as the lesser known search engines. I believe that the image for img synonym is not widely known, and the many such tools would therefore fail to pick up <image> as referencing an image resource.
They have different usages in SVGs. The image tag creates a specific element in an SVG and can not be replaced by the img tag.
Fiddle Example
I just finished debugging this problem, which I was committing, having not previously read the above answers.
While not full-blown browsers, an email client is often used as if it were a browser.
I discovered, the hard way, that the Android Gmail client, using naked HTML (with a default naked DTD specification), does exhibit this problem. It only responds to <img /> [i.e., not <image />]. gmail.com is fine with <image />, but not the Android gmail client.
While an email client isn't really a browser, I thought you might be interested anyway.
Indeed. Modern browsers will display code that is not valid in order to make sure that old websites still display correctly and slightly-invalid code doesn't screw up a page.
For example, forgetting to close a <tr> before you open a new one - all modern browsers will simply assume you closed it.
I'm not aware of a well-used, up-to-date browser that will fail to display an <image> tag, but will display an <img> tag.
Image is used by the DOM and is why it maps to the img tag in the html. Notice when you use background-image in css or drawImage in javascript, it is fully typed out.
Img is identified as an html tag referencing an image. A side note is that you can now use the <picture> tag besides <img> tag in the html.
The <picture> tag in HTML5 has/uses the properties that <audio> && <video> tags have. It helps remove issues with mobile device sizes and todays hi-res images.
What works well on desktop still renders properly when applied to a phone or table size screen.
See ~://quick over-view of picture vs. img

How to load a HTML file into canvas?

I know we can load an image into a canvas but I wonder if we are able to load a simple HTML file into a canvas. If yes, how?
Thanks.
Short answer: No, you cannot.
Long answer:
Not reliably, BUT yes you can in certain (possibly hackish) ways. The key is in what you define as an "image". You are aware that you can add an image to the canvas with drawImage() - what you mightn't be aware of is what that "image" can be (not necessarily an actual image).
Firstly, the "image" can be a HTML5 video element - so you can add videos to the canvas.
Secondly, in most modern browsers the "image" can be an SVG document, which can contain HTML via the SVG <foreignObject> element.
Browser support:
SVG documents in drawImage() are not currently supported in Firefox. The related bug is here and I think a fix is planned.
<foreignObject> is buggy in most browsers - Firefox (ironically) seems to have the best support.
Example:
<svg xmlns="http://www.w3.org/2000/svg">
<foreignObject x="0" y="0" height="800" width="800">
<body xmlns="http://www.w3.org/1999/xhtml">
<p>Hello world!</p>
<input type="date"/>
</body>
</foreignObject>
</svg>
Try loading that file with canvas drawImage() in Opera - as you'll see its interactivity is fairly buggy, but it displays fine.
He's talking about HTML5 / Javascript.
It's not possible without writing your own Rendering Engine (in Javascript).
html2canvas or rasterizeHTML.js seem the tools you are looking for.
A third solution without plugins is presented by Mozilla, but I could not get it running here: Although it's not trivial (for security reasons), it's possible to draw DOM content—such as HTML—into a canvas.
There is also PhantomJS, which supports Screen Capturing