Basic needs:
I am working on a Qt application that replaces colors in an svg.
A nice implementation is to parse the svg xml, and replace the colors as found with a good color match.
Unfortunately, the application must run on a platform with very limited speed and memory, and loading the svg into the QSvgRenderer from an xml (or text string) is extremely slow.
So - my current implementation is to string replace the occurrences of hex known colors in the QByteArray loaded by the renderer.
A big limitation - if I want to replace a fill color with a pen color, and they match, I end up with a broken blob.
A second limitation: I can only have 2 defined colors, a fill and a pen.
What I would like:
I want to be able to create a "parameterized" svg, where I can replace "color1", "color2", "color3" defined at the top, with whatever colors the user chooses.
Note - the svg has to be loaded by the QSvgRenderer, so the parameter values can't be in an outside html or js.
The svg must be self-contained... with no outside caller requirement.
But I can replace in code the parameter value before load.
I just want to be able to replace parameters in a single location, instead of actual values inside the xml everywhere they occur.
What I have tried:
I have read in the svg documentation that it is possible to create parameterized values. This is from an example, as much as I understand it...
w3.org example
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 110 40" width="100%" height="100%">
<title>Reusable Button</title>
<desc>Takes parameters from parent document's embedding element.</desc>
<defs>
<ref id="paramFill" param="color" default="blue"/>
<ref id="paramText" param="text-label">button</ref>
<ref id="paramStroke" param="outline" default="navy"/>
</defs>
<g>
<rect id="button_rect" x="5" y="5" width="100" height="30" rx="15" ry="15" fill="url(#paramFill)" stroke="url(#paramStroke)" />
<text id="button_label" x="55" y="30" text-anchor="middle" font-size="25" fill="black" font-family="Verdana">
<tref xlink:href="#paramText" />
</text>
</g>
</svg>
Unfortunately Qt doesn't load it and browsers show as error.
Second example: from S.O: Define color in SVG
<?xml version="1.0"?>
<svg width="704" height="702" xmlns="http://www.w3.org/2000/svg">
<style>
.myfill { fill:red }
</style>
<g fill="blue">
<rect x="0" y="0" width="704" height="702" class="myfill" />
</g>
</svg>
This loads in browser correctly as red, but Qt loads it with blue - so clearly it does not support the parameter value.
Is there any possible version of svg that uses parameters, that can be supported by Qt ?
Can somebody please help fix either of my examples or give a correct / better example ?
Thank you.
Qt version: 4.8
A long, long time ago, when some SVG renderers did not support style sheets, I solved this with XML entities:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY red "#ff0000">
]>
<svg width="704" height="702" xmlns="http://www.w3.org/2000/svg">
<g fill="blue">
<rect x="0" y="0" width="704" height="702" fill="&red;" />
</g>
</svg>
Related
Is there a way pass some data to a svg file when it's being used as background image. For example with something like this:
background-image:url("mysvg.svg?myparam=red")
and in mysvg.svg receive red from myparam parameter?
I've seen Parameter Variables in SVG but it seems require use of <object> in html, so just adding into svg
<defs>
<ref id="myparam" param="myparam" default="blue"/>
</defs>
<rect x="5" y="5" width="100" height="30" rx="15" ry="15" fill="url(#myparam)" />
doesn't work and I'm trying to avoid use any kind of inline-html inside CSS if all possible.
I am trying to make an svg that will be read in a QGraphicsSvgItem. I read some documentation, and it seems this is what I want:
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 14.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 43363) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="100px" height="100px" viewBox="0 0 100 100" enable-background="new 0 0 100 100"
xml:space="preserve">
<rect fill="#437624" stroke="none" fill-opacity="1" x="0" y="0" width="100" height="100" />
<text y="50" transform="translate(50)">
<tspan x="0" text-anchor="middle">No</tspan>
<tspan x="0" text-anchor="middle" dy="15">Arrow</tspan>
</text>
</svg>
This creates a rectangle - and a multi-line text centered inside:
This is what it looks like in the browser.
In Qt though, when loaded in QGraphicsSvgItem, it looks like this:
I imagine that something is not supported by the Qt SVG renderer...
Even worse, setting the font size makes my Qt text completely disappear:
<text y="40" font-size="24" transform="translate(50)">
<tspan x="0" text-anchor="middle">No</tspan>
<tspan x="0" text-anchor="middle" dy="30">Arrow</tspan>
</text>
How can I make Qt get a multi-line centered text, as the first image, from the svg (what should I put in the SVG) ?
(Qt 4.7 to 5.5...)
Edit:
This worked (but still can't figure out how to do multi-line other than determining individual items)
<text x="0" y="40" font-size="24" transform="translate(50)" text-anchor="middle">No</text>
<text x="0" y="70" font-size="24" transform="translate(50)" text-anchor="middle">Arrow</text>
I find it puzzling that even copying svgs from tutorials, any svgs that contain tspan render correctly in browser but don't show in QGraphicsSvgItem - or perhaps they do but in a complete different location.
I believe the answer to your question is in the documentation for both QGraphicsSvg and the standard SVG Tiny 1.2.
Your library only support SVG Tiny and not the full SVG specification and while SVG Tiny does support "tspan", it also states this:
"positional attributes such as 'x', 'y', and 'rotate' are not available on 'tspan' in SVG Tiny 1.2."
See SVG Tiny 1.2: https://www.w3.org/TR/SVGTiny12/text.html#TSpanElement
See also Does QT support svg?
Background
I have a set of SVG icons that all have drop shadows. To make this work in Chrome, I can't just use filter:drop-shadow. I have to use filter:url(#drop-shadow), and define the drop shadow in my <defs> section.
I also have multiple instances of these icons on the page (they are filetype icons in a list of files), so I am using <use> to keep my page DRY.
Code
Exernal SVG File
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
<defs>
<filter id="drop-shadow">
<feGaussianBlur xmlns="http://www.w3.org/2000/svg" in="SourceAlpha" stdDeviation="4"/>
..... more filter lines, shortened for brevity
</filter>
</defs>
<symbol id="download-pdf">
<path filter="url(#drop-shadow)" d="" fill="">...</path>
</symbol>
<symbol id="download-zip">
..... another icon
</symbol>
... more icons
</svg>
Inline SVG on the Page
<svg>
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="URL_OF_EXTERNAL_SVG"></use>
</svg>
See minimal working example here: http://h.andymercer.net/chrome-svg-bug/
Problem
The problem is that Chrome isn't finding the #drop-shadow link, and so is breaking the icons. Firefox, conversely, displays the icons perfectly.
Firefox:
Chrome:
If you notice, the Chrome screenshot DOES show some portion of the icon. It is displaying the portions that don't use the drop shadow filter.
I can't figure out why this is, because the drop shadow is in the <defs> that is on the same page as the <symbol>.
Question
Is there something I am missing, or is this a Chrome bug?
Edit
Per comments, I was asked for a MCVE. I hadn't done that because the problem inherently requires external URLs, which is typically frowned upon here. However, to demonstrate the problem, take a look at this:
http://h.andymercer.net/chrome-svg-bug/
In Firefox, you can see the icon. In Chrome, it is blank.
In Chrome, <defs> must be located inside the same <svg>.
In your case:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
<defs>
<filter id="drop-shadow">
<feGaussianBlur xmlns="http://www.w3.org/2000/svg" in="SourceAlpha" stdDeviation="4"/>
</filter>
</defs>
<symbol id="download-pdf">
<path filter="url(#drop-shadow)" d="" fill="">...</path>
</symbol>
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#download-pdf"></use>
</svg>
Conforming to modern browsers capabilities, it's easier and cleaner to create different external svg files, one for each icon, then embed them using <object> or <img> tags.
<object> lets javascript access and modify SVG code via DOM, while <img> embed SVGs denying DOM access to them. So, in your case using <img> should be a better choice.
I have easily made a mask with a PNG (black circle, transparent background) and using -webkit-mask-image:url(images/mask.png) for browsers like chrome. But i am having serious issues getting the mask to show in Firefox using SVG
<svg>
<defs>
<mask id="mask" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse">
<image width="78px" height="78px" xlink:href="images/mask.png"/>
</mask>
</defs>
<foreignObject width="78px" height="78px" style="mask: url(#mask);">
<img src="images/avatar-sample.jpg" />
</foreignObject>
</svg>
I really cannot see why this isn't working!
According to http://www.w3.org/TR/SVG/propidx.html you can apply a mask to container elements and graphics elements. Unfortunately <foreignObject> is in neither of these lists so the correct rendering for that element is to ignore the mask property. IE and Firefox are therefore correct in their rendering of this example.
Because IE does not understand the "foreign" object, you have to work around it with javascript and check if you can support it, if so inject it in, and if not avoid it. then you have to use IE's built in color filters to create your own chromakey effect specifically for IE. this site below shows you how to do it with examples.
http://thenittygritty.co/css-masking
You could rewrite your svg like this to make it work in all svg-supporting browsers:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<mask id="mask" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse">
<image width="78" height="78" xlink:href="images/mask.png"/>
</mask>
</defs>
<image xlink:href="images/avatar-sample.jpg" width="78" height="78"/>
</svg>
What are the cons to using SVG in terms of validation, accessibility, and maintainability for CMS-based websites?
In a project I need to make the Navigation fluid scalable without losing the quality of text and gradient. and it's not possible with HTML, CSS only.
A button like this:
So I found this example (although it's not exactly like what I want).
but it's not valid:
This button was made by SVG code-- no HTML and CSS here.
SVG Code:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="100%" height="100%" viewBox="0 0 480 360"
xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="button_surface" gradientUnits="objectBoundingBox"
x1="1" x2="1" y1="0" y2="1">
<stop stop-color="#434343" offset="0"/>
<stop stop-color="#000000" offset="0.67"/>
</linearGradient>
<linearGradient id="virtual_light" gradientUnits="objectBoundingBox"
x1="0" x2="0" y1="0" y2="1">
<stop stop-color="#EEEEEE" offset="0" stop-opacity="1"/>
<stop stop-color="#EEEEEE" offset="0.4" stop-opacity="0"/>
</linearGradient>
</defs>
<!-- button content -->
<rect x="10" y="10" rx="15" ry="15" width="150" height="80"
fill="url(#button_surface)" stroke="#363636"/>
<text x="30" y="55" fill="white"
font-family="Tahoma" font-size="20" font-weight="500">
SVG Button
</text>
<!-- vitual lighting effect -->
<rect x="12" y="12" rx="15" ry="15" width="146" height="76"
fill="url(#virtual_light)" stroke="#FFFFFF" stroke-opacity="0.4"/>
</svg>
My question arose because this website will be made using WordPress. What are the disadvantages to using SVG code over HTML, CSS, and JavaScript?
Edit: I found this article on Microsoft's Website, which says SVG is better than Canvas to make UI Elements because of less UI code.
The biggest problem you'll have is browser compatibility. If you need to support older versions of IE (and most public web sites will need to) then you can't use SVG without resorting to Javascript hacks because the browser doesn't support it.
In addition, SVG isn't supported in the Android browser prior to version 3.0, which currently accounts for virtually all Android mobiles out there apart from a few tablets. If you need to support these, then again SVG isn't the solution.
If you're okay with not supporting those browsers (or if you can work out a fall-back solution) then go for it.
In terms of maintainability, I recommend creating your button using a vector graphic editor that can export to SVG. It will be a lot easier to maintain if you have a source file which you can edit in a graphical environment than if you are trying to edit the SVG markup directly.
In terms of validation, the reason you're getting errors is because of the way you're embedding the SVG into your HTML. You shouldn't be defining an XML header for the SVG when it's embedded like this, be cause an XML header should only ever appear as the first line of an XML document.
If the whole document is XML (ie xhtml) then you need to put the namespace definitions for both xhtml and SVG at the top of the document. If the document is non-XML (ie plain HTML), then you don't need the XML declaration at all.
The following will work in all browsers that support embedded SVG:
<html>
<head>...</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
....svg content here....
</svg>
</body>
</html>
This should solve your validation issues.
If the SVG is to be loaded from an an external file, then it should include the XML declaraion.