Cocoa draw image with rounded corners and shadow - cocoa

I am trying to draw an image using core graphics such that it has rounded corners and a drop shadow. Here is a snippet of my code:
CGContextSetShadowWithColor(context, CGSizeMake(0, 1), 2, shadowColor);
CGContextAddPath(context, path);
CGContextClip(context);
CGContextDrawImage(context, rect, image);
The problem I am having is that the clipping to create the rounded corners is also clipping the shadow. Since the image may be transparent in areas, I cannot simply draw the rounded rectangle with a shadow under the image. I guess I need to apply the rounded shape to the image first, and then draw the resulting image to the screen and add the shadow. Does anyone know how to do this?
Thanks!

Okay, so assuming that you have a UIView subclass, which has an instance variable, image, which is a UIImage, then you can do your drawRect: function like so...
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
CGRect _bounds = [self bounds];
CGColorRef aColor;
CGContextRef context = UIGraphicsGetCurrentContext();
// Create a path
CGRect insetRect = CGRectInset(_bounds, kBSImageButtonBorder, kBSImageButtonBorder);
CGRect offsetRect = insetRect; offsetRect.origin = CGPointZero;
UIGraphicsBeginImageContext(insetRect.size);
CGContextRef imgContext = UIGraphicsGetCurrentContext();
CGPathRef clippingPath = [UIBezierPath bezierPathWithRoundedRect:offsetRect cornerRadius:CORNER_RADIUS].CGPath;
CGContextAddPath(imgContext, clippingPath);
CGContextClip(imgContext);
// Draw the image
[image drawInRect:offsetRect];
// Get the image
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// Setup the shadow
aColor = [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:0.5f].CGColor;
CGContextSetShadowWithColor(context, CGSizeMake(0.0f, 2.0f), 2.0f, aColor);
// Draw the clipped image in the context
[img drawInRect:insetRect];
}
I'm a little new to Quartz programming myself, but that should give you your image, centered in the rectangle, minus a border, with a corner radius, and a 2.f point shadow 2.f points below it. Hope that helps.

Here is a function to round the corners of an image using Daniel Thorpe's answer, in case you came here, like me, just looking for a way to do this.
+ (UIImage *) roundCornersOfImage:(UIImage *)image toRadius:(float)radius {
// create image sized context
UIGraphicsBeginImageContext(image.size);
CGContextRef context = UIGraphicsGetCurrentContext();
// add rounded rect clipping path to context using radius
CGRect imageBounds = CGRectMake(0, 0, image.size.width, image.size.height);
CGPathRef clippingPath = [UIBezierPath bezierPathWithRoundedRect:imageBounds cornerRadius:radius].CGPath;
CGContextAddPath(context, clippingPath);
CGContextClip(context);
// draw the image
[image drawInRect:imageBounds];
// get the image
UIImage *outImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return outImage;
}

You can use an imageView with a layer, the layer has properties for setting shadows and borders, this is how:
self.imageView = [[NSImageView alloc] initWithFrame:NSMakeRect(0,0,60,60)];
self.imageView.image = [NSImage imageNamed:#"yourImageName"];
self.imageView.wantsLayer = YES;
self.imageView.layer.cornerRadius = 10;
//make the shadow and set it
NSShadow* shadow = [[NSShadow alloc] init];
shadow.shadowBlurRadius = 2;
shadow.shadowOffset = NSMakeSize(2, -2);
shadow.shadowColor = [NSColor blackColor];
self.imageView.shadow = shadow;
Hope this helps, this is also much faster to draw then using drawRect overrides

Related

tvOS adjustsImageWhenAncestorFocused crops image collection view cell

When you use .imageView.adjustsImageWhenAncestorFocused you get your image scaled, you get it bigger on focus. The image goes beyond it's bounds. That means that you can't see full image - it's coped on all sides.
You have:
You want:
If you want it work from the box, you need to remember to reserve Focused/Safe zone size (from documentation) when you create your image.
In my case I have my images from server and I can't edit them.
What worked for me - it's to redraw image right before setting:
UIImage *oldImage = [UIImage imageNamed:#"example"];
CGFloat width = cell.imageView.frame.size.width;
CGFloat height = cell.imageView.frame.size.height;
CGSize newSize = CGSizeMake(width, height);
CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height));
CGImageRef imageRef = oldImage.CGImage;
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0);
CGContextRef resizeContext = UIGraphicsGetCurrentContext();
CGContextSetInterpolationQuality(resizeContext, kCGInterpolationHigh);
CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, newSize.height);
CGContextConcatCTM(resizeContext, flipVertical);
CGContextDrawImage(resizeContext, newRect, imageRef);
CGImageRef newImageRef = CGBitmapContextCreateImage(resizeContext);
UIImage *newImageResized = [UIImage imageWithCGImage:newImageRef];
CGImageRelease(newImageRef);
UIGraphicsEndImageContext();
dispatch_async(dispatch_get_main_queue(), ^{
cell.imageView.image = newImageResized;
});
It's nor necessary to redraw in this way, but the point is you need to draw your UIImage again in order to have your image displayed properly.
Code from here.

