转:http://www.cnblogs.com/xiaobaizhu/archive/2013/07/03/3170101.html

该控件有旋转,缩放,拖动,剪裁的功能,封装成了一个ImageCropperView类

需要导入的库:QuartzCore.framework

ImageCopperView.h

#import <UIKit/UIKit.h>

@protocol ImageCropperDelegate;

@interface ImageCropperView : UIView {
UIImageView *imageView; id <ImageCropperDelegate> delegate;
} @property (nonatomic, retain) UIImage *image;
@property (nonatomic, retain) UIImage *croppedImage; @property (nonatomic, assign) id <ImageCropperDelegate> delegate; @property (nonatomic, assign) BOOL enable;
@property (nonatomic, assign) BOOL isPaning; - (void)setup;
- (void)finishCropping;
- (void)reset; @end @protocol ImageCropperDelegate <NSObject>
- (void)changeMoveStateWithCropper:(UIPanGestureRecognizer*)gesture Crop:(ImageCropperView*)imageCrop;
@end

ImageCopperView.m

#import "ImageCropperView.h"
#import <QuartzCore/QuartzCore.h>
#include <math.h>
#import "UIImage+Rotation.h" @interface ImageCropperView()
{
@private
CGSize _originalImageViewSize;
} @property (nonatomic, retain) UIImageView *imageView;
@end @implementation ImageCropperView @synthesize imageView, image = _image, delegate, croppedImage; - (void)setup
{
_enable = YES;
self.clipsToBounds = YES;
self.backgroundColor = [UIColor clearColor]; self.imageView = [[[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, self.frame.size.width, self.frame.size.height)] autorelease];
imageView.userInteractionEnabled = YES;
[self addSubview:imageView]; UIRotationGestureRecognizer *rotateGes = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotateImage:)];
[imageView addGestureRecognizer:rotateGes];
[rotateGes release]; UIPinchGestureRecognizer *scaleGes = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(scaleImage:)];
[imageView addGestureRecognizer:scaleGes];
[scaleGes release]; UIPanGestureRecognizer *moveGes = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(moveImage:)];
[moveGes setMinimumNumberOfTouches:1];
[moveGes setMaximumNumberOfTouches:1];
[imageView addGestureRecognizer:moveGes];
[moveGes release];
} - (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame]; if (self) {
self.frame = frame;
[self setup];
} return self;
} float _lastTransX = 0.0, _lastTransY = 0.0;
- (void)moveImage:(UIPanGestureRecognizer *)sender
{
_isPaning = YES;
if (delegate&&[delegate respondsToSelector:@selector(changeMoveStateWithCropper:Crop:)]) {
[delegate changeMoveStateWithCropper:sender Crop:self];
}else{
return;
}
if (sender.numberOfTouches != 1||_enable == NO) {
return;
}
//获取在视图中手势的触点位置
CGPoint translatedPoint = [sender translationInView:self]; if([sender state] == UIGestureRecognizerStateBegan) {
_lastTransX = 0.0;
_lastTransY = 0.0;
} CGAffineTransform trans = CGAffineTransformMakeTranslation(translatedPoint.x - _lastTransX, translatedPoint.y - _lastTransY);
//CGAffineTransformConcat将imageView.transform和trans两个动画连续起来
CGAffineTransform newTransform = CGAffineTransformConcat(imageView.transform, trans);
_lastTransX = translatedPoint.x;
_lastTransY = translatedPoint.y;
NSLog(@"_lastTransX==%f,_lastTransY==%f",_lastTransX,_lastTransY);
imageView.transform = newTransform;
} float _lastScale = 1.0;
- (void)scaleImage:(UIPinchGestureRecognizer *)sender
{
_isPaning = NO;
if (sender.numberOfTouches != 2||_enable == NO) {
return;
} if([sender state] == UIGestureRecognizerStateBegan) { _lastScale = 1.0;
return;
} CGFloat scale = [sender scale]/_lastScale; CGAffineTransform currentTransform = imageView.transform;
CGAffineTransform newTransform = CGAffineTransformScale(currentTransform, scale, scale);
[imageView setTransform:newTransform]; _lastScale = [sender scale];
} float _lastRotation = 0.0;
- (void)rotateImage:(UIRotationGestureRecognizer *)sender
{
_isPaning = NO;
if (sender.numberOfTouches != 2||_enable == NO) {
return;
} if([sender state] == UIGestureRecognizerStateEnded) { _lastRotation = 0.0;
return;
} CGFloat rotation = -_lastRotation + [sender rotation]; CGAffineTransform currentTransform = imageView.transform;
CGAffineTransform newTransform = CGAffineTransformRotate(currentTransform,rotation);
[imageView setTransform:newTransform]; _lastRotation = [sender rotation]; } - (void)setImage:(UIImage *)image
{
if (_image != image) {
_image = [image retain];
} float _imageScale = self.frame.size.width / image.size.width;
self.imageView.frame = CGRectMake(0, 0, image.size.width*_imageScale, image.size.height*_imageScale);
_originalImageViewSize = CGSizeMake(image.size.width*_imageScale, image.size.height*_imageScale);
imageView.image = image;
imageView.center = CGPointMake(self.frame.size.width/2.0, self.frame.size.height/2.0);
} - (void)finishCropping {
float zoomScale = [[self.imageView.layer valueForKeyPath:@"transform.scale.x"] floatValue];
float rotate = [[self.imageView.layer valueForKeyPath:@"transform.rotation.z"] floatValue]; float _imageScale = _image.size.width/_originalImageViewSize.width;
CGSize cropSize = CGSizeMake(self.frame.size.width/zoomScale, self.frame.size.height/zoomScale);
CGPoint cropperViewOrigin = CGPointMake((0.0 - self.imageView.frame.origin.x)/zoomScale,
(0.0 - self.imageView.frame.origin.y)/zoomScale); if((NSInteger)cropSize.width % 2 == 1)
{
cropSize.width = ceil(cropSize.width);
}
if((NSInteger)cropSize.height % 2 == 1)
{
cropSize.height = ceil(cropSize.height);
} CGRect CropRectinImage = CGRectMake((NSInteger)(cropperViewOrigin.x*_imageScale) ,(NSInteger)( cropperViewOrigin.y*_imageScale), (NSInteger)(cropSize.width*_imageScale),(NSInteger)(cropSize.height*_imageScale)); UIImage *rotInputImage = [self.image imageRotatedByRadians:rotate];
CGImageRef tmp = CGImageCreateWithImageInRect([rotInputImage CGImage], CropRectinImage);
self.croppedImage = [UIImage imageWithCGImage:tmp scale:self.image.scale orientation:self.image.imageOrientation];
CGImageRelease(tmp);
} - (void)reset
{
self.imageView.transform = CGAffineTransformIdentity;
} - (void)dealloc {
self.image = nil;
self.croppedImage = nil;
self.imageView = nil; [super dealloc];
} @end

