现在网上WebP格式的图片是越来越多了,UWP在电脑上可以直接查看WebP格式的图片,只要去Windows应用商店找到"WebP 映像扩展"这个应用安装了就行,但是微软非常脑残,限制了只有Win10 17763及更高版本才能安装这个应用,而手机版的Win10 Mobile最多升级到15063,于是安装不了,只能自己想办法。


经过搜索和测试,发现微软自己就提供了解决办法,不知道为什么不直接集成到WebP映像扩展这个里面。我们直接在NUGET中搜索SkiaSharp这个包,这个包的作者就是Microsoft,它目前最新版本是3.119.0,但是我们无法使用,我们要安装1.68.0版本,这个是我测试可以生成UWP ARM版应用的最高版本,再高生成时就会出错了。

引用了这个包之后就要写代码了,这个包的作用是可以将WebP格式的图片转为Png、Jpg等传统格式,所以我们需要先通过URL将WebP图片下载到本地,然后转成Png图片去让Image控件显示。下面提供转换代码参考,其中图片的临时文件名我是用URL的Sha256摘要作为文件名,这样可以避免对于同一个图片链接重复生成临时文件在本地。
cs
public static async Task<string> ConvertWebpToJpg(string webpUrl)
{
try
{
var tempPicFileName = $"{HashHelper.GetSha256Hex(webpUrl)}.png";
var tempPicItem = await ApplicationData.Current.TemporaryFolder.TryGetItemAsync(tempPicFileName);
if (tempPicItem != null)
{
return tempPicItem.Name;
}
var hc = new HttpClient();
var response = await hc.GetAsync(webpUrl);
if (response.IsSuccessStatusCode && response.Content.Headers.ContentType.ToString().Trim().EqualsIgnoreCase("image/webp"))
{
var tempWebpFileName = $"{DateTimeOffset.Now:yyyyMMddHHmmssfffffff}-{Guid.NewGuid()}.webp";
var bytes = await response.Content.ReadAsByteArrayAsync();
StorageFile tempWebpFile =
await ApplicationData.Current.TemporaryFolder.CreateFileAsync(tempWebpFileName,
CreationCollisionOption.ReplaceExisting);
StorageFile tempPicFile =
await ApplicationData.Current.TemporaryFolder.CreateFileAsync(tempPicFileName,
CreationCollisionOption.ReplaceExisting);
using (var stream = await tempWebpFile.OpenAsync(FileAccessMode.ReadWrite))
{
using (var sw = stream.AsStreamForWrite())
{
sw.Write(bytes, 0, bytes.Length);
}
}
using (var inputStream = File.OpenRead(tempWebpFile.Path))
{
using (var bitmap = SKBitmap.Decode(inputStream))
{
using (var outputStream = File.OpenWrite(tempPicFile.Path))
{
using (var managedStream = new SKManagedWStream(outputStream))
{
bitmap.Encode(managedStream, SKEncodedImageFormat.Png, 100);
}
}
}
}
await tempWebpFile.DeleteAsync();
return tempPicFile.Name;
}
}
catch (Exception ex)
{
}
return null;
}
计算Sha256摘要的代码提供参考:
cs
public static string GetSha256Hex(string text)
{
var md5 = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Sha256);
IBuffer buffer = CryptographicBuffer.CreateFromByteArray(Encoding.UTF8.GetBytes(text));
var hashBytes = md5.HashData(buffer);
return CryptographicBuffer.EncodeToHexString(hashBytes);
}
然后,我们给Image控件添加ImageFailed事件的处理函数,这样就可以在图片加载失败时,自动下载转换显示。
cs
private async void Image_OnImageFailed(object sender, ExceptionRoutedEventArgs e)
{
if (sender is Image image && image.Source is BitmapImage bitmap && bitmap.UriSource != null)
{
var picFilePath = await WebpHelper.ConvertWebpToJpg(bitmap.UriSource.ToString());
if (!string.IsNullOrWhiteSpace(picFilePath))
{
bitmap.UriSource = new Uri($"ms-appdata:///temp/{picFilePath}");
}
else
{
ToastHelper.ShowMessage($"图片{image.Tag.ToString()}加载失败");
bitmap.UriSource = FailedImageSourceUri;
}
}
}
由于SkiaSharp包不支持将WebP保存为GIF格式,所以WebP格式的动图应该是没法在手机端查看了,不过能看静态图,已经解决大问题了。