2012-08-14 37 views
5

如何获得像Photoshop一样的以下笔刷光滑度(硬度)效果? iOS Photoshop笔刷硬度像Photoshop一样

我尝试:

CGContextRef context = UIGraphicsGetCurrentContext(); 
CGContextSaveGState(context); 
CGContextSetLineCap(context, kCGLineCapRound); 
CGContextSetLineWidth(context, 30); 
CGContextSetStrokeColorWithColor(context, [UIColor colorWithRed:1.0f green:0.0f blue:0.0f alpha:0.5f].CGColor); 
CGContextSetShadowWithColor(context, CGSizeMake(0, 0), 20.0f, [UIColor colorWithRed:1.0f green:0.0f blue:0.0f alpha:1.0f].CGColor); 
CGContextAddPath(context, path); 
CGContextStrokePath(context); 
CGContextRestoreGState(context); 

我试图调整Alpha值,阴影模糊的因素,但没有成功的结果。

有没有人有解决这个问题?任何帮助,将不胜感激。

回答

11

在这张图片您可以看到下面的代码结果。我相信它与你想要的几乎相同。

enter image description here

只是外部阴影不只是足以让那光滑的效果,这就是为什么我添加一些内阴影与白色来塑造。

- (void)drawRect:(CGRect)rect { 

    CGContextRef context = UIGraphicsGetCurrentContext(); 

    // Shadows 
    UIColor* shadow = UIColor.redColor; 
    CGSize shadowOffset = CGSizeMake(0.1, -0.1); 
    CGFloat shadowBlurRadius = 11; 
    UIColor* shadow2 = UIColor.whiteColor; // Here you can adjust softness of inner shadow. 
    CGSize shadow2Offset = CGSizeMake(0.1, -0.1); 
    CGFloat shadow2BlurRadius = 9; 

    // Rectangle Drawing 
    UIBezierPath* rectanglePath = [UIBezierPath bezierPathWithRoundedRect: CGRectMake(59, 58, 439, 52) cornerRadius: 21]; 
    CGContextSaveGState(context); 
    CGContextSetShadowWithColor(context, shadowOffset, shadowBlurRadius, [shadow CGColor]); 
    [UIColor.redColor setFill]; 
    [rectanglePath fill]; 

    // Rectangle Inner Shadow 
    CGContextSaveGState(context); 
    UIRectClip(rectanglePath.bounds); 
    CGContextSetShadowWithColor(context, CGSizeZero, 0, NULL); 

    CGContextSetAlpha(context, CGColorGetAlpha([shadow2 CGColor])); 
    CGContextBeginTransparencyLayer(context, NULL); 
    { 
     UIColor* opaqueShadow = [shadow2 colorWithAlphaComponent: 1]; 
     CGContextSetShadowWithColor(context, shadow2Offset, shadow2BlurRadius, [opaqueShadow CGColor]); 
     CGContextSetBlendMode(context, kCGBlendModeSourceOut); 
     CGContextBeginTransparencyLayer(context, NULL); 

     [opaqueShadow setFill]; 
     [rectanglePath fill]; 

     CGContextEndTransparencyLayer(context); 
    } 
    CGContextEndTransparencyLayer(context); 
    CGContextRestoreGState(context); 

    CGContextRestoreGState(context); 
} 

关于形状的大小,您必须调整内部和外部阴影模糊半径。

+0

它看起来像你正在使用矩形?你会如何做到这一点中风? – ninjaneer 2014-08-09 00:17:09

+0

@Ninja是的,它是矩形,你想在'touchesMoved'中画线并且有相同的影响吗? – mohacs 2014-08-09 00:57:46

+0

我不知道这会如何影响性能,但如果它达到了中风路径的效果,那就没问题。 – ninjaneer 2014-08-09 00:59:02

1

这可能不是最完美的答案,但这是我能够满足我需求的最佳选择。

抓住FXBlurView:https://github.com/nicklockwood/FXBlurView