How can I rotate image after face detection? iOS

I tried rotate image and view, only view or only image, but I have not got view that I need. I want just image with faces on the top of the screen, I can rotate a window, but I use my code not in AppDelegate and also I not want to rotate other elements, my code here, it rotate all view .
-(void)markFaces:(UIImageView *)facePicture
{
// draw a CI image with the previously loaded face detection picture
CIImage* image = [CIImage imageWithCGImage:facePicture.image.CGImage];
// create a face detector - since speed is not an issue we'll use a high accuracy
// detector
CIDetector* detector = [CIDetector detectorOfType:CIDetectorTypeFace
context:nil options:[NSDictionary dictionaryWithObject:CIDetectorAccuracyHigh forKey:CIDetectorAccuracy]];
// create an array containing all the detected faces from the detector
NSArray* features = [detector featuresInImage:image];
// we'll iterate through every detected face. CIFaceFeature provides us
// with the width for the entire face, and the coordinates of each eye
// and the mouth if detected. Also provided are BOOL's for the eye's and
// mouth so we can check if they already exist.
for(CIFaceFeature* faceFeature in features)
{
// get the width of the face
CGFloat faceWidth = faceFeature.bounds.size.width;
// create a UIView using the bounds of the face
UIView* faceView = [[UIView alloc] initWithFrame:faceFeature.bounds];
// add a border around the newly created UIView
faceView.layer.borderWidth = 1;
faceView.layer.borderColor = [[UIColor redColor] CGColor];
faceView.backgroundColor = [UIColor blackColor];
// add the new view to create a box around the face
//[faceView setTransform:CGAffineTransformMakeScale(-1, -1)];
[self.view addSubview:faceView];
[self.view setTransform:CGAffineTransformMakeScale(-1, -1)]; // !!!!
}
-(void)faceDetector
{
// Load the picture for face detection
UIImageView* image = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"test1.jpeg"]];
// Draw the face detection image
[self.view addSubview:image];
// Execute the method used to markFaces in background
[self performSelectorInBackground:#selector(markFaces:) withObject:image];
// flip image on y-axis to match coordinate system used by core image
[image setTransform:CGAffineTransformMakeScale(1, -1)];//!!
}

Mac App Store like toolbar with noise

I found this great subclass of NSWindow, however it does not add any noise to the gradient of the toolbar. If you look closely at The App Store, Reeder or Twitter they all have noise over the gradient.
How do I add noise to a gradient?
I found this thread but I don't understand how to put this into code.
First of all the nessesary code has been added to INAppStoreWindow, so i have no use case for this anymore. However for people who would like to know how to do this, heres how it's done by INAppStoreWindow.
First a function for making the image with noise is created.
static CGImageRef createNoiseImageRef(NSUInteger width, NSUInteger height, CGFloat factor)
{
NSUInteger size = width*height;
char *rgba = (char *)malloc(size); srand(124);
for(NSUInteger i=0; i < size; ++i){rgba[i] = rand()%256*factor;}
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
CGContextRef bitmapContext =
CGBitmapContextCreate(rgba, width, height, 8, width, colorSpace, kCGImageAlphaNone);
CFRelease(colorSpace);
free(rgba);
CGImageRef image = CGBitmapContextCreateImage(bitmapContext);
CFRelease(bitmapContext);
return image;
}
Then the image is used to overlay the noise over the current graphics
static CGImageRef noisePattern = nil;
if (noisePattern == nil) noisePattern = createNoiseImageRef(128, 128, 0.015);
[NSGraphicsContext saveGraphicsState];
[[NSGraphicsContext currentContext] setCompositingOperation:NSCompositePlusLighter];
CGRect noisePatternRect = CGRectZero;
noisePatternRect.size = CGSizeMake(CGImageGetWidth(noisePattern), CGImageGetHeight(noisePattern));
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
CGContextDrawTiledImage(context, noisePatternRect, noisePattern);
[NSGraphicsContext restoreGraphicsState];

