Пример #1
0
        partial void RemoveAsset(NSObject sender)
        {
            Action <bool, NSError> completion = (success, error) => {
                if (success)
                {
                    PHPhotoLibrary.SharedPhotoLibrary.UnregisterChangeObserver(this);
                    DispatchQueue.MainQueue.DispatchSync(() => NavigationController.PopViewController(true));
                }
                else
                {
                    Console.WriteLine($"can't remove asset: {error.LocalizedDescription}");
                }
            };

            if (AssetCollection != null)
            {
                // Remove asset from album
                PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() => {
                    var request = PHAssetCollectionChangeRequest.ChangeRequest(AssetCollection);
                    request.RemoveAssets(new PHObject [] { Asset });
                }, completion);
            }
            else
            {
                // Delete asset from library
                PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() =>
                                                                 PHAssetChangeRequest.DeleteAssets(new [] { Asset }), completion);
            }
        }
        partial void TrashButtonClickHandler(NSObject sender)
        {
            Action <bool, NSError> completionHandler = (success, error) => {
                if (success)
                {
                    DispatchQueue.MainQueue.DispatchAsync(() =>
                                                          NavigationController.PopViewController(true)
                                                          );
                }
                else
                {
                    Console.WriteLine(error.LocalizedDescription);
                }
            };

            if (AssetCollection != null)
            {
                // Remove asset from album
                PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() => {
                    var changeRequest = PHAssetCollectionChangeRequest.ChangeRequest(AssetCollection);
                    changeRequest.RemoveAssets(new PHObject[] { Asset });
                }, completionHandler);
            }
            else
            {
                // Delete asset from library
                PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() =>
                                                                 PHAssetChangeRequest.DeleteAssets(new [] { Asset }), completionHandler);
            }
        }
Пример #3
0
        void SaveToAlbum(string watermarkedPath)
        {
            var lib = PHPhotoLibrary.SharedPhotoLibrary;

            lib.PerformChanges(() =>
            {
                var album             = PHAssetCollection.FetchAssetCollections(new[] { Xamarin.Essentials.Preferences.Get("iOSAlbumIdentifier", string.Empty) }, null)?.firstObject as PHAssetCollection;
                var collectionRequest = PHAssetCollectionChangeRequest.ChangeRequest(album);

                if (UIDevice.CurrentDevice.CheckSystemVersion(9, 0))
                {
                    var options = new PHAssetResourceCreationOptions
                    {
                        ShouldMoveFile = true
                    };
                    var changeRequest = PHAssetCreationRequest.CreationRequestForAsset();
                    changeRequest.AddResource(PHAssetResourceType.Video, NSUrl.FromString(watermarkedPath), options);

                    collectionRequest.AddAssets(new[] { changeRequest.PlaceholderForCreatedAsset });
                }
                else
                {
                    var changeRequest2 = PHAssetChangeRequest.FromVideo(NSUrl.FromString(watermarkedPath));
                    collectionRequest.AddAssets(new[] { changeRequest2.PlaceholderForCreatedAsset });
                }

                RetrieveLastAssetSaved();
            }, (success, err) =>
            {
            });
        }
Пример #4
0
        void OnApplyFilter(object sender, EventArgs e)
        {
            Asset.RequestContentEditingInput(new PHContentEditingInputRequestOptions(),
                                             (input, options) => {
                var image = CIImage.FromUrl(input.FullSizeImageUrl);
                image     = image.CreateWithOrientation(input.FullSizeImageOrientation);

                var updatedPhoto = new CIPhotoEffectNoir {
                    Image = image
                };
                var ciContext = CIContext.FromOptions(null);
                var output    = updatedPhoto.OutputImage;

                // Get the upated image
                var uiImage    = UIImage.FromImage(ciContext.CreateCGImage(output, output.Extent));
                TheImage.Image = uiImage;

                // Save the image data to a PHContentEditingOutput instance
                var editingOutput = new PHContentEditingOutput(input);

                NSError error;
                var data = uiImage.AsJPEG();
                data.Save(editingOutput.RenderedContentUrl, false, out error);
                editingOutput.AdjustmentData = new PHAdjustmentData();;

                // Request to publish the changes form the editing output back to the photo library
                PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(
                    () => {
                    PHAssetChangeRequest request = PHAssetChangeRequest.ChangeRequest(Asset);
                    request.ContentEditingOutput = editingOutput;
                },
                    (ok, err) => Console.WriteLine("Photo updated : {0}, {1}", ok, err));
            });
        }
