Skip to content

Commit

Permalink
feat(svg): Added support for SvgImageSource on Wasm
Browse files Browse the repository at this point in the history
  • Loading branch information
carldebilly committed Nov 22, 2020
1 parent 2ff2133 commit 26c0b06
Show file tree
Hide file tree
Showing 23 changed files with 461 additions and 171 deletions.
11 changes: 8 additions & 3 deletions doc/articles/features/working-with-assets.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,14 @@ For most other assets, Uno.UI uses custom build tasks to lets you include assets

At the moment, only the following image file types are supported:

- `.png`
- `.jpg` or `.jpeg`
- `.gif`
| | .bmp (Win BMP) | .gif | .heic (Apple) | .jpg & .jpeg (JFIF) | .png | .webp | .pdf | .svg |
| ----------- | -------------- | ---- | ------------- | ------------------- | ---- | ----- | ---- | ---- |
| Windows UWP | ✔️ | ✔️ | | ✔️ | ✔️ | ✔️ || ✔️ |
| Android 10 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| iOS 13 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ ||||
| macOS | ✔️ | ✔️ | | ✔️ | ✔️ | | | |
| Wasm | ✔️ | ✔️ | | ✔️ | ✔️ | ✔️ || ✔️ |
| Skia WPF | ✔️ | ✔️ | | ✔️ | ✔️ | ✔️ |||

