Merge pull request #143 from microsoft/inlineData

Add support for image inline data
This commit is contained in:
Alexander Sklar 2021-10-21 20:04:42 -07:00 коммит произвёл GitHub
Родитель 4d46dc3309 00d53fc59a
Коммит a77916b50e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 110 добавлений и 35 удалений

Просмотреть файл

@ -76,13 +76,20 @@ If you have questions about a scenario you don't see below, please [file an issu
## Image
- For Image, note that you should specify its size so that RN reserves space for it, otherwise the image won't show.
- Supports Bitmap images and SVG files.
- Supports Bitmap images and SVG files URIs, as well as inline Base64-encoded data:
```jsx
<Image source="https://microsoft.github.io/react-native-windows/img/homepage/cross-platform.png"
width={200} height={100} />
```
```jsx
<Image
source="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4gPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyOCAyOCIgZmlsbD0ibm9uZSI+PHBhdGggZD0iTTEzLjEyNSAwSDBWMTMuMTI1SDEzLjEyNVYwWiIgZmlsbD0iI0YyNTAyMiI+PC9wYXRoPjxwYXRoIGQ9Ik0yOCAwSDE0Ljg3NVYxMy4xMjVIMjhWMFoiIGZpbGw9IiM3RkJBMDAiPjwvcGF0aD48cGF0aCBkPSJNMTMuMTI1IDE0Ljg3NUgwVjI4SDEzLjEyNVYxNC44NzVaIiBmaWxsPSIjMDBBNEVGIj48L3BhdGg+PHBhdGggZD0iTTI4IDE0Ljg3NUgxNC44NzVWMjhIMjhWMTQuODc1WiIgZmlsbD0iI0ZGQjkwMCI+PC9wYXRoPjwvc3ZnPiA="
width={80}
height={80} />
```
## ComboBox
```jsx

Просмотреть файл

@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Support SVG and PNG inline data",
"packageName": "react-native-xaml",
"email": "asklar@microsoft.com",
"dependentChangeType": "patch"
}

Просмотреть файл

@ -19,9 +19,11 @@
#include "Styling.h"
#include <winrt/Windows.Storage.Streams.h>
#include <winrt/Windows.Security.Cryptography.h>
namespace jsi = facebook::jsi;
using namespace winrt;
using namespace winrt::Microsoft::ReactNative;
#define MAKE_GET_DP(type, prop) IsType<type>, []() { return type::prop(); }
@ -323,4 +325,50 @@ void XamlMetadata::PopulateNativeProps(std::vector<std::string>& names, const wi
auto cn = winrt::get_class_name(rea);
auto trea = rea.try_as<xaml::Input::TappedRoutedEventArgs>();
}
}
winrt::IAsyncOperation<winrt::Windows::Storage::Streams::InMemoryRandomAccessStream> GetImageInlineDataAsync(const std::string& uri) {
size_t start = uri.find(',');
if (start == std::string::npos || start + 1 > uri.length())
co_return nullptr;
try {
co_await winrt::resume_background();
std::string_view base64String(uri.c_str() + start + 1, uri.length() - start - 1);
auto buffer =
winrt::Windows::Security::Cryptography::CryptographicBuffer::DecodeFromBase64String(winrt::to_hstring(base64String));
winrt::Windows::Storage::Streams::InMemoryRandomAccessStream memoryStream;
auto b = memoryStream.CanWrite();
co_await memoryStream.WriteAsync(buffer);
memoryStream.Seek(0);
co_return memoryStream;
}
catch (winrt::hresult_error const&) {
// Base64 decode failed
}
co_return nullptr;
}
winrt::fire_and_forget winrt::Microsoft::ReactNative::SetImageSourceForInlineData(std::string str, xaml::DependencyObject o, xaml::DependencyProperty dp) {
// inline data
const auto streamOp = GetImageInlineDataAsync(str);
auto stream = co_await streamOp;
xaml::Media::ImageSource source{ nullptr };
if (str.find("image/svg+xml;base64") != std::string::npos) {
auto src = xaml::Media::Imaging::SvgImageSource();
co_await src.SetSourceAsync(stream);
source = src;
}
else if (str.find("image/png;base64") != std::string::npos) {
auto src = xaml::Media::Imaging::BitmapImage();
co_await src.SetSourceAsync(stream);
source = src;
}
o.SetValue(dp, source);
}

Просмотреть файл

@ -15,7 +15,6 @@
#include "XamlObject.h"
#include <Wrapper.h>
using namespace xaml;
using namespace xaml::Controls;
using namespace winrt::Microsoft::ReactNative;
@ -37,13 +36,55 @@ namespace winrt::Microsoft::ReactNative {
value = xaml::Media::FontFamily(str);
}
inline void ReadValue(JSValue const& jsValue, xaml::Media::ImageSource& value) noexcept {
const auto uri = Uri{ winrt::to_hstring(jsValue.AsString()) };
if (jsValue.AsJSString().ends_with(".svg")) {
value = xaml::Media::Imaging::SvgImageSource {uri};
winrt::fire_and_forget SetImageSourceForInlineData(std::string str, xaml::DependencyObject o, xaml::DependencyProperty dp);
enum class XamlPropType {
Boolean,
Int,
Double,
String,
Object,
Enum,
};
template <typename T> bool IsType(const winrt::Windows::Foundation::IInspectable& i) { return i.try_as<T>() != nullptr; }
template<typename T, std::enable_if_t<std::is_enum<T>::value, int> = 0>
void SetPropValue(const xaml::DependencyObject o, const xaml::DependencyProperty& prop, const winrt::Microsoft::ReactNative::JSValue& v, const winrt::Microsoft::ReactNative::IReactContext&) {
auto valueEnum = MakeEnum<T>(v.AsInt32());
o.SetValue(prop, valueEnum);
}
template<typename T, std::enable_if_t<
!std::is_enum<T>::value &&
!std::is_same<winrt::hstring, T>::value &&
!std::is_same<winrt::Windows::Foundation::IInspectable, T>::value &&
!std::is_same<winrt::Windows::Foundation::Uri, T>::value &&
!std::is_same<xaml::Media::ImageSource, T>::value
, int> = 0>
void SetPropValue(const xaml::DependencyObject& o, const xaml::DependencyProperty& prop, const winrt::Microsoft::ReactNative::JSValue& v, const winrt::Microsoft::ReactNative::IReactContext&) {
auto b = v.To<T>();
o.SetValue(prop, winrt::box_value(b));
}
template<typename T, std::enable_if_t<
std::is_same<xaml::Media::ImageSource, T>::value, int> = 0>
void SetPropValue(const xaml::DependencyObject& o, const xaml::DependencyProperty& prop, const winrt::Microsoft::ReactNative::JSValue& v, const winrt::Microsoft::ReactNative::IReactContext&) {
const auto str = v.AsString();
const auto uri = Uri{ winrt::to_hstring(str) };
xaml::Media::ImageSource value{ nullptr };
if (uri.SchemeName() == L"data") {
SetImageSourceForInlineData(str, o, prop);
}
else if (str.ends_with(".svg") || str.ends_with(".svgz")) {
value = xaml::Media::Imaging::SvgImageSource{ uri };
o.SetValue(prop, value);
}
else {
value = xaml::Media::Imaging::BitmapImage{ uri };
o.SetValue(prop, value);
}
}
@ -57,34 +98,6 @@ namespace winrt::Microsoft::ReactNative {
}
}
enum class XamlPropType {
Boolean,
Int,
Double,
String,
Object,
Enum,
};
template <typename T> bool IsType(const winrt::Windows::Foundation::IInspectable& i) { return i.try_as<T>() != nullptr; }
template<typename T, std::enable_if_t<std::is_enum<T>::value, int> = 0>
void SetPropValue(const xaml::DependencyObject o, const xaml::DependencyProperty& prop, const winrt::Microsoft::ReactNative::JSValue& v, const winrt::Microsoft::ReactNative::IReactContext&) {
auto valueEnum = MakeEnum<T>(v.AsInt32());
o.SetValue(prop, valueEnum);
}
template<typename T, std::enable_if_t<
!std::is_enum<T>::value &&
!std::is_same<winrt::hstring, T>::value &&
!std::is_same<winrt::Windows::Foundation::IInspectable, T>::value &&
!std::is_same<winrt::Windows::Foundation::Uri, T>::value
, int> = 0>
void SetPropValue(const xaml::DependencyObject& o, const xaml::DependencyProperty& prop, const winrt::Microsoft::ReactNative::JSValue& v, const winrt::Microsoft::ReactNative::IReactContext&) {
auto b = v.To<T>();
o.SetValue(prop, winrt::box_value(b));
}
// MapStyle has a bug where it expects the property to be set as an IReference<MapStyle> always, and does not support IReference<uint32_t>
template<typename T, std::enable_if_t<