Пример #5
0
        public Task <OperationResult <string> > SaveVideo(string videoPath)
        {
            var tcs = new TaskCompletionSource <OperationResult <string> >();

            if (string.IsNullOrEmpty(videoPath) || !File.Exists(videoPath))
            {
                tcs.SetResult(OperationResult <string> .AsFailure("Invalid video file path specified"));
                return(tcs.Task);
            }

            var url = NSUrl.CreateFileUrl(videoPath, false, null);

            string localId = string.Empty;

            PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() =>
            {
                var request = PHAssetChangeRequest.FromVideo(url);
                localId     = request?.PlaceholderForCreatedAsset?.LocalIdentifier;
            }, (bool success, NSError error) =>
            {
                if (!success && error != null)
                {
                    tcs.SetResult(OperationResult <string> .AsFailure(error.LocalizedDescription));
                }
                else
                {
                    tcs.SetResult(OperationResult <string> .AsSuccess(localId));
                }
            });

            return(tcs.Task);
        }
Пример #6
0
        partial void AddAsset(NSObject sender)
        {
            var rnd = new Random();

            // Create a random dummy image.
            var size = (rnd.Next(0, 2) == 0)
                                ? new CGSize(400f, 300f)
                                : new CGSize(300f, 400f);

            var renderer = new UIGraphicsImageRenderer(size);
            var image    = renderer.CreateImage(context => {
                UIColor.FromHSBA((float)rnd.NextDouble(), 1, 1, 1).SetFill();
                context.FillRect(context.Format.Bounds);
            });

            // Add it to the photo library
            PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() => {
                PHAssetChangeRequest creationRequest = PHAssetChangeRequest.FromImage(image);

                if (AssetCollection != null)
                {
                    var addAssetRequest = PHAssetCollectionChangeRequest.ChangeRequest(AssetCollection);
                    addAssetRequest.AddAssets(new PHObject [] {
                        creationRequest.PlaceholderForCreatedAsset
                    });
                }
            }, (success, error) => {
                if (!success)
                {
                    Console.WriteLine(error.LocalizedDescription);
                }
            });
        }
        partial void AddButtonClickHandler(NSObject sender)
        {
            // Create a random dummy image.
            var rect = new Random().Next(0, 2) == 0 ?
                       new CGRect(0f, 0f, 400f, 300f) : new CGRect(0f, 0f, 300f, 400f);

            UIGraphics.BeginImageContextWithOptions(rect.Size, false, 1f);
            UIColor.FromHSBA(new Random().Next(0, 100) / 100f, 1f, 1f, 1f).SetFill();
            UIGraphics.RectFillUsingBlendMode(rect, CGBlendMode.Normal);
            UIImage image = UIGraphics.GetImageFromCurrentImageContext();

            UIGraphics.EndImageContext();

            // Add it to the photo library
            PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() => {
                PHAssetChangeRequest assetChangeRequest = PHAssetChangeRequest.FromImage(image);

                if (AssetCollection != null)
                {
                    PHAssetCollectionChangeRequest assetCollectionChangeRequest = PHAssetCollectionChangeRequest.ChangeRequest(AssetCollection);
                    assetCollectionChangeRequest.AddAssets(new PHObject[] {
                        assetChangeRequest.PlaceholderForCreatedAsset
                    });
                }
            }, (success, error) => {
                if (!success)
                {
                    Console.WriteLine(error.LocalizedDescription);
                }
            });
        }
Пример #8
0
        public static bool SaveImageToGalery(string imagePath, string albumName)
        {
            var saved = true;
            PHAssetCollection customAlbum = null;

            if (!string.IsNullOrEmpty(albumName))
            {
                customAlbum = FindOrCreateAlbum(albumName);
                if (customAlbum == null)
                {
                    return(false);
                }
            }

            PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(
                () =>
            {
                var assetRequest = PHAssetChangeRequest.FromImage(NSUrl.FromFilename(imagePath));
                if (customAlbum != null)
                {
                    var albumRequest = PHAssetCollectionChangeRequest.ChangeRequest(customAlbum);
                    albumRequest?.AddAssets(new[] { assetRequest.PlaceholderForCreatedAsset });
                }
            },
                (success, error) =>
            {
                if (!success)
                {
                    Console.WriteLine(error);
                    saved = success;
                }
            }
                );
            return(saved);
        }
