¿Cómo guardar la imagen en la biblioteca de fotos del iPhone?
-
05-07-2019 - |
Pregunta
¿Qué debo hacer para guardar una imagen que mi programa ha generado (posiblemente desde la cámara, posiblemente no) en la biblioteca de fotos del sistema en el iPhone?
Solución
Puedes usar esta función:
UIImageWriteToSavedPhotosAlbum(UIImage *image,
id completionTarget,
SEL completionSelector,
void *contextInfo);
Solo necesita completedTarget , completedSelector y contextInfo si desea recibir una notificación cuando se realice el UIImage
guardando, de lo contrario puede pasar en nil
.
Consulte la documentación oficial para UIImageWriteToSavedPhotosAlbum ()
.
Otros consejos
En desuso en iOS 9.0.
Hay mucho más rápido que UIImageWriteToSavedPhotosAlbum de la manera de hacerlo utilizando el marco de la biblioteca AssetsLibrary de iOS 4.0+
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeImageToSavedPhotosAlbum:[image CGImage] orientation:(ALAssetOrientation)[image imageOrientation] completionBlock:^(NSURL *assetURL, NSError *error){
if (error) {
// TODO: error handling
} else {
// TODO: success handling
}
}];
[library release];
La forma más sencilla es:
UIImageWriteToSavedPhotosAlbum(myUIImage, nil, nil, nil);
Para Swift
, puede consultar Guardar en la biblioteca de fotos de iOS usando swift
Una cosa para recordar: si usa una devolución de llamada, asegúrese de que su selector cumpla con el siguiente formulario:
- (void) image: (UIImage *) image didFinishSavingWithError: (NSError *) error contextInfo: (void *) contextInfo;
De lo contrario, se bloqueará con un error como el siguiente:
[NSInvocation setArgument: atIndex:]: índice (2) fuera de límites [-1, 1]
Simplemente pase las imágenes de una matriz a este como así
-(void) saveMePlease {
//Loop through the array here
for (int i=0:i<[arrayOfPhotos count]:i++){
NSString *file = [arrayOfPhotos objectAtIndex:i];
NSString *path = [get the path of the image like you would in DOCS FOLDER or whatever];
NSString *imagePath = [path stringByAppendingString:file];
UIImage *image = [[[UIImage alloc] initWithContentsOfFile:imagePath]autorelease];
//Now it will do this for each photo in the array
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
}
}
Lo siento por el tipo de error tipográfico que acabo de hacer sobre la marcha, pero obtienes el punto
Al guardar una serie de fotos, no use un bucle for, haga lo siguiente
-(void)saveToAlbum{
[self performSelectorInBackground:@selector(startSavingToAlbum) withObject:nil];
}
-(void)startSavingToAlbum{
currentSavingIndex = 0;
UIImage* img = arrayOfPhoto[currentSavingIndex];//get your image
UIImageWriteToSavedPhotosAlbum(img, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
}
- (void)image: (UIImage *) image didFinishSavingWithError: (NSError *) error contextInfo: (void *) contextInfo{ //can also handle error message as well
currentSavingIndex ++;
if (currentSavingIndex >= arrayOfPhoto.count) {
return; //notify the user it's done.
}
else
{
UIImage* img = arrayOfPhoto[currentSavingIndex];
UIImageWriteToSavedPhotosAlbum(img, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
}
}
En Swift :
// Save it to the camera roll / saved photo album
// UIImageWriteToSavedPhotosAlbum(self.myUIImageView.image, nil, nil, nil) or
UIImageWriteToSavedPhotosAlbum(self.myUIImageView.image, self, "image:didFinishSavingWithError:contextInfo:", nil)
func image(image: UIImage!, didFinishSavingWithError error: NSError!, contextInfo: AnyObject!) {
if (error != nil) {
// Something wrong happened.
} else {
// Everything is alright.
}
}
La siguiente función funcionaría. Puedes copiar desde aquí y pegar allí ...
-(void)savePhotoToAlbum:(UIImage*)imageToSave {
CGImageRef imageRef = imageToSave.CGImage;
NSDictionary *metadata = [NSDictionary new]; // you can add
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeImageToSavedPhotosAlbum:imageRef metadata:metadata completionBlock:^(NSURL *assetURL,NSError *error){
if(error) {
NSLog(@"Image save eror");
}
}];
}
homeDirectoryPath = NSHomeDirectory();
unexpandedPath = [homeDirectoryPath stringByAppendingString:@"/Pictures/"];
folderPath = [NSString pathWithComponents:[NSArray arrayWithObjects:[NSString stringWithString:[unexpandedPath stringByExpandingTildeInPath]], nil]];
unexpandedImagePath = [folderPath stringByAppendingString:@"/image.png"];
imagePath = [NSString pathWithComponents:[NSArray arrayWithObjects:[NSString stringWithString:[unexpandedImagePath stringByExpandingTildeInPath]], nil]];
if (![[NSFileManager defaultManager] fileExistsAtPath:folderPath isDirectory:NULL]) {
[[NSFileManager defaultManager] createDirectoryAtPath:folderPath attributes:nil];
}
mi última respuesta lo hará ..
para cada imagen que desee guardar, agréguela a un NSMutableArray
//in the .h file put:
NSMutableArray *myPhotoArray;
///then in the .m
- (void) viewDidLoad {
myPhotoArray = [[NSMutableArray alloc]init];
}
//However Your getting images
- (void) someOtherMethod {
UIImage *someImage = [your prefered method of using this];
[myPhotoArray addObject:someImage];
}
-(void) saveMePlease {
//Loop through the array here
for (int i=0:i<[myPhotoArray count]:i++){
NSString *file = [myPhotoArray objectAtIndex:i];
NSString *path = [get the path of the image like you would in DOCS FOLDER or whatever];
NSString *imagePath = [path stringByAppendingString:file];
UIImage *image = [[[UIImage alloc] initWithContentsOfFile:imagePath]autorelease];
//Now it will do this for each photo in the array
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
}
}
Creé una categoría UIImageView para esto, basada en algunas de las respuestas anteriores.
Archivo de encabezado:
@interface UIImageView (SaveImage) <UIActionSheetDelegate>
- (void)addHoldToSave;
@end
Implementación
@implementation UIImageView (SaveImage)
- (void)addHoldToSave{
UILongPressGestureRecognizer* longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
longPress.minimumPressDuration = 1.0f;
[self addGestureRecognizer:longPress];
}
- (void)handleLongPress:(UILongPressGestureRecognizer*)sender {
if (sender.state == UIGestureRecognizerStateEnded) {
UIActionSheet* _attachmentMenuSheet = [[UIActionSheet alloc] initWithTitle:nil
delegate:self
cancelButtonTitle:@"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:@"Save Image", nil];
[_attachmentMenuSheet showInView:[[UIView alloc] initWithFrame:self.frame]];
}
else if (sender.state == UIGestureRecognizerStateBegan){
//Do nothing
}
}
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
if (buttonIndex == 0) {
UIImageWriteToSavedPhotosAlbum(self.image, nil,nil, nil);
}
}
@end
Ahora simplemente llame a esta función en su vista de imagen:
[self.imageView addHoldToSave];
Opcionalmente, puedes modificar el parámetro minimumPressDuration.
En Swift 2.2
UIImageWriteToSavedPhotosAlbum(image: UIImage, _ completionTarget: AnyObject?, _ completionSelector: Selector, _ contextInfo: UnsafeMutablePointer<Void>)
Si no desea que se le notifique cuando se termine de guardar la imagen, puede pasar el nulo a completedTarget , completedSelector y contextInfo parámetros.
Ejemplo:
UIImageWriteToSavedPhotosAlbum(image, self, #selector(self.imageSaved(_:didFinishSavingWithError:contextInfo:)), nil)
func imageSaved(image: UIImage!, didFinishSavingWithError error: NSError?, contextInfo: AnyObject?) {
if (error != nil) {
// Something wrong happened.
} else {
// Everything is alright.
}
}
Lo importante a tener en cuenta aquí es que su método que observa el guardado de la imagen debe tener estos 3 parámetros, de lo contrario, se encontrará con errores de NSInvocation.
Espero que ayude.
Puedes usar esto
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UIImageWriteToSavedPhotosAlbum(img.image, nil, nil, nil);
});
Swift 4
func writeImage(image: UIImage) {
UIImageWriteToSavedPhotosAlbum(image, self, #selector(finishWriteImage), nil)
}
@objc private func finishWriteImage(_ image: UIImage, didFinishSavingWithError error: NSError?, contextInfo: UnsafeRawPointer) {
}