StorageFile.GetImagePropertiesAsync() 在将 StorageFileQueryResult 与图像元数据一起使用时给出错误的结果
StorageFile.GetImagePropertiesAsync() gives wrong results when using StorageFileQueryResult with image metadata
不幸的是,除非我弄错了,否则 StorageFile
查询 api 中似乎存在错误,这使得它不可靠。
下面的例子很简单。重现它的步骤是:
-拿一个文件夹,只放一张图片,因为下面的例子假设你只有一个文件。
-此图像应为 PEF 格式,取自 Pentax 645Z。您可以在此处找到整个项目以及 PEF 图像。 https://github.com/Ponant/StorageFileQueryResultBug。将示例图像放在一个文件夹中的索引位置,例如桌面。
-从 Microsoft Store 安装 Raw Image Extension
,https://www.microsoft.com/en-us/p/raw-image-extension/9nctdw2w1bh8?activetab=pivot:overviewtab . This extension is based on 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();
两个结果显示在两个文本块中。它们应该是相同的,但它们不是。文件夹查询 returns 空值。
我们如何解决这个问题?为什么 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.Width}x{imageProperties.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.Width}x{imageProperties.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>
我花时间安装了扩展并试用了您的代码。你说的都是对的。从 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.Width}x{imageProperties.Height} DateTaken {imageProperties.DateTaken}";
}
我可以确认有效。
如果您需要查询的强大功能,可以仅使用它来获取文件名列表,然后在 foreach 循环中使用 'StorageFolder.GetFileAsync(fileName)'。只要 StorageFile 来自 StorageFolder.GetXXX,它似乎就可以正常工作。
不幸的是,除非我弄错了,否则 StorageFile
查询 api 中似乎存在错误,这使得它不可靠。
下面的例子很简单。重现它的步骤是:
-拿一个文件夹,只放一张图片,因为下面的例子假设你只有一个文件。
-此图像应为 PEF 格式,取自 Pentax 645Z。您可以在此处找到整个项目以及 PEF 图像。 https://github.com/Ponant/StorageFileQueryResultBug。将示例图像放在一个文件夹中的索引位置,例如桌面。
-从 Microsoft Store 安装 Raw Image Extension
,https://www.microsoft.com/en-us/p/raw-image-extension/9nctdw2w1bh8?activetab=pivot:overviewtab . This extension is based on 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();
两个结果显示在两个文本块中。它们应该是相同的,但它们不是。文件夹查询 returns 空值。
我们如何解决这个问题?为什么 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.Width}x{imageProperties.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.Width}x{imageProperties.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>
我花时间安装了扩展并试用了您的代码。你说的都是对的。从 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.Width}x{imageProperties.Height} DateTaken {imageProperties.DateTaken}";
}
我可以确认有效。
如果您需要查询的强大功能,可以仅使用它来获取文件名列表,然后在 foreach 循环中使用 'StorageFolder.GetFileAsync(fileName)'。只要 StorageFile 来自 StorageFolder.GetXXX,它似乎就可以正常工作。