Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change picker to Finder for import when running on macOS #5

Open
wants to merge 5 commits into
base: rma-androidx-33
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/ios/CDVCamera.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ typedef NSUInteger CDVMediaType;
API_AVAILABLE(ios(14))
@interface CDVGalleryPicker : NSObject <UIAdaptivePresentationControllerDelegate>

@property (strong) PHPickerViewController* pickerViewController;
@property (strong) UIViewController* pickerViewController;

@property (strong) CDVPictureOptions* pictureOptions;
@property (copy) NSString* callbackId;
Expand Down Expand Up @@ -97,7 +97,8 @@ API_AVAILABLE(ios(14))
UINavigationControllerDelegate,
UIPopoverControllerDelegate,
CLLocationManagerDelegate,
PHPickerViewControllerDelegate>
PHPickerViewControllerDelegate,
UIDocumentPickerDelegate>
{}
@property (strong) CDVCameraPicker* pickerController;
@property (strong) CDVGalleryPicker* galleryPicker;
Expand Down
166 changes: 116 additions & 50 deletions src/ios/CDVCamera.m
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Licensed to the Apache Software Foundation (ASF) under one
#import <objc/message.h>
#import <Photos/Photos.h>
#import <PhotosUI/PhotosUI.h>
#import <UniformTypeIdentifiers/UTCoreTypes.h>

#ifndef __CORDOVA_4_0_0
#import <Cordova/NSData+Base64.h>
Expand Down Expand Up @@ -218,7 +219,17 @@ - (void)takePicture:(CDVInvokedUrlCommand*)command
CDVGalleryPicker* picker = [CDVGalleryPicker createFromPictureOptions:pictureOptions];
picker.callbackId = command.callbackId;
weakSelf.galleryPicker = picker;
picker.pickerViewController.delegate = weakSelf;

if ([picker.pickerViewController isKindOfClass:[PHPickerViewController class]]) {
PHPickerViewController* controller = (PHPickerViewController*) picker.pickerViewController;
controller.delegate = weakSelf;
} else if ([picker.pickerViewController isKindOfClass:[UIDocumentPickerViewController class]]) {
UIDocumentPickerViewController* controller = (UIDocumentPickerViewController*) picker.pickerViewController;
controller.delegate = weakSelf;
} else {
NSLog(@"FIA: no class matched");
}


[weakSelf.viewController presentViewController:picker.pickerViewController animated:true completion:^{
weakSelf.hasPendingOperation = NO;
Expand Down Expand Up @@ -459,56 +470,99 @@ - (NSData*)processImage:(UIImage*)image info:(NSDictionary*)info options:(CDVPic
return data;
}

- (void)picker:(PHPickerViewController *)picker didFinishPicking:(NSArray<PHPickerResult *> *)results API_AVAILABLE(ios(14)) {
- (void)documentPicker:(UIDocumentPickerViewController *)controller
didPickDocumentsAtURLs:(NSArray<NSURL *> *)urls; {
__weak CDVCamera* weakSelf = self;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't used anywhere.


if (urls.count > 0) {
NSURL *fileURL = [urls firstObject];

NSError *error;
NSData *data = [NSData dataWithContentsOfURL:fileURL options:NSDataReadingMappedIfSafe error:&error];

if (error) {
[self sendErrorResultWithMessage];
return;
}

// Create a UIImage from the data
UIImage *original = [[UIImage alloc] initWithData:data];
[self handleImageFromPicker:original withData:data];
} else {
[self sendErrorResultWithMessage];
}
}

- (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller; {
[self sendErrorResultWithMessage];
}

- (void)sendErrorResultWithMessage {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does more than the naming implies. More like onEndSelectionWithoutImage. And use it also in other instances (e.g. insisde picker:didFinishPicking:)

CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"No Image Selected"];
[self.commandDelegate sendPluginResult:result callbackId:self.galleryPicker.callbackId];

// Reset any pending operation state
self.hasPendingOperation = NO;
self.galleryPicker = nil;
}

- (void)handleImageFromPicker:(UIImage *)original withData:(NSData *)data {

__weak CDVCamera* weakSelf = self;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weak reference is unncessary at this point.


UIImage* image = [weakSelf conformImage:original toOptions:weakSelf.galleryPicker.pictureOptions];

NSData* processedImageData = nil;
switch (weakSelf.galleryPicker.pictureOptions.encodingType) {
case EncodingTypePNG:
processedImageData = UIImagePNGRepresentation(image);
break;
case EncodingTypeJPEG:
processedImageData = UIImageJPEGRepresentation(image, weakSelf.galleryPicker.pictureOptions.quality.floatValue / 100.0f);
break;
default:
NSAssert(NO, @"Missing implementation for encoding type (fallback to jpg)");
processedImageData = UIImageJPEGRepresentation(image, weakSelf.galleryPicker.pictureOptions.quality.floatValue / 100.0f);
}
CGImageSourceRef processedImageSource = CGImageSourceCreateWithData((__bridge CFDataRef) processedImageData, NULL);

NSDictionary* completeMetadata = [self convertImageMetadata:data];
NSDictionary* metadata = [self filterImageMetadataFrom:completeMetadata];

NSMutableData* imageDataWithExif = [NSMutableData data];
CFStringRef fileFormat = kuTTypeFromCDVEncodingType(weakSelf.galleryPicker.pictureOptions.encodingType);

CGImageDestinationRef destinationImage = CGImageDestinationCreateWithData((__bridge CFMutableDataRef) imageDataWithExif, fileFormat, 1, NULL);
CGImageDestinationAddImageFromSource(destinationImage, processedImageSource, 0, (__bridge CFDictionaryRef) metadata);
CGImageDestinationFinalize(destinationImage);

CFRelease(processedImageSource);
CFRelease(destinationImage);

NSString* extension = ExtensionFromCDVEncodingType(weakSelf.galleryPicker.pictureOptions.encodingType);
NSString* filePath = [self tempFilePath:extension];
NSError* err = nil;

CDVPluginResult* result = nil;
if (![imageDataWithExif writeToFile:filePath options:NSAtomicWrite error:&err]) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[err localizedDescription]];
} else {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[[self urlTransformer:[NSURL fileURLWithPath:filePath]] absoluteString]];
}

[weakSelf.commandDelegate sendPluginResult:result callbackId:weakSelf.galleryPicker.callbackId];
weakSelf.hasPendingOperation = NO;
weakSelf.galleryPicker = nil;
}

