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?

jblocksom
la source
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() .

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

La manière la plus simple est:

UIImageWriteToSavedPhotosAlbum(myUIImage, nil, nil, nil);

Pour Swift, vous pouvez vous référer à Enregistrer dans la photothèque iOS à l'aide de swift

Mutawe
la source
3
J'aime vraiment l'icône de votre profil utilisateur SO. Image Xcode assez cool.
Supertecnoboff
1
Incroyablement simple et très très facile!
Septronic
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]

Jeff C.
la source
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

mrburns05
la source
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);
   }
}
SamChen
la source
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.
            }
    }
Roi-sorcier
la source
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");
        }
    }];
}
iDevAmit
la source
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
la source
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);
        }
}
mrburns05
la source
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];
}
Bonjour
la source
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.

HugglesNL
la source
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.

Jarora
la source
0

Vous pouvez utiliser ceci

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