我在使用 XamarinEssentials.MediaPicker CapturePhotoAsync() 方法时遇到错误。我的应用程序的一些用户一直在经历无声崩溃,在接受拍摄的照片后,没有立即将任何内容记录到应用程序中心,而是重新启动应用程序。 (错误视频附在 here )。请注意,该视频是由持有小米红米 Note 9S 的用户拍摄的,我无权访问该设备。我无法在我测试过的任何设备上重现此错误。不处于开发模式或 Release模式。
显然这是 MediaPicker 代码内部的一些错误,消耗了设备的所有可用 RAM,迫使其重新启动。
我在互联网上看到了很多其他报告,但其中任何一个都会得出结论或解决方案。
有人可以帮我解决这个问题吗?
提前致谢!
在下面找到涉及捕获图片和后处理它的整个代码,涉及调整图像大小、旋转它、将其保存到图库以及保存缩略图。
public async Task TakePicture(object param)
{
var permissionsOk = await VerifyPermissions();
if (!permissionsOk) return;
try
{
var options = new MediaPickerOptions
{
};
var photo = await MediaPicker.CapturePhotoAsync();
await LoadPhotoAsync(photo);
Console.WriteLine($"CapturePhotoAsync COMPLETED: {PhotoPath}");
}
catch (FeatureNotSupportedException fnsEx)
{
// Feature is not supported on the device
var properties = new Dictionary<string, string>
{
{ "Função:", "TakePicture" },
{ "Arquivo:", "VisitDetailsRegistrationViewModel"},
{ "Observação", "FeatureNotSupportedException"}
};
Crashes.TrackError(fnsEx, properties);
}
catch (PermissionException pEx)
{
// Permissions not granted
var properties = new Dictionary<string, string>
{
{ "Função:", "TakePicture" },
{ "Arquivo:", "VisitDetailsRegistrationViewModel"},
{ "Observação", "PermissionException"}
};
Crashes.TrackError(pEx, properties);
}
catch (Exception ex)
{
var properties = new Dictionary<string, string>
{
{ "Função:", "TakePicture" },
{ "Arquivo:", "VisitDetailsRegistrationViewModel"},
{ "Observação", "Exception"}
};
Crashes.TrackError(ex, properties);
}
}
async Task LoadPhotoAsync(FileResult photo)
{
// canceled
if (photo == null)
{
PhotoPath = null;
return;
}
var meta = ImageMetadataReader.ReadMetadata(await photo.OpenReadAsync());
var subIfd0Directory = meta.OfType<ExifIfd0Directory>().FirstOrDefault();
var orientation = subIfd0Directory?.GetDescription(ExifDirectoryBase.TagOrientation);
var rotationAngle = GetRotationAngle(orientation);
// save the file into local storage
var newFile = System.IO.Path.Combine(FileSystem.CacheDirectory, photo.FileName);
using (var stream = await photo.OpenReadAsync())
{
var imageByteArray = ReadFully(stream);
//var resizedImageByteArray = ResizeImage(imageByteArray, 2000, 2000, 92);
var rotatedImageByteArray = RotateImage(imageByteArray, rotationAngle, 92);
//var mediaService = DependencyService.Get<IMediaService>();
//mediaService.SaveImageFromByte(rotatedImageByteArray, photo.FileName);
using (MemoryStream ms = new MemoryStream(rotatedImageByteArray))
{
using (var newStream = File.OpenWrite(newFile))
{
await ms.CopyToAsync(newStream);
}
}
using (MemoryStream ms2 = new MemoryStream(rotatedImageByteArray))
{
try
{
await MediaGallery.SaveAsync(MediaFileType.Image, ms2, photo.FileName);
}
catch (Exception ex)
{
var properties = new Dictionary<string, string>
{
{ "Função:", "LoadPhotoAsync" },
{ "Arquivo:", "VisitDetailsRegistrationViewModel"},
{ "Observação", "Exception"}
};
Crashes.TrackError(ex, properties);
}
}
}
PhotoPath = newFile;
var thumbFile = System.IO.Path.Combine(FileSystem.CacheDirectory, "Thumb-"+photo.FileName);
using (var stream = await photo.OpenReadAsync())
{
var thumbByteArray = ReadFully(stream);
var resizedThumbByteArray = ResizeImage(thumbByteArray, 500, 500, 92);
var rotatedThumbByteArray = RotateImage(resizedThumbByteArray, rotationAngle, 92);
using (MemoryStream ms = new MemoryStream(rotatedThumbByteArray))
{
using (var newStreamThumb = File.OpenWrite(thumbFile))
await ms.CopyToAsync(newStreamThumb);
}
}
ThumbPath = thumbFile;
}
public int GetRotationAngle(string orientationText)
{
if (orientationText == null) return 90;
if (orientationText.Contains("90")) return 90;
else if (orientationText.Contains("180")) return 180;
else if (orientationText.Contains("270")) return 270;
else return 0;
}
public static byte[] ReadFully(Stream input)
{
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
public static byte[] RotateImage(byte[] imageData, float degrees, int quality)
{
Bitmap originalImage = BitmapFactory.DecodeByteArray(imageData, 0, imageData.Length);
var matrix = new Matrix();
matrix.PostRotate(degrees);
Bitmap rotatedBitmap = Bitmap.CreateBitmap(originalImage, 0, 0, originalImage.Width, originalImage.Height, matrix, true);
using (MemoryStream ms = new MemoryStream())
{
rotatedBitmap.Compress(Bitmap.CompressFormat.Jpeg, quality, ms);
return ms.ToArray();
}
}
public static byte[] ResizeImage(byte[] imageData, float width, float height, int quality)
{
// Load the bitmap
Bitmap originalImage = BitmapFactory.DecodeByteArray(imageData, 0, imageData.Length);
float oldWidth = (float)originalImage.Width;
float oldHeight = (float)originalImage.Height;
float scaleFactor = 0f;
if (oldWidth > oldHeight)
{
scaleFactor = width / oldWidth;
}
else
{
scaleFactor = height / oldHeight;
}
float newHeight = oldHeight * scaleFactor;
float newWidth = oldWidth * scaleFactor;
Bitmap resizedImage = Bitmap.CreateScaledBitmap(originalImage, (int)newWidth, (int)newHeight, false);
using (MemoryStream ms = new MemoryStream())
{
resizedImage.Compress(Bitmap.CompressFormat.Jpeg, quality, ms);
return ms.ToArray();
}
}
最佳答案
迄今为止,任何 Xamarin 照片捕捉库均未修复此错误。这是由于回调Task存储在内存中,因此当Android决定需要在相机应用程序位于前台时释放资源时,应用程序将关闭,并且回调将丢失。
当用户拍摄照片后,应用程序将恢复,但在 OnActivityResult 中无法回调代码来处理照片。目前看来没有任何方法可以处理这种情况。
关于android - Xamarin MediaPicker CapturePhotoAsync 在按下 "Ok"按钮后重新启动应用程序并抛出无提示错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69744468/