Image inside NSScrollView drawing on top of other views

I have a custom NSView that lives inside of a NSScrollView that is in a NSSplitView. The custom view uses the following drawing code:
- (void)drawRect:(NSRect)dirtyRect {
NSGraphicsContext *ctx = [NSGraphicsContext currentContext];
[ctx saveGraphicsState];
// Rounded Rect
NSRect rect = [self bounds];
NSRect pathRect = NSMakeRect(rect.origin.x + 3, rect.origin.y + 6, rect.size.width - 6, rect.size.height - 6);
NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:pathRect cornerRadius:kDefaultCornerRadius];
// Shadow
[NSShadow setShadowWithColor:[NSColor colorWithCalibratedWhite:0 alpha:0.66]
blurRadius:4.0
offset:NSMakeSize(0, -3)];
[[NSColor colorWithCalibratedWhite:0.196 alpha:1.0] set];
[path fill];
[NSShadow clearShadow];
// Background Gradient
NSGradient *gradient = [[NSGradient alloc] initWithStartingColor:[UAColor darkBlackColor] endingColor:[UAColor lightBlackColor]];
[gradient drawInBezierPath:path angle:90.0];
[gradient release];
// Image
[path setClip];
NSRect imageRect = NSMakeRect(pathRect.origin.x, pathRect.origin.y, pathRect.size.height * kLargeImageRatio, pathRect.size.height);
[self.image drawInRect:imageRect
fromRect:NSZeroRect
operation:NSCompositeSourceAtop
fraction:1.0];
[ctx restoreGraphicsState];
[super drawRect:dirtyRect];
}
I have tried every different type of operation but the image still draws on top of the other half of the NSSplitView like so:
…instead of drawing under the NSScrollView. I think this has to do with drawing everything instead of the dirtyRect only, but I don't know how I could edit the image drawing code to only draw the part of it that lies in the dirtyRect. How can I either prevent it from drawing on top, or only draw the dirty rect for this NSImage?
I finally got it. I don't know if it is optimal yet, but I will find out when doing performance testing. I just had to figure out the intersection of the image rect and the dirty rect using NSIntersectionRect, then figuring out which subpart of the NSImage to draw for the drawInRect:fromRect:operation:fraction: call.
Here is the important part:
NSRect imageRect = NSMakeRect(pathRect.origin.x, pathRect.origin.y, pathRect.size.height * kLargeImageRatio, pathRect.size.height);
[self.image setSize:imageRect.size];
NSRect intersectionRect = NSIntersectionRect(dirtyRect, imageRect);
NSRect fromRect = NSMakeRect(intersectionRect.origin.x - imageRect.origin.x,
intersectionRect.origin.y - imageRect.origin.y,
intersectionRect.size.width,
intersectionRect.size.height);
[self.image drawInRect:intersectionRect
fromRect:fromRect
operation:NSCompositeSourceOver
fraction:1.0];

how to "crop" a uiimage?

I'm making an app in which the user chooses an image, resize it by zooming (in a uiscrollview) and move it in the view. When finished, I would like to save the image like we can see it in the uiscrollview. Do you have any idea ?
Thanks.
Here is the code ......
Here frontGround is a imageview and
testScrool is scroll view
hope this will work for you.
UIGraphicsBeginImageContext(testScrool.frame.size);
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGRect clippedRect = CGRectMake(0, 0, testScrool.frame.size.width, testScrool.frame.size.height);
CGContextClipToRect(currentContext, clippedRect);
CGRect drawRect = CGRectMake(testScrool.frame.origin.x * -1,
testScrool.frame.origin.y * -1,frontGround.frame.size.width, frontGround.frame.size.height);
CGContextDrawImage(currentContext, drawRect, frontGround.image.CGImage);
UIImage *cropped = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
frontGround.image = cropped;

Resources