Пример #9
0
        void ApplyNoirFilter(object sender, EventArgs e)
        {
            Asset.RequestContentEditingInput(new PHContentEditingInputRequestOptions(), (input, options) => {
                // perform the editing operation, which applies a noir filter in this case
                var image = CIImage.FromUrl(input.FullSizeImageUrl);
                image     = image.CreateWithOrientation((CIImageOrientation)input.FullSizeImageOrientation);
                var noir  = new CIPhotoEffectNoir {
                    Image = image
                };
                var ciContext = CIContext.FromOptions(null);
                var output    = noir.OutputImage;

                var uiImage     = UIImage.FromImage(ciContext.CreateCGImage(output, output.Extent));
                imageView.Image = uiImage;

                // save the filtered image data to a PHContentEditingOutput instance
                var editingOutput  = new PHContentEditingOutput(input);
                var adjustmentData = new PHAdjustmentData();
                var data           = uiImage.AsJPEG();
                NSError error;
                data.Save(editingOutput.RenderedContentUrl, false, out error);
                editingOutput.AdjustmentData = adjustmentData;

                // make a change request to publish the changes form the editing output
                PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(
                    () => {
                    PHAssetChangeRequest request = PHAssetChangeRequest.ChangeRequest(Asset);
                    request.ContentEditingOutput = editingOutput;
                },
                    (ok, err) => Console.WriteLine("photo updated successfully: {0}", ok));
            });
        }
Пример #10
0
        static async Task PlatformSaveAsync(MediaFileType type, string filePath)
        {
            using var fileUri = new NSUrl(filePath);

            await PhotoLibraryPerformChanges(() =>
            {
                using var request = type == MediaFileType.Video
                ? PHAssetChangeRequest.FromVideo(fileUri)
                : PHAssetChangeRequest.FromImage(fileUri);
            });
        }
Пример #11
0
 void RevertAsset(UIAlertAction action)
 {
     PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() => {
         var request = PHAssetChangeRequest.ChangeRequest(Asset);
         request.RevertAssetContentToOriginal();
     }, (success, error) => {
         if (!success)
         {
             Console.WriteLine($"can't revert asset: {error.LocalizedDescription}");
         }
     });
 }
 void RevertToOriginal()
 {
     PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() => {
         var request = PHAssetChangeRequest.ChangeRequest(Asset);
         request.RevertAssetContentToOriginal();
     }, (success, error) => {
         if (!success)
         {
             Console.WriteLine("Error: {0}", error.LocalizedDescription);
         }
     });
 }
 void ToggleFavoriteState()
 {
     PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() => {
         var request      = PHAssetChangeRequest.ChangeRequest(Asset);
         request.Favorite = !Asset.Favorite;
     }, (success, error) => {
         if (!success)
         {
             Console.WriteLine("Error: {0}", error.LocalizedDescription);
         }
     });
 }
        void ApplyFilter(CIFilter filter)
        {
            // Prepare the options to pass when requesting to edit the image.
            var options = new PHContentEditingInputRequestOptions();

            options.SetCanHandleAdjustmentDataHandler(adjustmentData => {
                bool result = false;
                InvokeOnMainThread(() => {
                    result = adjustmentData.FormatIdentifier == AdjustmentFormatIdentifier && adjustmentData.FormatVersion == "1.0";
                });

                return(result);
            });

            Asset.RequestContentEditingInput(options, (contentEditingInput, requestStatusInfo) => {
                // Create a CIImage from the full image representation.
                var url         = contentEditingInput.FullSizeImageUrl;
                int orientation = (int)contentEditingInput.FullSizeImageOrientation;
                var inputImage  = CIImage.FromUrl(url);
                inputImage      = inputImage.CreateWithOrientation((CIImageOrientation)orientation);

                // Create the filter to apply.
                filter.SetDefaults();
                filter.Image = inputImage;

                // Apply the filter.
                CIImage outputImage = filter.OutputImage;

                // Create a PHAdjustmentData object that describes the filter that was applied.
                var adjustmentData = new PHAdjustmentData(
                    AdjustmentFormatIdentifier,
                    "1.0",
                    NSData.FromString(filter.Name, NSStringEncoding.UTF8)
                    );

                var contentEditingOutput = new PHContentEditingOutput(contentEditingInput);
                NSData jpegData          = outputImage.GetJpegRepresentation(0.9f);
                jpegData.Save(contentEditingOutput.RenderedContentUrl, true);
                contentEditingOutput.AdjustmentData = adjustmentData;

                // Ask the shared PHPhotoLinrary to perform the changes.
                PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() => {
                    var request = PHAssetChangeRequest.ChangeRequest(Asset);
                    request.ContentEditingOutput = contentEditingOutput;
                }, (success, error) => {
                    if (!success)
                    {
                        Console.WriteLine("Error: {0}", error.LocalizedDescription);
                    }
                });
            });
        }
