12

実際の画像データを再エンコードせずに、いくつかのメタデータを変更した画像を一時フォルダーに保存したいと考えています。

これを実行できる唯一の方法はALAssetsLibrary/writeImageDataToSavedPhotosAlbum:metadata:completionBlock:ですが、これは画像をフォト ライブラリに保存します。代わりに、画像を一時フォルダーに保存したいと考えています (たとえば、写真ライブラリにデータを入力せずに電子メールで共有するため)。

CGImageDestinationRefCGImageDestinationAddImageFromSource )を使用してみましたが、デコードされた画像を使用してのみ作成できます。つまり、保存時に再エンコードされます(テスト済み、ピクセルバイトは異なって見えます)。

を使用する以外に、メタデータとともに画像データを保存できる iOS で利用可能な他のメソッド/クラスはありますCGImageDestinationRefか? 回避策の提案も歓迎します。

4

3 に答える 3

12

これは iOS SDK の厄介な問題です。まず、機能強化リクエストを提出することをお勧めします。

ALAsset がユーザーによって作成された場合 (つまり、そのeditableプロパティが であるYES場合)、基本的にデータを読み取り、メタデータと共に書き込み、再度読み取り、ディスクに保存し、元のメタデータと共に書き込むことができます。

このアプローチにより、重複するイメージの作成が回避されます。

// コメントを読んでください (メタデータ ディクショナリの作成など)。

ALAsset* asset; //get your asset, don't use this empty one
if (asset.editable) {

    // get the source data
    ALAssetRepresentation *rep = [asset defaultRepresentation];
    Byte *buffer = (Byte*)malloc(rep.size);
    // add error checking here
    NSUInteger buffered = [rep getBytes:buffer fromOffset:0.0 length:rep.size error:nil];
    NSData *sourceData = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES];

    // make your metadata whatever you want
    // you should use actual metadata, not a blank dictionary
    NSDictionary *metadataDictionary = [NSDictionary dictionary];

    // these are __weak to avoid creating an ARC retain cycle
    NSData __weak *originalData = sourceData;
    NSDictionary __weak *originalMetadata = [rep metadata];

    [asset setImageData:sourceData
               metadata:metadataDictionary
        completionBlock:^(NSURL *assetURL, NSError *error) {
            //now get your data and write it to file
            if (!error) {
                //get your data...
                NSString *assetPath = [assetURL path];
                NSData *targetData = [[NSFileManager defaultManager] contentsAtPath:assetPath];

                //...write to file...
                NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
                NSString *documentPath = [searchPaths lastObject];
                NSURL *fileURL = [NSURL fileURLWithPath:documentPath];
                [targetData writeToURL:fileURL atomically:YES];

                //...and put it back the way it was
                [asset setImageData:originalData metadata:originalMetadata completionBlock:nil];
            } else {
                // handle error on setting data
                NSLog(@"ERROR: %@", [error localizedDescription]);
            }
        }];
} else {
    // you'll need to make a new ALAsset which you have permission to edit and then try again

}

ご覧のとおり、ALAsset を所有していない場合は、ALAsset を作成する必要があります。これにより、ユーザーのライブラリに写真が追加されますが、これはまさに回避したかったことです。ただし、ご想像のとおり、ALAsset はアプリで作成したものであっても、ユーザーの写真ライブラリから削除することはできません。(それについては、別の機能強化リクエストを提出してください。)

そのため、写真/画像がアプリで作成されたものであれば、これでうまくいきます。

ただし、そうでない場合は、ユーザーが削除する必要がある追加のコピーが作成されます。

唯一の代替手段は、NSData を自分で解析することですが、これは面倒です。iOS SDK のこのギャップを埋めるオープンソース ライブラリは私が知っているものではありません。

于 2013-02-05T02:17:27.877 に答える
2

iphone-exif と Aaron の回答に加えて、libexif c ライブラリも参照してください。

イメージをロードせずに、ファイルシステム上の既存のイメージの EXIF データを書き込むまたは変更する方法に対する HCO23 の回答も参照してください。

(@HCO23 は iOS プロジェクトで libexif を使用しています)。

また、App Store にある「プロフェッショナルな」メタデータ編集アプリの多くは、サイドカー/xmp ファイルを作成することで問題を回避しているように見えることも注目に値します。

于 2013-02-12T04:34:09.653 に答える
2

これを試して :

- (void)saveImage: (UIImage*)image
{
    if (image != nil)
    {
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
                                                             NSUserDomainMask, YES);
        NSString *documentsDirectory = [paths objectAtIndex:0];
        NSString* path = [documentsDirectory stringByAppendingPathComponent:
                          @"test.png" ];
        NSData* data = UIImagePNGRepresentation(image);
        [data writeToFile:path atomically:YES];
    }
}

- (UIImage*)loadImage
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
                                                         NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString* path = [documentsDirectory stringByAppendingPathComponent:
                      @"test.png" ];
    UIImage* image = [UIImage imageWithContentsOfFile:path];
    [self sendAction:path];
    return image;
}
于 2013-02-06T08:20:23.080 に答える