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

Как получить квадратные эскизы из PHImageManager?

Кто-нибудь знает, как извлечь квадратные превью из PHImageManager? Параметр PHImageContentModeAspectFill не влияет.

[[PHImageManager defaultManager]
  requestImageForAsset:(PHAsset *)_asset
            targetSize:CGSizeMake(80, 80)
           contentMode:PHImageContentModeAspectFill
               options:nil
         resultHandler:^(UIImage *result, NSDictionary *info) {
    // sadly result is not a squared image
    imageView.image = result;
}];
4b9b3361

Ответ 1

Update:

Ошибка в обрезке изображений по мере их получения из PHImageManager была исправлена ​​в iOS 8.3, поэтому для этой версии iOS и более поздних версий мой оригинальный пример работает следующим образом: Кажется, что ошибки все еще существуют до IOS 8.4, включая IOS 8.4, я могу воспроизвести их со стандартными изображениями задней камеры iPhone 6s, взяв квадратную культуру размером в полный размер. Они правильно установлены в iOS 9.0, где даже большие посевы с разрешением 63 мегапикселя прекрасно работают.

Подход Apple определяет, должен пройти a CGRect в пространстве координат изображения, где начало координат (0,0), а максимальное - (1,1). Вы передаете этот прямоугольник в объекте PHImageRequestOptions вместе с resizeMode из PHImageRequestOptionsResizeModeExact, а затем вы должны вернуть обрезанное изображение.

- (void)showSquareImageForAsset:(PHAsset *)asset
{
    NSInteger retinaScale = [UIScreen mainScreen].scale;
    CGSize retinaSquare = CGSizeMake(100*retinaScale, 100*retinaScale);

    PHImageRequestOptions *cropToSquare = [[PHImageRequestOptions alloc] init];
    cropToSquare.resizeMode = PHImageRequestOptionsResizeModeExact;

    CGFloat cropSideLength = MIN(asset.pixelWidth, asset.pixelHeight);
    CGRect square = CGRectMake(0, 0, cropSideLength, cropSideLength);
    CGRect cropRect = CGRectApplyAffineTransform(square,
                                                 CGAffineTransformMakeScale(1.0 / asset.pixelWidth,
                                                                            1.0 / asset.pixelHeight));

    cropToSquare.normalizedCropRect = cropRect;

    [[PHImageManager defaultManager]
     requestImageForAsset:(PHAsset *)asset
     targetSize:retinaSquare
     contentMode:PHImageContentModeAspectFit
     options:cropToSquare
     resultHandler:^(UIImage *result, NSDictionary *info) {
         self.imageView.image = result;
     }];
}

Этот пример делает его cropRect боковой длины равным меньшей ширины и высоты актива, а затем преобразует его в пространство координат изображения с помощью CGRectApplyAffineTransform. Вы можете установить источник square на что-то иное, чем (0,0), так как часто вы хотите, чтобы квадрат обрезки был центрирован вдоль оси изображения, которое обрезается, но я оставлю это как упражнение для читатель.: -)

Исходный ответ:

Джон ответ получил большую часть пути, но, используя его код, я получал растянутые и раздавленные изображения. Здесь, как я получил imageView для отображения квадратных миниатюр, полученных из PHImageManager.

Во-первых, убедитесь, что для свойства contentMode для вашего UIImageView установлено значение ScaleAspectFill. Значение по умолчанию - ScaleToFill, которое не работает корректно для отображения квадратных эскизов из PHImageManager, поэтому убедитесь, что вы изменили это, внесли ли вы экземпляр UIImageView в код или в раскадровку.

//view dimensions are based on points, but we're requesting pixels from PHImageManager
NSInteger retinaMultiplier = [UIScreen mainScreen].scale;
CGSize retinaSquare = CGSizeMake(imageView.bounds.size.width * retinaMultiplier, imageView.bounds.size.height * retinaMultiplier);

[[PHImageManager defaultManager]
     requestImageForAsset:(PHAsset *)_asset
               targetSize:retinaSquare
              contentMode:PHImageContentModeAspectFill
                  options:nil
            resultHandler:^(UIImage *result, NSDictionary *info) {

    // The result is not square, but correctly displays as a square using AspectFill
    imageView.image = result;
}];

Указание PHImageRequestOptionsResizeModeExact для resizeMode не требуется, так как оно не даст вам обрезанного изображения, если вы также не поставляете normalizedCropRect, и его не следует использовать здесь, поскольку нет никакой пользы, и использование этого означает, что вы не получают преимущества быстро возвращаемых кешированных изображений.