对UIImage添加了一个category

UIImage+Rotation.h

#import <UIKit/UIKit.h>

@interface UIImage (Rotation)

- (UIImage *)imageRotatedByRadians:(CGFloat)radians;
- (UIImage *)imageRotatedByDegrees:(CGFloat)degrees; @end

UIImage+Rotation.m

#import "UIImage+Rotation.h"

/************
角度=弧度/Pi*180
弧度=角度/180*Pi
*************/ CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;};
CGFloat RadiansToDegrees(CGFloat radians) {return radians * 180/M_PI;}; @implementation UIImage (Rotation) - (UIImage *)imageRotatedByRadians:(CGFloat)radians
{
return [self imageRotatedByDegrees:RadiansToDegrees(radians)];
} - (UIImage *)imageRotatedByDegrees:(CGFloat)degrees
{
/*****
CGAffineTransformMakeRotation
通过指定角度来创建一个旋转矩阵
CGAffineTransformRotate
在已存在的矩阵中使用旋转
*****/
UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0,self.size.width, self.size.height)];
CGAffineTransform t = CGAffineTransformMakeRotation(DegreesToRadians(degrees));
//给view旋转角度
rotatedViewBox.transform = t;
CGSize rotatedSize = rotatedViewBox.frame.size;
[rotatedViewBox release];
//开始编辑图形上下文
UIGraphicsBeginImageContext(rotatedSize);
//定义一个图形上下文
CGContextRef bitmap = UIGraphicsGetCurrentContext();
//沿x轴移动rotatedSize.width/2,y轴移动rotatedSize.height
CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2);
//以原点(左下角)为中心旋转DegreesToRadians(degrees)弧度,正角度逆时针,负角度顺时针
CGContextRotateCTM(bitmap, DegreesToRadians(degrees));
//缩放x轴,y轴方向
CGContextScaleCTM(bitmap, 1.0, -1.0);
//绘制位图
CGContextDrawImage(bitmap, CGRectMake(-self.size.width / 2, -self.size.height / 2, self.size.width, self.size.height), [self CGImage]);
//赋值给UIImage
UIImage *resImage = UIGraphicsGetImageFromCurrentImageContext();
//结束绘制
UIGraphicsEndImageContext();
return resImage;
} @end;

ViewController.m

