2016-06-30 10 views
6

Görüntü ile birlikte bir görüntü örnek arabelleğinden meta verilerin SOME'unu kaydetmeye çalışıyorum.Swift: Özel kamera, görüntü ile değiştirilmiş meta verileri kaydetme

  • meta verilerle o görüntünün kaydet meta veri
  • götürüldü meta veri
  • kaydet tarih dan yönünü çıkarın meta veri
  • gelen yöne görüntüyü döndürme:

    ben gerek Belgeler dizini için

Verilerden bir UIImage oluşturmayı denedim, ancak bu çıktı meta veriler. Verilerden bir CIImage kullanmayı denedim, bu da meta verileri koruyor, ancak döndüremiyorum, sonra bir dosyaya kaydediyorum.

private func snapPhoto(success: (UIImage, CFMutableDictionary) -> Void, errorMessage: String -> Void) { 
    guard !self.stillImageOutput.capturingStillImage, 
     let videoConnection = stillImageOutput.connectionWithMediaType(AVMediaTypeVideo) else { return } 

    videoConnection.fixVideoOrientation() 

    stillImageOutput.captureStillImageAsynchronouslyFromConnection(videoConnection) { 
     (imageDataSampleBuffer, error) -> Void in 
     guard imageDataSampleBuffer != nil && error == nil else { 
      errorMessage("Couldn't snap photo") 
      return 
     } 

     let data = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer) 

     let metadata = CMCopyDictionaryOfAttachments(nil, imageDataSampleBuffer, CMAttachmentMode(kCMAttachmentMode_ShouldPropagate)) 
     let metadataMutable = CFDictionaryCreateMutableCopy(nil, 0, metadata) 

     let utcDate = "\(NSDate())" 
     let cfUTCDate = CFStringCreateCopy(nil, utcDate) 
     CFDictionarySetValue(metadataMutable!, unsafeAddressOf(kCGImagePropertyGPSDateStamp), unsafeAddressOf(cfUTCDate)) 

     guard let image = UIImage(data: data)?.fixOrientation() else { return } 
     CFDictionarySetValue(metadataMutable, unsafeAddressOf(kCGImagePropertyOrientation), unsafeAddressOf(1)) 

     success(image, metadataMutable) 
    } 
} 

Resim kaydetme kodum İşte.

func saveImageAsJpg(image: UIImage, metadata: CFMutableDictionary) { 
    // Add metadata to image 
    guard let jpgData = UIImageJPEGRepresentation(image, 1) else { return } 
    jpgData.writeToFile("\(self.documentsDirectory)/image1.jpg", atomically: true) 
} 

cevap

7

Herşeyi nasıl çalıştıracağımı anlamaya çalıştım. Bana en çok yardımcı olan şey, bir CFDictionary'ın bir NSMutableDictionary olarak yayınlanabileceğini bulmaktı.

İşte benim nihai kodudur:

ben sayısallaştırılmış tarih için EXIF ​​sözlüğüne bir özellik eklemek ve oryantasyon değerini değiştirdi görebileceğiniz gibi.

private func snapPhoto(success: (UIImage, NSMutableDictionary) -> Void, errorMessage: String -> Void) { 
    guard !self.stillImageOutput.capturingStillImage, 
     let videoConnection = stillImageOutput.connectionWithMediaType(AVMediaTypeVideo) else { return } 

    videoConnection.fixVideoOrientation() 

    stillImageOutput.captureStillImageAsynchronouslyFromConnection(videoConnection) { 
     (imageDataSampleBuffer, error) -> Void in 
     guard imageDataSampleBuffer != nil && error == nil else { 
      errorMessage("Couldn't snap photo") 
      return 
     } 

     let data = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer) 

     let rawMetadata = CMCopyDictionaryOfAttachments(nil, imageDataSampleBuffer, CMAttachmentMode(kCMAttachmentMode_ShouldPropagate)) 
     let metadata = CFDictionaryCreateMutableCopy(nil, 0, rawMetadata) as NSMutableDictionary 

     let exifData = metadata.valueForKey(kCGImagePropertyExifDictionary as String) as? NSMutableDictionary 
     exifData?.setValue(NSDate().toString("yyyy:MM:dd HH:mm:ss"), forKey: kCGImagePropertyExifDateTimeDigitized as String) 

     metadata.setValue(exifData, forKey: kCGImagePropertyExifDictionary as String) 
     metadata.setValue(1, forKey: kCGImagePropertyOrientation as String) 

     guard let image = UIImage(data: data)?.fixOrientation() else { 
      errorMessage("Couldn't create image") 
      return 
     } 

     success(image, metadata) 
    } 
} 

Ve meta verilerle görüntüyü kaydetmek için benim son kod: I hate bekçi cümlelerin

sürü, ama unwrapping kuvvet daha iyidir.

İşte
func saveImage(withMetadata image: UIImage, metadata: NSMutableDictionary) { 
    let filePath = "\(self.documentsPath)/image1.jpg" 

    guard let jpgData = UIImageJPEGRepresentation(image, 1) else { return } 

    // Add metadata to jpgData 
    guard let source = CGImageSourceCreateWithData(jpgData, nil), 
     let uniformTypeIdentifier = CGImageSourceGetType(source) else { return } 
    let finalData = NSMutableData(data: jpgData) 
    guard let destination = CGImageDestinationCreateWithData(finalData, uniformTypeIdentifier, 1, nil) else { return } 
    CGImageDestinationAddImageFromSource(destination, source, 0, metadata) 
    guard CGImageDestinationFinalize(destination) else { return } 

    // Save image that now has metadata 
    self.fileService.save(filePath, data: finalData) 
} 

benim güncellenen save yöntemi (Bu soruyu yazarken ben Swift 2.3 güncellendi beri ben kullanıyordum ama konsept aynı olduğunu tam aynı değil):

public func save(fileAt path: NSURL, with data: NSData) throws -> Bool { 
    guard let pathString = path.absoluteString else { return false } 
    let directory = (pathString as NSString).stringByDeletingLastPathComponent 

    if !self.fileManager.fileExistsAtPath(directory) { 
     try self.makeDirectory(at: NSURL(string: directory)!) 
    } 

    if self.fileManager.fileExistsAtPath(pathString) { 
     try self.delete(fileAt: path) 
    } 

    return self.fileManager.createFileAtPath(pathString, contents: data, attributes: [NSFileProtectionKey: NSFileProtectionComplete]) 
} 
+0

ben .first 'NSSearchPathForDirectoriesInDomains (.DocumentDirectory, .UserDomainMask, doğru) olan' filePath' alabilirsiniz varsayarak yaşıyorum! + "name.png". Ancak, 'fileService' nedir? FileService özel bir sınıf mı? –

+1

@ Carlos.V 'fileService'' NSFileManager'ı sarmak ve hayatımı kolaylaştırmak için yaptığım özel bir sınıftır. – SeanRobinson159

+0

Asıl meta verileri okuyabiliyorum ve değiştirebiliyorum, ancak yeni meta dosyasını dosyaya yazamıyorum. ".save()" işlevinin nasıl çalıştığını biraz açıklayabilir misiniz ?, 'fileMan.createFileAtPath (filePath, content: finalData, attributes: metadata as! [String: AnyObject]) 'yi kullanmayı denedim ama kaydetmedim meta veri, diğer özellikler içindir. Belki 'PHPhotoLibrary' kullanıyor musunuz? Bence böyle deniyorum ama% 100 çalışacağından emin değilim. –

0

Yukarıdaki kodun büyük ölçüde basitleştirilmiş bir sürümünü yaptım. Bir görüntü dosyası yapar, ancak Carlos'un belirttiği gibi, tekrar yüklediğinizde dosyada hiçbir özel meta veri yoktur. Diğer konulara göre, bu mümkün olmayabilir.

func saveImage(_ image: UIImage, withMetadata metadata: NSMutableDictionary, atPath path: URL) -> Bool { 
    guard let jpgData = UIImageJPEGRepresentation(image, 1) else { 
     return false 
    } 
    // make an image source 
    guard let source = CGImageSourceCreateWithData(jpgData as CFData, nil), let uniformTypeIdentifier = CGImageSourceGetType(source) else { 
     return false 
    } 
    // make an image destination pointing to the file we want to write 
    guard let destination = CGImageDestinationCreateWithURL(path as CFURL, uniformTypeIdentifier, 1, nil) else { 
     return false 
    } 

    // add the source image to the destination, along with the metadata 
    CGImageDestinationAddImageFromSource(destination, source, 0, metadata) 

    // and write it out 
    return CGImageDestinationFinalize(destination) 
} 
+0

Benim için çalışıyor. Üretilen dosyayı bir sunucuya yüklüyorum ve yeni meta verilere sahip. Yani kesinlikle mümkün. – SeanRobinson159

+0

Merhaba, Bu işleve meta verileri nasıl eklerim? Ayrıca, fotoğrafları fotoğraf arşivine kaydetmek istersem, bunu nasıl yapacağım? –

+0

Sözlüğü olun ve iletin. Sadece sözlüğündeki tuşların, Apple'ın desteklediği tuşlar olduğundan emin olun, aksi halde kaydedildikleri gibi görüneceklerdir, ancak kaydettiğinizde gerçek dosyada bulunmayacaklardır. –