How to Darken an Irregularly Shaped Transparent CALayer on the iPhone? - iphone

I'm putting an image into a CALayer that could be irregularly transparent:
theCardLayer.front = [CALayer layer];
theCardLayer.front.contents = (id)[cardDrawing CGImage];
In other words, it might be a square filling the layer or it might be an octagon that leaves the corners see-through.
I want to sometimes darken this layer, but without darkening the see-through bits. Any suggestions for how to do so in a programmatic way?

Take a look at CGBlendMode; a multiply blend, done by creating a new CGBitmapContext, drawing the image and then a grey fill, and assigning the resulting image to your layer, should work nicely.

You can use a CGShapeLayer. Set it's path to the shape you want to draw. You can also use shape layers as masks for other layers, if that's what you want.

Related

iOS Sprite Kit - SKSpriteNode - blend two sprites

Actually, I'm migrating a game from another platform, and I need to generate a sprite with two images.
The first image will be something like the form, a pattern or stamp, and the second is only a rectangle that sets color to the first. If the color was plane, it will be easy, I could use sprite.color and sprite.colorBlendFactor to play with it, but there are levels where the second image is a rectangle with two colors (red and green, for example).
Is there any way to implement these with Sprite Kit?
I mean, something like using Core image filter, and CIBlendWithAlphaMask, but only with Image and Mask image. (https://developer.apple.com/library/ios/documentation/graphicsimaging/Reference/CoreImageFilterReference/Reference/reference.html#//apple_ref/doc/uid/TP40004346) -> CIBlendWithAlphaMask.
Thanks.
Look into the SKCropNode class (documentation here) - it allows you to set a mask for an image underneath it.
In short, you would create two SKSpriteNodes - one with your stamp, the other with your coloured rectangle. Then:
SKCropNode *myCropNode = [SKCropNode node];
[myCropNode addChild:colouredRectangle]; // the colour to be rendered by the form/pattern
myCropNode.maskNode = stampNode; // the pattern sprite node
[self addChild:myCropNode];
Note that the results will probably be more similar to CIBlendWithMask rather than CIBlendWithAlphaMask, since the crop node will mask out any pixels below 5% transparency and render all pixels above this level, so the edges will be jagged rather than smoothly faded. Just don't use any semi-transparent areas in your mask and you'll be fine.

CAShapeLayer annoying clipping error

I am working on a map functionality. The map is built up out of multiple CAShapeLayers with CGPaths from calculated coordinates. I have a clipping problem. Look below on the screenshot where Alaska is badly clipped. The coordinates of the Alaska path extend beyond the bounds of my container layer. In effect, if i make my container layer big enough the clipping effect is gone (of course).
You see a dark line because at the bottom of Alaska is solid from left to right. Also the line is darker than the rest of the map because the map has opacity (it gets darker because it adds up).
I drilled down into the problem and i have narrowed it down to the single big polygon (there are not other polygons responsible for the clipping error).
As a workaround, i make the layer bigger to hide the line, then make the UIView smaller again to hide the line.
I'd like to know what is causing the issue instead of working with workarounds.
After a lot of digging, i managed to find an answer to my own question.
I was rendering the layers to an UIImage for improved performance. The background layer was scaled up by a UIScrollView and then several things went wrong:
Apparently, setting masksToBounds:YES has no effect when using renderInContext, just as it does with the mask property of a CALayer. MasksToBounds (or clipToBounds) only applies to childlayers.
When scaling a bitmap, be sure to include integral values to the scale argument of UIGraphicsBeginImageContextWithOptions. If not, the image will have fractional sizes, e.g. 24.2323 x 34.3290. Btw, that scale argument is used to create amazing detail on Retina screens, but it can be misused to zoom in on CAShapeLayer drawings.
When using fractional size images as a background layer, you get distortion at the edge.
The clipping effect disappeared after i updated my layer to image function. This one did the trick:
- (UIImage *)getImageWithSize:(CGSize)size opaque:(bool)opaque contentScale:(CGFloat)scale
{
CGContextRef context;
size = CGSizeMake(ceilf(size.width), ceilf(size.height));
scale = roundf(scale);
UIGraphicsBeginImageContextWithOptions(size, opaque, scale);
context = UIGraphicsGetCurrentContext();
[self renderInContext:context];
UIImage *outputImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return outputImg;
}
Using ceilf, roundf, or floorf didn't really matter. As long as you lose the fractions.
Sorry if my stupidity wasted any of your time, but perhaps others have the same issue.

CGPath masked off CGPoints

I'm trying to build this:
Where the white background is in fact transparent. I know how to clip a CGPath to a set region, but this seems to be to other way around, since I need to substract regions from a filled CGPath.
I guess the right way to go would be to substract the whole outer-circles from the CGPath and then to draw smaller circles at my CGPoints, but I'm not sure how to execute the former. Can anyone point me in the right direction?
That's what I would do :
1) Draw your general line
2) CGContextSetBlendMode(context, kCGBlendModeClear) to "clear the context" when you draw.
3) Draw you bigger circles
4) CGContextSetBlendMode(context, kCGBlendModeNormal) to return to normal drawing
5) Draw your little circles.
You could instead start a transparency layer, draw the lines, then draw the larger transparent circles using the clear color, then draw the smaller black circles. Then when you finish the transparency layer, it will composite exactly what you want back onto the context.

Is there a simple way to let a layer throw an smooth shadow?

I was drawing a path into a layer. Lets say I can't access that drawing code in any way, because it comes from a compiled lib. Now I want to let that layer throw a shadow which matches the shape of its irregular content shape.
Is there an easy way to do it? Or must I draw like 20 of those layers and scale them up on every iteration, adjusting their alpha and letting the GPU do the extraordinarily heavy compositing?
every CALayer has the following properties:
shadowOpacity
shadowRadius
shadowOffset
shadowColor
shadowPath
If you set shadowOpacity to something other than 0 (the default) you'll see a shadow.
(CALayer docs)

vertical color gradient

Horizontal gradient is working fine. Is there any way to get a vertical color gradient from horizontal gradient?
I have seen a related question regarding this where they did this by rotating the frames.
Is there any simpler way to achieve a vertical gradient?
The default startPoint and endPoint would have the gradient display your colors from top to bottom (which in my mind is a vertical gradient). If you want the gradient to display from left to right (again in my mind this is a horizontal gradient), use this code on your CAGradientLayer:
[gradientLayer setStartPoint:CGPointMake(0.0, 0.5)];
[gradientLayer setEndPoint:CGPointMake(1.0, 0.5)];
A 3D transform is unnecessary.
How about rotating it 90ยบ?
edit judging from your comment, it seems that you're doing this via CAGradientLayer. CAGradientLayer is a subclass of CALayer, which has a transform property. This transform property takes a CATransform3D, which is a struct that represents some sort of linear transformation to be applied to the layer (such as scaling, translation, or rotation).
So really you just need to make a rotational CATransform3D and set it as the transform property of your CAGradientLayer.
You could probably also make this work by fiddling with the startPoint and endPoint (which would actually probably be simpler).