## Adding an asset to your project

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,11 @@
#pragma warning disable 114 // new keyword hiding
namespace Windows.UI.Xaml.Media.Imaging
{
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
#if false || false || false || false || false || false || false
[global::Uno.NotImplemented]
#endif
public partial class SvgImageSource : global::Windows.UI.Xaml.Media.ImageSource
{
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public global::System.Uri UriSource
{
get
{
return (global::System.Uri)this.GetValue(UriSourceProperty);
}
set
{
this.SetValue(UriSourceProperty, value);
}
}
#endif
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public double RasterizePixelWidth
Expand Down Expand Up @@ -65,24 +51,16 @@ public double RasterizePixelHeight
typeof(global::Windows.UI.Xaml.Media.Imaging.SvgImageSource),
new FrameworkPropertyMetadata(default(double)));
#endif
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public static global::Windows.UI.Xaml.DependencyProperty UriSourceProperty { get; } =
Windows.UI.Xaml.DependencyProperty.Register(
nameof(UriSource), typeof(global::System.Uri),
typeof(global::Windows.UI.Xaml.Media.Imaging.SvgImageSource),
new FrameworkPropertyMetadata(default(global::System.Uri)));
#endif
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public SvgImageSource()
{
global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.UI.Xaml.Media.Imaging.SvgImageSource", "SvgImageSource.SvgImageSource()");
}
#endif
// Skipping already declared property UriSource
// Skipping already declared property RasterizePixelWidth
// Skipping already declared property RasterizePixelHeight
// Skipping already declared property RasterizePixelHeightProperty
// Skipping already declared property RasterizePixelWidthProperty
// Skipping already declared property UriSourceProperty
// Skipping already declared method Windows.UI.Xaml.Media.Imaging.SvgImageSource.SvgImageSource()
// Forced skipping of method Windows.UI.Xaml.Media.Imaging.SvgImageSource.SvgImageSource()
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
#if false || false || false || false || false || __NETSTD_REFERENCE__ || false
[global::Uno.NotImplemented("__NETSTD_REFERENCE__")]
public SvgImageSource( global::System.Uri uriSource)
{
global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.UI.Xaml.Media.Imaging.SvgImageSource", "SvgImageSource.SvgImageSource(Uri uriSource)");
Expand All @@ -99,47 +77,11 @@ public SvgImageSource( global::System.Uri uriSource)
// Forced skipping of method Windows.UI.Xaml.Media.Imaging.SvgImageSource.Opened.remove
// Forced skipping of method Windows.UI.Xaml.Media.Imaging.SvgImageSource.OpenFailed.add
// Forced skipping of method Windows.UI.Xaml.Media.Imaging.SvgImageSource.OpenFailed.remove
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public global::Windows.Foundation.IAsyncOperation<global::Windows.UI.Xaml.Media.Imaging.SvgImageSourceLoadStatus> SetSourceAsync( global::Windows.Storage.Streams.IRandomAccessStream streamSource)
{
throw new global::System.NotImplementedException("The member IAsyncOperation<SvgImageSourceLoadStatus> SvgImageSource.SetSourceAsync(IRandomAccessStream streamSource) is not implemented in Uno.");
}
#endif
// Skipping already declared method Windows.UI.Xaml.Media.Imaging.SvgImageSource.SetSourceAsync(Windows.Storage.Streams.IRandomAccessStream)
// Forced skipping of method Windows.UI.Xaml.Media.Imaging.SvgImageSource.UriSourceProperty.get
// Forced skipping of method Windows.UI.Xaml.Media.Imaging.SvgImageSource.RasterizePixelWidthProperty.get
// Forced skipping of method Windows.UI.Xaml.Media.Imaging.SvgImageSource.RasterizePixelHeightProperty.get
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public event global::Windows.Foundation.TypedEventHandler<global::Windows.UI.Xaml.Media.Imaging.SvgImageSource, global::Windows.UI.Xaml.Media.Imaging.SvgImageSourceFailedEventArgs> OpenFailed
{
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
add
{
global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.UI.Xaml.Media.Imaging.SvgImageSource", "event TypedEventHandler<SvgImageSource, SvgImageSourceFailedEventArgs> SvgImageSource.OpenFailed");
}
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
remove
{
global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.UI.Xaml.Media.Imaging.SvgImageSource", "event TypedEventHandler<SvgImageSource, SvgImageSourceFailedEventArgs> SvgImageSource.OpenFailed");
}
}
#endif
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public event global::Windows.Foundation.TypedEventHandler<global::Windows.UI.Xaml.Media.Imaging.SvgImageSource, global::Windows.UI.Xaml.Media.Imaging.SvgImageSourceOpenedEventArgs> Opened
{
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
add
{
global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.UI.Xaml.Media.Imaging.SvgImageSource", "event TypedEventHandler<SvgImageSource, SvgImageSourceOpenedEventArgs> SvgImageSource.Opened");
}
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
remove
{
global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.UI.Xaml.Media.Imaging.SvgImageSource", "event TypedEventHandler<SvgImageSource, SvgImageSourceOpenedEventArgs> SvgImageSource.Opened");
}
}
#endif
// Skipping already declared event Windows.UI.Xaml.Media.Imaging.SvgImageSource.OpenFailed
// Skipping already declared event Windows.UI.Xaml.Media.Imaging.SvgImageSource.Opened
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,12 @@
#pragma warning disable 114 // new keyword hiding
namespace Windows.UI.Xaml.Media.Imaging
{
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
#if false || false || false || false || false || false || false
[global::Uno.NotImplemented]
#endif
public partial class SvgImageSourceFailedEventArgs
{
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public global::Windows.UI.Xaml.Media.Imaging.SvgImageSourceLoadStatus Status
{
get
{
throw new global::System.NotImplementedException("The member SvgImageSourceLoadStatus SvgImageSourceFailedEventArgs.Status is not implemented in Uno.");
}
}
#endif
// Skipping already declared property Status
// Forced skipping of method Windows.UI.Xaml.Media.Imaging.SvgImageSourceFailedEventArgs.Status.get
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,16 @@
#pragma warning disable 114 // new keyword hiding
namespace Windows.UI.Xaml.Media.Imaging
{
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
#if false || false || false || false || false || false || false
#if false || false || false || false || false || false || false
[global::Uno.NotImplemented]
#endif
public enum SvgImageSourceLoadStatus
{
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
Success,
#endif
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
NetworkError,
#endif
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
InvalidFormat,
#endif
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
Other,
#endif
// Skipping already declared field Windows.UI.Xaml.Media.Imaging.SvgImageSourceLoadStatus.Success
// Skipping already declared field Windows.UI.Xaml.Media.Imaging.SvgImageSourceLoadStatus.NetworkError
// Skipping already declared field Windows.UI.Xaml.Media.Imaging.SvgImageSourceLoadStatus.InvalidFormat
// Skipping already declared field Windows.UI.Xaml.Media.Imaging.SvgImageSourceLoadStatus.Other
}
#endif
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#pragma warning disable 114 // new keyword hiding
namespace Windows.UI.Xaml.Media.Imaging
{
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
#if false || false || false || false || false || false || false
[global::Uno.NotImplemented]
#endif
public partial class SvgImageSourceOpenedEventArgs
Expand Down
6 changes: 4 additions & 2 deletions src/Uno.UI/UI/Xaml/Controls/Image/Image.wasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ private ExceptionRoutedEventArgs ImageFailedConverter(object sender, string e)
_htmlImage.SetAttribute("src", "");
break;
case ImageDataKind.Base64:
case ImageDataKind.DataUri:
case ImageDataKind.Url:
default:
if (MonochromeColor != null)
Expand All @@ -108,13 +108,15 @@ private ExceptionRoutedEventArgs ImageFailedConverter(object sender, string e)
}
else
{
Console.WriteLine($"Setting img src to {img.Value}");
_htmlImage.SetAttribute("src", img.Value);
}
break;
case ImageDataKind.Error:
_htmlImage.SetAttribute("src", "");
_htmlImage.InternalDispatchEvent("error", EventArgs.Empty);
var errorArgs = new ExceptionRoutedEventArgs(this, img.Error?.ToString());
_htmlImage.InternalDispatchEvent("error", errorArgs);
break;
}
});
Expand Down
2 changes: 1 addition & 1 deletion src/Uno.UI/UI/Xaml/FrameworkElement.Interface.wasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ private protected void SetAndObserveBackgroundBrush(Brush brush)
ResetStyle("background-color", "background-image", "background-size");
break;
case ImageDataKind.Base64:
case ImageDataKind.DataUri:
case ImageDataKind.Url:
default:
SetStyle(
Expand Down
61 changes: 60 additions & 1 deletion src/Uno.UI/UI/Xaml/Media/ImageBrush.wasm.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using Windows.Foundation;
using System;
using Windows.Foundation;
using Windows.UI.Xaml.Wasm;
using NotImplementedException = System.NotImplementedException;

namespace Windows.UI.Xaml.Media
{
Expand Down Expand Up @@ -35,5 +38,61 @@ internal string ToCssBackgroundSize()
_ => "auto"
};
}

internal (UIElement defElement, IDisposable subscription) ToSvgElement()
{
var pattern = new SvgElement("pattern");

var alignX = AlignmentX switch
{
AlignmentX.Left => "xMin",
AlignmentX.Center => "xMid",
AlignmentX.Right => "xMax",
_ => ""
};
var alignY = AlignmentY switch
{
AlignmentY.Top => "yMin",
AlignmentY.Center => "yMid",
AlignmentY.Bottom => "yMax",
_ => ""
};

var preserveAspectRatio = Stretch switch
{
Stretch.Fill => "none",
Stretch.None => "",
Stretch.Uniform => "meet",
Stretch.UniformToFill => "slice",
_ => "",
};

pattern.SetAttribute(
("x", "0"),
("y", "0"),
("width", "1"),
("height", "1"),
("preserveAspectRatio", alignX + alignY + " " + preserveAspectRatio));

var source = ImageSource;

var subscription = source?.Subscribe(OnImageData);

void OnImageData(ImageData data)
{
switch (data.Kind)
{
case ImageDataKind.Empty:
pattern.SetHtmlContent("");
break;
case ImageDataKind.DataUri:
case ImageDataKind.Url:
pattern.SetHtmlContent($"<image xlink:href=\"{data.Value}\" />");
break;
}
}

return (pattern, subscription);
}
}
}
7 changes: 7 additions & 0 deletions src/Uno.UI/UI/Xaml/Media/ImageData.netstd.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,12 @@ internal partial struct ImageData
#elif __SKIA__
public SkiaCompositionSurface Value { get; set; }
#endif
public override string ToString() =>
Kind switch
{
ImageDataKind.Empty => "Empty",
ImageDataKind.Error => $"Error[{Error}]",
_ => $"{Kind}: {Value}"
};
}
}
8 changes: 6 additions & 2 deletions src/Uno.UI/UI/Xaml/Media/ImageDataKind.netstd.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,16 @@ internal enum ImageDataKind
/// </summary>
Empty,

