How can I scale an SVG <image> while maintaining whole pixels? - svg

I have a pixelart-style image which intend to scale to 4x size with SVG. However, the following code blurs the pixels of the image:
<image x="0" y="0" width="1024" height="1024"
image-rendering="optimizeSpeed"
xlink:href="pixelart.bmp" />
Is there some attribute which will resolve this?

I think that image-rendering="optimizeSpeed" is the closest you can get. As the specs for that property state, it "should use a resampling algorithm which achieves the goal of fast rendering, with the requirement that the resampling algorithm shall be at least as good as nearest neighbor resampling." As this is the only section of the spec that mentions "nearest neighbor", I don't think you have any other option.
The only other related thing I can find is the IE9 property -ms-interpolation-mode:nearest-neighbor. This is (of course) IE specific, and is listed as a CSS property (so possibly only applicable to HTML).
Which OS/browser/version is giving you interpolated pixels as a result of upsizing with that attribute?
Also, note that you can use a combination of HTML5 Canvas and SVG to perfectly recreate your image with one SVG <rect> per pixel:
http://phrogz.net/tmp/canvas_image_zoom_svg.xhtml

CSS value image-rendering:pixelated; so:
<image x="0" y="0" width="1024" height="1024"
style="image-rendering:pixelated"
xlink:href="pixelart.bmp" />
This is from reading through the answer link above, in the "accepted" answer. It is not official as of time of writing, still "Proposed" for CSS4, but appears to be supported by Chrome already.

Related

Proper accessibility for inline svg used multiple times on the same page

What is the proper way to make an inline svg accessible when it is used multiple times on the same page? An example would be a twitter icon in the header and footer, or a logo that is repeated throughout the page. From my research I believe the following is best for unique svgs:
<svg aria-labelledby="title">
<title id="title" lang="en">Red Rectangle</title>
<g>
<rect x="0" y="0" width="100" height="50" fill="red" />
</g>
</svg>
Using aria-labelledby and title, as well as description if needed. However in the case of an inline svg that is repeated, I have not been able to find an answer on the web. Is something like the following acceptable?
<svg role="img">
<title>Red Rectangle</title>
<g>
<rect x="0" y="0" width="100" height="50" fill="red" />
</g>
</svg>
Or what about just using aria-label? Thanks in advance!
The human side
Why your image is repeated multiple times ?
While choosing an alternative text for your image, remember that there are two kind of images on the web: illustrative images, and functional images.
The former don't absolutely need an alt text, while the later absolutely requires an alt text.
IF you give an alt text for the former, it should be a description of the image, while the alt text for the later must rather tell what the action is about than a simple visual description.
You can look at this question and my answer for more details about that.
IF your images are repeated multiple times, it's quite probable that they are functional ones. If we assume that it's the case:
If they all trigger exactly the same action, they must all have exactly the same label. Examples: several links to the same page, or a share icon at the beginning and the end of an article
If they don't trigger exactly the same action, or not on the same item, then they must all have different label. Example: add an item to cart. In that case, ideally, the label of the image should also tell on which item it operates.
The technical side
If your images are functional and all doing exactly the same action (see above), your problem is that you can't have multiple times the same id for a whole page.
Technically, referencing a <title> present in another SVG should work, but I would still prefer avoid it just in case. Inline SVG aren't as well supported than good old <img/> by screen readers.
It would be better to use good old <img/>, or generate unique ids.
Note that aria-label and aria-labelledby are guaranteed to work with all screen readers only on interactive/focusable elements.
If your images are focusable, then fine as long as all id are unique, although it would even be better to have the alt text as a visually hidden text in an enclosing link or button.
IF your images aren't focusable, keep in mind that aria-label/aria-labelledby may be totally ignored, but anyway in that case you have another accessibility problem: in principle, functional image should be made focusable, otherwise keyboard only users won't be able to trigger the action.

Making screen-readers read out <text> items in SVG graphics?

