Open Noemata opened 5 years ago
This sounds like #312 which was an OS bug that was fixed in Windows 1903. I don't know if you're able to try this out on that build to confirm?
FYI, on 1809 / 1903 without the margin tweak you get:
Where as the image in Inkscape is like so:
The SVG page dimensions are correctly adjusted to the image area in Inkscape, unlike the XAML above, which has an odd gap at the bottom. Also, if you apply horizontal/vertical centering, it doesn't behave correctly. Take any random, somewhat involved SVG image from virtually any source, and you'll most likely see this behavior with 1809 / 1903 and all previous OS releases that supported SVG. This bug has been around for quite some time now. Which means the regression testing is flawed either because it uses an extremely narrow range of SVG content, or the test cases do not test boxing at all.
Once this is fixed, you'll need to preserve the old bug, unfortunately. The consequence of not getting it right the first time.
If you open your SVG file in a text editor, you'll see the XML inside it -- does it contain any "weird" features? Unfortunately SVG was designed with a combination of reliable and unreliable features. For example, SVG files have the ability to contain embedded CSS (the CSS from HTML) -- a complex bad design.
For example, if your SVG file uses unreliable and unnecessary features like this...
<svg xmlns="http://www.w3.org/2000/svg" style="margin-left: calc(50% - 0.5em)" viewBox="0 0 1024 1024" width="1024" height="1024">
<g transform="scale(0.03125)">
<path d="..."/>
</g>
</svg>
Then it might help if you simplify the SVG by removing the unreliable features as follows:
<svg xmlns="http://www.w3.org/2000/svg">
<path d="..."/>
</svg>
SVG is great when you avoid using the optional unreliable features such as embedded CSS, etc. SVG2 contains even more features. If every SVG feature is supported, then it guaranteed to malfunction under certain circumstances in certain situations, because the design includes so much unnecessary complexity that nobody will ever be able to write a 100% bug-free implementation of the entire SVG and SVG2 specifications. But if you limit yourself to the reliable portions of the specifications, then it works.
@verelpode, thanks for the workaround suggestion. Given Microsoft is a top tier company, in this case I expect the SVG API's to either be identified as experimental or beta if they are in a half baked state, or they should support the SVG spec in full. The harsh reality of being in the top three OS tier is that expectations are appropriately high, thus you have to deliver on your API promise. IOS API's are more stable and conformant than equivalent UWP API's, so UWP suffers from a lack of adoption because of its stability and conformance gap. Lastly, if it works in Inksace (Open Source) and Adobe, it must work in UWP. If you don't support the output of commonly available tooling, what's the point? Imagine having to tweak an MS Word binary so it could load in some third party application. You would consider such a product as unusable, despite the fact that MS Word files have gone through many iterations in structure.
@Noemata, can you share an SVG file you're seeing this problem with?
Note that not all of SVG is currently supported, as documented here: https://docs.microsoft.com/en-us/windows/desktop/Direct2D/svg-support
@Noemata
The harsh reality ... expectations are appropriately high, thus you have to deliver on your API promise.
I agree except that unfortunately it is most likely impossible in the case of SVG. Asking for SVG to be 100% supported and compatible is like asking for all HTML web browsers to deliver 100% compatibility with each other, and to render exactly the same as each other. It should happen like you said, but in practice, it's never going to happen. SVG, SVG2, and HTML are not the kind of standards that can be 100% supported and compatible. To achieve 100%, a standard must exclude vague/unreliable features and it must be designed in a certain way, but SVG, SVG2, and HTML are not designed in such a way. I want what you said but it's impossible -- that's the harsh reality. Thus the workaround is to edit your SVG file and remove all usage of vague and unreliable features.
@verelpode, I do not expect more than 95% SVG spec conformance. I do expect 100% tooling conformance with products like Adobe/Inkscape which have been around for ages. If you can't load Inkscape SVGs, which provides the loader/parser source code then you aren't really trying to be conformant. The designer folks aren't programmers, so we can't expect them to be tweaking the output from the tooling they use. Again, what's the point, if you can't support the tooling that's out there? I'm pretty sure Microsoft can do at least as well as Inkscape. Microsoft's Expression Design was pretty darn good, still is and it's got a boatload of mothballed code. Oh, Visio SVG's don't load correctly either. If Visio can load an SVG (Inkscape or Adobe) correctly, the XAML SVG capability should be at least as good.
@Noemata OK, if you can share a particular SVG file, then we can look inside and see exactly what Inkscape produced, and get a clearer idea of why it's malfunctioning in your program, and see whether or not the problem lies in usage of unreliable or unsupported features or some other reason. (BTW, I'm just a fellow developer with interest in SVG in UWP apps, not a MS staff member.)
@verelpode, most SVG files fail to behave correctly, including output from Visio. If Microsoft get's all Visio and Inkscape SVG output to load correctly, I'll consider that good enough for now. This is not something I need to prove further since it's so easy to generate complex output from either Visio or Inkscape for test purposes. A simple box isn't a valid test case, obviously. There are also the SVG v x.x test suites, which Microsoft clearly isn't using for validation purposes. These test suites provide expected output to validate conformance. Sorry, but I mostly disagree with your complexity premise @verelpode. Test suite conformance validation is available for the SVG spec, hence why I asked for Microsoft's test conformance strategy. Last but not least, Visio does better, and Microsoft can share this code with the XAML tooling folks. (https://www.w3.org/Graphics/SVG/WG/wiki/Test_Suite_Overview). Almost forgot, Microsoft Edge loads 99% of SVG content flawlessly.
(BTW, I'm just a fellow developer with interest in SVG in UWP apps, not a MS staff member.)
And thank you @verelpode for your help digging in on this issue! :)
@Noemata wrote:
This is not something I need to prove further
I wasn't expecting you to prove anything, rather I just hoped that you would make it easier for me to help you, especially because it's not my job to help you and I do have a bunch of other tasks that I need to complete. Out of interest, I'd like to try your example in Visual Studio and investigate deeper, but you haven't given the complete example. You've given the XAML but not the SVG. It'd help if you also give a specific SVG file that demonstrates the problem. Yes I could go and install Inkscape and make and test various SVG files myself, but that's extra work and it's not my job -- I'm just a volunteer with little spare time.
@jevansaks -- Thanks for the acknowledgement :)
@verelpode, since I have no expectation of you being able to resolve API bugs I would consider it unfair to burden you with trying to fix this.
But since you insist. I've stripped out the intermediate letters of the logo because I don't have permission to include the whole thing. The missing letters are immaterial to the result. I've also converted the logo to XAML in order to show how things should be rendered.
Here is the SVG content for ImajionLogo.svg:
`<?xml version="1.0" encoding="UTF-8" standalone="no"?>
` And here is the XAML: `Source code for sample:
@Noemata The problem appears to be far simpler than we thought, and unrelated to SVG. In your example, I replaced the SVG images with .JPG images and I observed that the behavior was identical regardless of whether I used .SVG or .JPG files, therefore SVG is a red herring.
Your XAML contains:
<Image Width="480" Height="300" Source="/Assets/ImajionLogo.svg" Stretch="Uniform" HorizontalAlignment="Left" Margin="14.5,-110,0,0" />
Thus your Image element is rendered as 300 pixels(DIP) high because the Height property is set to 300 -- yes, as simple as that.
Did I misunderstand you? I don't see any bug, rather the rendering that you've described is the correct rendering. In your earlier message, you wrote:
FYI, on 1809 / 1903 without the margin tweak you get:
Yes I get the same result as you, but it's not a bug. It's rendered correctly. Your Image element is set to Height="300" thus it consumes 300 pixels(DIP) vertically, regardless of the source image file, and regardless of whether it is .SVG, .JPG, or .PNG.
Thanks for all the discussion here and especially the help from @verelpode. It sounds like the problem is understood now. I'm closing this issue, but @Noemata please reactivate if you believe there's still a platform bug here.
I haven't got a clue what @verelpode is talking about. I provided a sample that demonstrates the problem. Had anyone actually looked at the source code provided in the link above, the problem would have been quite obvious.
Look at the code in the zip file and associated comments. I don't think I could have made this any easier to diagnose.
So, to emphasize the point, I've expanded on the obviousness of the problem some more.
How do we explain this output then (the png image renders as expected, not the SVG):
Link to code:
Sorry about that @Noemata, I'll see if i can get someone on the platform team to investigate what you're seeing. Just to clarify, what OS version are you running on? (you can run "winver" to see).
And if you remove the viewbox bit from the SVG, it renders, but then you have redraw issues.
So I guess there are multiple bugs to fix.
This is how things render with the "viewBox" part of the SVG markup taken out.
I'm a bit curious why there was such a rush to validate @verelpode? He was completely wrong. I was trying to be polite about it.
@Noemata I tried out your sample and agree that it's pretty clearly a platform bug, and you're right that it's the viewBox property in the SVG file. The docs do say that it should be supported so we'll have to debug why that's not working.
@verelpode was clearly just trying to help, and I apologize for not following this thread more closely.
If you (or anyone else) needs help in this repo with getting traction or getting an issue back on track, don't hesitate to @mention me on GitHub, send me email (you can find it in my GitHub profile) or DM me on twitter (https://twitter.com/jevansaks).
@jevansaks, thank you for acknowledging the issue at last. Hopefully the SVG parsing/rendering problems will be resolved soon. Having a working verions of this capability would be extremely useful.
I respectfully disagree with your assessment of @verelpode's "help". Had folks read what was provided here rather than ignoring the details, it would have been noticed from the outset that I had already found a workaround to the problem, so I didn't need help, what I was trying to do is help with the process of fixing a platform bug.
The highlighted viewBox documentation reference was no accident.
You got a pretty good sample that even included expected behavior. I suggest you re-evaluate how you evaluate and who you pay attention to and why.
@Noemata
I haven't got a clue what @verelpode is talking about.
Maybe this detail will help the understanding: In the XAML example in the very first message in this thread, your first Image element has:
Stretch="UniformToFill"
whereas your second Image element has:
Stretch="Uniform"
Did you realize that they have different Stretch
values and thus different behavior? I presumed that you mistakenly set these Image elements to different Stretch values, which then led to misunderstanding of the consequence of setting the Width and Height properties.
I downloaded the latest example and I see that the same mistake has again happened. The first Image element has Stretch="UniformToFill"
, and then you wrote "The above should behave precisely as what's below", but that's incorrect because the element below is Viewbox
with Stretch
unspecified meaning the default value meaning Uniform
. The default value of Stretch
is Uniform
not UniformToFill
.
Thus you have 2 elements, and you say that they should behave precisely the same as each other, but you've given them different values for the Stretch
property. An Image element does not behave the same as a Viewbox element when they have different values for the Stretch
property.
I was under the impression that the issue was placement behaviour because you wrote:
We encountered poor placement behaviour with many different SVG images.
In the first example, the placement behavior is the consequence of the values that you supplied for the Stretch, Width, and Height properties, and is the same regardless of whether the source image is SVG, PNG, or JPEG.
As far as I can see, the mistake lies in your XAML, not in the rendering, but admittedly there could be more to this story. I haven't fully investigated it today (no time), but this topic is a topic of interest for me, so I intend to investigate further when I get the chance.
if you remove the viewbox bit from the SVG, it renders
It's like I said in the beginning -- to make it work successfully, one must remove unnecessary stuff from the SVG file, in order to simplify the SVG file, in order to achieve a reliable unambiguous representation of a vector graphic. Not every SVG can be supported. But if the documentation says an element is supported and it isn't, then yes that needs to be fixed, either by updating the documentation or changing the code.
I suggest you re-evaluate how you evaluate and who you pay attention to and why.
I'm going to ignore that comment because I want to discuss software engineering rather than personality conflicts.
@jevansaks -- Hopefully you find it helpful that I've pointed out the difference in the usage of the Stretch
property, but I've had to rush this and can't spend more time on this topic today. I'm interested in investigating the effect of the SVG viewBox property but I'll have to wait until I find the time for it.
@verelpode, you are correct. I was playing around with different values and lost track that the code elements had become inconsistent. Sorry about that. Nonetheless, those specific details are not responsible for the SVG rendering problems.
Actually, I think I need to take that back (looking at code below):
`
I'd like to end this discussion here, please don't respond further @verelpode. Oh, and @verelpode is throwing other code examples into the mix which confuse the discussion given the sample provided was actually consistent. The ViewBox XAML variant was intended to simulate expected behavior, hence cannot be configured in an equivalent manner to the Image elements.
Quoting @jevansaks (the person best qualified to evaluate this):
"@Noemata I tried out your sample and agree that it's pretty clearly a platform bug, and you're right that it's the viewBox property in the SVG file. The docs do say that it should be supported so we'll have to debug why that's not working."
@Noemata Please Be respectful.
@verelpode calling out the possible difference in behavior being related to the Stretch mode is actually really helpful. It does appear that it is broken when Stretch="UniformToFill" but works when Stretch="Fill".
I still see a bug (weird stretching) when the Image is stretched beyond a certain threshold (1087 pixels), so you also have to set MaxWidth="1087" to avoid that. It's not obvious where 1087 comes from when the viewbox width is 1779. But this seems to work:
<Image Grid.Row="0" x:Name="SVGLogo" Source="/Assets/ImajionLogo.svg" Stretch="Fill" MaxWidth="1087"/>
@Noemata can you try this workaround?
Interesting, the proposed "workaround" is much closer to the expected behavior I provided with my ViewBox XAML approach.
Starts off being promising:
As the window scales the workaround mirrors my expected behavior:
And then this happens:
Yet another bug?
So it looks like @jevansaks has confirmed my expected behavior and the manner in which it was implemented was correct (thank you).
As for the specifics of the Stretch mode, I was expecting UniformToFill to maintain the aspect ratio as is done by the Image element approach.
@verelpode is correct, I was not consistent across samples in the way I set the Stretch mode.
Another test. Top is @jevansaks' workaround, middle is expected behavior done wiht XAML ViewBox, bottom is an bitmap (jpg) Image element (the pooch image was a bit confusing).
Everything starts off looking correct.
Scaling window horizontally.
Continued scaling of window horizontally.
At some critical point the workaround fails to render SVG correctly while the other two (bitmap Image and XAML path) continue to be correct. The outer bound MaxWidth limits the extent the workaround works?? I did try 8K for the MaxWidth and the render goes wonky at the same point, so I don't understand what the issue might be with the workaround.
I'm guessing it all comes down to an underlying bug with the way the SVG viewBox markup is handled.
The XAML Path approach and the bitmap Image wound up being exactly the same at all window widths provided you took care to create a bitmap image with a corresponding width.
I'm guessing it all comes down to an underlying bug with the way the SVG viewBox markup is handled.
Yes, and we'll continue to use this issue to track the bug(s) with viewBox that you've reported. Thanks for your persistence here!
@jevansaks, thank you for your patience with my machinations.
When you use the SVG viewBox
attribute, you need to also set the preserveAspectRatio
attribute. As I said, you need to stop using unreliable/unnecessary "features" of SVG. It's not your fault, rather it's the fault of the unnecessary complexity in the SVG specification. Unfortunately SVG defines the preserveAspectRatio
attribute with this default value:
preserveAspectRatio="xMidYMid meet"
Don't use that "feature" -- you need to change it to none
. Change your SVG file as follows, and then it will render in the manner that you expected it to render.
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1779 315" preserveAspectRatio="none">
In software engineering, it's necessary for you (anyone) to acknowledge the fact that you're not Superman. Nobody has superhuman abilities. Therefore unnecessary complexity needs to be removed, otherwise the product becomes incomprehensible and unreliable. It doesn't matter how smart a person is. Even the smartest person in the world trips up when the software contains an unnecessarily complex combination of features (and anyway, a "smartest person" doesn't exist in reality). Keep it simple. Simple is smart.
@jevansaks
It's not obvious where 1087 comes from when the viewbox width is 1779.
It comes from the initial size of the app window (the window size that can be changed by invoking Windows.UI.ViewManagement.ApplicationView.TryResizeView
). "Initial size" meaning the size of the app window before the XAML Image element is created, regardless of whether the user subsequently resizes the window. I've created an example to demonstrate how the window size influences the SVG rendering:
CroppedSvgExample.zip
To aid debugging, I've simplified this example by using Stretch="None"
, however the limit number (the 1087) still occurs but now in the form of an incorrect cropping based on window size. When the window size is smaller than the SVG image, the SVG image is cropped (ofcourse) but then it remains cropped even when the user resizes the window larger! Here's a screenshot showing the cropping bug:
Following is uncropped, produced by making the window larger by invoking TryResizeView(new Size(1000, 1000));
before displaying the SVG image.
The SVG image file is simply this:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="600" height="600" rx="20" style="fill:#f1ff43"/>
<circle cx="300" cy="300" r="292"/>
<circle cx="300" cy="300" r="150" style="fill:#f1cd43"/>
</svg>
As I mentioned in my previous message, a solution is to use preserveAspectRatio="none"
with viewBox
, however Windows still needs to render SVG files correctly in the case when viewBox
is not used, therefore it appears that a bug does exist in the rendering. In my example above, the rendering should be completely unaffected by the app window size, but it is cropped via the initial window size. Likewise the mysterious 1087 size came from the app window size, and this should not happen.
Even when all rendering bugs are fixed, I still highly recommend using preserveAspectRatio="none"
because otherwise an unnecessary and incomprehensible double manipulation of the aspect ratio occurs when the XAML Image element uses Stretch
and preserveAspectRatio
is anything other than none
(and unfortunately the default is not none
).
i.e. Noemata expected the SVG viewBox
to behave like when preserveAspectRatio="none"
, but none
is not the default value of preserveAspectRatio
, thus in any event, even after all rendering bugs are eliminated, he should use preserveAspectRatio="none"
when using viewBox
in order to get the result that he expected. However, Windows would be considerably friendlier if it would allow everyone to simply use SVG files that just begin with:
<svg xmlns="http://www.w3.org/2000/svg">
...without requiring the setting of any of the width, height, viewBox, preserveAspectRatio attributes.
For further reference, the cropping bug still occurs when the SVG file begins with any of these examples:
<svg xmlns="http://www.w3.org/2000/svg">
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
<svg xmlns="http://www.w3.org/2000/svg" width="600" height="600">
The cropping bug disappears if you use this:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600" preserveAspectRatio="none">
I don't have access to the SVG renderer source code, but if I did, I believe the first thing to do should be to look at how it ends up using the app window size in the rendering. To improve reliability, make it render entirely independently of the initial and current app window sizes. The app window size should be irrelevant.
I also suggest adding a note in the public documentation to say that if the SVG file uses the viewBox
attribute, then it is recommended to also set preserveAspectRatio="none"
otherwise the rendered result is not what people expect it to be.
preserveAspectRatio is not required when rendering SVG content in IE, it renders as expected, similarly with other 3rd party products that support SVG (Inkscape), so I suggest the default behavior on Windows should be that of IE as a minimal goal.
I agree with @Noemata. It shouldn't be necessary for people to edit their SVG files to insert preserveAspectRatio="none"
, therefore changes are needed in SvgImageSource
(or underlying Win2D). It might be necessary to make the SVG renderer violate the SVG specification deliberately, or let's say "ignore" rather than "violate". The solution might be to make the SVG renderer behave as if preserveAspectRatio="none"
regardless of whether preserveAspectRatio is explicitly specified in the SVG file, and regardless of any setting the SVG file specifies for preserveAspectRatio. Why? Because any value for preserveAspectRatio other than "none" causes behavior that doesn't suit the expected behavior of Windows.UI.Xaml.Controls.Image
and Image.Stretch
.
In other words, in order to make SvgImageSource
and Image.Stretch
reliable and user-friendly and NOT damn confusing and over-complicated, it may be necessary to override/force certain SVG "features" to off/none. As I mentioned, although SVG is great overall, some features in SVG shouldn't exist at all, therefore SvgImageSource
may need to ignore or disable those features, instead of trying to support them in a broken manner that confuses everyone.
Even if a software engineer is an absolute expert, it doesn't matter; sometimes a complicated feature is garbage that should be switched off or eliminated or simplified, regardless of whether it's used by beginners or experts.
Found another image the behaves strangely:
<Image Stretch="Uniform" Source="https://upload.wikimedia.org/wikipedia/commons/8/84/Example.svg"/>
It seems to clip itself when smaller and doesn't scale smoothly:
@michael-hawker It looks like that svg doesn't scale at all, which means it will clip if the XAML Image isn't given the full 600x600 space that svg is requesting. Some svg files can be fixed by changing the svg tag in the file to have width="auto" height="auto" preserveAspectRatio="xMinYMin meet", but those don't help here.
Thanks for the additional sample. XAML's svg handling clearly needs some work to automatically handle scaling without a bunch of custom hacks.
Rather than having a custom SVG renderer, implementing an SVG to XAML converter would be very useful. Then the SVG content could be leveraged in all sorts of ways beyond just displaying it. It would also increase the likelihood of having a fully XAML friendly implementation of SVG support.
Work like this has already been done for WPF.
Rather than having a custom SVG renderer, implementing an SVG to XAML converter would be very useful. Then the SVG content could be leveraged in all sorts of ways beyond just displaying it. It would also increase the likelihood of having a fully XAML friendly implementation of SVG support.
That'd be nice too, but would have to be on the designer pipeline export from whatever tool they're using without introducing a lot more overhead on a process stand-point.
It'd be nice though, as then it'd be easier to animate/manipulate graphics in storyboards and such.
The SVG renderer is clearly still broken, but I've had good luck with using Inkscape to save the files as XAML and using that in UWP, in case that helps anyone.
It might make more sense to have a special SVG mode for the browser control instead of having a specialized SVG renderer for XAML. @michael-hawker's idea of having tooling support is a good one, but we still need an SVG renderer in XAML. My UWP TV broadcasting app needs it bigtime! PDF and SVG rendering should have a native feel within XAML! SVG in particular.
Rather than having a custom SVG renderer, implementing an SVG to XAML converter would be very useful. Then the SVG content could be leveraged in all sorts of ways beyond just displaying it. It would also increase the likelihood of having a fully XAML friendly implementation of SVG support.
This is a viable workaround, but it's hardly a solution. XAML files generated from SVGs can't be used in other non-UWP apps, while SVG is [supposed] to be supported by all of them. A better solution would be to embed that conversion code into XAML's SVG 'parser'. That way, you can supply an SVG and it will be converted to XAML at runtime, rather than requiring devs to put together a second set of images/icons.
Rather than having a custom SVG renderer, implementing an SVG to XAML converter would be very useful. Then the SVG content could be leveraged in all sorts of ways beyond just displaying it. It would also increase the likelihood of having a fully XAML friendly implementation of SVG support.
This is a viable workaround, but it's hardly a solution. XAML files generated from SVGs can't be used in other non-UWP apps, while SVG is [supposed] to be supported by all of them. A better solution would be to embed that conversion code into XAML's SVG 'parser'. That way, you can supply an SVG and it will be converted to XAML at runtime, rather than requiring devs to put together a second set of images/icons.
"embed that conversion code into XAML's SVG 'parser'" is exactly what I had in mind, by the way.
I find UWP/.NET does not support styles and CSS like classes. Have you guys found an SVG optimizer that removes them and replace them with attributes? I've been getting SVGs from Illustrator, I modified them using Inkscape then passed them through SVGOMG then I needed to edit them to replace the remaining class attributes and remove the last styles. Not sure why they were not all removed by SVGO, maybe because SVGOMG is using an older version. Then it worked. Easy 🤣
XAML exports from Inkscape could not be loaded in my UWP project, it choked on that Figures attribute for some reason.
I find UWP/.NET does not support styles and CSS like classes. Have you guys found an SVG optimizer that removes them and replace them with attributes?
Actually Adobe Illustrator has an option to export SVGs without CSS styles.
This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 5 days.
WinUI 3 still has limited SVG support. This issue is still present and critical.
Changing to feature proposal
The image below below:
Is produced with the following XAML:
For the second SVG image, we're having to muck with Margin settings to get an approximation of the result we expect to get without such adjustments. The SVG image behaves correctly in every SVG editing tool we've tried, including all Adobe products, and Inkscape.
We encountered poor placement behaviour with many different SVG images. Occasionally, it almost works correctly, like the case with the first SVG image above, though adjusting centering has never worked as expected. Please provide an example of the test suite you use to qualify that this is working. We've never gotten proper placement to work as expected with anything but the simplest of SVG images.