Picking picture on macOS

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.

6 Likes