Como salvar uma imagem na biblioteca de fotos do iPhone?

193

O que preciso fazer para salvar uma imagem que meu programa gerou (possivelmente da câmera, possivelmente não) para a biblioteca de fotos do sistema no iPhone?

jblocksom
fonte
Você pode verificar este código . Ótimo dia!
precisa saber é o seguinte

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

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

A maneira mais simples é:

UIImageWriteToSavedPhotosAlbum(myUIImage, nil, nil, nil);

Para Swift, você pode consultar Salvando na biblioteca de fotos do iOS usando swift

Mutawe
fonte
3
Eu realmente gosto do seu ícone de perfil de usuário SO. Imagem muito legal do Xcode.
Supertecnoboff 29/05
1
Incrivelmente simples e muito, muito fácil!
Septronic
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]

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

mrburns05
fonte
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);
   }
}
SamChen
fonte
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.
            }
    }
O rei da bruxaria
fonte
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");
        }
    }];
}
iDevAmit
fonte
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
fonte
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);
        }
}
mrburns05
fonte
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];
}
Olá
fonte
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.

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

jarora
fonte
0

Você pode usar isso

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