一个绘画的Demo

最近,在做关于绘图方面,使用了很多种但是都出现了一些问题。使用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


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当您在Java程序中需要调用C/C++代码时,可以使用Java Native Interface(JNI)来实现。下面是一个简单的JNI示例,演示了如何将Java方法与C函数相互调用: 1. 创建一个Java类,例如"JNIDemo.java",其中包含您想要调用的本地方法: ```java public class JNIDemo { // 本地方法声明 public native void sayHello(); // 加载本地库 static { System.loadLibrary("jni_demo"); // 加载名为"jni_demo"的本地库 } // 测试 public static void main(String[] args) { JNIDemo demo = new JNIDemo(); demo.sayHello(); // 调用本地方法 } } ``` 2. 在命令行中使用`javac`编译Java类:`javac JNIDemo.java`。 3. 生成C头文件,可以使用`javah`工具:`javah JNIDemo`。这将生成名为"JNIDemo.h"的头文件。 4. 创建一个C源文件,例如"jni_demo.c",实现您在Java中声明的本地方法: ```c #include <stdio.h> #include "JNIDemo.h" JNIEXPORT void JNICALL Java_JNIDemo_sayHello(JNIEnv *env, jobject obj) { printf("Hello from C!\n"); } ``` 5. 在命令行中使用C编译器编译C源文件,并生成共享库文件(DLL或SO): - 对于Windows(使用MinGW):`gcc -shared -I"%JAVA_HOME%\include" -I"%JAVA_HOME%\include\win32" jni_demo.c -o jni_demo.dll` - 对于Linux/Mac:`gcc -shared -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/linux" jni_demo.c -o libjni_demo.so` 注意:请将`$JAVA_HOME`替换为您Java安装的实际路径。 6. 运行Java程序:`java JNIDemo`。您将看到输出:"Hello from C!"。 这是一个简单的JNI示例,演示了如何在Java和C之间进行方法调用。您可以根据自己的需求扩展和定制此示例。希望对您有帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值