当前位置: 移动技术网 > 移动技术>移动开发>IOS > IOS 照片编辑的view封装的实例详解

IOS 照片编辑的view封装的实例详解

2019年07月24日  | 移动技术网移动技术  | 我要评论

ios 照片编辑的view封装

该控件有旋转,缩放,拖动,剪裁的功能,封装成了一个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

如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网