在iOS上从UIView保存图像到应用程序文档文件夹

117

我有一个UIImageView,允许用户放置和保存图像。问题是,我不知道如何实际保存和检索我放置在视图中的图像。

我已经按照以下方式检索并放置了图像:

//Get Image 
- (void) getPicture:(id)sender {
    UIImagePickerController *picker = [[UIImagePickerController alloc] init];
    picker.delegate = self;
    picker.allowsEditing = YES;
    picker.sourceType = (sender == myPic) ? UIImagePickerControllerSourceTypeCamera : UIImagePickerControllerSourceTypeSavedPhotosAlbum;
    [self presentModalViewController:picker animated:YES];
    [picker release];
}


- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage (UIImage *)image editingInfo:(NSDictionary *)editingInfo {
    myPic.image = image;
    [picker dismissModalViewControllerAnimated:YES];
}

它可以在我的UIImageView中显示选定的图像,但我不知道如何保存它。我正在使用Core Data保存视图中的所有其他部分(主要是UITextfield)。我搜索并尝试了许多人建议的代码片段,但无论是我没有正确输入代码,还是那些建议不适用于我设置的方式,都不起作用。很可能是前者。我想使用相同的操作(保存按钮)来保存UITextFields中的文本,将图像保存在UIImageView中。以下是我保存UITextField信息的方法:

// Handle Save Button
- (void)save {

    // Get Info From UI
    [self.referringObject setValue:self.myInfo.text forKey:@"myInfo"];

就像我之前说的那样,我尝试了几种方法来让它工作,但是无法掌握。这是我生命中第一次想要对一个无生命的物体造成实质性伤害,但我设法克制自己。

我想能够将用户放置在UIImageView中的图像保存到应用程序文档文件夹中,然后在用户将该视图推入堆栈时检索并将其放置在另一个UIImageView中以进行显示。非常感谢任何帮助!

6个回答

344

别担心,放心吧。不要伤害你自己或别人。

如果数据集变得太大,将这些图像存储在Core Data中可能会影响性能。最好将图像写入文件。

NSData *pngData = UIImagePNGRepresentation(image);

这将提取出您所捕获的图像的PNG数据。从这里开始,您可以将其写入文件:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);  
NSString *documentsPath = [paths objectAtIndex:0]; //Get the docs directory 
NSString *filePath = [documentsPath stringByAppendingPathComponent:@"image.png"]; //Add the file name
[pngData writeToFile:filePath atomically:YES]; //Write the file

以后阅读也是同样的方式。像我们刚才做的那样建立路径,然后:

NSData *pngData = [NSData dataWithContentsOfFile:filePath];
UIImage *image = [UIImage imageWithData:pngData];

你可能想要做的是创建一个方法为你生成路径字符串,因为你不希望代码随处可见。这个方法可能看起来像这样:

- (NSString *)documentsPathForFileName:(NSString *)name
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);  
    NSString *documentsPath = [paths objectAtIndex:0];

    return [documentsPath stringByAppendingPathComponent:name]; 
}

希望这有所帮助。


2
完全正确 - 只是想提一下苹果存储指南,因此根据图像的性质,应将其存储在缓存下。 - Daij-Djan
我按照您的建议和代码进行了操作,但它并没有出现在照片部分。这是怎么发生的? - NovusMobile
@DaniloCampos 如何在“文档”目录中创建一个文件夹,然后将文件保存在该文件夹中? - Pradeep Reddy Kypa

4

Swift 3.0版本

let documentDirectoryPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
        
let img = UIImage(named: "1.jpg")!// Or use whatever way to get the UIImage object
let imgPath = URL(fileURLWithPath: documentDirectoryPath.appendingPathComponent("1.jpg"))// Change extension if you want to save as PNG

do{
    try UIImageJPEGRepresentation(img, 1.0)?.write(to: imgPath, options: .atomic)//Use UIImagePNGRepresentation if you want to save as PNG
}catch let error{
    print(error.localizedDescription)
}