- (void)picker:(PHPickerViewController *)picker didFinishPicking:(NSArray<PHPickerResult *> *)results API_AVAILABLE(ios(14)) {


[picker dismissViewControllerAnimated:YES completion:^{
if (results.count > 0 && [results.firstObject.itemProvider hasItemConformingToTypeIdentifier:(NSString*)kUTTypeImage]) {
[results.firstObject.itemProvider loadDataRepresentationForTypeIdentifier:(NSString*)kUTTypeImage completionHandler:^(NSData* data, NSError* error) {
UIImage* original = [[UIImage alloc] initWithData:data];
UIImage* image = [weakSelf conformImage:original toOptions:weakSelf.galleryPicker.pictureOptions];

NSData* processedImageData = nil;
switch (weakSelf.galleryPicker.pictureOptions.encodingType) {
case EncodingTypePNG:
processedImageData = UIImagePNGRepresentation(image);
break;
case EncodingTypeJPEG:
processedImageData = UIImageJPEGRepresentation(image, weakSelf.galleryPicker.pictureOptions.quality.floatValue / 100.0f);
break;
default:
NSAssert(NO, @"Missing implementation for encoding type (fallback to jpg)");
processedImageData = UIImageJPEGRepresentation(image, weakSelf.galleryPicker.pictureOptions.quality.floatValue / 100.0f);
}
CGImageSourceRef processedImageSource = CGImageSourceCreateWithData((__bridge CFDataRef) processedImageData, NULL);

NSDictionary* completeMetadata = [self convertImageMetadata:data];
NSDictionary* metadata = [self filterImageMetadataFrom:completeMetadata];

NSMutableData* imageDataWithExif = [NSMutableData data];
CFStringRef fileFormat = kuTTypeFromCDVEncodingType(weakSelf.galleryPicker.pictureOptions.encodingType);

CGImageDestinationRef destinationImage = CGImageDestinationCreateWithData((__bridge CFMutableDataRef) imageDataWithExif, fileFormat, 1, NULL);
CGImageDestinationAddImageFromSource(destinationImage, processedImageSource, 0, (__bridge CFDictionaryRef) metadata);
CGImageDestinationFinalize(destinationImage);

CFRelease(processedImageSource);
CFRelease(destinationImage);

NSString* extension = ExtensionFromCDVEncodingType(weakSelf.galleryPicker.pictureOptions.encodingType);
NSString* filePath = [self tempFilePath:extension];
NSError* err = nil;

CDVPluginResult* result = nil;
if (![imageDataWithExif writeToFile:filePath options:NSAtomicWrite error:&err]) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[err localizedDescription]];
} else {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[[self urlTransformer:[NSURL fileURLWithPath:filePath]] absoluteString]];
}

[weakSelf.commandDelegate sendPluginResult:result callbackId:weakSelf.galleryPicker.callbackId];
weakSelf.hasPendingOperation = NO;
weakSelf.galleryPicker = nil;
[self handleImageFromPicker:original withData:data];
}];
} else {
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"No Image Selected"];
Expand Down Expand Up @@ -969,11 +1023,23 @@ + (instancetype) createFromPictureOptions:(CDVPictureOptions*)pictureOptions {
CDVGalleryPicker* instance = [[CDVGalleryPicker alloc] init];
instance.pictureOptions = pictureOptions;

PHPickerConfiguration* singleImage = [[PHPickerConfiguration alloc] initWithPhotoLibrary:PHPhotoLibrary.sharedPhotoLibrary];
singleImage.filter = PHPickerFilter.imagesFilter;
singleImage.selectionLimit = 1;
instance.pickerViewController = [[PHPickerViewController alloc] initWithConfiguration:singleImage];
instance.pickerViewController.presentationController.delegate = instance;
NSProcessInfo *processInfo = [NSProcessInfo processInfo];

if ((processInfo.isMacCatalystApp || processInfo.iOSAppOnMac)) {
// Running on macOS under Mac Catalyst, use UIDocumentPickerViewController for image selection
UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initForOpeningContentTypes:@[UTTypeImage]];
documentPicker.allowsMultipleSelection = NO;
instance.pickerViewController = documentPicker; // Store as generic view controller
instance.pickerViewController.presentationController.delegate = instance;
} else {
// Use PHPickerViewController for image selection
PHPickerConfiguration* singleImage = [[PHPickerConfiguration alloc] initWithPhotoLibrary:PHPhotoLibrary.sharedPhotoLibrary];
singleImage.filter = PHPickerFilter.imagesFilter;
singleImage.selectionLimit = 1;
PHPickerViewController *photoPicker = [[PHPickerViewController alloc] initWithConfiguration:singleImage];
instance.pickerViewController = photoPicker; // Store as generic view controller
instance.pickerViewController.presentationController.delegate = instance;
}

return instance;
}
Expand Down