void FinishCapture(object sender, Tuple <NSObject, NSError> e) { if (Element == null || Control == null) { return; } if (e.Item2 != null) { Element.RaiseMediaCaptureFailed(e.Item2.LocalizedDescription); return; } var photoData = e.Item1 as NSData; if (!Element.SavePhotoToFile && photoData != null) { var data = UIImage.LoadFromData(photoData).AsJPEG().ToArray(); Device.BeginInvokeOnMainThread(() => { Element.RaiseMediaCaptured(new MediaCapturedEventArgs(imageData: data)); }); return; } PHObjectPlaceholder placeholder = null; PHPhotoLibrary.RequestAuthorization(status => { if (status != PHAuthorizationStatus.Authorized) { return; } // Save the captured file to the photo library. PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() => { var creationRequest = PHAssetCreationRequest.CreationRequestForAsset(); if (photoData != null) { creationRequest.AddResource(PHAssetResourceType.Photo, photoData, null); placeholder = creationRequest.PlaceholderForCreatedAsset; } else if (e.Item1 is NSUrl outputFileUrl) { creationRequest.AddResource( PHAssetResourceType.Video, outputFileUrl, new PHAssetResourceCreationOptions { ShouldMoveFile = true }); placeholder = creationRequest.PlaceholderForCreatedAsset; } }, (success2, error2) => { if (!success2) { Debug.WriteLine($"Could not save media to photo library: {error2}"); if (error2 != null) { Element.RaiseMediaCaptureFailed(error2.LocalizedDescription); return; } Element.RaiseMediaCaptureFailed($"Could not save media to photo library"); return; } if (!(PHAsset.FetchAssetsUsingLocalIdentifiers(new[] { placeholder.LocalIdentifier }, null).firstObject is PHAsset asset)) { Element.RaiseMediaCaptureFailed($"Could not save media to photo library"); return; } if (asset.MediaType == PHAssetMediaType.Image) { asset.RequestContentEditingInput(new PHContentEditingInputRequestOptions { CanHandleAdjustmentData = p => true }, (input, info) => { Device.BeginInvokeOnMainThread(() => { Element.RaiseMediaCaptured(new MediaCapturedEventArgs(input.FullSizeImageUrl.Path)); }); }); } else if (asset.MediaType == PHAssetMediaType.Video) { PHImageManager.DefaultManager.RequestAvAsset(asset, new PHVideoRequestOptions { Version = PHVideoRequestOptionsVersion.Original }, (avAsset, mix, info) => { if (!(avAsset is AVUrlAsset urlAsset)) { Element.RaiseMediaCaptureFailed($"Could not save media to photo library"); return; } Device.BeginInvokeOnMainThread(() => { Element.RaiseMediaCaptured(new MediaCapturedEventArgs(urlAsset.Url.Path)); }); }); } });
public void FinishedRecording(AVCaptureFileOutput captureOutput, NSUrl outputFileUrl, NSObject[] connections, NSError error) { /* * Note that currentBackgroundRecordingID is used to end the background task * associated with this recording. This allows a new recording to be started, * associated with a new UIBackgroundTaskIdentifier, once the movie file output's * `recording` property is back to NO — which happens sometime after this method * returns. * * Note: Since we use a unique file path for each recording, a new recording will * not overwrite a recording currently being saved. */ var currentBackgroundRecordingId = backgroundRecordingId; backgroundRecordingId = UIApplication.BackgroundTaskInvalid; Action cleanup = () => { if (NSFileManager.DefaultManager.FileExists(outputFileUrl.Path)) { NSError tError; NSFileManager.DefaultManager.Remove(outputFileUrl.Path, out tError); } if (currentBackgroundRecordingId != UIApplication.BackgroundTaskInvalid) { UIApplication.SharedApplication.EndBackgroundTask(currentBackgroundRecordingId); } }; var success = true; if (error != null) { Console.WriteLine($"Movie file finishing error: {error}"); var tmpObj = error.UserInfo[AVErrorKeys.RecordingSuccessfullyFinished]; if (tmpObj is NSNumber) { success = ((NSNumber)tmpObj).BoolValue; } else if (tmpObj is NSString) { success = ((NSString)tmpObj).BoolValue(); } } if (success) { // Check authorization status. PHPhotoLibrary.RequestAuthorization((PHAuthorizationStatus status) => { if (status == PHAuthorizationStatus.Authorized) { // Save the movie file to the photo library and cleanup. PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() => { var options = new PHAssetResourceCreationOptions(); options.ShouldMoveFile = true; var creationRequest = PHAssetCreationRequest.CreationRequestForAsset(); creationRequest.AddResource(PHAssetResourceType.Video, outputFileUrl, options); }, (cbSuccess, cbError) => { if (!cbSuccess) { Console.WriteLine($"Could not save movie to photo library: {cbError}"); } cleanup(); }); } else { cleanup(); } }); } else { cleanup(); } // Enable the Camera and Record buttons to let the user switch camera and start another recording. //DispatchQueue.MainQueue.DispatchAsync(() => //{ // // Only enable the ability to change camera if the device has more than one camera. // CameraButton.Enabled = (videoDeviceDiscoverySession.UniqueDevicePositionsCount() > 1); // RecordButton.Enabled = true; // CaptureModeControl.Enabled = true; // RecordButton.SetTitle(NSBundle.MainBundle.LocalizedString(@"Record", @"Recording button record title"), UIControlState.Normal); //}); }
public void FinishedRecording(AVCaptureFileOutput captureOutput, NSUrl outputFileUrl, NSObject[] connections, NSError error) { // Note that currentBackgroundRecordingID is used to end the background task associated with this recording. // This allows a new recording to be started, associated with a new UIBackgroundTaskIdentifier, once the movie file output's isRecording property // is back to false — which happens sometime after this method returns. // Note: Since we use a unique file path for each recording, a new recording will not overwrite a recording currently being saved. Action cleanup = () => { var path = outputFileUrl.Path; if (NSFileManager.DefaultManager.FileExists(path)) { NSError err; if (!NSFileManager.DefaultManager.Remove(path, out err)) { Console.WriteLine($"Could not remove file at url: {outputFileUrl}"); } } var currentBackgroundRecordingID = backgroundRecordingID; if (currentBackgroundRecordingID != -1) { backgroundRecordingID = -1; UIApplication.SharedApplication.EndBackgroundTask(currentBackgroundRecordingID); } }; bool success = true; if (error != null) { Console.WriteLine($"Movie file finishing error: {error.LocalizedDescription}"); success = ((NSNumber)error.UserInfo[AVErrorKeys.RecordingSuccessfullyFinished]).BoolValue; } if (success) { // Check authorization status. PHPhotoLibrary.RequestAuthorization(status => { if (status == PHAuthorizationStatus.Authorized) { // Save the movie file to the photo library and cleanup. PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() => { var options = new PHAssetResourceCreationOptions { ShouldMoveFile = true }; var creationRequest = PHAssetCreationRequest.CreationRequestForAsset(); creationRequest.AddResource(PHAssetResourceType.Video, outputFileUrl, options); }, (success2, error2) => { if (!success2) { Console.WriteLine($"Could not save movie to photo library: {error2}"); } cleanup(); }); } else { cleanup(); } }); } else { cleanup(); } // Enable the Camera and Record buttons to let the user switch camera and start another recording. DispatchQueue.MainQueue.DispatchAsync(() => { // Only enable the ability to change camera if the device has more than one camera. CameraButton.Enabled = UniqueDevicePositionsCount(videoDeviceDiscoverySession) > 1; RecordButton.Enabled = true; CaptureModeControl.Enabled = true; RecordButton.SetTitle("Record", UIControlState.Normal); }); }
public static void RestoreFromArchive(string filePath, Action onSuccess = null, Action <NSError> onFailure = null) { if (PHPhotoLibrary.AuthorizationStatus != PHAuthorizationStatus.Authorized) { onFailure?.Invoke(null); return; } var resources = new List <string>(); var rootPath = Path.Combine(Paths.Temporary, Path.GetFileNameWithoutExtension(filePath)); Directory.CreateDirectory(rootPath); using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) using (var archive = new ZipArchive(stream, ZipArchiveMode.Read)) { foreach (var entry in archive.Entries) { if (entry.Name == "@") { continue; } var entryPath = Path.Combine(rootPath, entry.Name); using (var fileStream = new FileStream(entryPath, FileMode.Create, FileAccess.ReadWrite, FileShare.None)) { entry.Open().CopyTo(fileStream); } if (entry.Name.Contains("(Photo)", StringComparison.InvariantCulture) || entry.Name.Contains("(Video)", StringComparison.InvariantCulture)) { resources.Insert(0, entryPath); } else { resources.Add(entryPath); } } } PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() => { var request = PHAssetCreationRequest.CreationRequestForAsset(); var options = new PHAssetResourceCreationOptions { ShouldMoveFile = true }; foreach (var path in resources) { var fileName = Path.GetFileName(path); if (fileName.IndexOf('(') != -1) { var indexLeft = fileName.IndexOf('(') + 1; var resourceType = fileName.Substring(indexLeft, fileName.IndexOf(')') - indexLeft); var type = (PHAssetResourceType)Enum.Parse(typeof(PHAssetResourceType), resourceType); request.AddResource(type, NSUrl.FromFilename(path), options); } } }, (isSuccess, error) => { try { Directory.Delete(rootPath, true); } catch { } if (isSuccess) { onSuccess?.Invoke(); } else { onFailure?.Invoke(error); } }); }
public void FinishedRecording(AVCaptureFileOutput captureOutput, NSUrl outputFileUrl, NSObject[] connections, NSError error) { // Note that currentBackgroundRecordingID is used to end the background task associated with this recording. // This allows a new recording to be started, associated with a new UIBackgroundTaskIdentifier, once the movie file output's isRecording property // is back to NO — which happens sometime after this method returns. // Note: Since we use a unique file path for each recording, a new recording will not overwrite a recording currently being saved. var currentBackgroundRecordingID = backgroundRecordingID; backgroundRecordingID = -1; Action cleanup = () => { NSError err; NSFileManager.DefaultManager.Remove(outputFileUrl, out err); if (currentBackgroundRecordingID != -1) { UIApplication.SharedApplication.EndBackgroundTask(currentBackgroundRecordingID); } }; bool success = true; if (error != null) { Console.WriteLine("Movie file finishing error: {0}", error); success = ((NSNumber)error.UserInfo [AVErrorKeys.RecordingSuccessfullyFinished]).BoolValue; } if (!success) { cleanup(); return; } // Check authorization status. PHPhotoLibrary.RequestAuthorization(status => { if (status == PHAuthorizationStatus.Authorized) { // Save the movie file to the photo library and cleanup. PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() => { // In iOS 9 and later, it's possible to move the file into the photo library without duplicating the file data. // This avoids using double the disk space during save, which can make a difference on devices with limited free disk space. if (UIDevice.CurrentDevice.CheckSystemVersion(9, 0)) { var options = new PHAssetResourceCreationOptions { ShouldMoveFile = true }; var changeRequest = PHAssetCreationRequest.CreationRequestForAsset(); changeRequest.AddResource(PHAssetResourceType.Video, outputFileUrl, options); } else { PHAssetChangeRequest.FromVideo(outputFileUrl); } }, (success2, error2) => { if (!success2) { Console.WriteLine("Could not save movie to photo library: {0}", error2); } cleanup(); }); } else { cleanup(); } }); }
void SnapStillImage(CameraViewController sender) { SessionQueue.DispatchAsync(async() => { AVCaptureConnection connection = StillImageOutput.ConnectionFromMediaType(AVMediaType.Video); var previewLayer = (AVCaptureVideoPreviewLayer)PreviewView.Layer; // Update the orientation on the still image output video connection before capturing. connection.VideoOrientation = previewLayer.Connection.VideoOrientation; // Flash set to Auto for Still Capture. SetFlashModeForDevice(AVCaptureFlashMode.Auto, VideoDeviceInput.Device); // Capture a still image. try { var imageDataSampleBuffer = await StillImageOutput.CaptureStillImageTaskAsync(connection); // The sample buffer is not retained. Create image data before saving the still image to the photo library asynchronously. NSData imageData = AVCaptureStillImageOutput.JpegStillToNSData(imageDataSampleBuffer); PHPhotoLibrary.RequestAuthorization(status => { if (status == PHAuthorizationStatus.Authorized) { // To preserve the metadata, we create an asset from the JPEG NSData representation. // Note that creating an asset from a UIImage discards the metadata. // In iOS 9, we can use AddResource method on PHAssetCreationRequest class. // In iOS 8, we save the image to a temporary file and use +[PHAssetChangeRequest creationRequestForAssetFromImageAtFileURL:]. if (UIDevice.CurrentDevice.CheckSystemVersion(9, 0)) { PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() => { var request = PHAssetCreationRequest.CreationRequestForAsset(); request.AddResource(PHAssetResourceType.Photo, imageData, null); }, (success, err) => { if (!success) { Console.WriteLine("Error occurred while saving image to photo library: {0}", err); } }); } else { var temporaryFileUrl = new NSUrl(GetTmpFilePath("jpg"), false); PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() => { NSError error = null; if (imageData.Save(temporaryFileUrl, NSDataWritingOptions.Atomic, out error)) { PHAssetChangeRequest.FromImage(temporaryFileUrl); } else { Console.WriteLine("Error occured while writing image data to a temporary file: {0}", error); } }, (success, error) => { if (!success) { Console.WriteLine("Error occurred while saving image to photo library: {0}", error); } // Delete the temporary file. NSError deleteError; NSFileManager.DefaultManager.Remove(temporaryFileUrl, out deleteError); }); } } }); } catch (NSErrorException ex) { Console.WriteLine("Could not capture still image: {0}", ex.Error); } }); }
private async void SnapStillImage() { // if ((m_videoDevice != null) && (m_stillImageOutput != null)) { if (m_videoDevice.HasFlash && m_videoDevice.IsFlashModeSupported(AVCaptureFlashMode.Auto)) { NSError error; if (m_videoDevice.LockForConfiguration(out error)) { m_videoDevice.FlashMode = AVCaptureFlashMode.Auto; m_videoDevice.UnlockForConfiguration(); } } AVCaptureConnection connection = m_stillImageOutput.ConnectionFromMediaType(AVMediaType.Video); var imageDataSampleBuffer = await m_stillImageOutput.CaptureStillImageTaskAsync(connection); //获得当前帧的压缩图像 var imageData = AVCaptureStillImageOutput.JpegStillToNSData(imageDataSampleBuffer); //得到当前帧压缩图像的图像数据... //RequestAuthorization(handler), handler是用户与权限对话框交互后,执行的动作。 PHPhotoLibrary.RequestAuthorization(status => { if (status == PHAuthorizationStatus.Authorized) { // 若用户授权了 // To preserve the metadata, we create an asset from the JPEG NSData representation. // Note that creating an asset from a UIImage discards the metadata. // In iOS 9, we can use AddResource method on PHAssetCreationRequest class. // In iOS 8, we save the image to a temporary file and use +[PHAssetChangeRequest creationRequestForAssetFromImageAtFileURL:]. if (UIDevice.CurrentDevice.CheckSystemVersion(9, 0)) { //PHPhotoLibrary.SharedPhotoLibrary 返回的是一个(共享)图片库对象 //PerformChanges (changeHandler, completionHandler) changeHandler 以及 completionHandler 是一个lambda PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() => { var request = PHAssetCreationRequest.CreationRequestForAsset(); request.AddResource(PHAssetResourceType.Photo, imageData, null); //保存当前照片 }, (success, err) => { if (!success) { Console.WriteLine("Error occurred while saving image to photo library: {0}", err); } }); } else { //用户没有授权 string outputFileName = NSProcessInfo.ProcessInfo.GloballyUniqueString; string tmpDir = Path.GetTempPath(); string outputFilePath = Path.Combine(tmpDir, outputFileName); string outputFilePath2 = Path.ChangeExtension(outputFilePath, "jpg"); NSUrl temporaryFileUrl = new NSUrl(outputFilePath2, false); PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() => { NSError error = null; if (imageData.Save(temporaryFileUrl, NSDataWritingOptions.Atomic, out error)) { PHAssetChangeRequest.FromImage(temporaryFileUrl); } else { Console.WriteLine("Error occured while writing image data to a temporary file: {0}", error); } }, (success, error) => { if (!success) { Console.WriteLine("Error occurred while saving image to photo library: {0}", error); } // Delete the temporary file. NSError deleteError; NSFileManager.DefaultManager.Remove(temporaryFileUrl, out deleteError); }); } } }); } }