3

この質問では、外部ライブラリなしで Xcode と iOS を使用した場合の可能性のみを尋ねます。私はすでにlibtiff別の質問で使用する可能性を探っています。

問題

私は何週間もスタックオーバーフローをふるいにかけており、すべての問題に対して独自の解決策を見つけました。私は働く必要がある4つのことがあります:

  1. カメラからのRGBAデータが必要です。圧縮は一切ありません
  2. できるだけ多くのメタデータ、特に EXIF が必要です
  3. 他のソフトウェアとの互換性と可逆性のために TIFF 形式で保存する必要があります
  4. フォト ライブラリではなくファイルに保存して、何気ない閲覧から保護したい

JPEGを使うと2と4ができます。カメラ バッファから作成された生データ (それぞれ NSData) を持つ 1、3、4 を持つことができます。Xcode と iOS で 4 つの前提条件をすべて満たすことはできますか? 私はあきらめようとしており、最後の手段としてあなたの意見を求めています.

これをまだ調査している間、私が試した別の方法であるlibtiffにも行き詰まっています。まだ頑張ってるけど…

これは私が試した素晴らしいアドバイスのリストです。私自身のコードは、次のようなスタック オーバーフロー ソースからまとめられています。

解決

からのアクションの完全なシーケンスcaptureStillImageAsynchronouslyFromConnection:

[[self myAVCaptureStillImageOutput] captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error)
 {
     //get all the metadata in the image
     CFDictionaryRef metadata = CMCopyDictionaryOfAttachments(kCFAllocatorDefault, imageSampleBuffer, kCMAttachmentMode_ShouldPropagate);
     // get image reference
     CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(imageSampleBuffer);
     // >>>>>>>>>> lock buffer address
     CVPixelBufferLockBaseAddress(imageBuffer, 0);

     //Get information about the image
     uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(imageBuffer);
     size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
     size_t width = CVPixelBufferGetWidth(imageBuffer);
     size_t height = CVPixelBufferGetHeight(imageBuffer);

     // create suitable color space
     CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

     //Create suitable context (suitable for camera output setting kCVPixelFormatType_32BGRA)
     CGContextRef newContext = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);

     // <<<<<<<<<< unlock buffer address
     CVPixelBufferUnlockBaseAddress(imageBuffer, 0);

     // release color space
     CGColorSpaceRelease(colorSpace);

     //Create a CGImageRef from the CVImageBufferRef
     CGImageRef newImage = CGBitmapContextCreateImage(newContext);

     // release context
     CGContextRelease(newContext);

     // create destination and write image with metadata
     CFURLRef url = (__bridge CFURLRef)[NSURL fileURLWithPath:filePath isDirectory:NO];
     CGImageDestinationRef destination = CGImageDestinationCreateWithURL(url, kUTTypeTIFF, 1, NULL);
     CGImageDestinationAddImage(destination, imageRef, metadata);

     // finalize and release destination
     CGImageDestinationFinalize(destination);
     CFRelease(destination);
 }

静止画出力関連のカメラ設定は次のとおりです。

[[self myAVCaptureSession] setSessionPreset:AVCaptureSessionPresetPhoto];

NSDictionary *outputSettings = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA], (id)kCVPixelBufferPixelFormatTypeKey, nil];
[myAVCaptureStillImageOutput setOutputSettings:outputSettings];

すべてのメタデータを含む名目上の TIFF 形式で、名目上の圧縮されていない素敵な画像を取得します。(他のシステムにミラーリングされていますが、EXIF やその他のメタデータを書き込むことができるようになりました。微調整することもできます)。

Wildakerの助けに感謝します。

4

2 に答える 2

2

このスレッドは、非常によく似た問題を解決するのに非常に役立ちました。そのため、誰かが探しに来た場合に備えて、ソリューションの Swift 2.0 実装に貢献すると思いました。

stillImageOutput?.captureStillImageAsynchronouslyFromConnection(videoConnection, completionHandler: { (imageDataSampleBuffer, error) -> Void in


    // get image meta data (EXIF, etc)
    let metaData: CFDictionaryRef? = CMCopyDictionaryOfAttachments( kCFAllocatorDefault, imageDataSampleBuffer, kCMAttachmentMode_ShouldPropagate )


    // get reference to image
    guard let imageBuffer = CMSampleBufferGetImageBuffer( imageDataSampleBuffer ) else { return }


    // lock the buffer
    CVPixelBufferLockBaseAddress( imageBuffer, 0 )


    // read image properties
    let baseAddress = CVPixelBufferGetBaseAddress( imageBuffer )

    let bytesPerRow = CVPixelBufferGetBytesPerRow( imageBuffer )

    let width = CVPixelBufferGetWidth( imageBuffer )

    let height = CVPixelBufferGetHeight( imageBuffer )


    // color space
    let colorSpace = CGColorSpaceCreateDeviceRGB()


    // context - camera output settings kCVPixelFormatType_32BGRA
    let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedFirst.rawValue).union(.ByteOrder32Little)

    let newContext = CGBitmapContextCreate( baseAddress, width, height, 8, bytesPerRow, colorSpace, bitmapInfo.rawValue )


    //unlock buffer
    CVPixelBufferUnlockBaseAddress( imageBuffer, 0 )

    //Create a CGImageRef from the CVImageBufferRef
    guard let newImage = CGBitmapContextCreateImage( newContext ) else {
        return
    }


    // create tmp file and write image with metadata
    let fileName = String(format: "%@_%@", NSProcessInfo.processInfo().globallyUniqueString, "cap.tiff")
    let fileURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).URLByAppendingPathComponent(fileName)

    if let destination = CGImageDestinationCreateWithURL( fileURL, kUTTypeTIFF, 1, nil) {

        CGImageDestinationAddImage( destination, newImage, metaData )

        let wrote = CGImageDestinationFinalize( destination )

        if !wrote || NSFileManager.defaultManager().fileExistsAtPath(fileURL.URLString) {

            return

        }

    }

}

psこれが機能するには、次のように画像バッファを構成する必要があります。

    stillImageOutput = AVCaptureStillImageOutput()

    stillImageOutput?.outputSettings = [ kCVPixelBufferPixelFormatTypeKey: Int(kCVPixelFormatType_32BGRA) ]
于 2016-06-03T09:06:36.227 に答える
2

すでに 1、3、4 をクラックしているので、欠けている唯一のハードルはデータとメタデータを一緒に保存することのようです。CMSampleBufferRefこれを試してください(未処理のデータが呼び出されたものであり、グラフィックデータを呼び出さmyImageDataSampleBufferれたものに入れるという面倒な作業を行ったと仮定します):CGImageRefmyImage

CFDictionaryRef metadata = CMCopyDictionaryOfAttachments(kCFAllocatorDefault,
  myImageDataSampleBuffer,
  kCMAttachmentMode_ShouldPropagate);
NSFileManager* fm = [[NSFileManager alloc] init];
NSURL* pathUrl = [fm URLForDirectory:saveDir
  inDomain:NSUserDomainMask
  appropriateForURL:nil
  create:YES
  error:nil];
NSURL* saveUrl = [pathUrl URLByAppendingPathComponent:@"myfilename.tif"];
CGImageDestinationRef destination = CGImageDestinationCreateWithURL((__bridge CFURLRef)saveUrl,
  (CFStringRef)@"public.tiff", 1, NULL);
CGImageDestinationAddImage(destination, myImage, metadata);
CGImageDestinationFinalize(destination);
CFRelease(destination);
于 2013-07-01T06:43:00.107 に答える