How to get pixel perfect drawing with cocoa - cocoa

I'm trying to draw some of my UI elements in Cocoa, mainly icons for buttons, but I'm having great difficulty getting the kind of precision I'd like.
I'm using super simple code like this to draw rectangles:
[[NSColor redColor] set];
[NSBezierPath strokeRect:myRect];
But what I'm seeing is the red rectangle line is always faded.
What am I missing here?

The Cocoa coordinates actually specify the center of the pixel you want to draw. This means, for example, if you want to draw on the bottom left pixel, you should use the coordinates (0.5,0.5).
Add/Subtract half a pixel to your coordinates and they should be pixel-perfect.

You can disable antialiasing for your graphics context like this:
[[NSGraphicsContext currentContext] setShouldAntialias:NO];
Or you could use NSFrameRect instead of a bezier path, and that would get the precision you want, while keeping antialiasing on:
NSFrameRect(myRect);

Related

Radial Gradient with Image IOS

I have a lot of different images in feed, that should be looking like this
http://s014.radikal.ru/i327/1603/14/97b12afe691f.png
In Sketch it s done by mask with RadialGradient. So i tried this way, but:
if i add a layer with gradient above, image is not transparent
if i redraw image with Quartz - i get lags and it is not transparent as it should be
I know it should be easy. Really easy. Please, someone - give me a clue!
Here is my gradient:
let colors: [CGFloat] = [ 88/255, 176/255, 113/255, 0.64, 90/255, 125/255, 113/255, 0.17, 88/255, 92/255, 110/255, 0.01]
let gradient = CGGradientCreateWithColorComponents(baseSpace, colors, [0.0, 0.7, 0.85], 3)
CGContextDrawRadialGradient(context, gradient, center, 10, center, self.size.width/2, .DrawsAfterEndLocation)
Create a CALayer the same size as your image. Draw your gradient into an image and install that CGImage as the contents of the layer. Them make the layer the mask of your image view's layer.
Take a look at my development blog entry ImageViewWithMask for a working example of using mask layers in Swift. (In my example I use a CAShapeLayer to draw a hard-edged mask. You will need to adapt it to use a gradient instead).
You should be able to use a CAGradientLayer, but those don't look like they support radial gradients. They have a gradient type property, but the only supported type appears to be Axial, which is silly.

NSBezierPath: how to invert the clip path?

I am drawing a rounded image in the centre of my custom view by creating a rounded NSBezierPath and adding it to the clipping region of the graphics context. This is working well, but I'm wondering if I can improve the performance of drawing the background of the view (the area outside of the rounded centred image) but inverting this clip and performing the background draw (an NSGradient fill).
Can anyone suggest a method of inverting a clip path?
You won't improve the drawing performance of the background by doing this. If anything, using a more complex clipping path will slow down drawing.
If you want to draw objects over a background without significant overhead of redrawing the background, you could use Core Animation layers as I explained in my answer to this question.
Regardless of performance, this question comes first when you try to invert clip.
So if that's what you're looking for:
Using NSBezierPath addClip - How to invert clip

Cocos2d: how to make a drawn circle doing scale or fade out animation

I know how to draw a circle in cocos2d & I know how to do cocos2d animation (scale and fade) with a ccsprite(loaded from a png file).
But I am wondering is it possible to store a drawn circle(in draw function) somehow and do animation with it just we normally do with ccsprite.
Thanks
Have a look at the inner workings of your animations and you should be able to piece together the rest.
Take a look at CCScaleTo for example. If you look at its update: function, all it does is change the scale of the CCNode it links to over time.
You should make your circle by extending CCSprite (or CCNode) and overriding the draw function. Here you can just call super to handle the translation or if you need a bit more control, you should modify your translation matrix yourself to take the position, rotation, scale into account (e.g. glScalef(x, y, z)) with OpenGLES.
-(void) draw
{
[super draw];
//Your draw code for the circle.
}

Multiplying colors when compositing with Quartz

I'm trying to draw an image with a certain color. To get this effect, first I draw the image (consisting of mostly white and black), and then I draw a rectangle over it in a specified color (let's say red). There are various compositing options available, but none are exactly what I want.
I want the colors (and alpha values) to be multiplied together. I think this is sometimes called a "Modulate" operation in other graphics systems. So, the white values in the image will be multiplied by the red values in the overlay rectangle to produce red. The black values in the image will be multiplied with black to product black.
In other words, R = S * D (result equals source multiplied by destination).
This is the code I'm working with now:
[image drawInRect:[self bounds] fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1];
NSColor * blend = [NSColor colorWithCalibratedRed:1 green:0 blue:0 alpha:1.0];
[blend setFill];
NSRectFillUsingOperation(self.bounds, NSCompositePlusDarker);
NSCompositePlusDarker is NOT what I want, but it's close. (It's addition instead of multiplication).
Is there a way to do this in Quartz? It's very easy to do in OpenGL for instance. I've looked at CIFilter's but they seem a bit cumbersome for this. But if that's the only way, I would appreciate any sample code to get me in the right direction.
Yes.
Note that AppKit compositing operations and Quartz blend modes, though there are quite a few in common, are not interchangeable. kCGBlendModeMultiply has the same numeric value as NSCompositeCopy, so the latter—flat overwriting—is what will happen if you try to pass it to any of AppKit's drawing APIs.
So, you'll need to use Quartz for every part of the fill. You can use NSGraphicsContext to get the CGContext you'll need, and you can ask your NSColor for its CGColor.

NSDrawNinePartImage gaps

I am working on drawing custom buttons/textfields with NSDrawNinePartImage. I slice up an image into nine parts in code and draw it into a rect with NSDrawNinePartImage.
Unfortunately I am getting some gaps in the drawing pattern. I thought it had something to do with my slicing code, but I saved them out as images from where I slice them, and they all look good (I even put them together and they looked good). Some of the cases where I use it to work just fine though despite some using the same images.
I am pretty confident that it comes down to the actual drawing.
Do you know of any NSGraphicsContext or other settings that would affect it or something else that may be causing this?
With gaps
Without gaps
I fixed a similar issue by disable the anti-alias option
NSGraphicsContext* theContext = [NSGraphicsContext currentContext];
[theContext saveGraphicsState];
[theContext setShouldAntialias: NO];
NSDrawNinePartImage(...);
[theContext restoreGraphicsState];
Is it possible that your upper left and lower right images are a pixel too wide?
This function uses the top-left and bottom-right corner images to
determine the widths and heights of the edge areas that need to be
filled. If the width or height of the bottom-left and top-right images
are not sized appropriately, they may be scaled to fill their corner
area. Edge areas between the corners are tiled using the corresponding
image. Similarly, the center area is tiled using the specified center
image.
Use even sizes in images. I did this, and it solved this problem for me.

Resources