2012-08-14 10 views
5

Come ottenere l'effetto di levigatezza (durezza) di un pennello come Photoshop? Durezza pennello iOS come Photoshop

Il mio tentativo:

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); 

ho provato la regolazione valori alfa, e il fattore di ombra sfocatura, ma nessun risultato positivo.

Qualcuno ha una soluzione a questo? Qualsiasi aiuto sarebbe apprezzato.

risposta

11

Su questa immagine è possibile vedere il seguente risultato del codice. Credo che sia quasi uguale a quello che vuoi.

enter image description here

ombra Proprio esterna non è sufficiente per dare quel effetto liscio che è il motivo per cui aggiungo qualche ombra interiore per modellare con il colore bianco.

- (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); 
} 

quanto riguarda le dimensioni della forma è necessario regolare ombre sia interni ed esterni Raggio di sfocatura.

+0

sembra che tu stia usando un rettangolo? come lo faresti con un ictus? – ninjaneer

+0

@Ninja si è un rettangolo, vuoi disegnare la linea in 'tocchiMoved' e lo stesso effetto? – mohacs

+0

Non sono sicuro di come ciò influirebbe sulle prestazioni, ma se raggiunge l'effetto su un tracciato di ictus, allora andrebbe bene. – ninjaneer

1

Questa probabilmente non è la risposta perfetta, ma è il meglio che posso fare per le mie esigenze.

Afferra il FXBlurView: https://github.com/nicklockwood/FXBlurView

è possibile disegnare i tratti su un FXBlurView o convertire l'UIView per UIImage dopo che hai finito di disegnare (utilizzando il codice ho preso da questa risposta 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; 
} 

e categoria d'uso del FXBlurView su UIImage:

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

per sfocare l'immagine risultante, dandole un pennello morbido di Photoshop come l'aspetto.

Sto ancora cercando una vera risposta però. Ho un progetto OpenCV che richiede una replica esatta dello strumento pennello morbido di Photoshop.

0

Ho lavorato a disegnare il percorso con bagliore interno, e in qualche modo riuscito (almeno per i miei gusti).

Ho implementato il codice di disegno sopra levinunnick's Smooth-Line-View. Il codice è concesso in licenza MIT, quindi dovrai aggiungerlo al tuo progetto.

Attualmente è possibile assegnare il colore della linea, la larghezza e la levigatezza della linea che si desidera disegnare. Fai attenzione con la scorrevolezza, usa un float tra 0 e 1. Ho cambiato i metodi touch perché avevo bisogno di accedere ai metodi di disegno da un'altra vista. Controllare il codice originale, se si desidera ripristinare i metodi touch.

Non ho ottimizzato il codice, se hai un'idea migliore, modifica questa risposta.

Ecco il file 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 

Questo è il file 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

È possibile ottenere un effetto simile a quello che si sta cercando di ottenere mescolando la vostra ombra con il tuo ictus

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); 

Con metodo di fusione Moltiplica, usando il colore bianco come colore del tratto e l'impostazione del colore del pennello vuole l'ombra, si ottiene il seguente risultato:

enter image description here

Ho collegato la funzione di disegno all'evento touchesMoved, in modo che modo il più io vuole per dipingere una parte dell'immagine, più il " Pennello "disegna (vedi la linea nera).

Problemi correlati