[ 登录注册 ]

ios

iphone图像裁剪功能实现

2016-08-11 11:18:57 admin 返回上一页

这两天在做图像剪裁功能。一致在尝试不同的解决方案,包括从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;
   
@private
 UIImageView *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

 作者“一样的世界,不一样的时间”
 

点击复制链接 与好友分享!回本站首页

文章来源:http://www.bozhiyue.com/ios/2016/0811/364072.html
返回上一页    返回分类 上一篇:   下一篇:
相关