When your application needs a picture, you may offer the user to pick a picture from the photo library. With the PHPickerViewControllerMBS class in our MBS Xojo iOS Plugin, you can let the user pick a picture from his/her photo library. And with the controller the user doesn't need to grant permission to the photo library.
To open the photo picker, you need to first define what you like it to do and thus create a configuration object. There you can pick video, photo or live photos or a combination of them with anyFilterMatchingSubfilters() function. We limit the user to one picture by setting the selection limit to one. The selection can be default, continuous if you need a lot of images and optional be ordered.
Sub ShowPicker()
var configuration As New PHPickerConfigurationMBS
configuration.Filter = PHPickerFilterMBS.imagesFilter
// set to zero for unlimited
configuration.SelectionLimit = 1
configuration.Selection = configuration.SelectionDefault
configuration.PreferredAssetRepresentationMode = configuration.AssetRepresentationModeCompatible
picker = New PHPickerViewControllerMBS(configuration)
AddHandler picker.didFinishPicking, AddressOf PickerFinished
picker.Present
End Sub
We use AddHandler to connect the PickerFinished function to handle the event without subclassing the PHPickerConfigurationMBS class. This event and our method are called when the user picked something. There is a little thing to handle: Images may come in different variants and we need to request the image asynchronously as it may need to be downloaded or converted. We check the available types and pick heic, png or try jpeg formats.
Sub PickerFinished(controller as PHPickerViewControllerMBS, results() as PHPickerResultMBS)
var result as PHPickerResultMBS = results(0)
var registeredTypeIdentifiers() As String = result.TypeIdentifiers
System.DebugLog "Types: "+String.FromArray(registeredTypeIdentifiers, EndOfLine)
// HEIC available?
if registeredTypeIdentifiers.IndexOf("public.heic") >= 0 then
result.loadFileRepresentationForTypeIdentifier("public.heic", WeakAddressOf LoadFileRepresentationCompleted)
elseif registeredTypeIdentifiers.IndexOf("public.png") >= 0 then
// try png
const identifier = "public.png"
result.loadFileRepresentationForTypeIdentifier(identifier, WeakAddressOf LoadFileRepresentationCompleted)
else
// try jpeg
const identifier = "public.jpeg"
result.loadFileRepresentationForTypeIdentifier(identifier, WeakAddressOf LoadFileRepresentationCompleted)
End If
End Sub
We use a callback method to run when the image is loaded. You may show a progress wheel while this happens. When we get the callback with the folderitem for the requested image, we load it as picture and show it in a canvas.
Sub LoadFileRepresentationCompleted(File as FolderItem, error as NSErrorMBS, result as PHPickerResultMBS)
if error <> nil then
MessageBox error.LocalizedDescription
end if
if file <> nil then
System.DebugLog file.NativePath
// normal opening
#if MBS.HasMacCIPlugin = false then
// load directly. Picture may be rotated
pic = Picture.Open(file)
Canvas1.Refresh
#else
// use CIImage to rotate to always be top left orientation
var ciImage As CIImageMBS = New CIImageMBS(file)
var properties As Dictionary = ciImage.properties
If properties.HasKey("Orientation") Then
var orientation As Integer = ciImage.properties.Value("Orientation")
ciImage = ciImage.imageByApplyingOrientation(orientation)
End If
var cgPic As CGImageMBS = ciImage.CreateCGImage
pic = cgPic.Picture
Canvas1.Refresh
#EndIf
End If
End Sub
Sometimes images are actually stored rotated and if we open them with Picture.Open, we get them rotated. So it may be a better way to open them with CIImageMBS class, apply the metadata about the rotation to rotate the image as needed and then ask for the picture.
Please try the above code. You can use it both in your macOS and iOS applications to provide a way for the users to pick a photo from their photo libraries.