您可以绘制笔划上FXBlurView或你的UIView绘制好后转换成的UIImage(使用我从这个答案https://stackoverflow.com/a/22494886/505259接过代码):

+ (UIImage *) imageWithView:(UIView *)view 
{ 
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0f); 
    [view drawViewHierarchyInRect:view.bounds afterScreenUpdates:NO]; 
    UIImage * snapshotImage = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 
    return snapshotImage; 
} 

,并使用FXBlurView的类别上的UIImage:

- (UIImage *)blurredImageWithRadius:(CGFloat)radius 
         iterations:(NSUInteger)iterations 
          tintColor:(UIColor *)tintColor; 

模糊产生的图像,给它像软外观一样的Photoshop软刷。

虽然我仍然在寻找真正的答案。我有一个OpenCV项目,需要Photoshop的软刷工具的精确副本。

0

我一直对绘画与内发光的路径,并以某种方式成功(至少对我的口味)。

我实现了在levinunnick's Smooth-Line-View顶部的绘制代码。该代码是MIT许可的,因此您需要将其添加到您的项目中。

目前,您可以指定线的颜色,宽度和你想画线的平滑度。注意平滑度,使用0到1之间的浮点数。我更改了触摸方法,因为我需要从另一个视图访问绘图方法。如果您想恢复到触摸方式,请检查原始代码。

我没有优化代码,如果你有更好的主意,只需编辑这个答案。

这里是.h文件:

@interface LineView : UIView 
- (instancetype)initWithFrame:(CGRect)frame andColor:(UIColor *)lineColor andWidth:(CGFloat)lineWidth andSmoothness:(CGFloat)lineSmooth;  
- (void)touchStartedWith:(CGPoint)location;  
- (void)touchMovedWith:(CGPoint)location; 
@end 

这是M档:

#import "LineView.h" 

static const CGFloat kPointMinDistance = 0.05f; 
static const CGFloat kPointMinDistanceSquared = kPointMinDistance * kPointMinDistance; 

@interface LineView() 
@property (strong) UIColor *lineColor; 
@property (assign) CGFloat lineWidth; 
@property (assign) CGFloat lineSmooth; 

@property (assign) CGPoint currentPoint; 
@property (assign) CGPoint previousPoint; 
@property (assign) CGPoint previousPreviousPoint; 
@end 

@implementation LineView 
{ 
@private 
    CGMutablePathRef _path; 
} 

- (instancetype)initWithFrame:(CGRect)frame andColor:(UIColor *)lineColor andWidth:(CGFloat)lineWidth andSmoothness:(CGFloat)lineSmooth 
{ 
    self = [super initWithFrame:frame]; 
    if (self) { 
    _path = CGPathCreateMutable(); 

    if (lineSmooth < 0) lineSmooth = 0; 
    if (lineSmooth > 1) lineSmooth = 1; 

    self.backgroundColor = [UIColor clearColor]; 
    self.lineColor = lineColor; 
    self.lineWidth = lineWidth; 
    self.lineSmooth = lineWidth * (lineSmooth/4); 
    self.opaque = NO; 
    } 
    return self; 
} 

