2016-06-30 1 views
6

이미지 샘플 버퍼의 메타 데이터 중 일부를 이미지와 함께 저장하려고합니다.스위프트 : 사용자 정의 카메라가 수정 된 메타 데이터를 이미지로 저장합니다.

  • 메타 데이터와 함께 해당 이미지 저장을 메타 데이터
  • 로 이동 메타 데이터
  • 저장 일로부터 방향을 제거 메타 데이터
  • 에서 한 방향으로 이미지를 회전 :

    내가 필요 문서 디렉토리에

데이터에서 UIImage를 만들려고 시도했지만 그 중 하나가 제거됩니다. 메타 데이터 메타 데이터를 유지하는 데이터에서 CIImage를 사용하여 시도했지만 파일을 회전 할 수 없습니다.

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

다음은 이미지 저장 코드입니다.

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

답변

7

내가 필요한 방식으로 모든 것을 작동시키는 방법을 알아 냈습니다. 가장 도움이되는 것은 CFDictionary를 NSMutableDictionary로 캐스팅 할 수 있다는 것입니다.

여기 내 마지막 코드 :

당신은 내가 디지털화 된 날짜에 대한 EXIF ​​사전에 속성을 추가하고, 방향 값을 변경할 볼 수 있듯이.

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

그리고 메타 데이터와 이미지를 저장하기위한 내 마지막 코드 : 싫어 가드 문의

제비,하지만 풀기 힘보다 낫다.

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

내 업데이트 save 방법 (나는이 질문을 쓸 때 내가 스위프트 2.3로 업데이트 한 이후이 사용되었지만, 개념은 동일 함을 동일한되지 않음) :

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

나는 좁은 방'NSSearchPathForDirectoriesInDomains (.DocumentDirectory, .UserDomainMask, 진정한)에서'filePath'를 얻을 수 있으리라 믿고있어! + "name.png"'. 그러나'fileService'는 무엇입니까? 'fileService'는 커스텀 클래스입니까? –

+1

@ Carlos.V'fileService'는'NSFileManager'를 래핑하고 내 인생을 더 쉽게 만들어주는 커스텀 클래스입니다. – SeanRobinson159

+0

실제 메타 데이터를 읽고 수정할 수는 있지만 새 메타를 파일에 쓸 수는 없습니다. '.save()'함수가 어떻게 작동하는지 조금 설명해 주시겠습니까?'fileMan.createFileAtPath (filePath, contents : finalData, attributes : metadata!! [String : AnyObject]) '를 사용하여 시도했지만 메타 데이터는 다른 속성을위한 것입니다. 어쩌면'PHPhotoLibrary'를 사용하고 있습니까? 나는 그런 식으로 시도한다고 생각하지만 100 % 효과가 있을지 확신하지 못합니다. –

0

위의 코드를 크게 단순화 한 버전을 만들었습니다. 이미지 파일을 만들지 만 Carlos가 지적했듯이 파일을 다시로드 할 때 파일에 사용자 지정 메타 데이터가 없습니다. 다른 스레드에 따르면, 이것은 단순히 가능하지 않을 수 있습니다.

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

그것은 나를 위해 작동합니다. 제작 된 파일을 가져 와서 서버에 업로드하고 새 메타 데이터가 있습니다. 그래서 확실히 가능합니다. – SeanRobinson159

+0

안녕하세요,이 기능에 메타 데이터를 어떻게 추가합니까? 또한, 사진 라이브러리에 사진을 저장하려면 어떻게해야합니까? –

+0

사전을 만들어서 전달하십시오. 사전에있는 키가 Apple이 지원하는 키인지 확인하십시오. 그렇지 않으면 저장중인 것처럼 보이지만 저장할 때 실제 파일에 저장되지는 ​​않습니다. –