#import "ViewController.h"
#import <QuartzCore/QuartzCore.h>
#import "ImagecropperView.h" @interface ViewController ()<ImageCropperDelegate>{
} @property (nonatomic, retain) IBOutlet ImageCropperView *cropper;
@property (nonatomic, retain) IBOutlet UIImageView *result;
@property (retain, nonatomic) IBOutlet UIImageView *resultSecond;
@property (nonatomic, retain) IBOutlet UIButton *btn;
@property (retain, nonatomic) IBOutlet ImageCropperView *cropperSecond; @property (retain, nonatomic) IBOutlet UIButton *cropButton; @end @implementation ViewController
//@synthesize cropper, result, btn; - (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_cropper.layer.borderWidth = 1.0;
_cropper.layer.borderColor = [UIColor blueColor].CGColor;
_cropper.delegate = self;
[_cropper setup];
_cropper.image = [UIImage imageNamed:@"2.jpg"];
[_btn addTarget:self action:@selector(buttonClicked) forControlEvents:UIControlEventTouchUpInside]; _cropperSecond.layer.borderColor = [UIColor blackColor].CGColor;
_cropperSecond.layer.borderWidth = 2.0;
_cropperSecond.delegate = self;
[_cropperSecond setup];
_cropperSecond.image = [UIImage imageNamed:@"1.jpg"];
[_cropButton addTarget:self action:@selector(tapCropButton) forControlEvents:UIControlEventTouchUpInside];
} - (void)buttonClicked
{
if ([_btn.currentTitle isEqualToString:@"Crop1"]) {
[_cropper finishCropping];//保存
_result.image = _cropper.croppedImage;
_cropper.hidden = YES;
[_btn setTitle:@"Back" forState:UIControlStateNormal];
[_btn setTitle:@"Back" forState:UIControlStateHighlighted];
}else
{
[_cropper reset];
_cropper.hidden = NO;
[_btn setTitle:@"Crop1" forState:UIControlStateNormal];
[_btn setTitle:@"Crop1" forState:UIControlStateHighlighted];
_result.image = nil;
}
_cropperSecond.enable = YES;
_cropper.enable = YES;
} - (void)tapCropButton{
if ([_cropButton.currentTitle isEqualToString:@"Crop2"]) {
[_cropperSecond finishCropping];
_cropperSecond.enable = NO;
_resultSecond.image = _cropperSecond.croppedImage;
_cropperSecond.hidden = YES;
[_cropButton setTitle:@"Back" forState:UIControlStateNormal];
[_cropButton setTitle:@"Back" forState:UIControlStateHighlighted];
}else
{
[_cropperSecond reset]; _cropperSecond.hidden = NO;
[_cropButton setTitle:@"Crop2" forState:UIControlStateNormal];
[_cropButton setTitle:@"Crop2" forState:UIControlStateHighlighted];
_resultSecond.image = nil;
}
_cropperSecond.enable = YES;
_cropper.enable = YES;
} #pragma mark - ImageCropperDelegate
- (void)changeMoveStateWithCropper:(UIPanGestureRecognizer*)gesture Crop:(ImageCropperView*)imageCrop{
if (gesture.state == UIGestureRecognizerStateEnded) {
NSLog(@"点击编辑器结束,两个_cropper都可以进行编辑");
_cropperSecond.enable = YES;
_cropper.enable = YES;
}
} - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event;
{
//判断点击在控件上
UITouch *touch = [touches anyObject];
if ([_cropper pointInside:[touch locationInView:_cropper] withEvent:nil]) {
NSLog(@"_cropper1 被触摸,禁用_cropper2");
_cropperSecond.enable = NO;
}else if ([_cropperSecond pointInside:[touch locationInView:_cropperSecond] withEvent:nil]){
NSLog(@"_cropper2 被触摸,禁用_cropper1");
_cropper.enable = NO;
}
} - (void)dealloc {
[_cropperSecond release];
[_cropButton release];
[_resultSecond release];
[super dealloc];
}
- (void)viewDidUnload {
[self setCropperSecond:nil];
[self setCropButton:nil];
[self setResultSecond:nil];
[super viewDidUnload];
}
@end

下面是截图

最后要注意,因为我是用xib做的,拖上去的UIView要将其Class改成ImageCropperView