I've searched all over the place and not have any success with this.
I'm making SVGs like the following one in order to make them scalable, and also help people who are dyslexic so they can highlight the text and use plugins like Read Out Loud:
https://www.ole.bris.ac.uk/bbcswebdav/institution/TEL/TEL%20guides/Published%20TEL%20guides/Replay/record-now-instructions-web.svg
But I've not been able to get my copy of NVDA to read out the tab-indexed fields as I tab through them. I've tried fields and aria-label on various things...
Is there something simple I can change so NVDA (and similar screen readers) will read out the text as I tab through (NVDA does this on HTML pages).
Or should I just put the full description of all the text in my description at the top?
I noticed you have role="img" in your svg root. That's borking everything, since it tells the accessibility API that it is just a single element, whose accessible name is always aria-labelledby="svgTitle svgDesc"
Try changing that to role="graphics-document" (or perhaps role="application" if you want fancier interactions) and I think you'll have a whole lot more luck.
The other option is to remove the role attribute from the <svg> element. It sounds counterintuative, but it should make any <text> elements accessible.
For an example, see tip 5 in this SitePoint article, which has great background and other helpful tips on making SVG more accessible in different use cases:
Tips for Creating Accessible SVG
From the above article:
<svg version="1.1" width="300" height="200" aria-labelledby="title desc">
<title id="title">Green rectangle</title>
<desc id="desc">A light green rectangle with rounded corners and a dark green border.</desc>
<rect width="75" height="50" rx="20" ry="20" fill="#90ee90" stroke="#228b22" stroke-fill="1" />
<text x="35" y="30" font-size="1em" text-anchor="middle" fill="#000000">Website</text>
</svg>

Is g id needed in SVG

This is a simple question but I can't find an answer that seems certain.
In an SVG where you'd see something like
<g id="Layer_3" data-name="Layer 3"><g id="Layer_3-1" data-name="Layer 1">
Is this something the SVG actually needs to have? They look the same when removed so I'm wondering if they're solely for identification?
No they are not required.
Even though if you are re-using same svg on a single page.
For example two SVG's with id="edit" it will cause ADA Compliance issue.

Display of SVG on Leaflet map

I have a moderately large SVG to be displayed as an overlay on a Leaflet map - it's basically a selection of roads from a road network. The leaflet map is instantiated with:
testMap = L.map('mapdiv', { renderer: L.svg({ padding: 100 }) })
.setView([33.085, -96.815], 11);
and the SVG layer is created with:
var imgUrl = url, imgBnds;
L.imageOverlay(imgUrl, imgBnds, {opacity:0.3}).addTo(testMap);
This all displays nicely when zoomed out, but when zooming in, the SVG gets tiled, and only the top-left tile is displayed even though this is not the area being shown in the map.
The SVG has the following:
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" xml:space="preserve"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" x="0" y="0" width="1920" height="767"
clip-path="url(#MapClipRectangle)" style="overflow:hidden;text-rendering:optimizeLegibility" xmlns="http://www.w3.org/2000/svg">
</desc>
<defs>
<clipPath clipPathUnits="userSpaceOnUse" id="MapClipRectangle">
<rect x="0" y="0" width="1920" height="767" />
</clipPath>
<symbol id="1" style="fill:none">
<path d="M985.96 476.76 l-0.26 0.06" />
<!-- ... Many Symbols and Paths, plus some Polygons, Text, Line_artwork, Map_decoration and a Map_frame... -->
And it ends up looking like this (example actually shows the top-left tile, but if I zoom in to the right, you don't actually see anything from the overlay SVG):
How do you stop/control this behaviour?
Sample SVG for which this behaviour occurs
I have not investigated this question in any depth, but in the interest of having some answer at all that might help:
It seems unusual to me that you want to use an svg for geospatial data like a road network.
If someone runs into a similar problem in the future, I would recommend, rather than trying to fix the svg rendering, convert the data to geojson which is more of a standard option for this sort of data display need and then style as needed using the options in leaflet.
To OP, did you ever find a solution?
As a note, it is not clear to me which part of the images posted are svg's vs which parts are basemap or other layers.

svg inside svg is rasterized causing blury results when scaling up

I'd like to embed an external SVG image file within an <svg> tag. To do this, i'm using SVG's <image> tag as follows:
<svg width="1000" height="1000"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<image x="0" y="0" width="48" height="48"
xlink:href="http://static.micahcarrick.com/media/images/autotools-tutorial/hello-world.svg"
transform="scale(5.0)" />
</svg>
As you can see, I'm trying to scale the nested SVG by 5.0 by adding a transform attribute. Unfortunately, in both Firefox and Chrome, I'm sometimes getting a blury image because it's rasterizing the nested SVG before scaling it up.
Note: It sometimes works as expected (The nested SVG stays crisp) in Firefox and Chrome, but not always (For example, if I open the attached JSFiddle in Chrome, it's blury/broken. If I press F5, it's crisp/working)
Is there any way to ensure that the nested SVG is never rasterized before scaling ?
Thanks :)
JSFiddle: http://jsfiddle.net/a9NRY/17/
This is a known bug in Chrome, caused by the fact that the image is cached. You can't fix this from your code, since it's a browser bug, but you could try to disable caching for that image on the server side.

Resources