3

使用扩展的Swift 4

extension UIImage{

func saveImage(inDir:FileManager.SearchPathDirectory,name:String){
    guard let documentDirectoryPath = FileManager.default.urls(for: inDir, in: .userDomainMask).first else {
        return
    }
    let img = UIImage(named: "\(name).jpg")!

    // Change extension if you want to save as PNG.
    let imgPath = URL(fileURLWithPath: documentDirectoryPath.appendingPathComponent("\(name).jpg").absoluteString)
    do {
        try UIImageJPEGRepresentation(img, 0.5)?.write(to: imgPath, options: .atomic)
    } catch {
        print(error.localizedDescription)
    }
  }
}

使用示例

 image.saveImage(inDir: .documentDirectory, name: "pic")

2
这是针对 Swift 4.2 的 宁芳铭的答案,更新了一种建议使用更 Swifty 的方法来检索文档目录路径,并提供了更好的文档说明。同时也感谢宁芳铭提供了新方法。
guard let documentDirectoryPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
    return
}

//Using force unwrapping here because we're sure "1.jpg" exists. Remember, this is just an example.
let img = UIImage(named: "1.jpg")!

// Change extension if you want to save as PNG.
let imgPath = documentDirectoryPath.appendingPathComponent("1.jpg")

do {
    //Use .pngData() if you want to save as PNG.
    //.atomic is just an example here, check out other writing options as well. (see the link under this example)
    //(atomic writes data to a temporary file first and sending that file to its final destination)
    try img.jpegData(compressionQuality: 1)?.write(to: imgPath, options: .atomic)
} catch {
    print(error.localizedDescription)
}

请查看此处所有可能的数据写入选项。

这正确吗?在另一个问题的答案这里中,我发现fileURLWithPathabsoluteString一起使用是错误的。 - dumbledad
@dumbledad 感谢您提供的信息,我已经更新了我的答案,并且也重写了Swift 4.2的代码。 - Tamás Sengel

2
#pragma mark - Save Image To Local Directory

- (void)saveImageToDocumentDirectoryWithImage:(UIImage *)capturedImage {
    NSError *error;
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
    NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:@"/images"];
    
    //Create a folder inside Document Directory
    if (![[NSFileManager defaultManager] fileExistsAtPath:dataPath])
        [[NSFileManager defaultManager] createDirectoryAtPath:dataPath withIntermediateDirectories:NO attributes:nil error:&error]; //Create folder

    NSString *imageName = [NSString stringWithFormat:@"%@/img_%@.png", dataPath, [self getRandomNumber]] ;
    // save the file
    if ([[NSFileManager defaultManager] fileExistsAtPath:imageName]) {
        // delete if exist
        [[NSFileManager defaultManager] removeItemAtPath:imageName error:nil];
    }
    
    NSData *imageDate = [NSData dataWithData:UIImagePNGRepresentation(capturedImage)];
    [imageDate writeToFile: imageName atomically: YES];
}


#pragma mark - Generate Random Number

- (NSString *)getRandomNumber {
    NSTimeInterval time = ([[NSDate date] timeIntervalSince1970]); // returned as a double
    long digits = (long)time; // this is the first 10 digits
    int decimalDigits = (int)(fmod(time, 1) * 1000); // this will get the 3 missing digits
    //long timestamp = (digits * 1000) + decimalDigits;
    NSString *timestampString = [NSString stringWithFormat:@"%ld%d",digits ,decimalDigits];
    return timestampString;
}

0

在 Swift 中:

let paths: [NSString?] = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .LocalDomainMask, true)
if let path = paths[0]?.stringByAppendingPathComponent(imageName) {
    do {
        try UIImagePNGRepresentation(image)?.writeToFile(path, options: .DataWritingAtomic)
    } catch {
        return
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接