更新:
在iOS 8.3中修复了从PHImageManager
检索图像时裁剪图像的错误,因此对于该版本的iOS和更高版本,我的原始示例有效,如下所示:似乎在iOS 8.4及以下版本中仍存在错误,我可以使用标准iPhone 6s后置摄像头拍摄的全尺寸正方形裁剪图像重现这些错误。但是,在iOS 9.0中已经完全修复了这些错误,即使是63兆像素全景图的大型裁剪也能正常工作。
Apple定义的方法是在图像的坐标空间中传递一个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)以外的其他位置,因为通常您希望裁剪正方形沿被裁剪的图像轴居中,但我将把这留给读者作为练习。 :-)
原始答案:
John的答案让我完成了大部分工作,但是使用他的代码,我的图片会被拉伸和压缩。以下是如何使
imageView
显示从PHImageManager获取的正方形缩略图。
首先,请确保您的
UIImageView
的
contentMode
属性设置为
ScaleAspectFill
。默认值为
ScaleToFill
,对于从
PHImageManager
显示正方形缩略图不起作用,因此无论您是在代码中还是在Storyboard中实例化了
UIImageView
,都要确保更改此设置。
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) {
imageView.image = result;
}];
指定
resizeMode
为
PHImageRequestOptionsResizeModeExact
并非必需,因为除非您还提供
normalizedCropRect
,否则它不会给您裁剪后的图像,并且在这里不应该使用它,因为没有好处,使用它意味着您无法获得快速返回缓存图像的好处。
result
中返回的
UIImage
与源具有相同的纵横比,但按正确比例缩放以用于设置为aspect fill的
UIImageView
,以显示为正方形,因此如果您只是要显示它,那么这是正确的方法。如果您需要将图像裁剪用于打印或导出到应用程序之外,则不是您想要的 - 请查看使用
normalizedCropRect
的方法。(编辑-请参见下面的示例,了解应该如何操作...)
除此之外,还要确保将UIImageView的内容模式设置为
UIViewContentModeScaleAspectFill
,并通过以下两行设置
clipsToBounds = YES
:
imageView.contentMode=UIViewContentModeScaleAspectFill
imageView.clipsToBounds=YES
添加使用normalizedCropRect的示例
警告 - 这个方法不起作用,但是应该能够根据苹果文档工作。
苹果定义的方法是在图像的坐标空间中传递一个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;
}];
}
我能提供的建议就是,如果你遇到这个问题,你可以向苹果公司
提交一个radar 请求他们修复它!