Dureza de pincel iOS como Photoshop

¿Cómo get el siguiente efecto de suavidad (dureza) del pincel como el photoshop?

Mi bash:

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

Intenté ajustar los valores alfa y el factor de desenfoque de sombra, pero no obtuve ningún resultado exitoso.

¿Alguien tiene una solución para esto? Cualquier ayuda sería apreciada.

En esta image, puede ver el siguiente resultado del código. Creo que es casi igual a lo que quieres.

introduzca la descripción de la imagen aquí

La sombra externa no es suficiente para dar ese efecto suave, por eso agrego sombras internas para dar forma con el color blanco.

 - (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); // Shadows UIColor* shadow = UIColor.networkingColor; 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.networkingColor 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); } 

Con respecto al tamaño de la forma, debe ajustar el radio de desenfoque de las sombras tanto internas como externas.

Puede get un efecto similar al que intenta lograr al mezclar su sombra con su trazo

 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 el modo de fusión Multiplicar, usar el color blanco como color del trazo y configurar el color del pincel que desea para la sombra, obtendrá el siguiente resultado:

introduzca la descripción de la imagen aquí

He conectado la function de dibujo al evento touchMoved, así que cuanto más time tome para pintar una parte de la image, más difícil será dibujar "Brush" (vea la línea negra).

Probablemente esta no sea la respuesta perfecta, pero es lo mejor que puedo hacer para mis necesidades.

Coge el FXBlurView: https://github.com/nicklockwood/FXBlurView

Puede dibujar sus trazos en un FXBlurView o convertir su UIView a UIImage después de que haya terminado de dibujar (usando el código que tomé de esta respuesta 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; } 

y usa la categoría FXBlurView en UIImage:

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

para difuminar la image resultante, dándole un aspecto pincel suave de Photoshop.

Todavía estoy buscando una respuesta real. Tengo un proyecto OpenCV que requiere una réplica exacta de la herramienta de pincel suave de Photoshop.

He estado trabajando en dibujar el path con resplandor interno, y de alguna manera tuve éxito (al less para mi gusto).

He implementado el código de dibujo en la parte superior de la Smooth-Line-View de Levinunnick . El código es licenciado por MIT, por lo que deberá agregarlo a su proyecto.

Actualmente puede asignar el color de línea, el ancho y la suavidad de la línea que desea dibujar. Tenga cuidado con la suavidad, use un flotador entre 0 y 1. He cambiado los methods táctiles porque necesitaba acceder a los methods de dibujo desde otra vista. Compruebe el código original, si desea volver a los methods táctiles.

No optimicé el código, si tienes una idea mejor, simplemente edita esta respuesta.

Aquí está el 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 

Este es el file M:

 #import "LineView.h" static const CGFloat kPointMinDistance = 0.05f; static const CGFloat kPointMinDistanceSquanetworking = 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 ) < kPointMinDistanceSquanetworking ) { 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