更新:
从PHImageManager 检索图像时裁剪图像的错误已在 iOS 8.3 中修复,因此对于该版本的 iOS 及更高版本,我的原始示例如下所示:
似乎错误仍然存在,包括 iOS 8.4,我可以用标准的 iPhone 6s 后置摄像头图像重现它们,并采用全尺寸方形裁剪。它们在 iOS 9.0 中得到了适当的修复,即使是 63 兆像素全景图的大裁剪也能正常工作。
Apple 定义的方法是在图像的坐标空间中传递一个CGRect,其中原点为 (0,0),最大值为 (1,1)。你在PHImageRequestOptions 对象中传递这个矩形,以及PHImageRequestOptionsResizeModeExact 的resizeMode,然后你应该得到一个裁剪的图像。
- (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 获取的方形缩略图。
首先,确保您的UIImageView 的contentMode 属性设置为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;
}];
不需要为resizeMode 指定PHImageRequestOptionsResizeModeExact,因为除非您还提供normalizedCropRect,否则它不会为您提供裁剪的图像,并且不应在此处使用,因为没有任何好处,使用它意味着您不要获得快速返回的缓存图像的好处。
result 中返回的UIImage 将与源的纵横比相同,但可以正确缩放以在设置为纵横比填充以显示为正方形的UIImageView 中使用,所以如果你只是显示它,这是要走的路。如果您需要裁剪图像以在应用程序之外打印或导出,这不是您想要的 - 请查看 normalizedCropRect 的使用。 (编辑 - 请参阅下面的示例,了解应该如何工作......)
除此之外,还要确保将 UIImageView 的内容模式设置为 UIViewContentModeScaleAspectFill 并通过以下两行设置 clipsToBounds = YES:
imageView.contentMode=UIViewContentModeScaleAspectFill;
imageView.clipsToBounds=YES;
编辑以添加 normalizedCropRect 用法示例
警告 - 这不起作用,但应根据 Apple's documentation。
Apple 定义的方法是在图像的坐标空间中传递一个CGRect,其中原点为 (0,0),最大值为 (1,1)。你在PHImageRequestOptions 对象中传递这个矩形,以及PHImageRequestOptionsResizeModeExact 的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;
}];
}
我只能建议,如果你有这个问题,你可以file a radar Apple 请求他们修复它!