Пример #15
0
 partial void ToggleFavorite(UIBarButtonItem sender)
 {
     PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() => {
         var request      = PHAssetChangeRequest.ChangeRequest(Asset);
         request.Favorite = !Asset.Favorite;
     }, (success, error) => {
         // Original sample updates FavoriteButton.Title here
         // but this doesn't work, because you have to wait PhotoLibraryDidChange notification.
         // At this point you just know is there any issue or everthing is ok.
         if (!success)
         {
             Console.WriteLine($"can't set favorite: {error.LocalizedDescription}");
         }
     });
 }
Пример #16
0
        private void OnExportCompleted(AVAssetExportSession session)
        {
            this.exportProgressView.Hidden = true;
            this.currentTimeLabel.Hidden   = false;
            var outputURL = session.OutputUrl;

            this.progressTimer.Invalidate();
            this.progressTimer.Dispose();
            this.progressTimer = null;

            if (session.Status != AVAssetExportSessionStatus.Completed)
            {
                Console.WriteLine($"exportSession error:{session.Error}");
                this.ReportError(session.Error);
            }
            else
            {
                this.exportProgressView.Progress = 1f;

                // Save the exported movie to the camera roll
                PHPhotoLibrary.RequestAuthorization((status) =>
                {
                    if (status == PHAuthorizationStatus.Authorized)
                    {
                        PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() => PHAssetChangeRequest.FromVideo(outputURL),
                                                                         (successfully, error) =>
                        {
                            if (error != null)
                            {
                                Console.WriteLine($"writeVideoToAssestsLibrary failed: {error}");
                                this.ReportError(error);
                            }

                            base.InvokeOnMainThread(() =>
                            {
                                this.playPauseButton.Enabled  = true;
                                this.transitionButton.Enabled = true;
                                this.scrubber.Enabled         = true;
                                this.exportButton.Enabled     = true;
                            });
                        });
                    }
                });
            }
        }
Пример #17
0
        public static bool DeleteImagesFromGallery(string[] localIds)
        {
            var images  = PHAsset.FetchAssetsUsingLocalIdentifiers(localIds, new PHFetchOptions());
            var assets  = images.Select(a => (PHAsset)a).ToArray();
            var success = PHPhotoLibrary.SharedPhotoLibrary.PerformChangesAndWait
                          (
                () =>
            {
                PHAssetChangeRequest.DeleteAssets(assets);
            }, out var error
                          );

            if (error != null)
            {
                Console.WriteLine(error);
            }
            return(success);
        }
Пример #18
0
        public static async Task <bool> SaveToLibrary(string path, string albumName)
        {
            var source = new TaskCompletionSource <bool>();
            PHAssetCollection album = await GetAlbum(albumName);

            PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() =>
            {
                var assetReq    = PHAssetChangeRequest.FromImage(NSUrl.CreateFileUrl(path, null));
                var albumReq    = PHAssetCollectionChangeRequest.ChangeRequest(album);
                var placeholder = assetReq.PlaceholderForCreatedAsset;
                albumReq.AddAssets(new[] { (PHObject)placeholder });
            }, (success, err) =>
            {
                Debug.WriteLine($"SaveToLibrary: {success}");
                source.SetResult(success);
            });
            return(await source.Task);
        }
Пример #19
0
        void DeleteOriginal(NSUrl url)
        {
            var assets    = PHAsset.FetchAssets(new NSUrl[] { url }, null);
            var asset     = (PHAsset)assets.firstObject;
            var sharedLib = PHPhotoLibrary.SharedPhotoLibrary;

            sharedLib.PerformChanges(() =>
            {
                var req = asset.CanPerformEditOperation(PHAssetEditOperation.Delete);
                if (req)
                {
                    PHAssetChangeRequest.DeleteAssets(new PHAsset[] { asset });
                }
            }, (success, err) =>
            {
                if (success)
                {
                    Debug.WriteLine("successfully deleted original");
                }
            });
        }
        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);
                            });
                        }
                    }
                });
            }
        }
