Как получить заданный размер изображения для iOS8 PhotoKit?

Я использую следующий код для получения изображения:

[[PHImageManager defaultManager] requestImageForAsset:asset 
targetSize:CGSizeMake(800, 600) 
contentMode:PHImageContentModeAspectFill 
options:options 
resultHandler:^(UIImage *result, NSDictionary *info) {
    NSLog(@"size:%@",NSStringFromCGSize(result.size));                
}];

Я запрашиваю размер изображения 800 х 600, но я получаю изображение размером 45 х 60, что очень плохое качество.

Как получить требуемый размер изображения с помощью PhotoKit?

Ответ 1

Мне удалось получить изображение размером 800 * 600 с помощью кода ниже:

PHImageRequestOptions* options = [[[PHImageRequestOptions alloc] init] autorelease];
options.version = PHImageRequestOptionsVersionCurrent;
options.deliveryMode =  PHImageRequestOptionsDeliveryModeHighQualityFormat;
options.resizeMode = PHImageRequestOptionsResizeModeExact;

[PHImageManager defaultManager]
requestImageForAsset:(PHAsset *)asset
targetSize:CGSizeMake(800, 600)
contentMode:PHImageContentModeAspectFit
options:options
resultHandler:^(UIImage *result, NSDictionary *info) {
   NSLog(@"Image size:%@",NSStringFromCGSize(result.size));
}];

И если вы хотите получить изображение полного размера, вы можете использовать PHImageManagerMaximumSize как targetSize.

Ответ 2

Автоответчик (Unnati's) будет работать, однако он упускает из виду ряд оптимизаций, которые Apple дает вам в своих рамках, которые получают изображения для вас, которые отображаются быстрее.

Исходный код был довольно верным, но вы включаете объект options, который вам, вероятно, не нужен, и, возможно, вызывают проблемы, если вы неправильно установили resizeMode. Вот код, который должен сработать для вас, я только что удалил ваш объект options.

[[PHImageManager defaultManager]
 requestImageForAsset:(PHAsset *)asset
 targetSize:CGSizeMake(800, 600)
 contentMode:PHImageContentModeAspectFit
 options:nil
 resultHandler:^(UIImage *result, NSDictionary *info) {
     NSLog(@"Image size:%@",NSStringFromCGSize(result.size));
 }];

Это должно быть проще и дать вам все оптимизации, которые Apple предоставляет своим фреймворком бесплатно. Вот объяснение того, что вы получаете:

Быстрый ответ с изображением низкого качества

Структура будет вызывать обработчик результата несколько раз с увеличением качественных изображений, позволяя вам отображать что-то пользователю, пока они ждут окончательного изображения. Из документации:

Фотографии могут вызывать блок обработчика результатов более одного раза. Сначала фотографии называет блок, чтобы обеспечить изображение низкого качества, подходящее для временного отображения, при подготовке высококачественного изображения. (Если данные низкого качества сразу доступны, первый вызов может произойти до того, как возвращается метод.) Когда изображение высокого качества будет готово, Photos снова вызовет ваш обработчик результатов, чтобы предоставить его.

Это означает, что ваш блок resultHandler должен быть безопасным для вызова более одного раза - блок в вашем коде, так как он только регистрирует размер, и для моего тестового изображения я получаю два сообщения журнала, сначала с низким качеством 40x26 px, а затем снова с высоким качеством изображения. Если вы откроете приложение iOS Photos, вы можете увидеть изображения низкого качества очень кратко, прежде чем они станут резче - вот что происходит здесь.

Использование options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat предотвращает это поведение, а ваш resultHandler будет вызываться только один раз с окончательным изображением, поэтому я предлагаю не устанавливать этот параметр, если вы не можете создать блок обработчика (в вашем реальном коде), который можно вызвать несколько раз.

Быстрое возвращение изображения с кешем высокого качества

Чтобы обеспечить окончательное изображение быстро, структура обеспечит изображение, близкое к запрашиваемому размеру, в последнем вызове к вашему блоку resultHandler, если он уже имеет кеширование. Если вы используете набор UIImageView с contentMode для заполнения или подгонки формата, это не будет проблемой, просто укажите соответствие contentMode в запросе вашего изображения. Например, по сравнению с моим тестовым изображением второй вызов моего resultHandler имеет изображение 1280x850, большее, чем я просил, но в правом шаре. Однако установка options.resizeMode = PHImageRequestOptionsResizeModeExact предотвратит это поведение и заставит структуру изменить размер новой копии изображения, а не использовать кешированную копию, которая требует времени.

Поскольку рамка Photos не обрезает изображения (даже если вы ее просите, но это ошибка;-)), вы не обязательно получите точный размер, который вы запрашиваете, даже используя параметр PHImageRequestOptionsResizeModeExact. Например, если вы запрашиваете 800x600 для изображения, которое не соответствует соотношению 4: 3, фотографии не могут вернуть изображение этого размера, оно просто становится как можно ближе - на моем последнем изображении, такой запрос получает изображение 800x531. Это означает, что вам нужно иметь возможность обрабатывать изображения, которые не являются точным размером, который вы запрашиваете, поэтому вы можете также воспользоваться преимуществами оптимизаций в рамках и избегать использования PHImageRequestOptionsResizeModeExact. Из документации:

Изменение размера, чтобы точно соответствовать целевому размеру, менее эффективно, чем использование опции быстрого изменения размера.

(У вас установлено это значение PHImageRequestOptionsResizeModeFast в исходном options объекте, который не был включен в вопрос? Возможно, это вызвало вашу проблему.)

Версии изображений

Можно запросить разные версии изображения, как и в своем собственном ответе с помощью options.version = PHImageRequestOptionsVersionCurrent. Однако этого не требуется, поскольку по умолчанию используется текущая версия.