- (void)drawRect:(CGRect)rect 
{ 
    [self.backgroundColor set]; 
    UIRectFill(rect); 

    @autoreleasepool { 

    CGColorRef theColor = self.lineColor.CGColor; 
    UIColor *theClearOpaque = [[UIColor whiteColor] colorWithAlphaComponent:1]; 

    CGContextRef context = UIGraphicsGetCurrentContext(); 
    CGContextAddPath(context, _path); 
    CGContextSetLineCap(context, kCGLineCapRound); 
    CGContextSetLineWidth(context, self.lineWidth); 
    CGContextSetStrokeColorWithColor(context, theColor); 

    // Outer shadow 
    CGSize shadowOffset = CGSizeMake(0.1f, -0.1f); 
    CGFloat shadowBlurRadius = self.lineSmooth; 
    CGContextSetShadowWithColor(context, shadowOffset, shadowBlurRadius, theColor); 

    CGContextStrokePath(context); 

    if (self.lineSmooth > 0) { 
     // Inner shadow 
     CGRect bounds = CGPathGetBoundingBox(_path); 
     CGRect drawBox = CGRectInset(bounds, -2.0f * self.lineWidth, -2.0f * self.lineWidth); 

     CGContextSaveGState(context); 
     UIRectClip(drawBox); 
     CGContextSetShadowWithColor(context, CGSizeZero, 0, NULL); 

     CGContextSetAlpha(context, CGColorGetAlpha(theClearOpaque.CGColor)); 
     CGContextBeginTransparencyLayer(context, NULL); 
     { 
     // Outer shadow 
     UIColor *oShadow = [theClearOpaque colorWithAlphaComponent:1]; 
     CGContextSetShadowWithColor(context, CGSizeMake(0.1f, -0.1f), self.lineWidth/64 * self.lineSmooth, oShadow.CGColor); 
     CGContextSetBlendMode(context, kCGBlendModeSourceOut); 
     CGContextBeginTransparencyLayer(context, NULL); 

     [oShadow setFill]; 

     // Draw the line again 
     CGContextAddPath(context, _path); 
     CGContextSetLineCap(context, kCGLineCapRound); 
     CGContextSetLineWidth(context, self.lineWidth); 
     CGContextSetStrokeColorWithColor(context, oShadow.CGColor); 
     CGContextStrokePath(context); 

     CGContextEndTransparencyLayer(context); 
     } 
     CGContextEndTransparencyLayer(context); 
     CGContextRestoreGState(context); 
    } 
    } 
} 

- (void)touchStartedWith:(CGPoint)location 
{ 
    self.previousPoint = location; 
    self.previousPreviousPoint = location; 
    self.currentPoint = location; 

    [self touchMovedWith:location]; 
} 

- (void)touchMovedWith:(CGPoint)location 
{ 
    CGRect drawBox; 

    @autoreleasepool { 
    CGFloat dx = location.x - self.currentPoint.x; 
    CGFloat dy = location.y - self.currentPoint.y; 

    if ((dx * dx + dy * dy) < kPointMinDistanceSquared) { 
     return; 
    } 

    self.previousPreviousPoint = self.previousPoint; 
    self.previousPoint = self.currentPoint; 
    self.currentPoint = location; 

    CGPoint mid1 = midPoint(self.previousPoint, self.previousPreviousPoint); 
    CGPoint mid2 = midPoint(self.currentPoint, self.previousPoint); 

    CGMutablePathRef subpath = CGPathCreateMutable(); 
    CGPathMoveToPoint(subpath, NULL, mid1.x, mid1.y); 
    CGPathAddQuadCurveToPoint(subpath, NULL, self.previousPoint.x, self.previousPoint.y, mid2.x, mid2.y); 

    CGRect bounds = CGPathGetBoundingBox(subpath); 
    drawBox = CGRectInset(bounds, -2.0f * self.lineWidth, -2.0f * self.lineWidth); 

    CGPathAddPath(_path, NULL, subpath); 
    CGPathRelease(subpath); 
    } 

    [self setNeedsDisplayInRect:drawBox]; 
} 

- (void)dealloc 
{ 
    CGPathRelease(_path); 
    _path = NULL; 
} 
@end 
3

你可以得到类似的效果,你想用混合你的影子来实现你的笔划

CGContextRef context = UIGraphicsGetCurrentContext(); 
CGContextAddPath(context, path); 
CGContextSetLineCap(context, kCGLineCapRound); 
CGContextSetLineWidth(context, self.lineWidth); 
CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor); 
CGContextSetShadowWithColor(context, CGSizeMake(0.f, 0.f), self.lineWidth/4, [self.lineColor CGColor]); 
CGContextSetBlendMode(context, kCGBlendModeMultiply); 
CGContextSetAlpha(context, self.lineAlpha); 
CGContextStrokePath(context); 

使用倍增混合模式,使用白色作为笔划颜色并设置刷子的颜色要的影子,你会得到以下结果:

enter image description here

我连绘图功能touchesMoved事件,所以这种方式,不再是我拿画的图像的一部分,越硬“画笔“画(看黑线)。