上篇写了使用相机拍照并裁剪的过程,本篇是关于从相册获取图片、图片裁剪的内容。
本篇使用的
iOS8.0
之后的Photos
框架
- 导入框架
#import <Photos/Photos.h>
- 获取所有的相册
- (void)getOriginalImages
{
// 获得所有的自定义相簿
PHFetchResult<PHAssetCollection *> *assetCollections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
// 遍历所有的自定义相簿
for (PHAssetCollection *assetCollection in assetCollections) {
[self enumerateAssetsInAssetCollection:assetCollection original:YES];
}
// 获得相机胶卷
PHAssetCollection *cameraRoll = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumUserLibrary options:nil].lastObject;
// 遍历相机胶卷,获取大图
[self enumerateAssetsInAssetCollection:cameraRoll original:YES];
}
- 得到相册后进行遍历,获取每个相册中所有的 PHAsset,PHAsset中包含图片和图片的信息
/**
* 遍历相簿中的所有图片
* @param assetCollection 相簿
* @param original 是否要原图
*/
- (void)enumerateAssetsInAssetCollection:(PHAssetCollection *)assetCollection original:(BOOL)original
{
NSLog(@"相簿名:%@", assetCollection.localizedTitle);
// 获得某个相簿中的所有PHAsset对象
PHFetchResult<PHAsset *> *assets = [PHAsset fetchAssetsInAssetCollection:assetCollection options:nil];
/*
这里是把 asset 直接作为数据源添加到数组中,没有进一步的转化为图片,原因有两点:
1.转化为图片很耗时,用户体验不好
2.直接转化图片内存占用很大,一开始我直接转化为高清图,结果内存暴增闪退了
*/
for (PHAsset *asset in assets) {
[self.dataSource addObject:asset];
}
//添加显示列表
[self.view addSubview:self.collectionView];
}
- 在collectionVIew 代理方法中逐个获取预览图(预览图较小,对内 存压力不大)
PHAsset *asset = self.dataSource[indexPath.row];
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
// 同步获得图片, 只会返回1张图片
options.synchronous = YES;
// 如果需要获取原图,尺寸取最大值
// CGSize size = CGSizeMake(asset.pixelWidth, asset.pixelHeight);
// 尺寸为零,获取的是预览图
CGSize size = CGSizeZero;
// 从asset中获得图片
[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:size contentMode:PHImageContentModeDefault options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
[cell updateCollectionViewCellInformationWithData:result];
}];
- 在得到原图之后就可以对其进行裁剪操作了,裁剪的处理过程和上篇的拍照裁剪类似,只是这里给图片添加了移动和缩放,所以裁剪会麻烦些,不过只要计算出裁剪比例和位置,剩下的就好处理了
/** 用于裁剪的原始图片 */
@property (strong, nonatomic) UIImage *image;
/** 图片显示 */
@property (strong, nonatomic) UIImageView *imageV;
/** 图片加载后的初始位置 */
@property (assign, nonatomic) CGRect norRect;
/** 裁剪框frame */
@property (assign, nonatomic) CGRect showRect;
/** 用于判断是否是放大操作 */
@property (assign, nonatomic) CGFloat lastImageW;
- 图片移动,根据位置使其回弹
- (void)panGR:(UIPanGestureRecognizer *)sender{
CGPoint point = [sender translationInView:self.view];
_imageV.center = CGPointMake(_imageV.centerX + point.x, _imageV.centerY + point.y);
[sender setTranslation:CGPointZero inView:self.view];
//手势结束,调整 imageView 位置
if (sender.state == UIGestureRecognizerStateEnded) {
if (_imageV.origin.x > _showRect.origin.x ||
_imageV.origin.y > _showRect.origin.y ||
_imageV.origin.x + _imageV.size.width < _showRect.origin.x + _showRect.size.width ||
_imageV.origin.y + _imageV.size.height < _showRect.origin.y + _showRect.size.height) {
CGRect newRect = _imageV.frame;
if (_imageV.origin.x > _showRect.origin.x) {
newRect.origin.x = _showRect.origin.x;
}
if (_imageV.origin.y > _showRect.origin.y &&
_imageV.frame.size.height > _showRect.size.height)
{
newRect.origin.y = _showRect.origin.y;
}
else if (_imageV.origin.y > _showRect.origin.y &&
_imageV.frame.size.height <= _showRect.size.height)
{
newRect.origin.y = (SCREEN_HEIGHT - _imageV.frame.size.height) / 2.0;
}
if ((_imageV.origin.x + _imageV.size.width < _showRect.origin.x + _showRect.size.width) )
{
newRect.origin.x += _showRect.origin.x + _showRect.size.width - (_imageV.origin.x + _imageV.size.width);
}
if ((_imageV.origin.y + _imageV.size.height < _showRect.origin.y + _showRect.size.height) &&
(_imageV.frame.size.height > _showRect.size.height))
{
newRect.origin.y += _showRect.origin.y + _showRect.size.height - (_imageV.origin.y + _imageV.size.height);
}
else if ((_imageV.origin.y + _imageV.size.height < _showRect.origin.y + _showRect.size.height) &&
(_imageV.frame.size.height <= _showRect.size.height))
{
newRect.origin.y = (SCREEN_HEIGHT - _imageV.frame.size.height) / 2.0;
}
[UIView animateWithDuration:0.3f animations:^{
_imageV.frame = newRect;
}];
}
}
}
- 图片缩放
- (void)pinGR:(UIPinchGestureRecognizer *)sender{
_imageV.transform = CGAffineTransformScale(_imageV.transform, sender.scale, sender.scale);
//缩放结束,调整 imageView 位置
if (sender.state == UIGestureRecognizerStateEnded) {
CGRect newRect = _imageV.frame;
if (_imageV.frame.size.width <= _showRect.size.width) {
CGFloat ret = _image.size.height / _image.size.width;
newRect.size.width = _showRect.size.width;
newRect.size.height = _showRect.size.width * ret;
newRect.origin.x = _showRect.origin.x;
newRect.origin.y = (SCREEN_HEIGHT - newRect.size.height) / 2.0;
}else{
if (newRect.size.width < _lastImageW){
if (_imageV.centerX <= _showRect.origin.x + _showRect.size.width / 2.0) {
newRect.origin.x = _showRect.origin.x + _showRect.size.width - newRect.size.width;
}else{
newRect.origin.x = _showRect.origin.x;
}
if (_imageV.centerY <= _showRect.origin.y + _showRect.size.height / 2.0) {
newRect.origin.y = _showRect.origin.y + _showRect.size.height - newRect.size.height;
}else{
newRect.origin.y = _showRect.origin.y;
}
}
}
[UIView animateWithDuration:0.3f animations:^{
_imageV.frame = newRect;
}];
_lastImageW = newRect.size.width;
}
sender.scale = 1.0;
}
- 计算裁剪区域并裁剪
- (void)rightButtonClicked{
CGRect clipRect = CGRectZero;
CGFloat h = 0;
CGFloat w = 0;
CGFloat originX = 0;
CGFloat originY = 0;
CGFloat clipW = 0;
CGFloat clipH = 0;
if (_imageV.size.width <= _showRect.size.width) { //图片没有放大
if (_imageV.size.height <= _showRect.size.height) //图片高度小于等于裁剪框高度,按图片高度截取正方形
{
h = _imageV.size.height;
w = h;
originX = (_imageV.size.width - w) / 2.0 / _imageV.size.width * _image.size.width;
originY = 0;
}
else{ //图片高度大于裁剪框高度,按裁剪框截取
h = _showRect.size.width;
w = _showRect.size.width;
originX = 0;
originY = (_showRect.origin.y - _imageV.frame.origin.y) / _imageV.size.height * _image.size.height;
}
}else{ //图片被放大
if (_imageV.size.height <= _showRect.size.height) { //图片高度小于等于裁剪框高度,按图片高度截取正方形
h = _imageV.size.height;
w = h;
originX = (_showRect.origin.x - _imageV.frame.origin.x + (_showRect.size.width - w) / 2.0) / _imageV.size.width * _image.size.width;
originY = 0;
}
else{ //图片高度大于裁剪框高度,按裁剪框截取
h = _showRect.size.width;
w = _showRect.size.width;
originX = (_showRect.origin.x - _imageV.frame.origin.x) / _imageV.frame.size.width * _image.size.width;
originY = (_showRect.origin.y - _imageV.frame.origin.y) / _imageV.frame.size.height * _image.size.height;
}
}
clipW = w / _imageV.size.width * _image.size.width;
clipH = h / _imageV.size.height * _image.size.height;
clipRect = CGRectMake(originX, originY, clipW, clipH);
//裁剪后得到的图片
UIImage *image = [self imageFromImage:self.image inRect:clipRect];
//裁剪完成回调
if (self.pictureSelectedBlock) {
self.pictureSelectedBlock();
}
[_imageV removeFromSuperview];
[self dismissViewControllerAnimated:YES completion:^{
[[NSNotificationCenter defaultCenter] postNotificationName:@"PicutreFromAlbum" object:nil userInfo:@{@"image":image}];
}];
}
//裁剪方法
- (UIImage *)imageFromImage:(UIImage *)image inRect:(CGRect)rect{
//将UIImage转换成CGImageRef
CGImageRef sourceImageRef = [image CGImage];
//按照给定的矩形区域进行剪裁
CGImageRef newImageRef = CGImageCreateWithImageInRect(sourceImageRef, rect);
//将CGImageRef转换成UIImage
UIImage *newImage = [UIImage imageWithCGImage:newImageRef];
//返回剪裁后的图片
return newImage;
}
完整Demo地址:CameraDemo