您的位置:首页 > 其它

iphone图像裁剪功能实现

2015-05-04 16:47 357 查看
这两天在做图像剪裁功能。一致在尝试不同的解决方案,包括从cocoachina查找的资料创意,一直不满意最终的效果。经过2天努力,终于完美实现。

方案实现功能如下:

1、可拖拽、缩放选区,截取所选区域部分图像

2、可缩放被裁剪图像,移动被裁剪图像,方便用户精确裁剪。

使用注意事项:

1、不要将代码实现的视图类实例添加为UIScrollView类实例的子视图。因为UIScrollView类实例会屏蔽子视图的拖拽事件(除非您自己实现一个子类,继承UIScrollView类,并按照苹果官方指南重写指定的几个方法。个人认为比较麻烦,而且不方便)。

2、若要获取选区对应的区域部分图像。使用

[plain]
view plaincopy

PictureCutView * pictureCutView;
pictureCutView.choosenImage; //获取选取区域部分图像对应的UIImage对象

方案已尽我最大努力实现优化,如果您有更好的优化意见,欢迎留言提出。

附注:

1、本代码部分参考网上资料,部分代码来源与网上。

2、本人保留代码的版权,如需使用代码,请保留版权说明。

[plain]
view plaincopy

//
// 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

[plain]
view plaincopy

//
// 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: