| 
					
				 | 
			
			
				@@ -0,0 +1,1589 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#import <Foundation/Foundation.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#import <Photos/Photos.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#import <MobileCoreServices/UTCoreTypes.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#import <MobileCoreServices/MobileCoreServices.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#import <ImageIO/ImageIO.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#import <AssetsLibrary/AssetsLibrary.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#import <PhotosUI/PhotosUI.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#ifdef UNITY_4_0 || UNITY_5_0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#import "iPhone_View.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+extern UIViewController* UnityGetGLViewController(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define CHECK_IOS_VERSION( version )  ([[[UIDevice currentDevice] systemVersion] compare:version options:NSNumericSearch] != NSOrderedAscending) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@interface UNativeGallery:NSObject 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (int)checkPermission:(BOOL)readPermission permissionFreeMode:(BOOL)permissionFreeMode; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (int)requestPermission:(BOOL)readPermission permissionFreeMode:(BOOL)permissionFreeMode asyncMode:(BOOL)asyncMode; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (void)showLimitedLibraryPicker; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (int)canOpenSettings; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (void)openSettings; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (int)canPickMultipleMedia; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (void)saveMedia:(NSString *)path albumName:(NSString *)album isImg:(BOOL)isImg permissionFreeMode:(BOOL)permissionFreeMode; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (void)pickMedia:(int)mediaType savePath:(NSString *)mediaSavePath permissionFreeMode:(BOOL)permissionFreeMode selectionLimit:(int)selectionLimit; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (int)isMediaPickerBusy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (int)getMediaTypeFromExtension:(NSString *)extension; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (char *)getImageProperties:(NSString *)path; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (char *)getVideoProperties:(NSString *)path; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (char *)getVideoThumbnail:(NSString *)path savePath:(NSString *)savePath maximumSize:(int)maximumSize captureTime:(double)captureTime; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (char *)loadImageAtPath:(NSString *)path tempFilePath:(NSString *)tempFilePath maximumSize:(int)maximumSize; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@end 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@implementation UNativeGallery 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static NSString *pickedMediaSavePath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static UIPopoverController *popup; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static UIImagePickerController *imagePicker; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static PHPickerViewController *imagePickerNew; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static int imagePickerState = 0; // 0 -> none, 1 -> showing (always in this state on iPad), 2 -> finished 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static BOOL simpleMediaPickMode; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static BOOL pickingMultipleFiles = NO; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#pragma clang diagnostic push 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#pragma clang diagnostic ignored "-Wdeprecated-declarations" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (int)checkPermission:(BOOL)readPermission permissionFreeMode:(BOOL)permissionFreeMode 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( CHECK_IOS_VERSION( @"8.0" ) ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// version >= iOS 8: check permission using Photos framework 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// On iOS 11 and later, permission isn't mandatory to fetch media from Photos 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( readPermission && permissionFreeMode && CHECK_IOS_VERSION( @"11.0" ) ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// Photos permissions has changed on iOS 14 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( CHECK_IOS_VERSION( @"14.0" ) ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			// Request ReadWrite permission in 2 cases: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			// 1) When attempting to pick media from Photos with PHPhotoLibrary (readPermission=true and permissionFreeMode=false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			// 2) When attempting to write media to a specific album in Photos using PHPhotoLibrary (readPermission=false and permissionFreeMode=false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatusForAccessLevel:( ( readPermission || !permissionFreeMode ) ? PHAccessLevelReadWrite : PHAccessLevelAddOnly )]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if( status == PHAuthorizationStatusAuthorized ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				return 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			else if( status == PHAuthorizationStatusRestricted ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				return 3; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			else if( status == PHAuthorizationStatusNotDetermined ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				return 2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if( status == PHAuthorizationStatusAuthorized ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				return 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			else if( status == PHAuthorizationStatusNotDetermined ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				return 2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// version < iOS 8: check permission using AssetsLibrary framework (Photos framework not available) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( status == ALAuthorizationStatusAuthorized ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		else if( status == ALAuthorizationStatusNotDetermined ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return 2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#pragma clang diagnostic pop 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (int)requestPermission:(BOOL)readPermission permissionFreeMode:(BOOL)permissionFreeMode asyncMode:(BOOL)asyncMode 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	int result; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( CHECK_IOS_VERSION( @"8.0" ) ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// version >= iOS 8: request permission using Photos framework 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// On iOS 11 and later, permission isn't mandatory to fetch media from Photos 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( readPermission && permissionFreeMode && CHECK_IOS_VERSION( @"11.0" ) ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			result = 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		else if( CHECK_IOS_VERSION( @"14.0" ) ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			// Photos permissions has changed on iOS 14. There are 2 permission dialogs now: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			// - AddOnly permission dialog: has 2 options: "Allow" and "Don't Allow". This dialog grants permission for save operations only. Unfortunately, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			//   saving media to a custom album isn't possible with this dialog, media can only be saved to the default Photos album 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			// - ReadWrite permission dialog: has 3 options: "Allow Access to All Photos" (i.e. full permission), "Select Photos" (i.e. limited access) and 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			//   "Don't Allow". To be able to save media to a custom album, user must grant Full Photos permission. Thus, even when readPermission is false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			//   this dialog will be used if PermissionFreeMode is set to false. So, PermissionFreeMode determines whether or not saving to a custom album is 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			//   be supported 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			result = [self requestPermissionNewest:( readPermission || !permissionFreeMode ) asyncMode:asyncMode]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			result = [self requestPermissionNew:asyncMode]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// version < iOS 8: request permission using AssetsLibrary framework (Photos framework not available) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		result = [self requestPermissionOld:asyncMode]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( asyncMode && result >= 0 ) // Result returned immediately, forward it 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		UnitySendMessage( "NGPermissionCallbackiOS", "OnPermissionRequested", [self getCString:[NSString stringWithFormat:@"%d", result]] ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return result; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Credit: https://stackoverflow.com/a/26933380/2373034 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#pragma clang diagnostic push 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#pragma clang diagnostic ignored "-Wdeprecated-declarations" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (int)requestPermissionOld:(BOOL)asyncMode 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( status == ALAuthorizationStatusAuthorized ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else if( status == ALAuthorizationStatusNotDetermined ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( asyncMode ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			[[[ALAssetsLibrary alloc] init] enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^( ALAssetsGroup *group, BOOL *stop ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				*stop = YES; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				UnitySendMessage( "NGPermissionCallbackiOS", "OnPermissionRequested", "1" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			failureBlock:^( NSError *error ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				UnitySendMessage( "NGPermissionCallbackiOS", "OnPermissionRequested", "0" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			}]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			__block BOOL authorized = NO; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			dispatch_semaphore_t sema = dispatch_semaphore_create( 0 ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			[[[ALAssetsLibrary alloc] init] enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^( ALAssetsGroup *group, BOOL *stop ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				*stop = YES; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				authorized = YES; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				dispatch_semaphore_signal( sema ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			failureBlock:^( NSError *error ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				dispatch_semaphore_signal( sema ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			}]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			dispatch_semaphore_wait( sema, DISPATCH_TIME_FOREVER ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return authorized ? 1 : 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#pragma clang diagnostic pop 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Credit: https://stackoverflow.com/a/32989022/2373034 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (int)requestPermissionNew:(BOOL)asyncMode 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( status == PHAuthorizationStatusAuthorized ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else if( status == PHAuthorizationStatusNotDetermined ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( asyncMode ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			[PHPhotoLibrary requestAuthorization:^( PHAuthorizationStatus status ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				UnitySendMessage( "NGPermissionCallbackiOS", "OnPermissionRequested", ( status == PHAuthorizationStatusAuthorized ) ? "1" : "0" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			}]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			__block BOOL authorized = NO; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			dispatch_semaphore_t sema = dispatch_semaphore_create( 0 ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			[PHPhotoLibrary requestAuthorization:^( PHAuthorizationStatus status ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				authorized = ( status == PHAuthorizationStatusAuthorized ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				dispatch_semaphore_signal( sema ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			}]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			dispatch_semaphore_wait( sema, DISPATCH_TIME_FOREVER ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return authorized ? 1 : 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (int)requestPermissionNewest:(BOOL)readPermission asyncMode:(BOOL)asyncMode 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatusForAccessLevel:( readPermission ? PHAccessLevelReadWrite : PHAccessLevelAddOnly )]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( status == PHAuthorizationStatusAuthorized ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else if( status == PHAuthorizationStatusRestricted ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return 3; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else if( status == PHAuthorizationStatusNotDetermined ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( asyncMode ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			[PHPhotoLibrary requestAuthorizationForAccessLevel:( readPermission ? PHAccessLevelReadWrite : PHAccessLevelAddOnly ) handler:^( PHAuthorizationStatus status ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if( status == PHAuthorizationStatusAuthorized ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					UnitySendMessage( "NGPermissionCallbackiOS", "OnPermissionRequested", "1" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				else if( status == PHAuthorizationStatusRestricted ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					UnitySendMessage( "NGPermissionCallbackiOS", "OnPermissionRequested", "3" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					UnitySendMessage( "NGPermissionCallbackiOS", "OnPermissionRequested", "0" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			}]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			__block int authorized = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			dispatch_semaphore_t sema = dispatch_semaphore_create( 0 ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			[PHPhotoLibrary requestAuthorizationForAccessLevel:( readPermission ? PHAccessLevelReadWrite : PHAccessLevelAddOnly ) handler:^( PHAuthorizationStatus status ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if( status == PHAuthorizationStatusAuthorized ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					authorized = 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				else if( status == PHAuthorizationStatusRestricted ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					authorized = 3; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				dispatch_semaphore_signal( sema ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			}]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			dispatch_semaphore_wait( sema, DISPATCH_TIME_FOREVER ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return authorized; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// When Photos permission is set to restricted, allows user to change the permission or change the list of restricted images 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// It doesn't support a deterministic callback; for example there is a photoLibraryDidChange event but it won't be invoked if 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// user doesn't change the list of restricted images 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (void)showLimitedLibraryPicker 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatusForAccessLevel:PHAccessLevelReadWrite]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( status == PHAuthorizationStatusNotDetermined ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		[self requestPermissionNewest:YES asyncMode:YES]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else if( status == PHAuthorizationStatusRestricted ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		[[PHPhotoLibrary sharedPhotoLibrary] presentLimitedLibraryPickerFromViewController:UnityGetGLViewController()]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Credit: https://stackoverflow.com/a/25453667/2373034 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (int)canOpenSettings 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return ( &UIApplicationOpenSettingsURLString != NULL ) ? 1 : 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Credit: https://stackoverflow.com/a/25453667/2373034 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#pragma clang diagnostic push 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#pragma clang diagnostic ignored "-Wdeprecated-declarations" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (void)openSettings 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( &UIApplicationOpenSettingsURLString != NULL ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( CHECK_IOS_VERSION( @"10.0" ) ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:nil]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#pragma clang diagnostic pop 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (int)canPickMultipleMedia 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( CHECK_IOS_VERSION( @"14.0" ) ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (void)saveMedia:(NSString *)path albumName:(NSString *)album isImg:(BOOL)isImg permissionFreeMode:(BOOL)permissionFreeMode 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( CHECK_IOS_VERSION( @"8.0" ) ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// version >= iOS 8: save to specified album using Photos framework 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// On iOS 14+, permission workflow has changed significantly with the addition of PHAuthorizationStatusRestricted permission. On those versions, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// user must grant Full Photos permission to be able to save to a custom album. Hence, there are 2 workflows: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// - If PermissionFreeMode is enabled, save the media directly to the default album (i.e. ignore 'album' parameter). This will present a simple 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		//   permission dialog stating "The app requires access to Photos to save media to it." and the "Selected Photos" permission won't be listed in the options 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// - Otherwise, the more complex "The app requires access to Photos to interact with it." permission dialog will be shown and if the user grants 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		//   Full Photos permission, only then the image will be saved to the specified album. If user selects "Selected Photos" permission, default album will be 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		//   used as fallback 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		[self saveMediaNew:path albumName:album isImage:isImg saveToDefaultAlbum:( permissionFreeMode && CHECK_IOS_VERSION( @"14.0" ) )]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// version < iOS 8: save using AssetsLibrary framework (Photos framework not available) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		[self saveMediaOld:path albumName:album isImage:isImg]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Credit: https://stackoverflow.com/a/22056664/2373034 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#pragma clang diagnostic push 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#pragma clang diagnostic ignored "-Wdeprecated-declarations" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (void)saveMediaOld:(NSString *)path albumName:(NSString *)album isImage:(BOOL)isImage 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( !isImage && ![library videoAtPathIsCompatibleWithSavedPhotosAlbum:[NSURL fileURLWithPath:path]]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		NSLog( @"Error saving video: Video format is not compatible with Photos" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		[[NSFileManager defaultManager] removeItemAtPath:path error:nil]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		UnitySendMessage( "NGMediaSaveCallbackiOS", "OnMediaSaveFailed", "" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	void (^saveBlock)(ALAssetsGroup *assetCollection) = ^void( ALAssetsGroup *assetCollection ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		void (^saveResultBlock)(NSURL *assetURL, NSError *error) = ^void( NSURL *assetURL, NSError *error ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			[[NSFileManager defaultManager] removeItemAtPath:path error:nil]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if( error.code == 0 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				[library assetForURL:assetURL resultBlock:^( ALAsset *asset ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					[assetCollection addAsset:asset]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					UnitySendMessage( "NGMediaSaveCallbackiOS", "OnMediaSaveCompleted", "" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				failureBlock:^( NSError* error ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					NSLog( @"Error moving asset to album: %@", error ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					UnitySendMessage( "NGMediaSaveCallbackiOS", "OnMediaSaveFailed", "" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				}]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				NSLog( @"Error creating asset: %@", error ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				UnitySendMessage( "NGMediaSaveCallbackiOS", "OnMediaSaveFailed", "" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( !isImage ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			[library writeImageDataToSavedPhotosAlbum:[NSData dataWithContentsOfFile:path] metadata:nil completionBlock:saveResultBlock]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			[library writeVideoAtPathToSavedPhotosAlbum:[NSURL fileURLWithPath:path] completionBlock:saveResultBlock]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	__block BOOL albumFound = NO; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	[library enumerateGroupsWithTypes:ALAssetsGroupAlbum usingBlock:^( ALAssetsGroup *group, BOOL *stop ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( [[group valueForProperty:ALAssetsGroupPropertyName] isEqualToString:album] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			*stop = YES; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			albumFound = YES; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			saveBlock( group ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		else if( group == nil && albumFound==NO ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			// Album doesn't exist 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			[library addAssetsGroupAlbumWithName:album resultBlock:^( ALAssetsGroup *group ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				saveBlock( group ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			failureBlock:^( NSError *error ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				NSLog( @"Error creating album: %@", error ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				[[NSFileManager defaultManager] removeItemAtPath:path error:nil]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				UnitySendMessage( "NGMediaSaveCallbackiOS", "OnMediaSaveFailed", "" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			}]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	failureBlock:^( NSError* error ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		NSLog( @"Error listing albums: %@", error ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		[[NSFileManager defaultManager] removeItemAtPath:path error:nil]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		UnitySendMessage( "NGMediaSaveCallbackiOS", "OnMediaSaveFailed", "" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#pragma clang diagnostic pop 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Credit: https://stackoverflow.com/a/39909129/2373034 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (void)saveMediaNew:(NSString *)path albumName:(NSString *)album isImage:(BOOL)isImage saveToDefaultAlbum:(BOOL)saveToDefaultAlbum 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	void (^saveToPhotosAlbum)() = ^void() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( isImage ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			// Try preserving image metadata (essential for animated gif images) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			[[PHPhotoLibrary sharedPhotoLibrary] performChanges: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			^{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				[PHAssetChangeRequest creationRequestForAssetFromImageAtFileURL:[NSURL fileURLWithPath:path]]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			completionHandler:^( BOOL success, NSError *error ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if( success ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					[[NSFileManager defaultManager] removeItemAtPath:path error:nil]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					UnitySendMessage( "NGMediaSaveCallbackiOS", "OnMediaSaveCompleted", "" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					NSLog( @"Error creating asset in default Photos album: %@", error ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					UIImage *image = [UIImage imageWithContentsOfFile:path]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					if( image != nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						UIImageWriteToSavedPhotosAlbum( image, self, @selector(image:didFinishSavingWithError:contextInfo:), (__bridge_retained void *) path ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						NSLog( @"Couldn't create UIImage from file at path: %@", path ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						[[NSFileManager defaultManager] removeItemAtPath:path error:nil]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						UnitySendMessage( "NGMediaSaveCallbackiOS", "OnMediaSaveFailed", "" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			}]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if( UIVideoAtPathIsCompatibleWithSavedPhotosAlbum( path ) ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				UISaveVideoAtPathToSavedPhotosAlbum( path, self, @selector(video:didFinishSavingWithError:contextInfo:), (__bridge_retained void *) path ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				NSLog( @"Video at path isn't compatible with saved photos album: %@", path ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				[[NSFileManager defaultManager] removeItemAtPath:path error:nil]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				UnitySendMessage( "NGMediaSaveCallbackiOS", "OnMediaSaveFailed", "" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	void (^saveBlock)(PHAssetCollection *assetCollection) = ^void( PHAssetCollection *assetCollection ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		[[PHPhotoLibrary sharedPhotoLibrary] performChanges: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		^{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			PHAssetChangeRequest *assetChangeRequest; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if( isImage ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImageAtFileURL:[NSURL fileURLWithPath:path]]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:[NSURL fileURLWithPath:path]]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			PHAssetCollectionChangeRequest *assetCollectionChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			[assetCollectionChangeRequest addAssets:@[[assetChangeRequest placeholderForCreatedAsset]]]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		completionHandler:^( BOOL success, NSError *error ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if( success ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				[[NSFileManager defaultManager] removeItemAtPath:path error:nil]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				UnitySendMessage( "NGMediaSaveCallbackiOS", "OnMediaSaveCompleted", "" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				NSLog( @"Error creating asset: %@", error ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				saveToPhotosAlbum(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		}]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( saveToDefaultAlbum ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		saveToPhotosAlbum(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		PHFetchOptions *fetchOptions = [[PHFetchOptions alloc] init]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		fetchOptions.predicate = [NSPredicate predicateWithFormat:@"localizedTitle = %@", album]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		PHFetchResult *fetchResult = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAny options:fetchOptions]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( fetchResult.count > 0 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			saveBlock( fetchResult.firstObject); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			__block PHObjectPlaceholder *albumPlaceholder; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			[[PHPhotoLibrary sharedPhotoLibrary] performChanges: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			^{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				PHAssetCollectionChangeRequest *changeRequest = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:album]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				albumPlaceholder = changeRequest.placeholderForCreatedAssetCollection; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			completionHandler:^( BOOL success, NSError *error ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if( success ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					PHFetchResult *fetchResult = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[albumPlaceholder.localIdentifier] options:nil]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					if( fetchResult.count > 0 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						saveBlock( fetchResult.firstObject); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						NSLog( @"Error creating album: Album placeholder not found" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						saveToPhotosAlbum(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					NSLog( @"Error creating album: %@", error ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					saveToPhotosAlbum(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			}]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	NSString* path = (__bridge_transfer NSString *)(contextInfo); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	[[NSFileManager defaultManager] removeItemAtPath:path error:nil]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( error == nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		UnitySendMessage( "NGMediaSaveCallbackiOS", "OnMediaSaveCompleted", "" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		NSLog( @"Error saving image with UIImageWriteToSavedPhotosAlbum: %@", error ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		UnitySendMessage( "NGMediaSaveCallbackiOS", "OnMediaSaveFailed", "" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (void)video:(NSString *)videoPath didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	NSString* path = (__bridge_transfer NSString *)(contextInfo); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	[[NSFileManager defaultManager] removeItemAtPath:path error:nil]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( error == nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		UnitySendMessage( "NGMediaSaveCallbackiOS", "OnMediaSaveCompleted", "" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		NSLog( @"Error saving video with UISaveVideoAtPathToSavedPhotosAlbum: %@", error ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		UnitySendMessage( "NGMediaSaveCallbackiOS", "OnMediaSaveFailed", "" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Credit: https://stackoverflow.com/a/10531752/2373034 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (void)pickMedia:(int)mediaType savePath:(NSString *)mediaSavePath permissionFreeMode:(BOOL)permissionFreeMode selectionLimit:(int)selectionLimit 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	pickedMediaSavePath = mediaSavePath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	imagePickerState = 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	simpleMediaPickMode = permissionFreeMode && CHECK_IOS_VERSION( @"11.0" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( CHECK_IOS_VERSION( @"14.0" ) ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// PHPickerViewController is used on iOS 14 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		PHPickerConfiguration *config = simpleMediaPickMode ? [[PHPickerConfiguration alloc] init] : [[PHPickerConfiguration alloc] initWithPhotoLibrary:[PHPhotoLibrary sharedPhotoLibrary]]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		config.preferredAssetRepresentationMode = PHPickerConfigurationAssetRepresentationModeCurrent; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		config.selectionLimit = selectionLimit; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		pickingMultipleFiles = selectionLimit != 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// mediaType is a bitmask: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// 1: image 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// 2: video 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// 4: audio (not supported) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( mediaType == 1 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			config.filter = [PHPickerFilter anyFilterMatchingSubfilters:[NSArray arrayWithObjects:[PHPickerFilter imagesFilter], [PHPickerFilter livePhotosFilter], nil]]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		else if( mediaType == 2 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			config.filter = [PHPickerFilter videosFilter]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			config.filter = [PHPickerFilter anyFilterMatchingSubfilters:[NSArray arrayWithObjects:[PHPickerFilter imagesFilter], [PHPickerFilter livePhotosFilter], [PHPickerFilter videosFilter], nil]]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		imagePickerNew = [[PHPickerViewController alloc] initWithConfiguration:config]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		imagePickerNew.delegate = (id) self; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		[UnityGetGLViewController() presentViewController:imagePickerNew animated:YES completion:^{ imagePickerState = 0; }]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// UIImagePickerController is used on previous versions 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		imagePicker = [[UIImagePickerController alloc] init]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		imagePicker.delegate = (id) self; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		imagePicker.allowsEditing = NO; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// mediaType is a bitmask: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// 1: image 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// 2: video 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// 4: audio (not supported) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( mediaType == 1 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if( CHECK_IOS_VERSION( @"9.1" ) ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				imagePicker.mediaTypes = [NSArray arrayWithObjects:(NSString *)kUTTypeImage, (NSString *)kUTTypeLivePhoto, nil]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				imagePicker.mediaTypes = [NSArray arrayWithObject:(NSString *)kUTTypeImage]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		else if( mediaType == 2 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			imagePicker.mediaTypes = [NSArray arrayWithObjects:(NSString *)kUTTypeMovie, (NSString *)kUTTypeVideo, nil]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if( CHECK_IOS_VERSION( @"9.1" ) ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				imagePicker.mediaTypes = [NSArray arrayWithObjects:(NSString *)kUTTypeImage, (NSString *)kUTTypeLivePhoto, (NSString *)kUTTypeMovie, (NSString *)kUTTypeVideo, nil]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				imagePicker.mediaTypes = [NSArray arrayWithObjects:(NSString *)kUTTypeImage, (NSString *)kUTTypeMovie, (NSString *)kUTTypeVideo, nil]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( mediaType != 1 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			// Don't compress picked videos if possible 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if( CHECK_IOS_VERSION( @"11.0" ) ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				imagePicker.videoExportPreset = AVAssetExportPresetPassthrough; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		UIViewController *rootViewController = UnityGetGLViewController(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone ) // iPhone 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			[rootViewController presentViewController:imagePicker animated:YES completion:^{ imagePickerState = 0; }]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			// iPad 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			popup = [[UIPopoverController alloc] initWithContentViewController:imagePicker]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			popup.delegate = (id) self; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			[popup presentPopoverFromRect:CGRectMake( rootViewController.view.frame.size.width / 2, rootViewController.view.frame.size.height / 2, 1, 1 ) inView:rootViewController.view permittedArrowDirections:0 animated:YES]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (int)isMediaPickerBusy 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( imagePickerState == 2 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( imagePicker != nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( imagePickerState == 1 || [imagePicker presentingViewController] == UnityGetGLViewController() ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			imagePicker = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else if( CHECK_IOS_VERSION( @"14.0" ) && imagePickerNew != nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( imagePickerState == 1 || [imagePickerNew presentingViewController] == UnityGetGLViewController() ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			imagePickerNew = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#pragma clang diagnostic push 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#pragma clang diagnostic ignored "-Wdeprecated-declarations" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	NSString *resultPath = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( [info[UIImagePickerControllerMediaType] isEqualToString:(NSString *)kUTTypeImage] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		NSLog( @"Picked an image" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// On iOS 8.0 or later, try to obtain the raw data of the image (which allows picking gifs properly or preserving metadata) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( CHECK_IOS_VERSION( @"8.0" ) ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			PHAsset *asset = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if( CHECK_IOS_VERSION( @"11.0" ) ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				// Try fetching the source image via UIImagePickerControllerImageURL 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				NSURL *mediaUrl = info[UIImagePickerControllerImageURL]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if( mediaUrl != nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					NSString *imagePath = [mediaUrl path]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					if( imagePath != nil && [[NSFileManager defaultManager] fileExistsAtPath:imagePath] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						NSError *error; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						NSString *newPath = [pickedMediaSavePath stringByAppendingPathExtension:[imagePath pathExtension]]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						if( ![[NSFileManager defaultManager] fileExistsAtPath:newPath] || [[NSFileManager defaultManager] removeItemAtPath:newPath error:&error] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							if( [[NSFileManager defaultManager] copyItemAtPath:imagePath toPath:newPath error:&error] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								resultPath = newPath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								NSLog( @"Copied source image from UIImagePickerControllerImageURL" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								NSLog( @"Error copying image: %@", error ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							NSLog( @"Error deleting existing image: %@", error ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if( resultPath == nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					asset = info[UIImagePickerControllerPHAsset]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if( resultPath == nil && !simpleMediaPickMode ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if( asset == nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					NSURL *mediaUrl = info[UIImagePickerControllerReferenceURL] ?: info[UIImagePickerControllerMediaURL]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					if( mediaUrl != nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						asset = [[PHAsset fetchAssetsWithALAssetURLs:[NSArray arrayWithObject:mediaUrl] options:nil] firstObject]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				resultPath = [self trySavePHAsset:asset atIndex:1]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( resultPath == nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			// Save image as PNG 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			UIImage *image = info[UIImagePickerControllerOriginalImage]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if( image != nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				resultPath = [pickedMediaSavePath stringByAppendingPathExtension:@"png"]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if( ![self saveImageAsPNG:image toPath:resultPath] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					NSLog( @"Error creating PNG image" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					resultPath = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				NSLog( @"Error fetching original image from picker" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else if( CHECK_IOS_VERSION( @"9.1" ) && [info[UIImagePickerControllerMediaType] isEqualToString:(NSString *)kUTTypeLivePhoto] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		NSLog( @"Picked a live photo" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// Save live photo as PNG 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		UIImage *image = info[UIImagePickerControllerOriginalImage]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( image != nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			resultPath = [pickedMediaSavePath stringByAppendingPathExtension:@"png"]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if( ![self saveImageAsPNG:image toPath:resultPath] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				NSLog( @"Error creating PNG image" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				resultPath = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			NSLog( @"Error fetching live photo's still image from picker" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		NSLog( @"Picked a video" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		NSURL *mediaUrl = info[UIImagePickerControllerMediaURL] ?: info[UIImagePickerControllerReferenceURL]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( mediaUrl != nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			resultPath = [mediaUrl path]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			// On iOS 13, picked file becomes unreachable as soon as the UIImagePickerController disappears, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			// in that case, copy the video to a temporary location 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if( CHECK_IOS_VERSION( @"13.0" ) ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				NSError *error; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				NSString *newPath = [pickedMediaSavePath stringByAppendingPathExtension:[resultPath pathExtension]]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if( ![[NSFileManager defaultManager] fileExistsAtPath:newPath] || [[NSFileManager defaultManager] removeItemAtPath:newPath error:&error] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					if( [[NSFileManager defaultManager] copyItemAtPath:resultPath toPath:newPath error:&error] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						resultPath = newPath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						NSLog( @"Error copying video: %@", error ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						resultPath = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					NSLog( @"Error deleting existing video: %@", error ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					resultPath = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	popup = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	imagePicker = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	imagePickerState = 2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	UnitySendMessage( "NGMediaReceiveCallbackiOS", "OnMediaReceived", [self getCString:resultPath] ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	[picker dismissViewControllerAnimated:NO completion:nil]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#pragma clang diagnostic pop 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Credit: https://ikyle.me/blog/2020/phpickerviewcontroller 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++(void)picker:(PHPickerViewController *)picker didFinishPicking:(NSArray<PHPickerResult *> *)results 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	imagePickerNew = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	imagePickerState = 2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	[picker dismissViewControllerAnimated:NO completion:nil]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( results != nil && [results count] > 0 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		NSMutableArray<NSString *> *resultPaths = [NSMutableArray arrayWithCapacity:[results count]]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		NSLock *arrayLock = [[NSLock alloc] init]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		dispatch_group_t group = dispatch_group_create(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		for( int i = 0; i < [results count]; i++ ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			PHPickerResult *result = results[i]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			NSItemProvider *itemProvider = result.itemProvider; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			NSString *assetIdentifier = result.assetIdentifier; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			__block NSString *resultPath = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			int j = i + 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			//NSLog( @"result: %@", result ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			//NSLog( @"%@", result.assetIdentifier); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			//NSLog( @"%@", result.itemProvider); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if( [itemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeImage] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				NSLog( @"Picked an image" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if( !simpleMediaPickMode && assetIdentifier != nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					PHAsset *asset = [[PHAsset fetchAssetsWithLocalIdentifiers:[NSArray arrayWithObject:assetIdentifier] options:nil] firstObject]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					resultPath = [self trySavePHAsset:asset atIndex:j]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if( resultPath != nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					[arrayLock lock]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					[resultPaths addObject:resultPath]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					[arrayLock unlock]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					dispatch_group_enter( group ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					[itemProvider loadFileRepresentationForTypeIdentifier:(NSString *)kUTTypeImage completionHandler:^( NSURL *url, NSError *error ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						if( url != nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							// Copy the image to a temporary location because the returned image will be deleted by the OS after this callback is completed 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							resultPath = [url path]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							NSString *newPath = [[NSString stringWithFormat:@"%@%d", pickedMediaSavePath, j] stringByAppendingPathExtension:[resultPath pathExtension]]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							if( ![[NSFileManager defaultManager] fileExistsAtPath:newPath] || [[NSFileManager defaultManager] removeItemAtPath:newPath error:&error] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								if( [[NSFileManager defaultManager] copyItemAtPath:resultPath toPath:newPath error:&error]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									resultPath = newPath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									NSLog( @"Error copying image: %@", error ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									resultPath = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								NSLog( @"Error deleting existing image: %@", error ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								resultPath = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							NSLog( @"Error getting the picked image's path: %@", error ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						if( resultPath != nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							[arrayLock lock]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							[resultPaths addObject:resultPath]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							[arrayLock unlock]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							if( [itemProvider canLoadObjectOfClass:[UIImage class]] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								dispatch_group_enter( group ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								[itemProvider loadObjectOfClass:[UIImage class] completionHandler:^( __kindof id<NSItemProviderReading> object, NSError *error ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									if( object != nil && [object isKindOfClass:[UIImage class]] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										resultPath = [[NSString stringWithFormat:@"%@%d", pickedMediaSavePath, j] stringByAppendingPathExtension:@"png"]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										if( ![self saveImageAsPNG:(UIImage *)object toPath:resultPath] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+											NSLog( @"Error creating PNG image" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+											resultPath = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										NSLog( @"Error generating UIImage from picked image: %@", error ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									[arrayLock lock]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									[resultPaths addObject:( resultPath != nil ? resultPath : @"" )]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									[arrayLock unlock]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									dispatch_group_leave( group ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								}]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								NSLog( @"Can't generate UIImage from picked image" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								[arrayLock lock]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								[resultPaths addObject:@""]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								[arrayLock unlock]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						dispatch_group_leave( group ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					}]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			else if( CHECK_IOS_VERSION( @"9.1" ) && [itemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeLivePhoto] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				NSLog( @"Picked a live photo" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if( [itemProvider canLoadObjectOfClass:[UIImage class]] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					dispatch_group_enter( group ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					[itemProvider loadObjectOfClass:[UIImage class] completionHandler:^( __kindof id<NSItemProviderReading> object, NSError *error ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						if( object != nil && [object isKindOfClass:[UIImage class]] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							resultPath = [[NSString stringWithFormat:@"%@%d", pickedMediaSavePath, j] stringByAppendingPathExtension:@"png"]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							if( ![self saveImageAsPNG:(UIImage *)object toPath:resultPath] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								NSLog( @"Error creating PNG image" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								resultPath = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							NSLog( @"Error generating UIImage from picked live photo: %@", error ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						[arrayLock lock]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						[resultPaths addObject:( resultPath != nil ? resultPath : @"" )]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						[arrayLock unlock]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						dispatch_group_leave( group ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					}]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				else if( [itemProvider canLoadObjectOfClass:[PHLivePhoto class]] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					dispatch_group_enter( group ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					[itemProvider loadObjectOfClass:[PHLivePhoto class] completionHandler:^( __kindof id<NSItemProviderReading> object, NSError *error ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						if( object != nil && [object isKindOfClass:[PHLivePhoto class]] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							// Extract image data from live photo 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							// Credit: https://stackoverflow.com/a/41341675/2373034 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							NSArray<PHAssetResource*>* livePhotoResources = [PHAssetResource assetResourcesForLivePhoto:(PHLivePhoto *)object]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							PHAssetResource *livePhotoImage = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							for( int k = 0; k < [livePhotoResources count]; k++ ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								if( livePhotoResources[k].type == PHAssetResourceTypePhoto ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									livePhotoImage = livePhotoResources[k]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							if( livePhotoImage == nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								NSLog( @"Error extracting image data from live photo" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								[arrayLock lock]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								[resultPaths addObject:@""]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								[arrayLock unlock]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								dispatch_group_enter( group ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								NSString *originalFilename = livePhotoImage.originalFilename; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								if( originalFilename == nil || [originalFilename length] == 0 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									resultPath = [NSString stringWithFormat:@"%@%d", pickedMediaSavePath, j]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									resultPath = [[NSString stringWithFormat:@"%@%d", pickedMediaSavePath, j] stringByAppendingPathExtension:[originalFilename pathExtension]]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								[[PHAssetResourceManager defaultManager] writeDataForAssetResource:livePhotoImage toFile:[NSURL fileURLWithPath:resultPath] options:nil completionHandler:^( NSError * _Nullable error2 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									if( error2 != nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										NSLog( @"Error saving image data from live photo: %@", error2 ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										resultPath = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									[arrayLock lock]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									[resultPaths addObject:( resultPath != nil ? resultPath : @"" )]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									[arrayLock unlock]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									dispatch_group_leave( group ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								}]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							NSLog( @"Error generating PHLivePhoto from picked live photo: %@", error ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							[arrayLock lock]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							[resultPaths addObject:@""]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							[arrayLock unlock]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						dispatch_group_leave( group ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					}]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					NSLog( @"Can't convert picked live photo to still image" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					[arrayLock lock]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					[resultPaths addObject:@""]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					[arrayLock unlock]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			else if( [itemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeMovie] || [itemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeVideo] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				NSLog( @"Picked a video" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				// Get the video file's path 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				dispatch_group_enter( group ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				[itemProvider loadFileRepresentationForTypeIdentifier:([itemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeMovie] ? (NSString *)kUTTypeMovie : (NSString *)kUTTypeVideo) completionHandler:^( NSURL *url, NSError *error ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					if( url != nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						// Copy the video to a temporary location because the returned video will be deleted by the OS after this callback is completed 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						resultPath = [url path]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						NSString *newPath = [[NSString stringWithFormat:@"%@%d", pickedMediaSavePath, j] stringByAppendingPathExtension:[resultPath pathExtension]]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						if( ![[NSFileManager defaultManager] fileExistsAtPath:newPath] || [[NSFileManager defaultManager] removeItemAtPath:newPath error:&error] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							if( [[NSFileManager defaultManager] copyItemAtPath:resultPath toPath:newPath error:&error]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								resultPath = newPath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								NSLog( @"Error copying video: %@", error ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								resultPath = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							NSLog( @"Error deleting existing video: %@", error ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							resultPath = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						NSLog( @"Error getting the picked video's path: %@", error ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					[arrayLock lock]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					[resultPaths addObject:( resultPath != nil ? resultPath : @"" )]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					[arrayLock unlock]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					dispatch_group_leave( group ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				}]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				// Unknown media type picked? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				NSLog( @"Couldn't determine type of picked media: %@", itemProvider ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				[arrayLock lock]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				[resultPaths addObject:@""]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				[arrayLock unlock]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		dispatch_group_notify( group, dispatch_get_main_queue(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		^{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if( !pickingMultipleFiles ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				UnitySendMessage( "NGMediaReceiveCallbackiOS", "OnMediaReceived", [self getCString:resultPaths[0]] ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				UnitySendMessage( "NGMediaReceiveCallbackiOS", "OnMultipleMediaReceived", [self getCString:[resultPaths componentsJoinedByString:@">"]] ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		NSLog( @"No media picked" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( !pickingMultipleFiles ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			UnitySendMessage( "NGMediaReceiveCallbackiOS", "OnMediaReceived", "" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			UnitySendMessage( "NGMediaReceiveCallbackiOS", "OnMultipleMediaReceived", "" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	NSLog( @"UIImagePickerController cancelled" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	popup = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	imagePicker = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	UnitySendMessage( "NGMediaReceiveCallbackiOS", "OnMediaReceived", "" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	[picker dismissViewControllerAnimated:NO completion:nil]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	NSLog( @"UIPopoverController dismissed" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	popup = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	imagePicker = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	UnitySendMessage( "NGMediaReceiveCallbackiOS", "OnMediaReceived", "" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (NSString *)trySavePHAsset:(PHAsset *)asset atIndex:(int)filenameIndex 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( asset == nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	__block NSString *resultPath = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	options.synchronous = YES; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	options.version = PHImageRequestOptionsVersionCurrent; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( CHECK_IOS_VERSION( @"13.0" ) ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		[[PHImageManager defaultManager] requestImageDataAndOrientationForAsset:asset options:options resultHandler:^( NSData *imageData, NSString *dataUTI, CGImagePropertyOrientation orientation, NSDictionary *imageInfo ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if( imageData != nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				resultPath = [self trySaveSourceImage:imageData withInfo:imageInfo atIndex:filenameIndex]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				NSLog( @"Couldn't fetch raw image data" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		}]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		[[PHImageManager defaultManager] requestImageDataForAsset:asset options:options resultHandler:^( NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *imageInfo ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if( imageData != nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				resultPath = [self trySaveSourceImage:imageData withInfo:imageInfo atIndex:filenameIndex]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				NSLog( @"Couldn't fetch raw image data" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		}]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return resultPath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (NSString *)trySaveSourceImage:(NSData *)imageData withInfo:(NSDictionary *)info atIndex:(int)filenameIndex 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	NSString *filePath = info[@"PHImageFileURLKey"]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( filePath != nil ) // filePath can actually be an NSURL, convert it to NSString 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		filePath = [NSString stringWithFormat:@"%@", filePath]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( filePath == nil || [filePath length] == 0 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		filePath = info[@"PHImageFileUTIKey"]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( filePath != nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			filePath = [NSString stringWithFormat:@"%@", filePath]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	NSString *resultPath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( filePath == nil || [filePath length] == 0 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		resultPath = [NSString stringWithFormat:@"%@%d", pickedMediaSavePath, filenameIndex]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		resultPath = [[NSString stringWithFormat:@"%@%d", pickedMediaSavePath, filenameIndex] stringByAppendingPathExtension:[filePath pathExtension]]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	NSError *error; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( ![[NSFileManager defaultManager] fileExistsAtPath:resultPath] || [[NSFileManager defaultManager] removeItemAtPath:resultPath error:&error] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( ![imageData writeToFile:resultPath atomically:YES] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			NSLog( @"Error copying source image to file" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			resultPath = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		NSLog( @"Error deleting existing image: %@", error ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		resultPath = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return resultPath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Credit: https://lists.apple.com/archives/cocoa-dev/2012/Jan/msg00052.html 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (int)getMediaTypeFromExtension:(NSString *)extension 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	CFStringRef fileUTI = UTTypeCreatePreferredIdentifierForTag( kUTTagClassFilenameExtension, (__bridge CFStringRef) extension, NULL ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// mediaType is a bitmask: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// 1: image 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// 2: video 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// 4: audio (not supported) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	int result = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( UTTypeConformsTo( fileUTI, kUTTypeImage ) ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		result = 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else if( CHECK_IOS_VERSION( @"9.1" ) && UTTypeConformsTo( fileUTI, kUTTypeLivePhoto ) ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		result = 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else if( UTTypeConformsTo( fileUTI, kUTTypeMovie ) || UTTypeConformsTo( fileUTI, kUTTypeVideo ) ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		result = 2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else if( UTTypeConformsTo( fileUTI, kUTTypeAudio ) ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		result = 4; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	CFRelease( fileUTI ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return result; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Credit: https://stackoverflow.com/a/4170099/2373034 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (NSArray *)getImageMetadata:(NSString *)path 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	int width = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	int height = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	int orientation = -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	CGImageSourceRef imageSource = CGImageSourceCreateWithURL( (__bridge CFURLRef) [NSURL fileURLWithPath:path], nil ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( imageSource != nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO] forKey:(__bridge NSString *)kCGImageSourceShouldCache]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex( imageSource, 0, (__bridge CFDictionaryRef) options ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		CFRelease( imageSource ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		CGFloat widthF = 0.0f, heightF = 0.0f; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( imageProperties != nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if( CFDictionaryContainsKey( imageProperties, kCGImagePropertyPixelWidth ) ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				CFNumberGetValue( (CFNumberRef) CFDictionaryGetValue( imageProperties, kCGImagePropertyPixelWidth ), kCFNumberCGFloatType, &widthF ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if( CFDictionaryContainsKey( imageProperties, kCGImagePropertyPixelHeight ) ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				CFNumberGetValue( (CFNumberRef) CFDictionaryGetValue( imageProperties, kCGImagePropertyPixelHeight ), kCFNumberCGFloatType, &heightF ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if( CFDictionaryContainsKey( imageProperties, kCGImagePropertyOrientation ) ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				CFNumberGetValue( (CFNumberRef) CFDictionaryGetValue( imageProperties, kCGImagePropertyOrientation ), kCFNumberIntType, &orientation ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if( orientation > 4 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					// Landscape image 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					CGFloat temp = widthF; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					widthF = heightF; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					heightF = temp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			CFRelease( imageProperties ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		width = (int) roundf( widthF ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		height = (int) roundf( heightF ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return [[NSArray alloc] initWithObjects:[NSNumber numberWithInt:width], [NSNumber numberWithInt:height], [NSNumber numberWithInt:orientation], nil]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (char *)getImageProperties:(NSString *)path 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	NSArray *metadata = [self getImageMetadata:path]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	int orientationUnity; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	int orientation = [metadata[2] intValue]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// To understand the magic numbers, see ImageOrientation enum in NativeGallery.cs 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// and http://sylvana.net/jpegcrop/exif_orientation.html 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( orientation == 1 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		orientationUnity = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else if( orientation == 2 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		orientationUnity = 4; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else if( orientation == 3 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		orientationUnity = 2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else if( orientation == 4 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		orientationUnity = 6; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else if( orientation == 5 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		orientationUnity = 5; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else if( orientation == 6 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		orientationUnity = 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else if( orientation == 7 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		orientationUnity = 7; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else if( orientation == 8 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		orientationUnity = 3; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		orientationUnity = -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return [self getCString:[NSString stringWithFormat:@"%d>%d> >%d", [metadata[0] intValue], [metadata[1] intValue], orientationUnity]]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (char *)getVideoProperties:(NSString *)path 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	CGSize size = CGSizeZero; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	float rotation = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	long long duration = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	AVURLAsset *asset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:path] options:nil]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( asset != nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		duration = (long long) round( CMTimeGetSeconds( [asset duration] ) * 1000 ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		CGAffineTransform transform = [asset preferredTransform]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		NSArray<AVAssetTrack *>* videoTracks = [asset tracksWithMediaType:AVMediaTypeVideo]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( videoTracks != nil && [videoTracks count] > 0 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			size = [[videoTracks objectAtIndex:0] naturalSize]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			transform = [[videoTracks objectAtIndex:0] preferredTransform]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		rotation = atan2( transform.b, transform.a ) * ( 180.0 / M_PI ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return [self getCString:[NSString stringWithFormat:@"%d>%d>%lld>%f", (int) roundf( size.width ), (int) roundf( size.height ), duration, rotation]]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (char *)getVideoThumbnail:(NSString *)path savePath:(NSString *)savePath maximumSize:(int)maximumSize captureTime:(double)captureTime 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	AVAssetImageGenerator *thumbnailGenerator = [[AVAssetImageGenerator alloc] initWithAsset:[[AVURLAsset alloc] initWithURL:[NSURL fileURLWithPath:path] options:nil]]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	thumbnailGenerator.appliesPreferredTrackTransform = YES; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	thumbnailGenerator.maximumSize = CGSizeMake( (CGFloat) maximumSize, (CGFloat) maximumSize ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	thumbnailGenerator.requestedTimeToleranceBefore = kCMTimeZero; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	thumbnailGenerator.requestedTimeToleranceAfter = kCMTimeZero; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( captureTime < 0.0 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		captureTime = 0.0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		AVURLAsset *asset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:path] options:nil]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( asset != nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			double videoDuration = CMTimeGetSeconds( [asset duration] ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if( videoDuration > 0.0 && captureTime >= videoDuration - 0.1 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if( captureTime > videoDuration ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					captureTime = videoDuration; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				thumbnailGenerator.requestedTimeToleranceBefore = CMTimeMakeWithSeconds( 1.0, 600 ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	NSError *error = nil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	CGImageRef image = [thumbnailGenerator copyCGImageAtTime:CMTimeMakeWithSeconds( captureTime, 600 ) actualTime:nil error:&error]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( image == nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( error != nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			NSLog( @"Error generating video thumbnail: %@", error ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			NSLog( @"Error generating video thumbnail..." ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return [self getCString:@""]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	UIImage *thumbnail = [[UIImage alloc] initWithCGImage:image]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	CGImageRelease( image ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( ![UIImagePNGRepresentation( thumbnail ) writeToFile:savePath atomically:YES] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		NSLog( @"Error saving thumbnail image" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return [self getCString:@""]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return [self getCString:savePath]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (BOOL)saveImageAsPNG:(UIImage *)image toPath:(NSString *)resultPath 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return [UIImagePNGRepresentation( [self scaleImage:image maxSize:16384] ) writeToFile:resultPath atomically:YES]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (UIImage *)scaleImage:(UIImage *)image maxSize:(int)maxSize 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	CGFloat width = image.size.width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	CGFloat height = image.size.height; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	UIImageOrientation orientation = image.imageOrientation; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( width <= maxSize && height <= maxSize && orientation != UIImageOrientationDown && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		orientation != UIImageOrientationLeft && orientation != UIImageOrientationRight && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		orientation != UIImageOrientationLeftMirrored && orientation != UIImageOrientationRightMirrored && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		orientation != UIImageOrientationUpMirrored && orientation != UIImageOrientationDownMirrored ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return image; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	CGFloat scaleX = 1.0f; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	CGFloat scaleY = 1.0f; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( width > maxSize ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		scaleX = maxSize / width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( height > maxSize ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		scaleY = maxSize / height; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// Credit: https://github.com/mbcharbonneau/UIImage-Categories/blob/master/UIImage%2BAlpha.m 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	CGImageAlphaInfo alpha = CGImageGetAlphaInfo( image.CGImage ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	BOOL hasAlpha = alpha == kCGImageAlphaFirst || alpha == kCGImageAlphaLast || alpha == kCGImageAlphaPremultipliedFirst || alpha == kCGImageAlphaPremultipliedLast; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	CGFloat scaleRatio = scaleX < scaleY ? scaleX : scaleY; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	CGRect imageRect = CGRectMake( 0, 0, width * scaleRatio, height * scaleRatio ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// Resize image with UIGraphicsImageRenderer (Apple's recommended API) if possible 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( CHECK_IOS_VERSION( @"10.0" ) ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		UIGraphicsImageRendererFormat *format = [image imageRendererFormat]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		format.opaque = !hasAlpha; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		format.scale = image.scale; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	    
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:imageRect.size format:format]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		image = [renderer imageWithActions:^( UIGraphicsImageRendererContext* _Nonnull myContext ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			[image drawInRect:imageRect]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		}]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		UIGraphicsBeginImageContextWithOptions( imageRect.size, !hasAlpha, image.scale ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		[image drawInRect:imageRect]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		image = UIGraphicsGetImageFromCurrentImageContext(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		UIGraphicsEndImageContext(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return image; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (char *)loadImageAtPath:(NSString *)path tempFilePath:(NSString *)tempFilePath maximumSize:(int)maximumSize 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// Check if the image can be loaded by Unity without requiring a conversion to PNG 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// Credit: https://stackoverflow.com/a/12048937/2373034 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	NSString *extension = [path pathExtension]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	BOOL conversionNeeded = [extension caseInsensitiveCompare:@"jpg"] != NSOrderedSame && [extension caseInsensitiveCompare:@"jpeg"] != NSOrderedSame && [extension caseInsensitiveCompare:@"png"] != NSOrderedSame; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( !conversionNeeded ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// Check if the image needs to be processed at all 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		NSArray *metadata = [self getImageMetadata:path]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		int orientationInt = [metadata[2] intValue];  // 1: correct orientation, [1,8]: valid orientation range 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( orientationInt == 1 && [metadata[0] intValue] <= maximumSize && [metadata[1] intValue] <= maximumSize ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return [self getCString:path]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	UIImage *image = [UIImage imageWithContentsOfFile:path]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( image == nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return [self getCString:path]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	UIImage *scaledImage = [self scaleImage:image maxSize:maximumSize]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( conversionNeeded || scaledImage != image ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if( ![UIImagePNGRepresentation( scaledImage ) writeToFile:tempFilePath atomically:YES] ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			NSLog( @"Error creating scaled image" ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return [self getCString:path]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return [self getCString:tempFilePath]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return [self getCString:path]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Credit: https://stackoverflow.com/a/37052118/2373034 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ (char *)getCString:(NSString *)source 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if( source == nil ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		source = @""; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	const char *sourceUTF8 = [source UTF8String]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	char *result = (char*) malloc( strlen( sourceUTF8 ) + 1 ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	strcpy( result, sourceUTF8 ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return result; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@end 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+extern "C" int _NativeGallery_CheckPermission( int readPermission, int permissionFreeMode ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return [UNativeGallery checkPermission:( readPermission == 1 ) permissionFreeMode:( permissionFreeMode == 1 )]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+extern "C" int _NativeGallery_RequestPermission( int readPermission, int permissionFreeMode, int asyncMode ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return [UNativeGallery requestPermission:( readPermission == 1 ) permissionFreeMode:( permissionFreeMode == 1 ) asyncMode:( asyncMode == 1 )]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+extern "C" void _NativeGallery_ShowLimitedLibraryPicker() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return [UNativeGallery showLimitedLibraryPicker]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+extern "C" int _NativeGallery_CanOpenSettings() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return [UNativeGallery canOpenSettings]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+extern "C" void _NativeGallery_OpenSettings() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	[UNativeGallery openSettings]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+extern "C" int _NativeGallery_CanPickMultipleMedia() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return [UNativeGallery canPickMultipleMedia]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+extern "C" void _NativeGallery_ImageWriteToAlbum( const char* path, const char* album, int permissionFreeMode ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	[UNativeGallery saveMedia:[NSString stringWithUTF8String:path] albumName:[NSString stringWithUTF8String:album] isImg:YES permissionFreeMode:( permissionFreeMode == 1 )]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+extern "C" void _NativeGallery_VideoWriteToAlbum( const char* path, const char* album, int permissionFreeMode ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	[UNativeGallery saveMedia:[NSString stringWithUTF8String:path] albumName:[NSString stringWithUTF8String:album] isImg:NO permissionFreeMode:( permissionFreeMode == 1 )]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+extern "C" void _NativeGallery_PickMedia( const char* mediaSavePath, int mediaType, int permissionFreeMode, int selectionLimit ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	[UNativeGallery pickMedia:mediaType savePath:[NSString stringWithUTF8String:mediaSavePath] permissionFreeMode:( permissionFreeMode == 1 ) selectionLimit:selectionLimit]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+extern "C" int _NativeGallery_IsMediaPickerBusy() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return [UNativeGallery isMediaPickerBusy]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+extern "C" int _NativeGallery_GetMediaTypeFromExtension( const char* extension ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return [UNativeGallery getMediaTypeFromExtension:[NSString stringWithUTF8String:extension]]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+extern "C" char* _NativeGallery_GetImageProperties( const char* path ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return [UNativeGallery getImageProperties:[NSString stringWithUTF8String:path]]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+extern "C" char* _NativeGallery_GetVideoProperties( const char* path ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return [UNativeGallery getVideoProperties:[NSString stringWithUTF8String:path]]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+extern "C" char* _NativeGallery_GetVideoThumbnail( const char* path, const char* thumbnailSavePath, int maxSize, double captureTimeInSeconds ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return [UNativeGallery getVideoThumbnail:[NSString stringWithUTF8String:path] savePath:[NSString stringWithUTF8String:thumbnailSavePath] maximumSize:maxSize captureTime:captureTimeInSeconds]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+extern "C" char* _NativeGallery_LoadImageAtPath( const char* path, const char* temporaryFilePath, int maxSize ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return [UNativeGallery loadImageAtPath:[NSString stringWithUTF8String:path] tempFilePath:[NSString stringWithUTF8String:temporaryFilePath] maximumSize:maxSize]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 |