欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2023-12-21 12:23:34
ios 照片编辑的view封装 该控件有旋转,缩放,拖动,剪裁的功能,封装成了一个imagecropperview类 需要导入的库:quartzcore.framewo...

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

截图:

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

最后要注意,因为我是用xib做的,拖上去的uiview要将其class改成imagecropperview

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

上一篇:

下一篇: