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

193

¿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?

jblocksom
fuente
Puedes consultar este código . ¡Gran día!
Celil Bozkurt el

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() .

Martin Gordon
fuente
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];
Denis Fileev
fuente
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
30

La forma más simple es:

UIImageWriteToSavedPhotosAlbum(myUIImage, nil, nil, nil);

Para Swift, puede consultar Guardar en la biblioteca de fotos de iOS usando swift

Mutawe
fuente
3
Realmente me gusta su icono de perfil de usuario SO. Muy buena imagen de Xcode.
Supertecnoboff
1
¡Fantásticamente simple y muy, muy fácil!
Septronic
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]

Jeff C.
fuente
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

mrburns05
fuente
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);
   }
}
SamChen
fuente
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.
            }
    }
Rey Mago
fuente
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");
        }
    }];
}
iDevAmit
fuente
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!")
    }
}
luhuiya
fuente
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);
        }
}
mrburns05
fuente
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];
}
Hola
fuente
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.

HugglesNL
fuente
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.

jarora
fuente
0

Puedes usar esto

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
   UIImageWriteToSavedPhotosAlbum(img.image, nil, nil, nil);
});
Pratik Somaiya
fuente