将 StorageFileQueryResult 与图像元数据一起使用时,StorageFile.GetImagePropertiesAsync() 会给出错误的结果
Posted
技术标签:
【中文标题】将 StorageFileQueryResult 与图像元数据一起使用时,StorageFile.GetImagePropertiesAsync() 会给出错误的结果【英文标题】:StorageFile.GetImagePropertiesAsync() gives wrong results when using StorageFileQueryResult with image metadata 【发布时间】:2020-05-14 06:53:37 【问题描述】:不幸的是,除非我弄错了,否则StorageFile
Query api 中似乎存在一个错误,使其不可靠。
下面的例子很简单。重现它的步骤是:
-创建一个文件夹并只放入一张图片,因为下面的示例假设您只有一个文件。
-此图像应为 PEF 格式,取自 Pentax 645Z。您可以在此处找到整个项目以及 PEF 图像。 https://github.com/Ponant/StorageFileQueryResultBug 。将示例图像放在一个文件夹中的索引位置,例如桌面。
-从 Microsoft Store https://www.microsoft.com/en-us/p/raw-image-extension/9nctdw2w1bh8?activetab=pivot:overviewtab 安装 Raw Image Extension
。此扩展基于https://www.libraw.org/
他们支持这个相机https://www.libraw.org/supported-cameras
运行应用,你会看到两个按钮:
1) 按钮 1 启动文件夹选择器,创建一个 StorageFileQueryResult
,它允许获取文件夹中唯一的文件。然后它调用图像属性的 Api
var imageProperties = await file.Properties.GetImagePropertiesAsync();
2) 按钮 2 启动 FilePicker
,因此您导航到文件夹,选择相同的文件,然后运行相同的方法
var imageProperties = await file.Properties.GetImagePropertiesAsync();
两个结果显示在两个文本块中。他们应该是相同的,他们不是。文件夹查询返回空值。
我们如何解决这个问题?为什么 Filepicker 在同一个 StorageFile
上给出正确的结果?
任何人都可以确认这是否是一个已知的错误,我们可以帮助解决它吗?
我们非常依赖StorageFileQueryResult
来构建一个允许人们查看图片并显示元数据的应用程序。至少可以说,遇到这个可靠性问题是很可怕的,我们不能提示用户在 10k 图像上使用 FilePicker
:)。
附加说明:文件资源管理器,就像FilePicker
,给出了正确的答案。
我们还在网上找到了一个 UWP 文件资源管理器应用程序,它可以从 Win+R
运行,它提供了正确的信息。
shell:AppsFolder\c5e2524a-ea46-4f67-841f-6a9465d9d515_cw5n1h2txyewy!App
这希望 UWP 可以在不使用文件选择器而是通过查询文件夹的情况下显示正确的信息。我们可以通过选择来实现这一点
IndexerOption = IndexerOption.DoNotUseIndexer,
在查询选项中,因此不依赖索引器,但很遗憾,这会降低应用程序的性能,此外还会让我们添加额外的代码,因为我们确实大量使用索引器。
谢谢
public sealed partial class Scenario4 : Page
public Scenario4()
this.InitializeComponent();
private async void FolderPickerButton_Click(object sender, RoutedEventArgs e)
var folderPicker = new FolderPicker
SuggestedStartLocation = PickerLocationId.Desktop,
ViewMode = PickerViewMode.Thumbnail
;
folderPicker.FileTypeFilter.Add("*");
var folder = await folderPicker.PickSingleFolderAsync();
if (folder == null)
return;
var queryOptions = new QueryOptions
IndexerOption = IndexerOption.UseIndexerWhenAvailable,
;
var query = folder.CreateFileQueryWithOptions(queryOptions);
var files = (await query.GetFilesAsync());
foreach (var file in files)
var imageProperties = await file.Properties.GetImagePropertiesAsync();
folderThenQueryMethodTextBlock.Text =
$"Dimensions imageProperties.WidthximageProperties.Height DateTaken imageProperties.DateTaken";
private async void OpenFileAppBarButton_Click(object sender, RoutedEventArgs e)
FileOpenPicker picker = new FileOpenPicker();
picker.FileTypeFilter.Add("*");
picker.SuggestedStartLocation = PickerLocationId.Desktop;
var file = await picker.PickSingleFileAsync();
if (file != null)
var imageProperties = await file.Properties.GetImagePropertiesAsync();
filePickerMethodTextBlock.Text =
$"Dimensions imageProperties.WidthximageProperties.Height DateTaken imageProperties.DateTaken";
XAML
<Page
x:Class="Virtualization.Scenario4"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="using:Virtualization"
mc:Ignorable="d"
Background="ThemeResource ApplicationPageBackgroundThemeBrush">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center"
BorderBrush="Blue" BorderThickness="2" Margin="0,8,0,0">
<Button x:Name="FolderPickerButton" Content="Query folder with one file"
Click="FolderPickerButton_Click"/>
<Button Content="File picker" Click="OpenFileAppBarButton_Click" Margin="16,0,0,0"/>
<AppBarSeparator/>
</StackPanel>
<StackPanel Grid.Row="1" HorizontalAlignment="Center">
<TextBlock Text="Using Query after Folder Picker"/>
<TextBlock x:Name="folderThenQueryMethodTextBlock"/>
<TextBlock Text="Using File Picker"/>
<TextBlock x:Name="filePickerMethodTextBlock"/>
</StackPanel>
</Grid>
【问题讨论】:
【参考方案1】:我花时间安装了扩展并试用了您的代码。你说的一切都是正确的。从 StorageFileQueryResult 获取的 StorageFile 会导致 PEF 文件的默认(错误)图像属性,但适用于 jpg 文件。这显然是一个错误。我不知道该错误是在框架中还是在 RAW 图像扩展中。请注意,该扩展在 Windows 应用商店中有很多负面反馈。
有一个合理的解决方法。您不必一次处理一个文件。您可以这样做,而不是使用查询:
var files = await folder.GetFilesAsync();
foreach (var file in files)
var imageProperties = await file.Properties.GetImagePropertiesAsync();
folderThenQueryMethodTextBlock.Text =
$"Dimensions imageProperties.WidthximageProperties.Height DateTaken imageProperties.DateTaken";
我可以确认它有效。
如果您需要查询的强大功能,您可以使用它来获取文件名列表,然后在 foreach 循环中使用“StorageFolder.GetFileAsync(fileName)”。只要 StorageFile 来自 StorageFolder.GetXXX,它似乎就可以正常工作。
【讨论】:
肖恩,谢谢。您的方法确实像我指出的那样有效,您删除了索引。但是这两种方法都会比在索引位置上使用查询慢 2-3 个数量级。此外,假设您有带有子文件夹的文件夹,使用文件名将不起作用,因为它仅限于浅查询。 Microsoft 建议 docs.microsoft.com/en-us/windows/uwp/files/fast-file-properties 使用 while 循环,但它也非常慢。我会更新我的问题以更具体地说明我们的要求,但感谢您的尝试。 看来我可以将 GetFileAsync 与子文件夹一起使用。我正在进一步调查。但是是的,原始图像扩展有很多负面评论,但我没有其他选择。 肖恩,我接受了你的回答,因为它以某种方式与 GetFileAsync 一起工作,它允许查询子文件夹。但是,它会弹出与原始错误相关的其他问题,这些问题保持不变,因此读者应该注意这一点。谢谢。以上是关于将 StorageFileQueryResult 与图像元数据一起使用时,StorageFile.GetImagePropertiesAsync() 会给出错误的结果的主要内容,如果未能解决你的问题,请参考以下文章