2012-08-14 72 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事件,所以這種方式,不再是我拿畫的圖像的一部分,越硬「畫筆「畫(看黑線)。