Подтвердить что ты не робот

Сохранять исходные данные изображения с измененными метаданными (без повторного кодирования) на iOS

Я хочу сохранить изображение с некоторыми изменениями метаданных в папке temp, без повторного кодирования фактических данных изображения.

Единственный метод, который я нашел в этом, - ALAssetsLibrary/writeImageDataToSavedPhotosAlbum:metadata:completionBlock:, однако он сохраняет изображение в Фотобиблиотеке. Вместо этого я хочу сохранить изображение в временную папку (например, чтобы поделиться им по электронной почте, не заполняя Photo Library).

Я пробовал использовать CGImageDestinationRef (CGImageDestinationAddImageFromSource), но его можно создать только с помощью декодированного изображения, что означает его перекодировать его при сохранении (проверенные, пиксельные байты выглядят по-разному).

Существуют ли какие-либо другие методы/классы для iOS, которые могут сохранять данные изображения вместе с метаданными, кроме использования CGImageDestinationRef? Также приветствуются предложения об обходных решениях.

4b9b3361

Ответ 1

Это неприятная проблема с SDK iOS. Во-первых, я рекомендую подать запрос .

Теперь вот потенциальное обходное решение: если 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 из библиотеки фотографий пользователя, даже если ваше приложение создало его. (Не стесняйтесь записать еще один запрос на повышение.)

Итак, если фото/изображение было создано в вашем приложении, это будет работать для вас.

Но если нет, он создаст дополнительную копию, которую пользователь должен удалить.

Единственная альтернатива - это самостоятельно проанализировать NSData, что будет больно. Нет никакой библиотеки с открытым исходным кодом, о которой я знаю, чтобы заполнить этот пробел в SDK iOS.

Ответ 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;
}

Ответ 3

Наряду с iphone-exif и ответом Аарона вы также можете посмотреть библиотеку libexif c.

см. также HCO23 ответ на вопрос Как записать или изменить данные EXIF ​​для существующего изображения в файловой системе, не загружая изображение?

(@HCO23 использовал libexif в проектах iOS).

Также стоит отметить, что многие из "профессиональных" приложений для редактирования метаданных в магазине приложений, похоже, обходят вокруг проблемы, создавая файлы sidecar/xmp.