Zapisz obraz w folderze dokumentów aplikacji z UIView w systemie IOS

114

Mam UIImageView, który umożliwia użytkownikowi umieszczanie i zatrzymywanie obrazu, dopóki nie będzie można go zapisać. Problem polega na tym, że nie mogę dowiedzieć się, jak właściwie zapisać i odzyskać obraz, który umieściłem w widoku.

Pobrałem i umieściłem obraz w UIImageView w następujący sposób:

//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];
}

Wyświetla wybrany obraz w moim UIImageView dobrze, ale nie mam pojęcia, jak go zapisać. Zapisuję wszystkie pozostałe fragmenty widoku (głównie UITextfield) w danych podstawowych. Szukałem i szukałem, i wypróbowałem wiele fragmentów kodu, które ludzie sugerowali, ale albo nie wpisuję kodu poprawnie, albo te sugestie nie działają ze sposobem, w jaki mam skonfigurowany kod. To prawdopodobnie pierwsza. Chciałbym zapisać obraz w UIImageView przy użyciu tej samej akcji (przycisku zapisywania), której używam do zapisywania tekstu w UITextFields. Oto jak zapisuję informacje o moim polu UITextField:

// Handle Save Button
- (void)save {

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

Jak powiedziałem wcześniej, próbowałem kilku metod, aby to zadziałało, ale nie mogę tego pojąć. Po raz pierwszy w życiu chciałem wyrządzić fizyczną krzywdę obiektowi nieożywionemu, ale zdołałem się powstrzymać.

Chciałbym móc zapisać obraz, który użytkownik umieszcza w UIImageView w folderze dokumentów aplikacji, a następnie móc go pobrać i umieścić w innym UIImageView w celu wyświetlenia, gdy użytkownik wypchnie ten widok na stos. Każda pomoc jest mile widziana!

zapomniałem
źródło

Odpowiedzi:

341

Wszystko w porządku, stary. Nie krzywdź siebie ani innych.

Prawdopodobnie nie chcesz przechowywać tych obrazów w danych podstawowych, ponieważ może to wpłynąć na wydajność, jeśli zestaw danych stanie się zbyt duży. Lepiej zapisywać obrazy do plików.

NSData *pngData = UIImagePNGRepresentation(image);

To wyciąga dane PNG przechwyconego obrazu. Stąd możesz zapisać go do pliku:

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

Czytanie go później działa w ten sam sposób. Zbuduj ścieżkę tak jak powyżej, a następnie:

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

Prawdopodobnie będziesz chciał zrobić metodę, która tworzy dla ciebie ciągi ścieżek, ponieważ nie chcesz, aby ten kod był zaśmiecony wszędzie. Może to wyglądać tak:

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

    return [documentsPath stringByAppendingPathComponent:name]; 
}

Mam nadzieję, że to pomocne.

Danilo Campos
źródło
2
całkowicie poprawne - wystarczy wspomnieć o Wytycznych dotyczących przechowywania danych firmy Apple, więc W ZALEŻNOŚCI od natury obrazów należy je przechowywać w pamięci podręcznej
Daij-Djan
Postępowałem zgodnie z twoją sugestią i kodem. ale nie pojawia się w sekcjach ze zdjęciami. Jak to się stało?
NovusMobile
@DaniloCampos Jak utworzyć folder w katalogu dokumentów, a następnie zapisać plik w tym folderze?
Pradeep Reddy Kypa
3

Wersja 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)
}
Fangming
źródło
2

To jest odpowiedź Fangming Ninga na Swift 4.2 , zaktualizowana o zalecaną i bardziej Swifty metodę pobierania ścieżki katalogu dokumentu oraz lepszą dokumentację. Podziękowania dla Fangming Ning również za nową metodę.

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

Sprawdź tutaj wszystkie możliwe opcje zapisu danych.

Tamás Sengel
źródło
Czy to jest poprawne? Powyżej w odpowiedzi na inne pytanie tutaj znalazłem, że fileURLWithPathrazem ze absoluteStringjest źle.
dumbledad
@dumbledad Dziękuję za informację, zaktualizowałem moją odpowiedź i przepisałem również kod dla 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;
}
Mannam Brahmam
źródło
1

Swift 4 z rozszerzeniem

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

Przykład użycia

 image.saveImage(inDir: .documentDirectory, name: "pic")
levin varghese
źródło
0

W 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
    }
}
NatashaTheRobot
źródło