Пример #21
0
        void ApplyFilter(CIFilter filter)
        {
            // Set up a handler to make sure we can handle prior edits.
            var options = new PHContentEditingInputRequestOptions();

            options.CanHandleAdjustmentData = (adjustmentData => {
                return(adjustmentData.FormatIdentifier == formatIdentifier && adjustmentData.FormatVersion == formatVersion);
            });

            // Prepare for editing.
            Asset.RequestContentEditingInput(options, (input, requestStatusInfo) => {
                if (input == null)
                {
                    throw new InvalidProgramException($"can't get content editing input: {requestStatusInfo}");
                }

                // This handler gets called on the main thread; dispatch to a background queue for processing.
                DispatchQueue.GetGlobalQueue(DispatchQueuePriority.Default).DispatchAsync(() => {
                    // Create a PHAdjustmentData object that describes the filter that was applied.
                    var adjustmentData = new PHAdjustmentData(
                        formatIdentifier,
                        formatVersion,
                        NSData.FromString(filter.Name, NSStringEncoding.UTF8));

                    // NOTE:
                    // This app's filter UI is fire-and-forget. That is, the user picks a filter,
                    // and the app applies it and outputs the saved asset immediately. There's
                    // no UI state for having chosen but not yet committed an edit. This means
                    // there's no role for reading adjustment data -- you do that to resume
                    // in-progress edits, and this sample app has no notion of "in-progress".
                    //
                    // However, it's still good to write adjustment data so that potential future
                    // versions of the app (or other apps that understand our adjustement data
                    // format) could make use of it.

                    // Create content editing output, write the adjustment data.
                    var output = new PHContentEditingOutput(input)
                    {
                        AdjustmentData = adjustmentData
                    };

                    // Select a filtering function for the asset's media type.
                    Action <CIFilter, PHContentEditingInput, PHContentEditingOutput, Action> applyFunc;
                    if (Asset.MediaSubtypes.HasFlag(PHAssetMediaSubtype.PhotoLive))
                    {
                        applyFunc = ApplyLivePhotoFilter;
                    }
                    else if (Asset.MediaType == PHAssetMediaType.Image)
                    {
                        applyFunc = ApplyPhotoFilter;
                    }
                    else
                    {
                        applyFunc = ApplyVideoFilter;
                    }

                    // Apply the filter.
                    applyFunc(filter, input, output, () => {
                        // When rendering is done, commit the edit to the Photos library.
                        PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() => {
                            var request = PHAssetChangeRequest.ChangeRequest(Asset);
                            request.ContentEditingOutput = output;
                        }, (success, error) => {
                            if (!success)
                            {
                                Console.WriteLine($"can't edit asset: {error.LocalizedDescription}");
                            }
                        });
                    });
                });
            });
        }
Пример #22
0
        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);
                }
            });
        }
Пример #23
0
        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();
                }
            });
        }
Пример #24
0
        public async Task <string> ImageSave(MemoryStream stream, bool compatibleMode, string fileName = null)
        {
            NSError error = null;

            //虽然对于iOS没有这两个权限,但要保证方法异步,所以还是保留下来了
            await Permissions.RequestAsync <Permissions.StorageWrite>();

            await Permissions.RequestAsync <Permissions.StorageRead>();

            //判断相册是否存在,不存在就创建
            PHAssetCollection appAlbum = null;
            PHFetchResult     albums   = PHAssetCollection.FetchAssetCollections(PHAssetCollectionType.Album, PHAssetCollectionSubtype.Any, null);

            foreach (PHAssetCollection album in albums)
            {
                if (album.LocalizedTitle == albumName)
                {
                    appAlbum = album;
                }
            }
            if (appAlbum == null)   //相册不存在,新建
            {
                string[] albumID = new string[1];
                PHPhotoLibrary.SharedPhotoLibrary.PerformChangesAndWait(() =>
                {
                    albumID[0] = PHAssetCollectionChangeRequest.CreateAssetCollection(albumName).PlaceholderForCreatedAssetCollection.LocalIdentifier;
                }, out error);
                appAlbum = PHAssetCollection.FetchAssetCollections(albumID, null)[0] as PHAssetCollection;
            }

            //获取路径及名称
            string documentsPath;

            documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            if (fileName == null || fileName == "")
            {
                fileName = "Tank_" + DateTime.Now.ToLocalTime().ToString("yyyyMMdd_HHmmss") + ".png";
            }
            string path = Path.Combine(documentsPath, fileName);

            //保存
            FileStream photoTankFile = new FileStream(path, FileMode.Create);

            byte[] photoTank = stream.ToArray();
            photoTankFile.Write(photoTank, 0, photoTank.Length);
            photoTankFile.Flush();
            photoTankFile.Close();

            //如果是图片或视频,就添加到相册里
            string MimeType = MimeUtility.GetMimeMapping(path);

            if (MimeType.IndexOf("image") != -1 || MimeType.IndexOf("video") != -1)
            {
                string[] assetID = new string[1];
                PHPhotoLibrary.SharedPhotoLibrary.PerformChangesAndWait(() =>
                {
                    if (MimeType.IndexOf("image") != -1)
                    {
                        assetID[0] = PHAssetChangeRequest.FromImage(new NSUrl(path, true)).PlaceholderForCreatedAsset.LocalIdentifier;
                    }
                    if (MimeType.IndexOf("video") != -1)
                    {
                        assetID[0] = PHAssetChangeRequest.FromVideo(new NSUrl(path, true)).PlaceholderForCreatedAsset.LocalIdentifier;
                    }
                }, out error);
                PHAsset    asset = PHAsset.FetchAssetsUsingLocalIdentifiers(assetID, null)[0] as PHAsset;
                PHObject[] objs  = { asset };
                PHPhotoLibrary.SharedPhotoLibrary.PerformChangesAndWait(() =>
                {
                    PHAssetCollectionChangeRequest collectionChangeRequest = PHAssetCollectionChangeRequest.ChangeRequest(appAlbum);
                    collectionChangeRequest.InsertAssets(objs, new NSIndexSet(0));
                }, out error);
            }

            return(Path.Combine(fileName));
        }
