Como salvar uma imagem na biblioteca de fotos do iPhone?


Respostas:


411

Você pode usar esta função:

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

Você só precisa completionTarget , completionSelector e contextInfo se você quiser ser notificado quando o UIImageé feito salvar, caso contrário, você pode passar nil.

Veja a documentação oficial paraUIImageWriteToSavedPhotosAlbum() .


Tome um para a resposta exata
Niru Mukund Shah

Oi, obrigado pela sua ótima solução. Aqui eu tenho uma dúvida de como podemos evitar duplicatas enquanto salvamos imagens na biblioteca de fotos. Desde já, obrigado.
Naresh

Se você deseja economizar em melhor qualidade, consulte: stackoverflow.com/questions/1379274/…
Eonil

4
Agora você precisará adicionar 'Privacidade - Descrição da utilização das adições à biblioteca de fotos' no iOS 11 para salvar as fotos do álbum dos usuários.
horsejockey

1
como dar um nome às imagens salvas?
Priyal

63

Descontinuado no iOS 9.0.

Há muito mais rápido do que o modo UIImageWriteToSavedPhotosAlbum de fazê-lo usando o iOS 4.0+ ou mais

    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
Existe uma maneira de salvar metadados arbitrários junto com a foto?
perfil completo de zakdances

2
Eu tentei salvar usando ALAssetsLibrary, leva apenas o mesmo tempo para salvar como UIImageWriteToSavedPhotosAlbum.
Hlung 05/05

E este congela a câmera :( Eu acho que não é fundo suportado?
Hlung

Este é muito mais limpo porque você pode usar um bloco para lidar com a conclusão.
Jspwain #

5
Estou usando esse código e incluindo esta estrutura #import <AssetsLibrary / AssetsLibrary.h> não a AVFoundation. A resposta não deve ser editada? @Denis
Julian Osorio


13

Uma coisa a lembrar: se você usar um retorno de chamada, verifique se o seletor está em conformidade com o seguinte formato:

- (void) image: (UIImage *) image didFinishSavingWithError: (NSError *) error contextInfo: (void *) contextInfo;

Caso contrário, ocorrerá um erro como o seguinte:

[NSInvocation setArgument:atIndex:]: index (2) out of bounds [-1, 1]


10

Basta passar as imagens de uma matriz para ela da seguinte maneira

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

Desculpe pelo erro de digitação apenas fez isso em tempo real, mas você entendeu


Usando isso vai perder algumas das fotos, eu tentei. A maneira correta de fazer isso é usar o retorno de chamada do seletor de conclusão.
SamChen

1
podemos salvar imagens com o nome personalizado?
Utilizador 1531343

Nunca se deve usar o loop for para isso. Isso leva à condição de corrida e trava.
Saurabh

4

Ao salvar uma matriz de fotos, não use um loop for, faça o seguinte

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

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

sim ... Nice..but após salvar imagem que eu quero carregar a imagem de galeria em ... como fazer isso
EI Capitão v2.0

4

A função abaixo funcionaria. Você pode copiar daqui e colar lá ...

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

minha última resposta vai fazer isso ..

para cada imagem que você deseja salvar, adicione-a a um 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);
        }
}

Eu tentei sua solução, ela sempre perdeu algumas das fotos. Dê uma olhada na minha resposta. Link
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 resposta não está correta porque não salva a imagem na Biblioteca de fotos do sistema, mas na caixa de areia.
Evan

1

Criei uma categoria UIImageView para isso, com base em algumas das respostas acima.

Arquivo de cabeçalho:

@interface UIImageView (SaveImage) <UIActionSheetDelegate>
- (void)addHoldToSave;
@end

Implementação

@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

Agora, basta chamar esta função na visualização de imagem:

[self.imageView addHoldToSave];

Opcionalmente, você pode alterar o parâmetro minimumPressDuration.


1

No Swift 2.2

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

Se você não desejar ser notificado quando a imagem terminar de salvar, poderá passar nulo nos parâmetros de conclusãoTarget , conclusãoSeletor e contextInfo .

Exemplo:

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

O importante a ser observado aqui é que seu método que observa o salvamento da imagem deve ter esses três parâmetros, caso contrário, você encontrará erros do NSInvocation.

Espero que ajude.


0

Você pode usar isso

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
   UIImageWriteToSavedPhotosAlbum(img.image, nil, nil, nil);
});
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.