Comment enregistrer une image dans la photothèque iPhone?


193

Que dois-je faire pour enregistrer une image que mon programme a générée (éventuellement à partir de l'appareil photo, peut-être pas) dans la photothèque système de l'iPhone?


Vous pouvez vérifier ce code . Belle journée!
Celil Bozkurt

Réponses:


411

Vous pouvez utiliser cette fonction:

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

Vous avez seulement besoin completionTarget , completionSelector et contextInfo si vous souhaitez être averti lorsque le UIImagesauve faire, sinon vous pouvez passernil .

Voir la documentation officielle pourUIImageWriteToSavedPhotosAlbum() .


Prenez +1 pour la réponse exacte
Niru Mukund Shah

Salut merci pour votre excellente solution. Ici, j'ai un doute sur la façon d'éviter les doublons lors de l'enregistrement de l'image dans la photothèque. Merci d'avance.
Naresh

Si vous voulez économiser en meilleure qualité, voyez ceci: stackoverflow.com/questions/1379274/…
eonil

4
Vous devez maintenant ajouter «Confidentialité - Description de l'utilisation des compléments de la bibliothèque de photos» à partir d'iOS 11 pour enregistrer les photos de l'album des utilisateurs.
horsejockey

1
comment donner un nom aux images enregistrées?
Priyal

63

Déconseillé dans iOS 9.0.

Il y a beaucoup plus rapide que la méthode UIImageWriteToSavedPhotosAlbum pour le faire en utilisant 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
Existe-t-il un moyen de sauvegarder des métadonnées arbitraires avec la photo?
zakdances

2
J'ai essayé d'enregistrer en utilisant ALAssetsLibrary, cela prend juste le même temps pour enregistrer en tant que UIImageWriteToSavedPhotosAlbum.
Hlung

Et cela gèle la caméra :( Je suppose que ce n'est pas le fond supporté?
Hlung

Celui-ci est tellement plus propre b / c que vous pouvez utiliser un bloc pour gérer l'achèvement.
jpswain

5
J'utilise ce code et j'inclus ce framework #import <AssetsLibrary / AssetsLibrary.h> pas l'AVFoundation. La réponse ne devrait-elle pas être modifiée? @Denis
Julian Osorio


13

Une chose à retenir: si vous utilisez un rappel, assurez-vous que votre sélecteur est conforme au formulaire suivant:

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

Sinon, vous vous planterez avec une erreur telle que la suivante:

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


10

Passez-y simplement les images d'un tableau

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

Désolé pour le genre de faute de frappe qui vient de le faire à la volée, mais vous obtenez le point


En utilisant cela, certaines photos manqueront, je l'ai essayé. La bonne façon d'y accéder est d'utiliser le rappel depuis le sélecteur de fin.
SamChen

1
pouvons-nous enregistrer des images avec le nom personnalisé?
Utilisateur 1531343

Il ne faut jamais utiliser de boucle pour cela. Cela conduit à la condition de course et se bloque.
saurabh

4

Lorsque vous enregistrez un tableau de photos, n'utilisez pas de boucle for, procédez comme suit

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

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

oui ... bien..mais après avoir sauvegardé l'image, je veux charger l'image de la galerie ... comment faire
EI Captain v2.0

4

La fonction ci-dessous fonctionnerait. Vous pouvez copier d'ici et coller là-bas ...

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

ma dernière réponse le fera ..

pour chaque image que vous souhaitez enregistrer, ajoutez-la à 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);
        }
}

J'ai essayé votre solution, il manquait toujours certaines photos. Jetez un oeil à ma réponse. 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];
}

Cette réponse n'est pas correcte car elle n'enregistre pas l'image dans la photothèque du système, mais dans le bac à sable.
Evan

1

J'ai créé une catégorie UIImageView pour cela, basée sur certaines des réponses ci-dessus.

En tête de fichier:

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

la mise en oeuvre

@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

Maintenant, appelez simplement cette fonction sur votre imageview:

[self.imageView addHoldToSave];

Vous pouvez éventuellement modifier le paramètre minimumPressDuration.


1

Dans Swift 2.2

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

Si vous ne souhaitez pas être averti de la fin de l'enregistrement de l'image, vous pouvez passer nil dans les paramètres d' achèvementTarget , d' achèvementSelector et contextInfo .

Exemple:

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

La chose importante à noter ici est que votre méthode qui observe l'enregistrement d'image devrait avoir ces 3 paramètres sinon vous rencontrerez des erreurs NSInvocation.

J'espère que ça aide.


0

Vous pouvez utiliser ceci

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
   UIImageWriteToSavedPhotosAlbum(img.image, nil, nil, nil);
});
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.