PhotoKit en Xamarin.iOS
PhotoKit es un nuevo marco que permite a las aplicaciones consultar la biblioteca de imágenes del sistema y crear interfaces de usuario personalizadas para ver y modificar su contenido. Incluye una serie de clases que representan recursos de imagen y vídeo, así como colecciones de recursos como álbumes y carpetas.
Permisos
Antes de que la aplicación pueda acceder a la biblioteca de fotos, se mostrará al usuario un cuadro de diálogo de permisos. Debe proporcionar texto explicativo en el archivo Info.plist para explicar cómo usa la aplicación la biblioteca de fotos, por ejemplo:
<key>NSPhotoLibraryUsageDescription</key>
<string>Applies filters to photos and updates the original image</string>
Objetos de modelo
PhotoKit representa estos recursos en lo que llama objetos de modelo. Los objetos de modelo que representan las fotos y los vídeos son de tipo PHAsset
. Un elemento PHAsset
metadatos, como el tipo de medio del recurso y su fecha de creación.
Del mismo modo, las clases PHAssetCollection
y PHCollectionList
contienen metadatos sobre colecciones de recursos y listas de colecciones, respectivamente. Las colecciones de recursos son grupos de recursos, como todas las fotos y vídeos de un año determinado. Del mismo modo, las listas de colecciones son grupos de colecciones de recursos, como fotos y vídeos agrupados por año.
Consulta de datos del modelo
PhotoKit facilita la consulta de datos del modelo mediante diversos métodos de captura. Por ejemplo, para recuperar todas las imágenes, llamaría a PHAsset.Fetch
, pasando el tipo de medio PHAssetMediaType.Image
.
PHFetchResult fetchResults = PHAsset.FetchAssets (PHAssetMediaType.Image, null);
La instancia PHFetchResult
contendría entonces todas las instancias PHAsset
que representan imágenes. Para obtener las imágenes propiamente dichas, use PHImageManager
(o la versión de almacenamiento en caché, PHCachingImageManager
) para realizar una solicitud de la imagen llamando a RequestImageForAsset
. Por ejemplo, el código siguiente recupera una imagen de cada recurso de un elemento PHFetchResult
para mostrarla en una celda de la vista de la colección:
public override UICollectionViewCell GetCell (UICollectionView collectionView, NSIndexPath indexPath)
{
var imageCell = (ImageCell)collectionView.DequeueReusableCell (cellId, indexPath);
imageMgr.RequestImageForAsset (
(PHAsset)fetchResults [(uint)indexPath.Item],
thumbnailSize,
PHImageContentMode.AspectFill, new PHImageRequestOptions (),
(img, info) => {
imageCell.ImageView.Image = img;
}
);
return imageCell;
}
El resultado es una cuadrícula de imágenes, como se muestra a continuación:
Guardar cambios en la fototeca
Así es como se controla la consulta y la lectura de datos. También puede escribir los cambios de vuelta a la biblioteca. Dado que varias aplicaciones interesadas pueden interactuar con la fototeca del sistema, puede registrar un observador para recibir notificaciones de los cambios mediante un objeto PhotoLibraryObserver
. A continuación, cuando se produzcan cambios, la aplicación puede actualizarse en consecuencia. Por ejemplo, esta es una implementación sencilla para volver a cargar la vista de la colección anterior:
class PhotoLibraryObserver : PHPhotoLibraryChangeObserver
{
readonly PhotosViewController controller;
public PhotoLibraryObserver (PhotosViewController controller)
{
this.controller = controller;
}
public override void PhotoLibraryDidChange (PHChange changeInstance)
{
DispatchQueue.MainQueue.DispatchAsync (() => {
var changes = changeInstance.GetFetchResultChangeDetails (controller.fetchResults);
controller.fetchResults = changes.FetchResultAfterChanges;
controller.CollectionView.ReloadData ();
});
}
}
Para volver a escribir los cambios en la aplicación, cree una solicitud de cambio. Cada una de las clases del modelo tiene una clase de solicitud de cambio asociada. Por ejemplo, para cambiar un objeto PHAsset
, crearía un objeto PHAssetChangeRequest
. Los pasos para realizar los cambios que se escriben de nuevo en la fototeca y que se envían a observadores como el anterior son los siguientes:
- Realice la operación de edición.
- Guarde los datos de imagen filtrados en una instancia
PHContentEditingOutput
. - Realice una solicitud de cambio para publicar los cambios desde la salida de edición.
Este es un ejemplo en el que se vuelve a escribir un cambio en una imagen que aplica un filtro negro a la imagen principal:
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.GetSharedPhotoLibrary.PerformChanges (() => {
PHAssetChangeRequest request = PHAssetChangeRequest.ChangeRequest(Asset);
request.ContentEditingOutput = editingOutput;
},
(ok, err) => Console.WriteLine ("photo updated successfully: {0}", ok));
});
}
Cuando el usuario selecciona el botón, se aplica el filtro:
Y gracias al objeto PHPhotoLibraryChangeObserver
, el cambio se refleja en la vista de la colección cuando el usuario vuelve a desplazarse a ella: