Skip to content

Commit

Permalink
- Added saveAsJPEG parameter to NativeCamera.TakePicture (has no effe…
Browse files Browse the repository at this point in the history
…ct on Android)

- Images captured on iOS now have their EXIF metadata preserved (except geo-location data, it requires handling an additional location permission, I don't plan to support it for now)
  • Loading branch information
yasirkula committed Oct 18, 2019
1 parent 298d78a commit 2ab5c57
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 13 deletions.
13 changes: 4 additions & 9 deletions Plugins/NativeCamera/NativeCamera.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ private static string TemporaryImagePath
{
if( m_temporaryImagePath == null )
{
m_temporaryImagePath = Path.Combine( Application.temporaryCachePath, "__tmpImG" );
m_temporaryImagePath = Path.Combine( Application.temporaryCachePath, "tmpImg" );
Directory.CreateDirectory( Application.temporaryCachePath );
}

Expand All @@ -136,7 +136,7 @@ private static string IOSSelectedImagePath
{
if( m_iOSSelectedImagePath == null )
{
m_iOSSelectedImagePath = Path.Combine( Application.temporaryCachePath, "tmp.png" );
m_iOSSelectedImagePath = Path.Combine( Application.temporaryCachePath, "CameraImg" );
Directory.CreateDirectory( Application.temporaryCachePath );
}

Expand Down Expand Up @@ -210,7 +210,7 @@ public static void OpenSettings()
#endregion

#region Camera Functions
public static Permission TakePicture( CameraCallback callback, int maxSize = -1, PreferredCamera preferredCamera = PreferredCamera.Default )
public static Permission TakePicture( CameraCallback callback, int maxSize = -1, bool saveAsJPEG = true, PreferredCamera preferredCamera = PreferredCamera.Default )
{
Permission result = RequestPermission();
if( result == Permission.Granted && !IsCameraBusy() )
Expand All @@ -222,7 +222,7 @@ public static Permission TakePicture( CameraCallback callback, int maxSize = -1,
maxSize = SystemInfo.maxTextureSize;

NCCameraCallbackiOS.Initialize( callback );
_NativeCamera_TakePicture( IOSSelectedImagePath, maxSize, (int) preferredCamera );
_NativeCamera_TakePicture( IOSSelectedImagePath + ( saveAsJPEG ? ".jpeg" : ".png" ), maxSize, (int) preferredCamera );
#else
if( callback != null )
callback( null );
Expand Down Expand Up @@ -373,11 +373,6 @@ public static ImageProperties GetImageProperties( string imagePath )
int orientationInt;
if( int.TryParse( properties[3].Trim(), out orientationInt ) )
orientation = (ImageOrientation) orientationInt;

#if !UNITY_EDITOR && UNITY_IOS
if( orientation == ImageOrientation.Unknown ) // captured media is saved in correct orientation on iOS
orientation = ImageOrientation.Normal;
#endif
}
}

Expand Down
3 changes: 2 additions & 1 deletion Plugins/NativeCamera/README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ delegate void CameraCallback( string path );
// This operation is asynchronous! After user takes a picture or cancels the operation, the callback is called (on main thread)
// CameraCallback takes a string parameter which stores the path of the captured image, or null if the operation is canceled
// maxSize: determines the maximum size of the returned image in pixels on iOS. A larger image will be down-scaled for better performance. If untouched, its value will be set to SystemInfo.maxTextureSize. Has no effect on Android
// saveAsJPEG: determines whether the image is saved as JPEG or PNG. Has no effect on Android
// preferredCamera: determines whether the rear camera or the front camera should be opened by default
NativeCamera.Permission NativeCamera.TakePicture( CameraCallback callback, int maxSize = -1, PreferredCamera preferredCamera = PreferredCamera.Default );
NativeCamera.Permission NativeCamera.TakePicture( CameraCallback callback, int maxSize = -1, bool saveAsJPEG = true, PreferredCamera preferredCamera = PreferredCamera.Default );

// quality: determines the quality of the recorded video
// maxDuration: determines the maximum duration, in seconds, for the recorded video. If untouched, there will be no limit. Please note that the functionality of this parameter depends on whether the device vendor has added this capability to the camera or not. So, this parameter may not have any effect on some devices
Expand Down
50 changes: 47 additions & 3 deletions Plugins/NativeCamera/iOS/NativeCamera.mm
Original file line number Diff line number Diff line change
Expand Up @@ -320,15 +320,59 @@ + (char *)loadImageAtPath:(NSString *)path tempFilePath:(NSString *)tempFilePath
}

+ (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSString *path;
NSString *path = nil;
if ([info[UIImagePickerControllerMediaType] isEqualToString:(NSString *)kUTTypeImage]) { // took picture
// Temporarily save image as PNG
UIImage *image = info[UIImagePickerControllerEditedImage] ?: info[UIImagePickerControllerOriginalImage];
if (image == nil)
path = nil;
else {
[UIImagePNGRepresentation([self scaleImage:image maxSize:cameraMaxImageSize]) writeToFile:pickedMediaSavePath atomically:YES];
path = pickedMediaSavePath;
NSString *extension = [pickedMediaSavePath pathExtension];
BOOL saveAsJPEG = [extension caseInsensitiveCompare:@"jpg"] == NSOrderedSame || [extension caseInsensitiveCompare:@"jpeg"] == NSOrderedSame;

// Try to save the image with metadata
// Credit: https://stackoverflow.com/a/15858955
NSDictionary *metadata = [info objectForKey:UIImagePickerControllerMediaMetadata];
NSMutableDictionary *mutableMetadata = nil;
CFDictionaryRef metadataRef;
CFStringRef imageType;

if (saveAsJPEG) {
mutableMetadata = [metadata mutableCopy];
[mutableMetadata setObject:@(1.0) forKey:(__bridge NSString *)kCGImageDestinationLossyCompressionQuality];

metadataRef = (__bridge CFDictionaryRef)mutableMetadata;
imageType = kUTTypeJPEG;
}
else {
metadataRef = (__bridge CFDictionaryRef)metadata;
imageType = kUTTypePNG;
}

CGImageDestinationRef imageDestination = CGImageDestinationCreateWithURL((__bridge CFURLRef)[NSURL fileURLWithPath:pickedMediaSavePath], imageType , 1, NULL);
if (imageDestination == NULL )
NSLog(@"Failed to create image destination");
else {
CGImageDestinationAddImage(imageDestination, image.CGImage, metadataRef);
if (CGImageDestinationFinalize(imageDestination))
path = pickedMediaSavePath;
else
NSLog(@"Failed to finalize the image");

CFRelease(imageDestination);
}

if (path == nil) {
NSLog(@"Attempting to save the image without metadata as fallback");

if ((saveAsJPEG && [UIImageJPEGRepresentation([self scaleImage:image maxSize:cameraMaxImageSize], 1.0) writeToFile:pickedMediaSavePath atomically:YES]) ||
(!saveAsJPEG && [UIImagePNGRepresentation([self scaleImage:image maxSize:cameraMaxImageSize]) writeToFile:pickedMediaSavePath atomically:YES]) )
path = pickedMediaSavePath;
else {
NSLog(@"Error saving image without metadata");
path = nil;
}
}
}
}
else { // recorded video
Expand Down

0 comments on commit 2ab5c57

Please sign in to comment.