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


原创粉丝点击