iphone图像裁剪功能实现
来源:互联网 发布:list转json字符串 编辑:程序博客网 时间:2024/06/15 19:15
这两天在做图像剪裁功能。一致在尝试不同的解决方案,包括从cocoachina查找的资料创意,一直不满意最终的效果。经过2天努力,终于完美实现。
方案实现功能如下:
1、可拖拽、缩放选区,截取所选区域部分图像
2、可缩放被裁剪图像,移动被裁剪图像,方便用户精确裁剪。
使用注意事项:
1、不要将代码实现的视图类实例添加为UIScrollView类实例的子视图。因为UIScrollView类实例会屏蔽子视图的拖拽事件(除非您自己实现一个子类,继承UIScrollView类,并按照苹果官方指南重写指定的几个方法。个人认为比较麻烦,而且不方便)。
2、若要获取选区对应的区域部分图像。使用
PictureCutView * pictureCutView;pictureCutView.choosenImage; //获取选取区域部分图像对应的UIImage对象
方案已尽我最大努力实现优化,如果您有更好的优化意见,欢迎留言提出。
附注:
1、本代码部分参考网上资料,部分代码来源与网上。
2、本人保留代码的版权,如需使用代码,请保留版权说明。
//// PictureCutView.h// Taonan//// Created by zengconggen on 11-9-19.// Copyright 2011 yongmengsoft. All rights reserved.//#import <UIKit/UIKit.h>@interface PictureCutView : UIView { @public UIImage * sourceImage; UIImage * choosenImage; @privateUIImageView *bgImageView;//要编辑的图片视图UIImageView *imageView;//选择区域框的图片视图CGPoint mouseXY;//鼠标单击坐标CGFloat sx,sy,w,h,ex,ey,sxm,sym;/* sx:imageView的起始X坐标 sy:imageView的起始y坐标 w:imageView的width:宽 h:imageView的height:高 ex:imageView的右下角坐标endX:终止X坐标 ey:imageView的endY:终止Y坐标 sxm:触摸点距离imageView的起始X坐标的位置 sym:触摸点距离imageView的起始Y坐标的位置 */NSInteger number;//记录触摸点不同位置的不同处理方案 UIImage * originImage; CGFloat originSpace; CGFloat scale; CGFloat totalScale; UITouch * currentTouch;}@property(nonatomic,retain, setter=setSourceImage:) UIImage * sourceImage;@property(nonatomic,readonly, getter=getChoosenImage) UIImage * choosenImage;@property(nonatomic,retain) UIImageView *bgImageView;@property(nonatomic,retain) UIImageView *imageView;@property(nonatomic) CGPoint mouseXY;@property(nonatomic) CGFloat sx,sy,w,h,ex,ey,sxm,sym;@property(nonatomic) NSInteger number;@property(nonatomic,retain) UIImage * originImage;@property(nonatomic) CGFloat scale;@property(nonatomic) CGFloat totalScale;@property(nonatomic) CGFloat originSpace;@property(nonatomic,retain) UITouch * currentTouch;- (void)setSourceImage:(UIImage *)image;- (UIImage *)getChoosenImage;//裁剪图片-(UIImage *)imageFromImage:(UIImage *)image inRect:(CGRect)rect;//改变图片的大小-(UIImage *)scaleFromImage:(UIImage *)image toSize:(CGSize)size;-(CGFloat)spaceToPoint:(CGPoint)first FromPoint:(CGPoint)two;-(void)scaleTo:(CGFloat)x;@end
//// PictureCutView.m// Taonan//// Created by zengconggen on 11-9-19.// Copyright 2011 yongmengsoft. All rights reserved.//#import "PictureCutView.h"#define CONTROL_WIDTH 20#define MIN_OFFSET 5@implementation PictureCutView@synthesize sourceImage, choosenImage;@synthesize bgImageView,imageView,mouseXY,sx,sy,w,h,ex,ey,sxm,sym,number,originImage,scale,totalScale,originSpace;@synthesize currentTouch;//触摸事件-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ //NSLog(@"touchesBegan count:%d", [touches count]); [super touchesBegan:touches withEvent:event]; if ([touches count] ==2) { NSArray* twoTouches=[touches allObjects]; originSpace=[self spaceToPoint:[[twoTouches objectAtIndex:0] locationInView:self] FromPoint:[[twoTouches objectAtIndex:1]locationInView:self]]; }else if ([touches count] ==1 && currentTouch == nil) { imageView.alpha = 1.0; //CGRect bgRect = bgImageView.frame; //获取触摸点 UITouch *touch = [touches anyObject]; self.currentTouch = touch; mouseXY = [touch locationInView:self]; //NSLog(@"++++ mouseXY in touchesBegan(Touch:%@): (%f, %f)", touch,mouseXY.x, mouseXY.y); //获取触摸时的各个参数 sx = imageView.frame.origin.x; sy = imageView.frame.origin.y; w = imageView.frame.size.width; h = imageView.frame.size.height; ex = sx+w; ey = sy+h; //记录触摸点的所在位置 if(mouseXY.x>sx+CONTROL_WIDTH&&mouseXY.x<ex-CONTROL_WIDTH&&mouseXY.y>sy+CONTROL_WIDTH&&mouseXY.y<ey-CONTROL_WIDTH){ //NSLog(@"启动时已经进入"); sxm = mouseXY.x-sx; sym = mouseXY.y-sy; number = 1; }else if(mouseXY.x>=ex-CONTROL_WIDTH && mouseXY.x<=ex+CONTROL_WIDTH && mouseXY.y>=ey-CONTROL_WIDTH && mouseXY.y<=ey+CONTROL_WIDTH){ number = 2; }else if(mouseXY.x>=ex-CONTROL_WIDTH && mouseXY.x<=ex+CONTROL_WIDTH && mouseXY.y>=sy-CONTROL_WIDTH && mouseXY.y<=sy+CONTROL_WIDTH){ number = 3; }else if(mouseXY.x>=sx-CONTROL_WIDTH && mouseXY.x<=sx+CONTROL_WIDTH && mouseXY.y>=ey-CONTROL_WIDTH && mouseXY.y<=ey+CONTROL_WIDTH){ number = 4; }else if(mouseXY.x>=sx-CONTROL_WIDTH && mouseXY.x<=sx+CONTROL_WIDTH && mouseXY.y>=sy-CONTROL_WIDTH && mouseXY.y<=sy+CONTROL_WIDTH){ number = 5; }else { number = 6; } }else { [super touchesBegan:touches withEvent:event]; }}//拖动事件-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{ NSAutoreleasePool * aPool = [[NSAutoreleasePool alloc] init]; //NSLog(@"touchesMoved count:%d", [touches count]); [super touchesMoved:touches withEvent:event]; if ([touches count] ==2) { @synchronized(self) { NSArray* twoTouches=[touches allObjects]; CGFloat currSpace=[self spaceToPoint:[[twoTouches objectAtIndex:0] locationInView:self] FromPoint:[[twoTouches objectAtIndex:1]locationInView:self]]; //如果先触摸一根手指,再触摸另一根手指,则触发touchesMoved方法而不是touchesBegan方法 //此时originSpace应该是0,我们要正确设置它的值为当前检测到的距离,否则可能导致0除错误 if (originSpace==0) { originSpace=currSpace; } if (fabsf(currSpace-originSpace)>=MIN_OFFSET) {//两指间移动距离超过min_offset,识别为手势“捏合” CGFloat s=currSpace/originSpace;//计算缩放比例 //NSLog(@"++++ scale: %f", s); [self scaleTo:s]; originSpace = currSpace; } } }else if ([touches count] ==1) { //NSLog(@"Moveimageview:%@,poing的坐标:%@,sx:%f,sy:%f,w:%f,h:%f,ex:%f,ey:%f,sxm:%f,sym:%f,number:%i",imageView,NSStringFromCGPoint(mouseXY),sx,sy,w,h,ex,ey,sxm,sym,number); //NSLog(@"imageView的X坐标:%f,Y坐标:%f",imageView.frame.origin.x,imageView.frame.origin.y); UITouch *touch = [touches anyObject]; if ([touch isEqual:currentTouch]) { CGPoint point = [touch locationInView:self]; CGRect bgRect = bgImageView.frame; CGFloat x,y,width,height; if(number == 1){ //NSLog(@"修改前的边界:%@,X:%f,Y:%f,width:%f,height:%f",NSStringFromCGPoint(mouseXY),x,y,width,height); //触摸点在imageview中 x = point.x-sxm; y = point.y-sym; width = w; height = h; }else if (number == 2) { //触摸点在imageview的右下角 x = sx; y = sy; width = point.x-sx; height = point.y-sy; }else if(number == 3){ //触摸点在imageview的右上角 x = sx; y = point.y; if(point.y<sy){ height = h+sy-point.y; }else { height = ey-point.y; } if(point.x<ex){ width = w-(ex-point.x); }else { width = w+point.x-ex; } }else if(number == 4){ //触摸点在imageview的左下角 x = point.x; y = sy; if(point.y<ey){ height = h-(ey-point.y); }else { height = h+point.y-ey; } width = ex-point.x; }else if(number == 5){ //触摸点在imageview的左上角 x = point.x; y = point.y; height = ey-point.y; width = ex-point.x; }else { //触摸点不在imageview上 //挪动整个视图 CGFloat offsetX = point.x-mouseXY.x; CGFloat offsetY = point.y-mouseXY.y; CGFloat bgSX = bgRect.origin.x+offsetX; CGFloat bgSY = bgRect.origin.y+offsetY; CGFloat bgEX = bgSX+bgRect.size.width; CGFloat bgEY = bgSY+bgRect.size.height; if (offsetX > 0) { if (bgRect.size.width > self.frame.size.width) { //判断左点是否入界,控制左边不显示空白 if (bgSX > 0) { bgSX = 0; offsetX = bgSX-bgRect.origin.x; } }else { //控制右点是否出界,控制图片完整显示 if (bgEX > self.frame.size.width) { bgEX = self.frame.size.width; offsetX = bgEX - bgRect.origin.x-bgRect.size.width; } } }else { if (bgRect.size.width > self.frame.size.width) { //判断右点是否入界,控制左边不显示空白 if (bgEX < self.frame.size.width) { bgEX = self.frame.size.width; offsetX = bgEX - bgRect.origin.x-bgRect.size.width; } }else { //控制左点是否出界,控制图片完整显示 if (bgSX < 0) { bgSX = 0; offsetX = bgSX-bgRect.origin.x; } } } if (offsetY > 0) { if (bgRect.size.height > self.frame.size.height) { //判断上点是否入界,控制左边不显示空白 if (bgSY > 0) { bgSY = 0; offsetY = bgSY-bgRect.origin.y; } }else { //控制下点是否出界,控制图片完整显示 if (bgEY > self.frame.size.height) { bgEY = self.frame.size.height; offsetY = bgEY - bgRect.origin.y-bgRect.size.height; } } }else { if (bgRect.size.height > self.frame.size.height) { //判断下点是否入界,控制左边不显示空白 if (bgEY < self.frame.size.height) { bgEY = self.frame.size.height; offsetY = bgEY - bgRect.origin.y-bgRect.size.height; } }else { //控制上点是否出界,控制图片完整显示 if (bgSY < 0) { bgSY = 0; offsetY = bgSY-bgRect.origin.y; } } } x = imageView.frame.origin.x+offsetX; y = imageView.frame.origin.y+offsetY; width = w; height = h; CGRect newBgRect = CGRectMake(bgRect.origin.x+offsetX, bgRect.origin.y+offsetY, bgRect.size.width, bgRect.size.height); bgImageView.frame = newBgRect; } if(x-bgRect.origin.x<0){ width = imageView.frame.size.width; x=bgRect.origin.x; } if(y-bgRect.origin.y<0){ height = imageView.frame.size.height; y=bgRect.origin.y; } CGFloat xL,yL; xL = x+width; if(xL>bgRect.origin.x+bgRect.size.width){ x = bgRect.origin.x+bgRect.size.width-width; } yL = y+height; if(yL>bgRect.origin.y+bgRect.size.height){ y = bgRect.origin.y+bgRect.size.height-height; } imageView.frame = CGRectMake(x, y, width, height);//容器大小的改变放在setimage前边,因为imageview的contentmode为scallapsecttofit模式 if (number !=6) { UIImage *endImage = [self imageFromImage:sourceImage inRect:CGRectMake(x-bgRect.origin.x, y-bgRect.origin.y, width, height)]; imageView.image = endImage; } mouseXY = point; //NSLog(@"++++ mouseXY in touchesMoved(Touch:%@): (%f, %f)", touch,mouseXY.x, mouseXY.y); } }else { [super touchesMoved:touches withEvent:event]; } [aPool release];}- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{ //NSLog(@"touchesEnded count:%d", [touches count]); if ([[event allTouches] containsObject:currentTouch]) { self.currentTouch = nil; } self.originSpace = 0; if ([touches count] ==2) { /* NSArray* twoTouches=[touches allObjects]; CGFloat currSpace=[self spaceToPoint:[[twoTouches objectAtIndex:0] locationInView:self] FromPoint:[[twoTouches objectAtIndex:1]locationInView:self]]; //如果先触摸一根手指,再触摸另一根手指,则触发touchesMoved方法而不是touchesBegan方法 //此时originSpace应该是0,我们要正确设置它的值为当前检测到的距离,否则可能导致0除错误 if (originSpace==0) { originSpace=currSpace; } if (fabsf(currSpace-originSpace)>=MIN_OFFSET) {//两指间移动距离超过min_offset,识别为手势“捏合” CGFloat s=currSpace/originSpace;//计算缩放比例 [self scaleTo:s]; } */ }else { [super touchesEnded:touches withEvent:event]; }}- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event{ //NSLog(@"touchesCanceled count:%d", [touches count]); if ([[event allTouches] containsObject:currentTouch]) { self.currentTouch = nil; } self.originSpace = 0; [super touchesCancelled:touches withEvent:event];} -(void)scaleTo:(CGFloat)x{ scale=x; //totalScale *=scale; //重设imageView的frame self.sourceImage = originImage;}- (id)initWithFrame:(CGRect)aframe { if (self = [super initWithFrame:aframe]) { self.contentMode = UIViewContentModeCenter; self.clipsToBounds = YES; self.exclusiveTouch = YES; self.bgImageView = [[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, aframe.size.width, aframe.size.height)] autorelease]; bgImageView.contentMode =UIViewContentModeScaleAspectFit; bgImageView.center = CGPointMake(aframe.size.width/2, aframe.size.height/2); bgImageView.alpha = 0.5; self.imageView = [[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)] autorelease]; imageView.contentMode = UIViewContentModeScaleAspectFit; imageView.center = CGPointMake(aframe.size.width/2, aframe.size.height/2); [self addSubview:bgImageView]; [self addSubview:imageView]; [self setUserInteractionEnabled:YES]; [self setMultipleTouchEnabled:YES]; [bgImageView setUserInteractionEnabled:NO]; //[bgImageView setMultipleTouchEnabled:YES]; [imageView setUserInteractionEnabled:NO]; //[imageView setMultipleTouchEnabled:YES]; scale = 1.0f; } return self;}- (id)init { return [self initWithFrame:CGRectMake(0, 44, 320, 416)];}- (void)setSourceImage:(UIImage *)image{ NSAutoreleasePool * aPool = [[NSAutoreleasePool alloc] init]; BOOL firstDraw = YES; if (self.originImage != nil) { firstDraw = NO; }else { self.originImage = image; } CGSize newSize = CGSizeMake(bgImageView.frame.size.width*scale, bgImageView.frame.size.height*scale); CGFloat widthRate = newSize.width/originImage.size.width; CGFloat heightRate = newSize.height/originImage.size.height; if (widthRate < 0.5 || heightRate < 0.5) { CGFloat lastTotalScale = totalScale; totalScale = 0.5; scale = totalScale/lastTotalScale; newSize = CGSizeMake(originImage.size.width*totalScale, originImage.size.height*totalScale); }else if (widthRate > 5 && heightRate > 5) { CGFloat lastTotalScale = totalScale; totalScale = 5; scale = totalScale/lastTotalScale; newSize = CGSizeMake(originImage.size.width*totalScale, originImage.size.height*totalScale); } sourceImage = [[self scaleFromImage:image toSize:newSize] retain]; totalScale = sourceImage.size.width/originImage.size.width; newSize = sourceImage.size; CGRect newBgRect; if (widthRate != heightRate) { //适应bgimageview大小 newBgRect = CGRectMake((self.frame.size.width*scale-newSize.width)/2, (self.frame.size.height*scale-newSize.height)/2, newSize.width, newSize.height); }else { newBgRect = CGRectMake(bgImageView.frame.origin.x*scale, bgImageView.frame.origin.y*scale, newSize.width, newSize.height); } bgImageView.frame = newBgRect; CGRect newChooseRect = CGRectMake(imageView.frame.origin.x*scale, imageView.frame.origin.y*scale, imageView.frame.size.width*scale, imageView.frame.size.height*scale); imageView.frame = newChooseRect; if (firstDraw) { bgImageView.image = sourceImage; } sx = (imageView.frame.origin.x > newBgRect.origin.x)? imageView.frame.origin.x : newBgRect.origin.x; sy = (imageView.frame.origin.y > newBgRect.origin.y)? imageView.frame.origin.y : newBgRect.origin.y; w = imageView.frame.size.width; h = imageView.frame.size.height; ex = sx+w; ey = sy+h; if (ex > newBgRect.origin.x+newBgRect.size.width) { sx = newBgRect.origin.x+newBgRect.size.width - w; } if (ey > newBgRect.origin.y+newBgRect.size.height) { sy = newBgRect.origin.x+newBgRect.size.height - h; } UIImage *endImage = [self imageFromImage:sourceImage inRect:CGRectMake(sx-newBgRect.origin.x, sy-newBgRect.origin.y, w, h)]; imageView.image = endImage; [aPool release];}- (UIImage *)getChoosenImage{ return imageView.image;}-(UIImage *)imageFromImage:(UIImage *)image inRect:(CGRect)rect{ //CGRect realRect = CGRectMake(rect.origin.x/totalScale , rect.origin.y/totalScale, rect.size.width/totalScale, rect.size.height/totalScale); CGRect realRect = rect;CGImageRef sourceImageRef = [image CGImage];CGImageRef newImageRef = CGImageCreateWithImageInRect(sourceImageRef, realRect); UIImage *newImage = [[[UIImage alloc] initWithCGImage:newImageRef] autorelease]; CGImageRelease(newImageRef); return newImage; } -(UIImage *)scaleFromImage:(UIImage *)image toSize:(CGSize)size{ CGFloat imageRate = image.size.width/image.size.height; CGFloat newRate = size.width/size.height; if (imageRate > newRate) { size.height = image.size.height * size.width/image.size.width; }else { size.width = image.size.width * size.height/image.size.height; } //scale = size.width/image.size.width * scale; UIGraphicsBeginImageContext(size); [image drawInRect:CGRectMake(0, 0, size.width, size.height)]; UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); //CGSize imgSize = newImage.size; return newImage;}-(CGFloat)spaceToPoint:(CGPoint)first FromPoint:(CGPoint)two{//计算两点之间的距离 float x = first.x - two.x; float y = first.y - two.y; return sqrt(x * x + y * y); }- (void)dealloc { [bgImageView removeFromSuperview]; [imageView removeFromSuperview]; [sourceImage release];[bgImageView release];[imageView release]; [originImage release]; [currentTouch release]; [super dealloc];}@end
- iphone图像裁剪功能实现
- iphone图像裁剪功能实现
- YII实现图像上传裁剪功能
- Android 实现最新版QQ图像裁剪功能
- iphone 实现裁剪图片
- 获取图像并裁剪,实现类似设置头像功能
- 图像裁剪的实现
- MapGIS裁剪功能实现
- JAVA实现图像ROI裁剪
- JQuery 图像裁剪插件Jcrop实现图片上传功能(mysql DB)
- canvas实现图片裁剪功能
- 扩展JLabel实现图像的裁剪
- C#实现图像的鼠标裁剪
- tensorflow实现图像的裁剪和填充
- tensorflow实现图像的等比例裁剪
- openCV实现鼠标响应裁剪图像
- 图像裁剪
- 图像裁剪
- Java的for循环新用法 -- foreach与数组
- SQL Server 2008开启远程连接
- Python中文乱码
- OpenGL中的glLoadIdentity、glTranslatef、glRotatef原理 (转载)
- 如何添加ActiveReports 6导出PDF时的安全设置和数字签名
- iphone图像裁剪功能实现
- 折半查找算法实现
- 嵌入式Linux之我行——ARM MMU工作原理剖析
- jquery的表单验证
- 利用WINDOWS命名漏洞等建立的特殊文件或文件夹
- ARM嵌入式学习自顶向下平台介绍和相关说明
- Android源码地址
- 8种nosql数据库系统对比
- 使用 jQuery dataTables