objective-c drawing core-graphics quartz-graphics shadow

objective c - CoreGraphics Cuarzo dibujando sombra en un camino alfa transparente



objective-c drawing (4)

Por su solicitud en los comentarios, aquí hay una exploración más profunda. Considere la siguiente captura de pantalla (StackOverflow lo reduce para mí; ayuda a verlo en tamaño completo):

Lo que está viendo aquí es 5 enfoques de dibujo diferentes (de arriba a abajo) sobre tres fondos diferentes (de izquierda a derecha). (También he eliminado el alfa de relleno de 0,8 a 0,5 para que los efectos sean más fáciles de ver). Los tres enfoques de dibujo diferentes son (de arriba a abajo):

  1. Solo el trazo, no el relleno, con una sombra.
  2. La forma en que publicaste en el código en tu pregunta original
  3. El trazo y relleno, sin sombra aplicada.
  4. Sólo la sombra, por sí misma.
  5. El camino que propuso @ DavidRönnqvist en su respuesta.

Los tres orígenes diferentes deben ser auto explicativos.

Usted dijo en su pregunta original:

Lo primero que noto, la sombra es solo alrededor del trazo.

Por eso incluí el primer enfoque de dibujo. Eso es lo que realmente parece cuando hay solo un trazo, sin relleno, y (por lo tanto) solo el trazo está siendo sombreado.

Entonces, dijiste:

Pero ese no es el problema hasta ahora. La sombra detrás de la ruta / rect sigue siendo visible, lo que significa que el color de la sombra está efectuando el color de relleno de mi ruta. El color de relleno debe ser blanco pero en cambio es gris.