ios 照片编辑的view封装的更多相关文章

  1. iOS视频编辑SDK

    IOS视频编辑SDK接入说明 一.名词解释 分辨率:用于计算机视频处理的图像,以水平和垂直方向上所能显示的像素数来表示分辨率.常见视频分辨率的有1080P即1920x1080,720P即1080x72 ...

  2. IOS 开发中 Whose view is not in the window hierarchy 错误的解决办法

    在 IOS 开发当中经常碰到 whose view is not in the window hierarchy 的错误,该错误简单的说,是由于 "ViewController" ...

  3. IOS照片颠倒分析及移动/页面端的处理策略和思路

    前言: 前几天, 写了一篇关于IOS手机上传照片颠倒的技术分析文章: IOS照片颠倒分析及PHP服务端的处理. 不过其思路是从服务器来进行处理的, 这种做法相当普遍. 今天来讲述下, 如何从移动端/页 ...

  4. 关于报错:'sharedApplication' is unavailable: not available on iOS (App Extension) - Use view controller based

    最近在看Extension相关知识的时候,自己写了个小demo 发现[UIApplication sharedApplication]这个方法敲不出来了, 总是报错:'sharedApplicatio ...

  5. IOS—通过ChildViewController实现view的切换

    IOS-通过ChildViewController实现view的切换 在以前,一个UIViewController的View可能有很多小的子view.这些子view很多时候被盖在最后,我们在最外层Vi ...

  6. 详解iOS开发之自定义View

    iOS开发之自定义View是本文要将介绍的内容,iOS SDK中的View是UIView,我们可以很方便的自定义一个View.创建一个 Window-based Application程序,在其中添加 ...

  7. iOS 容器控制器 (Container View Controller)

    iOS 容器控制器 (Container View Controller) 一个控制器包含其他一个或多个控制器,前者为容器控制器 (Container View Controller),后者为子控制器 ...

  8. Luminar 3 for Mac(照片编辑工具)v3.1.0中文特别版

    Luminar for Mac是一款多功能照片编辑软件,使用独特的AI工具加快速度,具备AI Sky Enhancer.Accent AI.太阳光线等创新功能.当然也保留了原有的功能,帮助你轻松的修复 ...

  9. iOS9中找不到XXX.dylib 与 is unavailable no availabel on ios (app extension) - use view controller 的解决办法

    在 iOS9 中现在找不到 XXX.dylib 了,比如libz.tbd  如果要用到 libz.dylib,可以用下面的办法,来自 Stack Overflow. Go to Build Phase ...

随机推荐

  1. Unity3D 游戏开发构架篇 —— 动态大场景生成 = 区域加载+对象池管理

    项目做一个类似无尽模式的场景,想了一想,其实方法很简单,做一个相关的总结. 主要先谈一谈构架,后期附上代码. 一.区域加载 其实无尽场景的实现很简单,因为屏幕限制,那么不论何时何地,我们只能看到自己的 ...

  2. MVC4.0中下来列表框的,两种使用方法DropDownList

    后台控制器代码 public ActionResult Drop() { var list = new List<SchoolInfo>(); list.Add(new SchoolInf ...

  3. hdu 1133 Buy the Ticket

    首先,记50的为0,100的为1. 当m=4,n=3时,其中的非法序列有0110010; 从不合法的1后面开始,0->1,1->0,得到序列式0111101 也就是说,非法序列变为了n-1 ...

  4. [SQL Server 系] -- 模糊查询

    SQL Server中的通配符有下面四种 通配符 说明 % 包含零个或多个字符的任意字符串 _(下划线) 任意单个字符 [ ] 任意在指定范围或集合中的单个字符 [^ ] 任意不在指定范围或集合中的单 ...

  5. Android 监测手机联网状态 wifi、移动数据流量、无联网状态

    手机当完成联网时会发送一个广播,我们只要创建一个广播接收者即可,代码如下: package com.example.NetworkChangeReceiver2; import android.con ...

  6. 01 - 编译链接第一个wxWidgets3.0例子

    1. preprocessor #define __WXMSW__#define WXUSINGDLL 2. vc10中设置Include dir, lib dir, dll path VC++平台编 ...

  7. Android中数据存储之SharedPreferences

    import android.content.Context; import android.content.SharedPreferences; import android.content.Sha ...

  8. java登陆验证码与JS无刷新验证

    最近公司的项目的登陆模块由我负责,所以就做了个登陆小功能进行练手,其包括了用jQuery对用户名和密码进行不为null验证,和出于安全性考虑加了一个验证码的校验 别的不说先上代码 controller ...

  9. spring @qualifier注解

    1.spring @qualifier注解用来在spring按类型装配可能存在多个bean的情况下,@qualifier注解可以用来缩小范围或者指定唯一. 也可以用来指定方法参数 2.@qualifi ...

  10. Win32 SDK程序创建一些控件(简单调用InitCommonControlsEx,并指定ICC_LISTVIEW_CLASSES控件就可以了)

    在Win32 SDK中创建一些控件的时候需要注意一下(具体是哪些控件请参看MSDN文档中列出来的) /* MSDN:Carries information used to load common co ...