-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
ImageExtensions.cs
172 lines (148 loc) · 5.13 KB
/
ImageExtensions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
using Gdk;
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Xamarin.Forms.Internals;
using Xamarin.Forms.Platform.GTK.Renderers;
namespace Xamarin.Forms.Platform.GTK.Extensions
{
public static class ImageExtensions
{
public static Pixbuf ToPixbuf(this ImageSource imagesource)
{
return ToPixbufAux(imagesource, null);
}
public static Pixbuf ToPixbuf(this ImageSource imagesource, Size size)
{
return ToPixbufAux(imagesource, size);
}
private static Pixbuf ToPixbufAux(this ImageSource imagesource, Size? size)
{
try
{
Pixbuf image = null;
var filesource = imagesource as FileImageSource;
if (filesource != null)
{
var file = filesource.File;
if (!string.IsNullOrEmpty(file))
{
var imagePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, file);
image = size.HasValue
? new Pixbuf(imagePath, (int)size.Value.Width, (int)size.Value.Height)
: new Pixbuf(imagePath);
}
}
return image;
}
catch
{
return null;
}
}
internal static async Task<Pixbuf> GetNativeImageAsync(this ImageSource imageSource, CancellationToken cancellationToken = default(CancellationToken))
{
if (imageSource == null || imageSource.IsEmpty)
return null;
var handler = Registrar.Registered.GetHandlerForObject<IImageSourceHandler>(imageSource);
if (handler == null)
return null;
try
{
return await handler.LoadImageAsync(imageSource, cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
Log.Warning("Image loading", "Image load cancelled");
}
catch (Exception ex)
{
Log.Warning("Image loading", $"Image load failed: {ex}");
}
return null;
}
internal static Task ApplyNativeImageAsync(this IVisualElementRenderer renderer, BindableProperty imageSourceProperty, Action<Pixbuf> onSet, Action<bool> onLoading = null, CancellationToken cancellationToken = default(CancellationToken))
{
return renderer.ApplyNativeImageAsync(null, imageSourceProperty, onSet, onLoading, cancellationToken);
}
internal static async Task ApplyNativeImageAsync(this IVisualElementRenderer renderer, BindableObject bindable, BindableProperty imageSourceProperty, Action<Pixbuf> onSet, Action<bool> onLoading = null, CancellationToken cancellationToken = default(CancellationToken))
{
_ = renderer ?? throw new ArgumentNullException(nameof(renderer));
_ = imageSourceProperty ?? throw new ArgumentNullException(nameof(imageSourceProperty));
_ = onSet ?? throw new ArgumentNullException(nameof(onSet));
// TODO: it might be good to make sure the renderer has not been disposed
// makse sure things are good before we start
var element = bindable ?? renderer.Element;
var nativeRenderer = renderer as IVisualNativeElementRenderer;
if (element == null || renderer.Container == null || (nativeRenderer != null && nativeRenderer.Control == null))
return;
onLoading?.Invoke(true);
if (element.GetValue(imageSourceProperty) is ImageSource initialSource && !initialSource.IsEmpty)
{
try
{
using (var drawable = await initialSource.GetNativeImageAsync(cancellationToken))
{
// TODO: it might be good to make sure the renderer has not been disposed
// we are back, so update the working element
element = bindable ?? renderer.Element;
// makse sure things are good now that we are back
if (element == null || renderer.Container == null || (nativeRenderer != null && nativeRenderer.Control == null))
return;
// only set if we are still on the same image
if (element.GetValue(imageSourceProperty) == initialSource)
onSet(drawable);
}
}
finally
{
if (element != null && onLoading != null)
{
// only mark as finished if we are still on the same image
if (element.GetValue(imageSourceProperty) == initialSource)
onLoading.Invoke(false);
}
}
}
else
{
onSet(null);
onLoading?.Invoke(false);
}
}
internal static async Task ApplyNativeImageAsync(this BindableObject bindable, BindableProperty imageSourceProperty, Action<Pixbuf> onSet, Action<bool> onLoading = null, CancellationToken cancellationToken = default(CancellationToken))
{
_ = bindable ?? throw new ArgumentNullException(nameof(bindable));
_ = imageSourceProperty ?? throw new ArgumentNullException(nameof(imageSourceProperty));
_ = onSet ?? throw new ArgumentNullException(nameof(onSet));
onLoading?.Invoke(true);
if (bindable.GetValue(imageSourceProperty) is ImageSource initialSource)
{
try
{
using (var drawable = await initialSource.GetNativeImageAsync(cancellationToken))
{
// only set if we are still on the same image
if (bindable.GetValue(imageSourceProperty) == initialSource)
onSet(drawable);
}
}
finally
{
if (onLoading != null)
{
// only mark as finished if we are still on the same image
if (bindable.GetValue(imageSourceProperty) == initialSource)
onLoading.Invoke(false);
}
}
}
else
{
onSet(null);
onLoading?.Invoke(false);
}
}
}
}