i'm using drawRect inside a custom UIButton to draw a bordered button with an image inside. The code is the following:
- (void) drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
//Draw a rectangle
CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor);
CGContextSetStrokeColorWithColor(context, [[UIColor grayColor] CGColor]);
//Define a rectangle
CGRect drawrect = CGRectMake(CGRectGetMinX(rect),CGRectGetMinY(rect),rect.size.width,rect.size.height);
CGContextStrokeRect(context,drawrect);}
The problem is that on corners i got an extra pixel (see the attached image). What am i doing wrong?
thanks
You are drawing your rectangle along the edges of pixels, instead of drawing it along the centers of pixels. So your rectangle only covers half of most pixels. On the corners it covers three-quarters of the pixels.
To draw along the pixel centers, you have to use half-integer coordinates. Try this:
CGContextStrokeRect(context, CGRectInset(rect, 0.5, 0.5));
Related
I want to draw a circle on UIImageView. I have tried it but it didn't work.
This is a example image of what i want to achieve:
The circle should be drawn on where user taps on UIImageView and I want to do it without adding any sublayer.
Is it some way to do this?
so far i have used this code from the internet but it didn't worked.
- (UIImage *)imageByDrawingCircleOnImage:(UIImage *)image
pointX:(float) x
PointY:(float) y
{
// begin a graphics context of sufficient size
UIGraphicsBeginImageContext(image.size);
// draw original image into the context
[image drawAtPoint:CGPointZero];
// get the context for CoreGraphics
CGContextRef ctx = UIGraphicsGetCurrentContext();
// set stroking color and draw circle
[[UIColor redColor] setStroke];
// make circle rect 5 px from border
CGRect circleRect = CGRectMake(0, 0,
image.size.width,
image.size.height);
circleRect = CGRectInset(circleRect, x, y);
// draw circle
CGContextStrokeEllipseInRect(ctx, circleRect);
// make image out of bitmap context
UIImage *retImage = UIGraphicsGetImageFromCurrentImageContext();
// free the context
UIGraphicsEndImageContext();
return retImage;
}
Suppose your object's view is square, Set the cornerRadius to half of the width or height.
maskToBounds set your image as per shape of rounded imageView
For example,add this code for your requirement,
yourImageView.layer.cornerRadius = yourImageView.imageView.frame.size.height /2;
yourImageView.layer.masksToBounds = YES;
Hope this will help you :)
To sort out my last problem : Draw/Paint like sketch color inside a bezier path in UIView, I took an exact Image (of path) filled with selected color. Then, to draw that in UIView, for context color I took:
lineColor=[UIColor colorWithPatternImage:img];
in drawrect :
CGPoint mid1 = midPoint(previousPoint1, previousPoint2);
CGPoint mid2 = midPoint(currentPoint, previousPoint1);
[curImage drawInRect:CGRectZero];
CGContextRef context = UIGraphicsGetCurrentContext();
[self.layer renderInContext:context];
CGContextMoveToPoint(context, mid1.x, mid1.y);
CGContextAddQuadCurveToPoint(context,
previousPoint1.x,
previousPoint1.y,
mid2.x,
mid2.y);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetBlendMode(context, kCGBlendModeCopy);
CGContextSetLineJoin(context, kCGLineJoinRound);
CGContextSetLineWidth(context, self.lineWidth);
CGContextSetStrokeColorWithColor(context,lineColor.CGColor);
CGContextSetShouldAntialias(context, YES);
CGContextSetAllowsAntialiasing(context, YES);
CGContextSetFlatness(context,0.5);
CGContextSetAlpha(context, 1.0);
CGContextStrokePath(context);
It draws exactly in the path of view but on boundaries the color goes out like melting effect.
Source Image in which color has to be filled :
image to be used as colorWithPatternImage (img)
After drawing on touches ,resultimg Image :
What am I missing here to fill it perfectly?
Any help with core graphics is most welcomed!
Thank You!
To mask the image I also did :
-(void)clipView :(MyUIBezierPath*)path drawingView:(DrawingView*)myView
{
MyUIBezierPath *myClippingPath =path;
CAShapeLayer *mask = [CAShapeLayer layer];
mask.path = myClippingPath.CGPath;
myView.layer.mask = mask;
}
But colorWithPatternImage and this masking does the same trick i.e lets me draw only inside the path , the problem I am facing now is : It gives a bad effect on drawing on touch points around the boundaries of path !
Well its working with my own masking method via colorWithPatternImage , though masking it by clipping is the same thing.Drawing issue was because of the image being drawn at touch point in the method "calculateMinImageArea: CGPoint1 :CGPoint2 :CGPoint3". Changing its dimensions (height-width according to line width) sorts it out.
You can create a path points out of this image. Then make a CGPathRef or CGMutablePathRef and then use it as a mask to your CGContextRef.
I am trying to change the width and color of a rectangle that is drawn using CG. In the following function I am masking the image with a different color, but how do I change the width?
- (void)colorImage:(UIImage *)origImage withColor:(UIColor *)color withWidth:(float) width
{
UIImage *image = origImage;
NSLog(#"%f", width);
CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, width);
CGContextClipToMask(context, rect, image.CGImage);
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImage *flippedImage = [UIImage imageWithCGImage:img.CGImage
scale:1.0 orientation: UIImageOrientationDownMirrored];
self.image = flippedImage;
}
You set the line width with CGContextSetLineWidth(context, width).
The reason why you're seeing no effect from this is because you aren't stroking anything. Line width applies to the line painted by stroking. You're filling, not stroking, and a fill has no line to give width to.
If you want to put a border around the rectangle, you need to stroke it. That's what draws a line all the way around the perimeter of some shape.
You have three options:
Call CGContextSetLineWidth, then CGContextStrokeRect.
Call CGContextStrokeRectWithWidth.
Call CGContextSetLineWidth, then CGContextAddRect (to add the rectangle to the current path), then CGContextDrawPath with kCGPathFillStroke. (Or call AddRect before SetLineWidth if you prefer—they only need to both happen before DrawPath.)
Note that a stroke is centered on the path outline, so half of it will be inside the path/rectangle and half of it will be outside. If your line is 1 pixel wide, this will appear as the line being halfway transparent (because there's no other way to represent “half a pixel”). If your line is some even number of pixels wide, and you stroke the entire bounds of the context (or view), you'll only see the half of the line that's inside.
You also should decide whether you really meant to fill at all, or whether stroke alone is what you wanted.
I might not be explaining this in the best way possible, so please bear with me.
What I have is a drawn CGPath on top of a MKMapView object:
The way I was able to achieve this is to create a CGPath for the darker blue line, then create a copy of that path, and then stroke a thicker version of it with a semi-transparent blue color. Here's the code that I'm currently using for this:
// set the shadow around the path line
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextSetRGBStrokeColor(context, 0.0f, 0.0f, 0.0f, 0.0f);
CGContextSetRGBFillColor(context, 0.0f, 0.0f, 1.0f, 0.4f);
CGPathRef shadowPath = CGPathCreateCopyByStrokingPath(self.path.CGPath, NULL, 80.0f, kCGLineCapRound, kCGLineJoinRound, 0.0f);
CGContextBeginPath(context);
CGContextAddPath(context, shadowPath);
CGContextDrawPath(context, kCGPathFillStroke);
CGContextRestoreGState(context);
CGPathRelease(shadowPath);
Works pretty well, nothing wrong so far.
However, what I would like to do though is to get a CGPathRef of the outline of that thicker semi-transparent blue area. Here's another screenshot showing the pseudo-path that I want out of this (hand drawn in red):
How is this possible?
Simple: just use CGPathCreateCopyByStrokingPath. Pass in a wide line width, and a cap of kCGLineCapRound.
You can draw two stokes.
one stroke with width n (which n is the outline width) and black color.
another stroke is then drawn on top of the first one, with eraser mode:
CGContextSetBlendMode(context, kCGBlendModeCopy);
CGContextSetFillColorWithColor(context, [[UIColor clearColor] CGColor]);
I want to fill the remaining part of a CGCntext after drawing a rect? How can I do that? Thank you!
But the thing is, I set the blend mode of the cgcontext kCGBlendModeClear. I want to make the little rect in the context to transparent. If a draw the background first, can I still see the image in the rect?
If you want to fill the context (whose frame is bigRect), except for a rectangle inside it (whose frame is smallRect):
CGContextBeginPath(context);
CGContextAddRect(context, bigRect);
CGContextAddRect(context, smallRect);
CGContextSetFillColorWithColor(context, color);
CGContextEOFillPath(context, bigRect);
Do the background first...
CGRect bounds = [self bounds];
[[UIColor blackColor] set];
UIBezierPath* backgroundPath = [UIBezierPath bezierPathWithRect:bounds];
[backgroundPath fill];
CGRect innerRect = CGRectMake(self.bounds-10,
self.bounds-10,
self.bounds.width-20
self.bounds.height-20);
[[UIColor redColor] set];
UIBezierPath* foregroundPath = [UIBezierPath bezierPathWithRect:innerRect];
[foregroundPath fill];
Draw your background and then use CGContextClearRect to clear the area you want to be transparent.
arbitrary shape:
// do your foreground drawing
CGPathRef arbitraryShape; // asign your arbitrary shape
CGContextBeginPath(ctx);
CGContextAddRect(ctx, bounds); // rect in full size of the context
CGContextAddPath(ctx, arbitraryShape); // set the area you dont want to be drawn on
CGContextClip(ctx);
// do your background drawing