Su código original es la siguiente versión (# 2). Lo que está viendo allí es que la sombra para el trazo es más oscura que la sombra para el relleno. Esto se debe a que el alfa del color del trazo es 1.0 y el alfa del relleno es menor que 1.0 . Esto podría ser más fácil de ver en la versión # 4, que es solo la sombra: es más oscuro alrededor del borde donde se encuentra el trazo. La versión # 3 muestra el dibujo sin una sombra. ¿Ves que puedes ver el rojo y la imagen semi-obscura en el relleno de la forma? Así que en tu dibujo original estás viendo la propia sombra del objeto a través del objeto mismo.

Si eso no tiene sentido, intente pensar en un pedazo de vidrio que tenga un tinte (si le gusta la fotografía, piense en un filtro de densidad neutra ). Si mantienes ese vidrio entre una fuente de luz y otra superficie, y luego miras por el costado y miras la superficie inferior, sabes que el vidrio semitransparente proyectará una sombra, pero no una sombra tan oscura como algo. Completamente opaco (como un pedazo de cartón). Esto es lo que estás viendo: estás mirando a través del objeto a su sombra.

La versión # 5 es el enfoque de @DavenRönnqvist. El efecto alucinante del que estaba hablando en mi comentario es más fácil de apreciar (para mí, de todos modos) al observar las formas dibujadas sobre el fondo de la imagen. El aspecto que tiene (en la versión # 5) es que la forma es una parte de la imagen bordeada y copiada que se ha superpuesto con una máscara blanca semitransparente de algún tipo. Si miras hacia atrás a la versión # 3, está claro, en ausencia de la sombra, lo que está pasando: estás mirando a través de la forma semitransparente a la imagen de abajo. Luego, si observa la versión # 4, también está claro que tiene una sombra proyectada por un objeto que está detrás de su ojo / cámara. A partir de ahí, diría que eso también es claro cuando se mira la versión # 2 sobre la imagen que está pasando (incluso si es menos clara sobre un color sólido). A primera vista, mi ojo / cerebro no sabe lo que está viendo en la versión 5: hay un momento de "disonancia visual" antes de establecer el modelo mental de "parte de la imagen copiada, enmascarada, que flota sobre el original". imagen."

Entonces, si ese efecto (# 5) era lo que buscabas, entonces la solución de David funcionará muy bien. Solo quería señalar que es una especie de efecto no intuitivo.

Espero que esto sea de ayuda. He puesto el proyecto de muestra completo que utilicé para generar esta captura de pantalla en GitHub .

Buscando en la web durante aproximadamente 4 horas no obteniendo respuesta, entonces:
¿Cómo dibujar una sombra en un camino que tiene transparencia?

- (void)drawRect:(CGRect)rect { CGContextRef c = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(c, 2); CGContextSetStrokeColorWithColor(c, [[UIColor whiteColor] CGColor]); CGContextSetShadowWithColor(c, CGSizeMake(0, 5), 5.0, [[UIColor blackColor]CGColor]); CGContextSetFillColorWithColor(c, [[UIColor colorWithWhite:1.0 alpha:0.8] CGColor]); // Sample Path CGContextMoveToPoint(c, 20.0, 10.0); CGContextAddLineToPoint(c, 100.0, 40.0); CGContextAddLineToPoint(c, 40.0, 70.0); CGContextClosePath(c); CGContextDrawPath(c, kCGPathFillStroke); }

Lo primero que noto, la sombra es solo alrededor del trazo. Pero ese no es el problema hasta ahora. La sombra detrás de la ruta / rect sigue siendo visible, lo que significa que el color de la sombra está efectuando el color de relleno de mi ruta. El color de relleno debe ser blanco pero en cambio es gris. ¿Cómo resolver este problema?


Tendrás que recortar el contexto y dibujar dos veces.

Primero, crea una referencia a su ruta, ya que tendrá que usarla varias veces y guardar el contexto de sus gráficos para que pueda volver a ella.

Luego, recorta el contexto de los gráficos en un único dibujo fuera de su ruta. Esto se hace agregando su ruta a la ruta que cubre toda la vista. Una vez que hayas recortado, dibuja tu camino con la sombra para que se dibuje en el exterior.

A continuación, restaura el contexto de los gráficos al estado en que se encontraba antes de recortar y dibuja su ruta nuevamente sin la sombra.

Se verá así en un fondo naranja (el fondo blanco no era muy visible)

El código para hacer el dibujo de arriba es este:

- (void)drawRect:(CGRect)rect { CGContextRef c = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(c, 2); CGContextSetStrokeColorWithColor(c, [[UIColor whiteColor] CGColor]); CGContextSetFillColorWithColor(c, [[UIColor colorWithWhite:1.0 alpha:0.5] CGColor]); // Sample Path CGMutablePathRef path = CGPathCreateMutable(); CGPathMoveToPoint(path, NULL, 20.0, 10.0); CGPathAddLineToPoint(path, NULL, 40.0, 70.0); CGPathAddLineToPoint(path, NULL, 100.0, 40.0); CGPathCloseSubpath(path); // Save the state so we can undo the shadow and clipping later CGContextSaveGState(c); { // Only for readability (so we know what are inside the save/restore scope CGContextSetShadowWithColor(c, CGSizeMake(0, 5), 5.0, [[UIColor blackColor]CGColor]); CGFloat width = CGRectGetWidth(self.frame); CGFloat height = CGRectGetHeight(self.frame); // Create a mask that covers the entire frame CGContextMoveToPoint(c, 0, 0); CGContextAddLineToPoint(c, width, 0); CGContextAddLineToPoint(c, width, height); CGContextAddLineToPoint(c, 0, height); CGContextClosePath(c); // Add the path (which by even-odd rule will remove it) CGContextAddPath(c, path); // Clip to that path (drawing will only happen outside our path) CGContextClip(c); // Now draw the path in the clipped context CGContextAddPath(c, path); CGContextDrawPath(c, kCGPathFillStroke); } CGContextRestoreGState(c); // Go back to before the clipping and before the shadow // Draw the path without the shadow to get the transparent fill CGContextAddPath(c, path); CGContextDrawPath(c, kCGPathFillStroke); }

Si desea que toda la sombra sea tan fuerte y no desea que la transparencia del color de relleno la debilite, entonces puede usar un color totalmente opaco al rellenar la primera vez. Se cortará para que no se vea en el camino. Solo afectará a la sombra.


CGFloat lineWidth = 2.0f; CGContextRef c = UIGraphicsGetCurrentContext(); CGContextSaveGState(c); CGContextSetLineWidth(c, lineWidth); CGContextSetStrokeColorWithColor(c, [[UIColor whiteColor] CGColor]); CGContextSetShadowWithColor(c, CGSizeMake(0, 5), 5.0, [[UIColor blackColor]CGColor]); CGContextAddRect(c, someRect); CGContextDrawPath(c, kCGPathStroke); CGContextRestoreGState(c); someRect.origin.x += lineWidth/2; someRect.origin.y += lineWidth/2; someRect.size.width -= lineWidth; someRect.size.height -= lineWidth; CGContextClearRect(c, someRect); CGContextSetFillColorWithColor(c, [[[UIColor whiteColor] colorWithAlphaComponent:0.8] CGColor]); CGContextAddRect(c, someRect); CGContextDrawPath(c, kCGPathFill);


NSShadow* shadow = [[NSShadow alloc] init]; [shadow setShadowColor: [NSColor blackColor]]; [shadow setShadowOffset: NSMakeSize(2.1, -3.1)]; [shadow setShadowBlurRadius: 5]; NSBezierPath* bezierPath = [NSBezierPath bezierPath]; [bezierPath moveToPoint: NSMakePoint(12.5, 6.5)]; [bezierPath curveToPoint: NSMakePoint(52.5, 8.5) controlPoint1: NSMakePoint(40.5, 13.5) controlPoint2: NSMakePoint(52.5, 8.5)]; [bezierPath lineToPoint: NSMakePoint(115.5, 13.5)]; [bezierPath lineToPoint: NSMakePoint(150.5, 6.5)]; [bezierPath lineToPoint: NSMakePoint(201.5, 13.5)]; [bezierPath lineToPoint: NSMakePoint(222.5, 8.5)]; [NSGraphicsContext saveGraphicsState]; [shadow set]; [[NSColor blackColor] setStroke]; [bezierPath setLineWidth: 1]; [bezierPath stroke]; [NSGraphicsContext restoreGraphicsState];