我正在编写一个移动的应用程序,当一个项目在平台上旋转时,可以拍摄多张照片。这将为用户提供物品的360度视图中的图片。到目前为止,我可以用Camera.Maui插件很好地拍摄多张照片,我甚至可以自动保存照片到手机的“相机”文件夹中。
我想给予用户一个选项来预览图片之前,他们得到保存。因此,我有一个页面/活动,在其中显示所有图片的“缩略图”。如果用户点击图片,它会转到另一个页面/活动,在那里我想显示全尺寸的图片,并允许用户放大/缩小和平移,然后移动到下一个/上一个图片做同样的事情。我还没有得到缩放或平移功能,因为我坚持试图在这个页面上显示图像。
问题发生在两个地方,而且是同一个问题。这些地方是当我尝试保存图像(只要我不尝试首先显示它,它就可以工作),当我尝试在第二个预览/缩放页面上显示图像时。当我第二次尝试使用从相机插件获得的ImageSource
时,它说流已关闭,我意识到这是意料之中的。
我将集中精力在第二次显示图片,因为我相信保存图像将重用找到的任何解决方案。
所以,在预览过程中:MainPage有一个CameraView
元素,用于显示摄像头看到的内容。我使用一个线程多次调用“GrabSnapshot”方法,该方法从相机提要中获取快照,并将其放入“pics”List
中,作为我从相机获得的原始ImageSource
。(我使用线程来防止主线程陷入困境,以及其他与这个问题无关的原因。
当所有的照片都拍摄完成后,预览按钮将可用,这样用户就可以转到一个新的页面/活动,该页面/活动将构建一个网格,并为拍摄的每张照片创建一个新的ImageButton
。可以点击该按钮,这样整个List
和所选图片的索引就会被发送到另一个页面。这个新页面尝试将选定的图片放入Image
元素中,并表示流已经关闭。
**问题:**如何在不关闭原始流的情况下显示图片?
是否必须为每个ImageSource
创建一个副本,并将该副本设置为ImageButton
或Image
元素的源?我曾经简单地尝试研究过如何做到这一点,但如果不先将其转换为byte[]
,然后创建一个新的流,我就找不到这样做的方法。这似乎是一个非常间接和内存昂贵的方式来做到这一点。我肯定担心内存管理,内存中的每张图片至少有2个(如果不是3个)副本。
注意:我不确定人们实际上想要多少张图片,但我认为他们可能想要20张小物品,也许30张,40张,50张或更多的大物品。我甚至不确定每张照片占用了多少内存。当前保存的图像为PNG,约为350 k至450 k,像素为720 x1462。不幸的是,它更像是一个截图,而不是一个实际的图片,所以我将尝试找到一个不同的方式来获得高分辨率的图片。我知道带有该相机的特定手机可以以4160 x3120的分辨率拍摄JPG,文件大小约为3, 800 kb,这就是我想要的相机。(我不知道这是我从相机插件中得到的,还是只是我保存它的方式,但我保存它时没有调整大小或更改DPI。
我使用C# .Net 7在Maui项目中编写应用程序。到目前为止,我只在Android上使用运行API 28和31的真实的设备进行了测试。正如我前面提到的,我正在使用Camera.Maui插件,这是我可以使用的第一个相机插件/功能。
也许我需要的是一个不同的方法/插件/功能来拍摄照片摆在首位。
在我的项目中有一堆文件/类来处理所有这些,所以我试图帕雷代码并尽可能多地合并它们。
我的代码:
MainPage.xaml.cs
using Camera.MAUI;
private readonly CameraView camera;
private readonly List<ImageSource> pics = new();
public MainPage()
{
InitializeComponent();
camera = cameraView; // cameraView is the XAML x:Name of the CameraView element
}
public void GrabSnapshot()
{
pics.Add(camera.GetSnapShot());
}
MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:cv="clr-namespace:Camera.MAUI;assembly=Camera.MAUI"
x:Class="XXX.MainPage"
Title="">
<Grid VerticalOptions="Fill" HorizontalOptions="Fill">
<cv:CameraView x:Name="cameraView"
VerticalOptions="Fill"
HorizontalOptions="Fill"
CamerasLoaded="CameraView_CamerasLoaded" />
<HorizontalStackLayout Spacing="30" HorizontalOptions="Center" VerticalOptions="End" Margin="0,0,20,0" x:Name="ButtonPane">
<ImageButton Source="switch_camera_icon.jpg" HeightRequest="50" WidthRequest="60" IsOpaque="True" Clicked="SwapButton_Clicked" x:Name="SwapButton" />
<Button Text="Start" Clicked="StartButton_Clicked" x:Name="StartButton"/>
<Button Text="Options" Clicked="OptionsButton_Clicked" x:Name="OptionsButton" />
<Button Text="Preview" Clicked="PreviewButton_Clicked" x:Name="PreviewButton" IsVisible="False" IsEnabled="False" />
</HorizontalStackLayout>
</Grid>
</ContentPage>
PreviewPage.xaml.cs
private void DisplayPics()
{
// yes, this could be done in a for loop, I just haven't cleaned this up yet
int counter = 0;
/*
Grid row and column definitions for the "GridLayout"
*/
foreach (ImageSource pic in pics)
{
int row = (int)Math.Floor(counter / 2m);
int column = counter % 2;
ImageButton button = new() { Source = pic };
GridLayout.Add(button, column, row);
counter++;
}
}
/*
<Grid x:Name="GridLayout" VerticalOptions="Fill" HorizontalOptions="Fill" />
*/
ImagePage.xaml
private readonly List<ImageSource> pics = new();
private int index;
public ImagePage(int indexParam, List<ImageSource> picsList)
{
InitializeComponent();
pics = picsList;
index = indexParam;
ImagePanel.Source = pics[index];
/*
<Image x:Name="ImagePanel" VerticalOptions="Fill" HorizontalOptions="Fill" />
*/
}
1条答案
按热度按时间polhcujo1#
从与@Jason的讨论开始,我已经将从
GetSnapShot
方法返回的ImageSource
转换为字节数组。随后,我更改了变量数据类型以及如何设置Image
和ImageButton
元素来显示图片。“pics”变量现在是
List<byte[]>
而不是List<ImageSource>
。成为
由于速度的需要,我可能会将方法调用分离到另一个线程中,因为我需要为这个项目快速拍照。(我希望能够以每秒2-3张的速度拍照,但我不确定这是否可以实现。最后我可能会问另一个问题,就是如何处理这个问题。)
显示图像从
到
这是我需要的工作,所以现在已经足够了。至少在我做更多测试之前。我可能最终会保存文件并以这种方式使用它们。我担心的是,当我不再需要这些文件时,我必须设法删除它们,以及当/如果用户决定保留这些图片时,将它们移动到一个易于访问的位置。但这是另一天和/或问题。
顺便说一句,我是用
ImageSource
把图像保存到手机上的“相机”文件夹,或者用户选择保存它们的任何地方。我仍然没有改变保存方法,但这已经偏离了主题。我的Windows实现已经使用了一个字节数组,所以这个变化实际上会使该方法更简单。我确信有iOS和Android方法使用字节数组,但我还没有研究过,但同样,这是这个问题的题外话。编辑/更新:
我还没有在iOS或Windows上测试过这个,但是我在Windows上保存的东西似乎在Android上工作,并且不会在iOS上编译失败,所以我已经为一个方法摆脱了OS特定的类。它至少可以从Android手机上生成一个有效的图像。我在保存PNG和JPEG之间的转换之前做了一些额外的步骤,但我也对如何调用“GetSnapShot”方法进行了更改,因此现在该方法提供PNG或JPG文件格式,而无需转换和保存非常简单。