iOS: выберите GIF из библиотеки фотографий, преобразуйте в NSData для использования в multipart / form-data - PullRequest
9 голосов
/ 04 марта 2011

Что сейчас работает в моем коде:

Я выбираю JPG или PNG из библиотеки фотографий (используя стандартные методы ImagePicker) и преобразую это изображение в NSData, используя:

self.myImageData = UIImageJPEGRepresentation(myImage, 0.9); 

, который я затем публикую на сервере, используя multipart / form-data.

Теперь я хочу сделать то же самое для GIF, сохраняя при этом исходные данные GIF (чтобы анимированный GIF, поступающий в библиотеку, возвращался с анимацией).

В didFinishPickingMediaWithInfo я могу получить URL исходного GIF с помощью

self.myGIFURL = [info objectForKey:UIImagePickerControllerReferenceURL]. 

Вот один из примеров того, что меня может заинтересовать:

активы библиотека: //asset/asset.GIF ID = 1000000034 & вн = GIF

Вот два способа, которыми я пытался сейчас вставить этот GIF в NSData, и каждый раз, когда я показываю myImageData (ноль).

Я пытался использовать initWithContentsOfURL:

NSData *dataFromGIFURL = [[NSData alloc] initWithContentsOfURL: myGIFURL];
self.myImageData = dataFromGIFURL;
[dataFromGIFURL release];

Затем я попытался преобразовать NSURL в строку для initWithContentsOfFile:

NSString *stringFromURL = [NSString stringWithFormat:@"%@", myGIFURL];
NSData *dataFromGIFURL = [[NSData alloc] initWithContentsOfFile: stringFromURL];
self.myImageData = dataFromGIFURL;
[dataFromGIFURL release];

Есть предложения? Спасибо.

Ответы [ 3 ]

13 голосов
/ 04 марта 2011

Ключ UIImagePickerControllerReferenceURL не появляется до iOS 4.1. Поэтому я полагаю, что в вашем вопросе подразумевается, что можно использовать инфраструктуру AssetsLibrary, которая появилась в iOS только в версии 4.0. В этом случае вы можете использовать следующее:

- (void)imagePickerController:(UIImagePickerController *)picker 
        didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
    [library assetForURL:[info objectForKey:UIImagePickerControllerReferenceURL]
        resultBlock:^(ALAsset *asset)
        {
            ALAssetRepresentation *representation = [asset defaultRepresentation];

            NSLog(@"size of asset in bytes: %d", [representation size]);

            unsigned char bytes[4];
            [representation getBytes:bytes fromOffset:0 length:4 error:nil];
            NSLog(@"first four bytes: %02x (%c) %02x (%c) %02x (%c) %02x (%c)",
                               bytes[0], bytes[0], 
                               bytes[1], bytes[1], 
                               bytes[2], bytes[2], 
                               bytes[3], bytes[3]);

            [library autorelease];
        }
        failureBlock:^(NSError *error)
        {
            NSLog(@"couldn't get asset: %@", error);

            [library autorelease];
        }
    ];
}

Итак, вы создаете ALAssetsLibrary, просите его найти вам ресурс с указанным URL-адресом (он понимает схему assets-library: // URL), затем, когда вы получаете актив, вы берете его представление по умолчанию и используете его для кормить вас байтами. Они будут фактическими байтами на диске, представление по умолчанию для ресурса из библиотеки является его формой на диске.

Например, выбор произвольного GIF, который я случайно выбрал из изображений Google, из средства выбора изображений, подключенного к делегату с таким методом, дает мне вывод:

2011-03-03 23: 17: 37.451 IPTest [1199: 307] размер актива в байт: 174960

2011-03-03 23: 17: 37.459 IPTest [1199: 307] первые четыре байта: 47 (G) 49 (I) 46 (F) 38 (8)

Итак, это начало стандартного заголовка GIF. Выбор PNG или JPG дает распознаваемые первые четыре байта заголовков PNG и JPG.

РЕДАКТИРОВАТЬ: чтобы закончить мысль, очевидно, вы можете использовать ALAssetRepresentation, чтобы прочитать все байты, описывающие файл в подходящем malloc'd массиве C, затем использовать NSData + (id) dataWithBytes: length: (или, более вероятно, + dataWithBytesNoCopy: length: freeWhenDone :), чтобы обернуть это в NSData.

6 голосов
/ 20 февраля 2016

Вот версия, в которой используется более новая платформа Photos:

- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {

    NSURL * refUrl = [info objectForKey:UIImagePickerControllerReferenceURL];
    if (refUrl) {
        PHAsset * asset = [[PHAsset fetchAssetsWithALAssetURLs:@[refUrl] options:nil] lastObject];
        if (asset) {
            PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
            options.synchronous = YES;
            options.networkAccessAllowed = NO;
            options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
            [[PHImageManager defaultManager] requestImageDataForAsset:asset options:options resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
                NSNumber * isError = [info objectForKey:PHImageErrorKey];
                NSNumber * isCloud = [info objectForKey:PHImageResultIsInCloudKey];
                if ([isError boolValue] || [isCloud boolValue] || ! imageData) {
                    // fail
                } else {
                    // success, data is in imageData
                }
            }];
        }
    }
}
4 голосов
/ 20 июня 2017

Вот версия Элая с использованием Swift 3:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String: Any]) {
    guard let imageURL = info[UIImagePickerControllerReferenceURL] as? URL else { return }
    guard let asset = PHAsset.fetchAssets(withALAssetURLs: [imageURL], options: nil).lastObject else { return }

    if picker.sourceType == .photoLibrary || picker.sourceType == .savedPhotosAlbum {
        let options = PHImageRequestOptions()
        options.isSynchronous = true
        options.isNetworkAccessAllowed = false
        options.deliveryMode = .highQualityFormat
        PHImageManager.default().requestImageData(for: asset, options: options) { data, uti, orientation, info in
            guard let info = info else { return }

            if let error = info[PHImageErrorKey] as? Error {
                log.error("Cannot fetch data for GIF image: \(error)")
                return
            }

            if let isInCould = info[PHImageResultIsInCloudKey] as? Bool, isInCould {
                log.error("Cannot fetch data from cloud. Option for network access not set.")
                return
            }

            // do something with data (it is a Data object)
        }
    } else {
        // do something with media taken via camera
    }
}
...