Пример #25
0
        void UpdateToolbars()
        {
            // Enable editing buttons if the asset can be edited.
            EditButton.Enabled     = Asset.CanPerformEditOperation(PHAssetEditOperation.Content);
            FavoriteButton.Enabled = Asset.CanPerformEditOperation(PHAssetEditOperation.Properties);
            FavoriteButton.Title   = Asset.Favorite ? "♥︎" : "♡";

            // Enable the trash button if the asset can be deleted.
            if (AssetCollection != null)
            {
                TrashButton.Enabled = AssetCollection.CanPerformEditOperation(PHCollectionEditOperation.RemoveContent);
            }
            else
            {
                TrashButton.Enabled = Asset.CanPerformEditOperation(PHAssetEditOperation.Delete);
            }

            // Set the appropriate toolbarItems based on the mediaType of the asset.
            if (Asset.MediaType == PHAssetMediaType.Video)
            {
#if __TVOS__
                NavigationItem.LeftBarButtonItems = new UIBarButtonItem[] { PlayButton, FavoriteButton, TrashButton };
#elif __IOS__
                ToolbarItems = new UIBarButtonItem[] { FavoriteButton, Space, PlayButton, Space, TrashButton };
                if (NavigationController != null)
                {
                    NavigationController.ToolbarHidden = false;
                }
#endif
            }
            else
            {
#if __TVOS__
                // In tvOS, PHLivePhotoView doesn't do playback gestures,
                // so add a play button for Live Photos.
                if (Asset.PlaybackStyle == PHAssetPlaybackStyle.LivePhoto)
                {
                    NavigationItem.LeftBarButtonItems = new UIBarButtonItem[] { LivePhotoPlayButton, FavoriteButton, TrashButton }
                }
                ;
                else
                {
                    NavigationItem.LeftBarButtonItems = new UIBarButtonItem[] { FavoriteButton, TrashButton }
                };
#elif __IOS__
                // In iOS, present both stills and Live Photos the same way, because
                // PHLivePhotoView provides the same gesture-based UI as in Photos app.
                ToolbarItems = new UIBarButtonItem[] { FavoriteButton, Space, TrashButton };
                if (NavigationController != null)
                {
                    NavigationController.ToolbarHidden = false;
                }
#endif
            }
        }

        void UpdateStillImage()
        {
            // Prepare the options to pass when fetching the (photo, or video preview) image.
            var options = new PHImageRequestOptions
            {
                DeliveryMode         = PHImageRequestOptionsDeliveryMode.HighQualityFormat,
                NetworkAccessAllowed = true,
                ProgressHandler      = (double progress, NSError error, out bool stop, NSDictionary info) =>
                {
                    stop = false;
                    // Handler might not be called on the main queue, so re-dispatch for UI work.
                    DispatchQueue.MainQueue.DispatchSync(() =>
                    {
                        ProgressView.Progress = (float)progress;
                    });
                }
            };

            ProgressView.Hidden = false;
            PHImageManager.DefaultManager.RequestImageForAsset(Asset, GetTargetSize(), PHImageContentMode.AspectFit, options, (image, info) =>
            {
                // Hide the progress view now the request has completed.
                ProgressView.Hidden = true;

                // If successful, show the image view and display the image.
                if (image == null)
                {
                    return;
                }

                // Now that we have the image, show it.
                ImageView.Hidden = false;
                ImageView.Image  = image;
            });
        }

        void UpdateLivePhoto()
        {
            // Prepare the options to pass when fetching the live photo.
            var options = new PHLivePhotoRequestOptions
            {
                DeliveryMode         = PHImageRequestOptionsDeliveryMode.HighQualityFormat,
                NetworkAccessAllowed = true,
                ProgressHandler      = (double progress, NSError error, out bool stop, NSDictionary dictionary) =>
                {
                    stop = false;
                    // Handler might not be called on the main queue, so re-dispatch for UI work.
                    DispatchQueue.MainQueue.DispatchSync(() => ProgressView.Progress = (float)progress);
                }
            };

            ProgressView.Hidden = false;
            // Request the live photo for the asset from the default PHImageManager.
            PHImageManager.DefaultManager.RequestLivePhoto(Asset, GetTargetSize(), PHImageContentMode.AspectFit, options, (livePhoto, info) =>
            {
                // Hide the progress view now the request has completed.
                ProgressView.Hidden = true;

                // If successful, show the live photo view and display the live photo.
                if (livePhoto == null)
                {
                    return;
                }

                // Now that we have the Live Photo, show it.
                ImageView.Hidden         = true;
                AnimatedImageView.Hidden = true;
                LivePhotoView.Hidden     = false;
                LivePhotoView.LivePhoto  = livePhoto;

                // Playback a short section of the live photo; similar to the Photos share sheet.
                if (!isPlayingHint)
                {
                    isPlayingHint = true;
                    LivePhotoView.StartPlayback(PHLivePhotoViewPlaybackStyle.Hint);
                }
            });
        }

        void UpdateAnimatedImage()
        {
            // Prepare the options to pass when fetching the (photo, or video preview) image.
            var options = new PHImageRequestOptions
            {
                DeliveryMode         = PHImageRequestOptionsDeliveryMode.HighQualityFormat,
                Version              = PHImageRequestOptionsVersion.Original,
                NetworkAccessAllowed = true,
                ProgressHandler      = (double progress, NSError error, out bool stop, NSDictionary info) =>
                {
                    stop = false;
                    // Handler might not be called on the main queue, so re-dispatch for UI work.
                    DispatchQueue.MainQueue.DispatchSync(() =>
                    {
                        ProgressView.Progress = (float)progress;
                    });
                }
            };

            ProgressView.Hidden = false;
            PHImageManager.DefaultManager.RequestImageData(Asset, options, (data, dataUti, orientation, info) =>
            {
                // Hide the progress view now the request has completed.
                ProgressView.Hidden = true;

                // If successful, show the image view and display the image.
                if (data == null)
                {
                    return;
                }

                var animatedImage = new AnimatedImage(data);

                LivePhotoView.Hidden            = true;
                ImageView.Hidden                = true;
                AnimatedImageView.Hidden        = false;
                AnimatedImageView.AnimatedImage = animatedImage;
                AnimatedImageView.IsPlaying     = true;
            });
        }

        #endregion

        #region Asset editing

        void RevertAsset(UIAlertAction action)
        {
            PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() =>
            {
                var request = PHAssetChangeRequest.ChangeRequest(Asset);
                request.RevertAssetContentToOriginal();
            }, (success, error) =>
            {
                if (!success)
                {
                    Console.WriteLine($"can't revert asset: {error.LocalizedDescription}");
                }
            });
        }

        void ApplyFilter(CIFilter filter)
        {
            // Set up a handler to make sure we can handle prior edits.
            var options = new PHContentEditingInputRequestOptions();

            options.CanHandleAdjustmentData = (adjustmentData =>
            {
                return(adjustmentData.FormatIdentifier == formatIdentifier && adjustmentData.FormatVersion == formatVersion);
            });

            // Prepare for editing.
            Asset.RequestContentEditingInput(options, (input, requestStatusInfo) =>
            {
                if (input == null)
                {
                    throw new InvalidProgramException($"can't get content editing input: {requestStatusInfo}");
                }

                // This handler gets called on the main thread; dispatch to a background queue for processing.
                DispatchQueue.GetGlobalQueue(DispatchQueuePriority.Default).DispatchAsync(() =>
                {
                    // Create a PHAdjustmentData object that describes the filter that was applied.
                    var adjustmentData = new PHAdjustmentData(
                        formatIdentifier,
                        formatVersion,
                        NSData.FromString(filter.Name, NSStringEncoding.UTF8));

                    // NOTE:
                    // This app's filter UI is fire-and-forget. That is, the user picks a filter,
                    // and the app applies it and outputs the saved asset immediately. There's
                    // no UI state for having chosen but not yet committed an edit. This means
                    // there's no role for reading adjustment data -- you do that to resume
                    // in-progress edits, and this sample app has no notion of "in-progress".
                    //
                    // However, it's still good to write adjustment data so that potential future
                    // versions of the app (or other apps that understand our adjustement data
                    // format) could make use of it.

                    // Create content editing output, write the adjustment data.
                    var output = new PHContentEditingOutput(input)
                    {
                        AdjustmentData = adjustmentData
                    };

                    // Select a filtering function for the asset's media type.
                    Action <CIFilter, PHContentEditingInput, PHContentEditingOutput, Action> applyFunc;
                    if (Asset.MediaSubtypes.HasFlag(PHAssetMediaSubtype.PhotoLive))
                    {
                        applyFunc = ApplyLivePhotoFilter;
                    }
                    else if (Asset.MediaType == PHAssetMediaType.Image)
                    {
                        applyFunc = ApplyPhotoFilter;
                    }
                    else
                    {
                        applyFunc = ApplyVideoFilter;
                    }

                    // Apply the filter.
                    applyFunc(filter, input, output, () =>
                    {
                        // When rendering is done, commit the edit to the Photos library.
                        PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() =>
                        {
                            var request = PHAssetChangeRequest.ChangeRequest(Asset);
                            request.ContentEditingOutput = output;
                        }, (success, error) =>
                        {
                            if (!success)
                            {
                                Console.WriteLine($"can't edit asset: {error.LocalizedDescription}");
                            }
                        });
                    });
                });
            });
        }

        void ApplyPhotoFilter(CIFilter filter, PHContentEditingInput input, PHContentEditingOutput output, Action completion)
        {
            // Load the full size image.
            var inputImage = new CIImage(input.FullSizeImageUrl);

            if (inputImage == null)
            {
                throw new InvalidProgramException("can't load input image to edit");
            }

            // Apply the filter.
            filter.Image = inputImage.CreateWithOrientation(input.FullSizeImageOrientation);
            var outputImage = filter.OutputImage;

            // Write the edited image as a JPEG.
            // TODO: https://bugzilla.xamarin.com/show_bug.cgi?id=44503
            NSError error;

            if (!ciContext.WriteJpegRepresentation(outputImage, output.RenderedContentUrl, inputImage.ColorSpace, new NSDictionary(), out error))
            {
                throw new InvalidProgramException($"can't apply filter to image: {error.LocalizedDescription}");
            }

            completion();
        }

        void ApplyLivePhotoFilter(CIFilter filter, PHContentEditingInput input, PHContentEditingOutput output, Action completion)
        {
            // This app filters assets only for output. In an app that previews
            // filters while editing, create a livePhotoContext early and reuse it
            // to render both for previewing and for final output.
            var livePhotoContext = new PHLivePhotoEditingContext(input);

            livePhotoContext.FrameProcessor2 = (IPHLivePhotoFrame frame, ref NSError _) =>
            {
                filter.Image = frame.Image;
                return(filter.OutputImage);
            };
            livePhotoContext.SaveLivePhoto(output, (PHLivePhotoEditingOption)null, (success, error) =>
            {
                if (success)
                {
                    completion();
                }
                else
                {
                    Console.WriteLine("can't output live photo");
                }
            });
            // Applying edits to a Live Photo currently crashes
            // TODO: https://bugzilla.xamarin.com/show_bug.cgi?id=58227
        }

        void ApplyVideoFilter(CIFilter filter, PHContentEditingInput input, PHContentEditingOutput output, Action completion)
        {
            // Load AVAsset to process from input.
            var avAsset = input.AudiovisualAsset;

            if (avAsset == null)
            {
                throw new InvalidProgramException("can't get AV asset to edit");
            }

            // Set up a video composition to apply the filter.
            var composition = AVVideoComposition.CreateVideoComposition(avAsset, request =>
            {
                filter.Image = request.SourceImage;
                var filtered = filter.OutputImage;
                request.Finish(filtered, null);
            });

            // Export the video composition to the output URL.
            var export = new AVAssetExportSession(avAsset, AVAssetExportSessionPreset.HighestQuality)
            {
                OutputFileType   = AVFileType.QuickTimeMovie,
                OutputUrl        = output.RenderedContentUrl,
                VideoComposition = composition
            };

            export.ExportAsynchronously(completion);
        }