Что мне нужно сделать, чтобы сохранить изображение, созданное моей программой (возможно, с камеры, а возможно, нет) в системную библиотеку фотографий на iPhone?





Вы можете использовать эту функцию:
UIImageWriteToSavedPhotosAlbum(UIImage *image,
id completionTarget,
SEL completionSelector,
void *contextInfo);
Вам нужны только CompleteTarget, ЗавершениеСелектор и contextInfo, если вы хотите получать уведомление, когда UIImage завершит сохранение, в противном случае вы можете передать nil.
См. официальная документация для UIImageWriteToSavedPhotosAlbum().
Возьмите +1 за точный ответ
Привет, спасибо за отличное решение. Здесь у меня есть одно сомнение, как можно избежать дублирования при сохранении изображения в библиотеке фотографий. Заранее спасибо.
Если хотите сохранить в лучшем качестве, смотрите это: stackoverflow.com/questions/1379274/…
Не забудьте добавить ключ "Конфиденциальность - описание использования библиотеки фотографий" в файл info.plist.
Теперь вам нужно будет добавить «Конфиденциальность - описание использования дополнений фото-библиотеки» в iOS 11, чтобы сохранять фотографии в альбоме пользователей.
как дать имя сохраненным изображениям?
Просто передайте ему изображения из массива вот так
-(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);
}
}
Извините за опечатку, просто сделал это на лету, но вы поняли
Используя это, пропустите некоторые фотографии, я пробовал. Правильный способ сделать это - использовать обратный вызов из селектора завершения.
можем ли мы сохранять изображения с произвольным именем?
Для этого никогда не следует использовать цикл for. Это приводит к состоянию гонки и сбоям.
мой последний ответ сделает это ..
для каждого изображения, которое вы хотите сохранить, добавьте его в 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);
}
}
Я пробовал ваше решение, он всегда пропускал некоторые фотографии. Посмотри на мой ответ. связь
Не рекомендуется в iOS 9.0.
Есть гораздо более быстрый способ сделать это, чем UIImageWriteToSavedPhotosAlbum, с использованием фреймворка AssetsLibrary iOS 4.0+.
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];
Есть ли способ сохранить произвольные метаданные вместе с фотографией?
Я пробовал сохранять с помощью ALAssetsLibrary, на сохранение требуется столько же времени, что и с UIImageWriteToSavedPhotosAlbum.
И это замораживает камеру :( Я думаю, это не поддерживается в фоновом режиме?
Этот настолько чище b / c, что вы можете использовать блок для обработки завершения.
Я использую этот код и включаю этот фреймворк #import <AssetsLibrary / AssetsLibrary.h>, а не AVFoundation. Разве ответ нельзя отредактировать? @Денис
Красиво, но не рекомендуется в iOS 9 SDK.
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];
}
Этот ответ неверен, потому что он сохраняет изображение не в системной библиотеке фотографий, а в песочнице.
Следует помнить одну вещь: если вы используете обратный вызов, убедитесь, что ваш селектор соответствует следующей форме:
- (void) image: (UIImage *) image didFinishSavingWithError: (NSError *) error contextInfo: (void *) contextInfo;
В противном случае произойдет сбой с такой ошибкой:
[NSInvocation setArgument:atIndex:]: index (2) out of bounds [-1, 1]
При сохранении массива фотографий не используйте цикл for, выполните следующие действия.
-(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);
}
}
Самый простой способ:
UIImageWriteToSavedPhotosAlbum(myUIImage, nil, nil, nil);
Для Swift вы можете обратиться к Сохранение в фото-библиотеку iOS с помощью swift
Мне очень нравится ваш значок профиля пользователя SO. Довольно крутое изображение Xcode.
Фантастически просто и очень-очень просто!
Вы можете использовать это
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UIImageWriteToSavedPhotosAlbum(img.image, nil, nil, nil);
});
В Быстрый:
// 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.
}
}
да ... красиво ... но после сохранения изображения я хочу загрузить изображение из галереи ... как это сделать
Я создал для этого категорию UIImageView, основываясь на некоторых из приведенных выше ответов.
Заголовочный файл:
@interface UIImageView (SaveImage) <UIActionSheetDelegate>
- (void)addHoldToSave;
@end
Выполнение
@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
Теперь просто вызовите эту функцию в своем просмотре изображения:
[self.imageView addHoldToSave];
При желании вы можете изменить параметр minimumPressDuration.
Ниже будет работать функция. Вы можете скопировать отсюда и вставить туда ...
-(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");
}
}];
}
В Swift 2.2
UIImageWriteToSavedPhotosAlbum(image: UIImage, _ completionTarget: AnyObject?, _ completionSelector: Selector, _ contextInfo: UnsafeMutablePointer<Void>)
Если вы не хотите получать уведомления о завершении сохранения изображения, вы можете указать nil в параметрах CompleteTarget, ЗавершениеСелектор и contextInfo.
Пример:
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.
}
}
Здесь важно отметить, что ваш метод, наблюдающий за сохранением изображения, должен иметь эти 3 параметра, иначе вы столкнетесь с ошибками NSInvocation.
Надеюсь, это поможет.
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!")
}
}
Для Swift 5.0
Я использовал этот код для копирования изображений в фотоальбомы, созданные моим приложением; Когда я хочу скопировать файлы изображений, я вызываю функцию startSavingPhotoAlbume (). Сначала я получаю UIImage из папки приложения, а затем сохраняю его в фотоальбомах. Поскольку это не имеет значения, я не показываю, как читать изображение из папки приложения.
var saveToPhotoAlbumCounter = 0
func startSavingPhotoAlbume(){
saveToPhotoAlbumCounter = 0
saveToPhotoAlbume()
}
func saveToPhotoAlbume(){
let image = loadImageFile(fileName: imagefileList[saveToPhotoAlbumCounter], folderName: folderName)
UIImageWriteToSavedPhotosAlbum(image!, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)
}
@objc func image(_ image: UIImage, didFinishSavingWithError error: NSError?, contextInfo: UnsafeRawPointer) {
if (error != nil) {
print("ptoto albume savin error for \(imageFileList[saveToPhotoAlbumCounter])")
} else {
if saveToPhotoAlbumCounter < imageFileList.count - 1 {
saveToPhotoAlbumCounter += 1
saveToPhotoAlbume()
} else {
print("saveToPhotoAlbume is finished with \(saveToPhotoAlbumCounter) files")
}
}
}
Вы можете проверить этот код. Отличный день!