UIImage, возвращенный в result, будет иметь такое же соотношение сторон, что и исходный, но правильно масштабируется для использования в UIImageView, который установлен на аспектное заполнение для отображения в виде квадрата, поэтому, если вы просто показывая это, это путь. Если вам нужно обрезать изображение для печати или экспорта за пределами приложения, это не то, что вы хотите - посмотрите на использование normalizedCropRect для этого. (отредактируйте - см. ниже, например, что должно работать...)

Кроме того, убедитесь, что вы установили режим содержимого UIImageView в UIViewContentModeScaleAspectFill и установили clipToBounds = YES следующими двумя строками:

imageView.contentMode=UIViewContentModeScaleAspectFill;
imageView.clipsToBounds=YES;

Изменить, чтобы добавить пример использования normalizedCropRect
ПРЕДУПРЕЖДЕНИЕ - это не работает, но должно соответствовать документации Apple.

Подход Apple определяет, должен пройти a CGRect в пространстве координат изображения, где начало координат (0,0), а максимальное - (1,1). Вы передаете этот прямоугольник в объекте PHImageRequestOptions вместе с resizeMode из PHImageRequestOptionsResizeModeExact, а затем вы должны вернуть обрезанное изображение. Проблема в том, что вы этого не делаете, она возвращается как исходное соотношение сторон и полное изображение.

Я проверил, что прямоугольник обрезки создается правильно в пространстве координат изображения и следуют инструкции для использования PHImageRequestOptionsResizeModeExact, но обработчик результата все равно будет передан образ в исходном соотношении сторон. Это похоже на ошибку в структуре, и когда она исправлена, следующий код должен работать.

- (void)showSquareImageForAsset:(PHAsset *)asset
{
    NSInteger retinaScale = [UIScreen mainScreen].scale;
    CGSize retinaSquare = CGSizeMake(100*retinaScale, 100*retinaScale);

    PHImageRequestOptions *cropToSquare = [[PHImageRequestOptions alloc] init];
    cropToSquare.resizeMode = PHImageRequestOptionsResizeModeExact;

    CGFloat cropSideLength = MIN(asset.pixelWidth, asset.pixelHeight);
    CGRect square = CGRectMake(0, 0, cropSideLength, cropSideLength);
    CGRect cropRect = CGRectApplyAffineTransform(square,
                                                 CGAffineTransformMakeScale(1.0 / asset.pixelWidth,
                                                                            1.0 / asset.pixelHeight));

    cropToSquare.normalizedCropRect = cropRect;

    [[PHImageManager defaultManager]
     requestImageForAsset:(PHAsset *)asset
     targetSize:retinaSquare
     contentMode:PHImageContentModeAspectFit
     options:cropToSquare
     resultHandler:^(UIImage *result, NSDictionary *info) {
         self.imageView.image = result;
     }];
}

Все, что я могу предложить, это то, что если у вас есть эта проблема, вы файл радара с Apple, чтобы попросить их исправить!

Ответ 2

  PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init]; 
    options.resizeMode = PHImageRequestOptionsResizeModeExact;

  NSInteger retinaMultiplier = [UIScreen mainScreen].scale;
  CGSize retinaSquare = CGSizeMake(imageView.bounds.size.width * retinaMultiplier, imageView.bounds.size.height * retinaMultiplier);

    [[PHImageManager defaultManager]
             requestImageForAsset:(PHAsset *)_asset
                       targetSize:retinaSquare
                      contentMode:PHImageContentModeAspectFill
                          options:options
                    resultHandler:^(UIImage *result, NSDictionary *info) {

                    imageView.image =[UIImage imageWithCGImage:result.CGImage scale:retinaMultiplier orientation:result.imageOrientation];

    }];

Ответ 3

Чтобы получить точный квадрат, вам нужно указать, что вы хотите получить точный размер, передав параметры, например:

    PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];

    // No, really, we want this exact size    
    options.resizeMode = PHImageRequestOptionsResizeModeExact

    [[PHImageManager defaultManager]
             requestImageForAsset:(PHAsset *)_asset
                       targetSize:CGSizeMake(160, 160)
                      contentMode:PHImageContentModeAspectFill
                          options:options
                    resultHandler:^(UIImage *result, NSDictionary *info) {

    // Happily, result is now a squared image
    imageView.image = result;
    }];

Ответ 4

Это отлично работает для меня:

 __block UIImage* imgThumb;

CGSize size=CGSizeMake(45, 45);// Size for Square image

[self.imageManager requestImageForAsset:<your_current_phAsset>
                             targetSize:size
                            contentMode:PHImageContentModeAspectFill
                                options:nil
                          resultHandler:^(UIImage *result, NSDictionary *info) {

                              imgThumb = result;

  }];