iOS 相机拍照、相册获取照片(仿微信) 一一 从相册获取图片、图片裁剪

从相册获取图片、图片仿微信界面进行裁剪

Posted by HuberyYang on June 10, 2017

上篇写了使用相机拍照并裁剪的过程,本篇是关于从相册获取图片、图片裁剪的内容。

本篇使用的 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