一个绘画的Demo

郁景龙
2023-12-01

最近,在做关于绘图方面,使用了很多种但是都出现了一些问题。使用opengl绘制,画出的线条不平滑。在使用UIBezierPath绘制时,在实现擦除时有困难还没有找到解决方法。在使用CGMutablePathRef绘制时,每一笔都保存在一个Path数组中,由于是在每次画下一笔的时候,都会对前面的绘图进行重绘导致到后面绘画很卡。下面是经过比较最好的一种方法,每次将绘制的保存为一张图片下次画时再重新加载。实现了颜色,线条粗细,擦除,撤销,清除基本功能。

@interface SmoothLineView : UIView {
    @private
    CGPoint currentPoint;
    CGPoint previousPoint1;
    CGPoint previousPoint2;
    CGFloat lineWidth;
    UIColor *lineColor;
    UIImage *curImage;
    BOOL isErase;
    CGContextRef context;
    NSUndoManager *undoManager;
}
@property (nonatomic, retain) UIColor *lineColor;
@property (readwrite) CGFloat lineWidth;
@property (nonatomic,assign)BOOL isErase;
@property (nonatomic, retain)NSUndoManager *undoManager;
-(void)clear;
-(void)undo;
- (UIImage *)imageRepresentation;
@end


#import "SmoothLineView.h"
#import <QuartzCore/QuartzCore.h>

#define DEFAULT_COLOR [UIColor blackColor]
#define DEFAULT_WIDTH 5.0f

@interface SmoothLineView () 

#pragma mark Private Helper function

CGPoint midPoint(CGPoint p1, CGPoint p2);

@end

@implementation SmoothLineView

@synthesize isErase;
@synthesize undoManager;
#pragma mark -

-(void)setup
{
    self.lineWidth = DEFAULT_WIDTH;
    self.lineColor = DEFAULT_COLOR;
    NSUndoManager *tempUndoManager = [[NSUndoManager alloc] init];
    [tempUndoManager setLevelsOfUndo:10];
    [self setUndoManager:tempUndoManager];
    [tempUndoManager release];
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.backgroundColor = [UIColor clearColor];
        [self setup];
    }
    return self;
}

-(id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        [self setup];
    }
    return self;
}

#pragma mark Private Helper function

CGPoint midPoint(CGPoint p1, CGPoint p2)
{
    return CGPointMake((p1.x + p2.x) * 0.5, (p1.y + p2.y) * 0.5);
}


-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [[self.undoManager prepareWithInvocationTarget:self] setImage:[self imageRepresentation]];
    
    UITouch *touch = [touches anyObject];
    
    previousPoint1 = [touch previousLocationInView:self];
    previousPoint2 = [touch previousLocationInView:self];
    currentPoint = [touch locationInView:self];
    
    [self touchesMoved:touches withEvent:event];
}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    
    UITouch *touch  = [touches anyObject];
    
    previousPoint2  = previousPoint1;
    previousPoint1  = [touch previousLocationInView:self];
    currentPoint    = [touch locationInView:self];
    
    // calculate mid point
    CGPoint mid1    = midPoint(previousPoint1, previousPoint2); 
    CGPoint mid2    = midPoint(currentPoint, previousPoint1);
    
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, NULL, mid1.x, mid1.y);
    CGPathAddQuadCurveToPoint(path, NULL, previousPoint1.x, previousPoint1.y, mid2.x, mid2.y);
    CGRect bounds = CGPathGetBoundingBox(path);
    CGPathRelease(path);
    
    CGRect drawBox = bounds;
    
    //Pad our values so the bounding box respects our line width
    drawBox.origin.x        -= self.lineWidth * 2;
    drawBox.origin.y        -= self.lineWidth * 2;
    drawBox.size.width      += self.lineWidth * 4;
    drawBox.size.height     += self.lineWidth * 4;
    
    UIGraphicsBeginImageContext(drawBox.size);
	[self.layer renderInContext:UIGraphicsGetCurrentContext()];
	curImage = UIGraphicsGetImageFromCurrentImageContext();
    [curImage retain];
	UIGraphicsEndImageContext();
    
    [self setNeedsDisplayInRect:drawBox];
    //[self setNeedsDisplay];
    
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    //CGPathRelease(currentPath);
}

- (UIImage *)imageRepresentation {
    UIGraphicsBeginImageContext(self.bounds.size);
    [self.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *image= UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}
-(void)setImage:(UIImage *)image
{
    curImage = [image retain];
}
- (void)drawRect:(CGRect)rect
{
    [curImage drawAtPoint:CGPointMake(0, 0)];
    CGPoint mid1 = midPoint(previousPoint1, previousPoint2); 
    CGPoint mid2 = midPoint(currentPoint, previousPoint1);

    context = UIGraphicsGetCurrentContext(); 
    
    [self.layer renderInContext:context];

    CGContextMoveToPoint(context, mid1.x, mid1.y);
    CGContextAddQuadCurveToPoint(context, previousPoint1.x, previousPoint1.y, mid2.x, mid2.y); 
    CGContextSetLineCap(context, kCGLineCapRound);
    CGContextSetLineWidth(context, isErase? 20.0f:self.lineWidth);
    CGContextSetStrokeColorWithColor(context, isErase?[UIColor clearColor].CGColor:self.lineColor.CGColor);
    CGContextSetBlendMode(context, isErase ? kCGBlendModeDestinationIn:kCGBlendModeNormal);

    CGContextStrokePath(context);

    [super drawRect:rect];
    
    [curImage release];
    
}

- (void)dealloc
{
    self.lineColor = nil;
    [super dealloc];
}
-(void)clear
{
    //CGContextClearRect(context, CGRectMake(0, 60, 768, 1024));
    [self setImage:nil];
    previousPoint1=CGPointMake(0, 0);
    previousPoint2=CGPointMake(0, 0);
    currentPoint = CGPointMake(0, 0);
    [self setNeedsDisplay];
}
-(void)undo
{
    if ([self.undoManager canUndo]) {
        [self.undoManager undo];
        NSData *data;
        if (UIImagePNGRepresentation(curImage) == nil)
            data = UIImageJPEGRepresentation(curImage, 1);
        else
            data = UIImagePNGRepresentation(curImage);
        NSFileManager *fileManager = [NSFileManager defaultManager];
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);//程序文件夹主目录
        NSString *documentsDirectory = [paths objectAtIndex:0];//Document目录
        static int i =1;
        [fileManager createFileAtPath:[documentsDirectory stringByAppendingString:[NSString stringWithFormat:@"/image%d.png",i++]] contents:data attributes:nil];
        previousPoint1=CGPointMake(0, 0);
        previousPoint2=CGPointMake(0, 0);
        currentPoint = CGPointMake(0, 0);
        [self setNeedsDisplay];
    }
}
@synthesize lineColor,lineWidth;
@end


 类似资料: