I have a app where i need to pick images from the phone and display them in the order the user picked them (i need img's in the order picked , not "most recent edited" that is why i am not using UIImagePickerController)
To do this i have a page that shows the latest 50 images with the possibility to load more.
I am getting the Image path and orientation with this code below.
My problem: The CompletionHandler (in RequestContentEditingInput) will only run 17 times... I can see that the the RequestContentEditingInput is called for every image (on this phone 138 times)
I have tried to wait but nothing happens.
The code works as intended when i have less than 17 images...
I have tried to implement a SemaphoreSlim lock in the CompletionHandler code to control that i would only process 10 images at the time but the end result was ether the same or no images was processed at all.
UpdateInfo: It seems its all the LivePhotos that is not processed.
Do anyone have an idea on what is happening here?
An idea for a fix?
Is there another way i can get all image paths and orientation?
Or a totally other solution to let the user pick images from the phone and get the order the user picked them in?
public class GalleryHelper : IGalleryHelper
{
private List<(string, string, string)> _retval;
private nint _numberofImg = 0;
private nint _currentImg = 0;
public List<(string, string, string)> GetAllImgFromGallery()
{
_retval = new List<(string, string, string)>();
_currentImg = 0;
GetAllImg();
return _retval;
}
private void GetAllImg()
{
var fetchOptions = new PHFetchOptions();
PHFetchResult allPhotos = PHAsset.FetchAssets(PHAssetMediaType.Image, fetchOptions);
_numberofImg = allPhotos.Count;
Debug.WriteLine("Total img no + " + _numberofImg);
for (nint i = 0; i < allPhotos.Count; i++)
{
Debug.WriteLine("Starting " + i);
(allPhotos[i] as PHAsset).RequestContentEditingInput(new PHContentEditingInputRequestOptions(), CompletionHandler);
}
}
private void CompletionHandler(PHContentEditingInput contentEditingInput, NSDictionary requestStatusInfo)
{
Debug.WriteLine("Starting CompletionHandler " + (1 + _currentImg));
var path = contentEditingInput.FullSizeImageUrl.Path;
if (path != null)
{
var orientation = contentEditingInput.FullSizeImageOrientation;
switch (orientation)
{
case CIImageOrientation.TopLeft:
//Standard position
_retval.Add((path, null, "0"));
break;
case CIImageOrientation.LeftBottom:
//Rotate 90 degrees clockwise
_retval.Add((path, null, "-90"));
break;
case CIImageOrientation.RightTop:
//Rotate 90 degrees counterclockwise
_retval.Add((path, null, "90"));
break;
case CIImageOrientation.BottomRight:
//Rotate 180 degrees
_retval.Add((path, null, "180"));
break;
case CIImageOrientation.BottomLeft:
//Mirror image rotated 180 degrees
_retval.Add((path, null, "180"));
break;
case CIImageOrientation.TopRight:
//Mirror image
_retval.Add((path, null, "0"));
break;
case CIImageOrientation.LeftTop:
//Mirror image rotate 90 degrees clockwise
_retval.Add((path, null, "-90"));
break;
case CIImageOrientation.RightBottom:
//Mirror image rotate 90 degrees counterclockwise.
_retval.Add((path, null, "90"));
break;
default:
_retval.Add((path, null, "0"));
break;
}
}
_currentImg++;
Debug.WriteLine("Images done " + _currentImg);
MessagingCenter.Send((App)Xamarin.Forms.Application.Current, "ImagesReady", _retval);
}
}
A paste from my Debug Output on a run:
[0:] Total img no + 138
[0:] Starting 0
[0:] Starting 1
(...)
[0:] Starting 137
[0:] Starting CompletionHandler 1
[0:] Images done 1
[0:] Starting CompletionHandler 2
[0:] Images done 2
[0:] Starting CompletionHandler 3
[0:] Images done 3
(...)
[0:] Starting CompletionHandler 15
[0:] Images done 15
[0:] Starting CompletionHandler 16
[0:] Images done 16
[0:] Starting CompletionHandler 17
[0:] Images done 17
Thread started: #17
Thread finished: #15
The thread 0xf has exited with code 0 (0x0).
Thread finished: #3
If anyone in the future has the same problem. Use PHImageManager.DefaultManager.RequestImageData() instead of PHAsset.RequestContentEditingInput() as it do not crash if you ask it to process alot of images.
I do something like:
var fetchOptions = new PHFetchOptions();
PHFetchResult allPhotos = PHAsset.FetchAssets(PHAssetMediaType.Image, fetchOptions);
_numberofImg = allPhotos.Count;
Debug.WriteLine("Total img no + " + _numberofImg);
await Task.Yield();
await Task.Run(() => ImgProcess(allPhotos));
return true;
private void ImgProcess(PHFetchResult allPhotos)
{
//await Task.Run(() =>
//{
for (nint i = 0; i < allPhotos.Count; i++)
{
Debug.WriteLine("Starting " + i);
var phasset = allPhotos[i] as PHAsset;
var options = new PHImageRequestOptions()
{
Synchronous = true,
NetworkAccessAllowed = false,
DeliveryMode = PHImageRequestOptionsDeliveryMode.FastFormat
};
PHImageManager.DefaultManager.RequestImageData(phasset, options, ComplManager);
}
//});
//return;
}
even if this solution still have problems when the number of images get over something like 300...