/// <summary>
/// An Url (usually http: or https:)
/// </summary>
Url,

/// <summary>
/// A base64 encoded image
/// A data: data payload encoded in the url itself. Usually using base64.
/// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs
/// </summary>
Base64,
DataUri,

/// <summary>
/// The image failed to load (cf. The Error property)
Expand Down
23 changes: 8 additions & 15 deletions src/Uno.UI/UI/Xaml/Media/ImageSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ private void InitializeDownloader()
Downloader = DefaultDownloader;
}

#if !(__NETSTD__)
internal Stream Stream { get; set; }
#endif

internal string FilePath { get; private set; }

Expand Down Expand Up @@ -125,31 +127,22 @@ private void InitFromFile(string filePath)

partial void InitFromResource(Uri uri);

static public implicit operator ImageSource(string url)
public static implicit operator ImageSource(string url)
{
//This check is done in order to force a null to return if a empty string is passed.
if (url.IsNullOrWhiteSpace())
{
return null;
}
return new BitmapImage(url);
return url.IsNullOrWhiteSpace() ? null : new BitmapImage(url);
}

static public implicit operator ImageSource(Uri uri)
{
return new BitmapImage(uri);
}
public static implicit operator ImageSource(Uri uri) => new BitmapImage(uri);

static public implicit operator ImageSource(Stream stream)
public static implicit operator ImageSource(Stream stream)
{
throw new NotSupportedException("Implicit conversion from Stream to ImageSource is not supported");
}

partial void DisposePartial();
public void Dispose()
{
DisposePartial();
}

public void Dispose() => DisposePartial();

/// <summary>
/// Downloads an image from the provided Uri.
Expand Down
Loading

0 comments on commit 26c0b06

Please sign in to comment.