¿Cómo guardar la imagen en la biblioteca de fotos del iPhone?


Respuestas:


411

Puedes usar esta función:

UIImageWriteToSavedPhotosAlbum(UIImage *image, 
                               id completionTarget, 
                               SEL completionSelector, 
                               void *contextInfo);

Solo necesita completeTarget , completeSelector y contextInfo si desea recibir una notificación cuando termine deUIImage guardar, de lo contrario puede pasar nil.

Consulte la documentación oficial paraUIImageWriteToSavedPhotosAlbum() .


Tome +1 para obtener la respuesta precisa
Niru Mukund Shah

Hola, gracias por tu gran solución. Aquí tengo una duda de cómo podemos evitar duplicados al guardar la imagen en la biblioteca de fotos. Gracias por adelantado.
Naresh

Si desea ahorrar en mejor calidad, vea esto: stackoverflow.com/questions/1379274/…
eonil

44
Ahora tendrá que agregar 'Privacidad - Descripción de uso de adiciones a la biblioteca de fotos' a partir de iOS 11 para guardar las fotos del álbum de los usuarios.
horsejockey

1
¿Cómo dar un nombre a las imágenes guardadas?
Priyal

63

En desuso en iOS 9.0.

Hay mucho más rápido que UIImageWriteToSavedPhotosAlbum para hacerlo usando iOS 4.0+ AssetsLibrary framework

    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];

1
¿Hay alguna manera de guardar metadatos arbitrarios junto con la foto?
zakdances

2
Traté de guardar usando ALAssetsLibrary, toma exactamente el mismo tiempo para guardar como UIImageWriteToSavedPhotosAlbum.
Hlung

Y esto congela la cámara :( ¿Supongo que no es compatible con el fondo?
Hlung 05 de

Este es mucho más limpio b / c que puede usar un bloque para manejar la finalización.
jpswain

55
Estoy usando este código e incluyo este marco #import <AssetsLibrary / AssetsLibrary.h> no la AVFoundation. ¿No debería ser editada la respuesta? @Denis
Julian Osorio el


13

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:]: index (2) out of bounds [-1, 1]


10

Simplemente pasa las imágenes de una matriz a ella 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);
        }
}

Perdón por los errores tipográficos que acabo de hacer sobre la marcha pero entiendes


Al usar esto, echaré de menos algunas de las fotos, lo he probado. La forma correcta de hacerlo es usar la devolución de llamada desde el selector de finalización.
SamChen

1
¿podemos guardar imágenes con el nombre personalizado?
Usuario 1531343

Uno nunca debe usar for loop para esto. Conduce a la condición de carrera y se bloquea.
saurabh

4

Al guardar una gran variedad 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);
   }
}

4

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.
            }
    }

sí ... agradable ... pero después de guardar la imagen quiero cargar la imagen de la galería ... cómo hacer eso
EI Captain v2.0

4

La siguiente función funcionaría. Puede 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");
        }
    }];
}

2

Swift 4

func writeImage(image: UIImage) {
    UIImageWriteToSavedPhotosAlbum(image, self, #selector(self.finishWriteImage), nil)
}

@objc private func finishWriteImage(_ image: UIImage, didFinishSavingWithError error: NSError?, contextInfo: UnsafeRawPointer) {
    if (error != nil) {
        // Something wrong happened.
        print("error occurred: \(String(describing: error))")
    } else {
        // Everything is alright.
        print("saved success!")
    }
}

1

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);
        }
}

He probado tu solución, siempre me faltaron algunas de las fotos. Mira mi respuesta. enlace
SamChen

1
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];
}

Esta respuesta no es correcta porque no guarda la imagen en la biblioteca de fotos del sistema, sino en la caja de arena.
Evan

1

Creé una categoría UIImageView para esto, basada en algunas de las respuestas anteriores.

Archivo de cabecera:

@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, puede modificar el parámetro mínimo PressDuration.


1

En Swift 2.2

UIImageWriteToSavedPhotosAlbum(image: UIImage, _ completionTarget: AnyObject?, _ completionSelector: Selector, _ contextInfo: UnsafeMutablePointer<Void>)

Si no desea recibir una notificación cuando la imagen se haya guardado, puede pasar nulo en los parámetros completeTarget , completeSelector y contextInfo .

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 eso ayude.


0

Puedes usar esto

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
   UIImageWriteToSavedPhotosAlbum(img.image, nil, nil, nil);
});
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.