Drawing a circular image on top of another image - UIGraphicsBeginImageContextWithOptions - ios

I've been struggling with this method for a while. I am drawing an avatar on top of another image. The user picture I want to be a circle, however I can't seem to figure out how. The user picture is a UIImage and not a UIImageView. I am aware of how to make a circle if it is an imageview. Below is the code. There might be a better approach.
-(UIImage *)drawImage:(UIImage*)pinImage withBadge:(UIImage *)user{
UIGraphicsBeginImageContextWithOptions(pinImage.size, NO, 0.0f);
[pinImage drawInRect:CGRectMake(0, 0, pinImage.size.width, pinImage.size.height)];
[user drawInRect:CGRectMake(20.0, 10.0, user.size.width/2, user.size.height/2)];
UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return resultImage;
}
The result is good, but the user image is still square, it is not circle. I have tried making the add the User image to a UIImageView, transform it to a circle, and then use it in the method by calling yourImageView.image, but no luck. I also tried numerous other ways. My logic is more than likely incorrect.
The desired outcome is a rounded image place on top of a pin/annotation. Where the black dot would be an image (a bigger circle than this).

You can clip the image context to the path of an image
// Start the image context
UIGraphicsBeginImageContextWithOptions(pinImage.size, NO, 0.0);
UIImage *resultImage = nil;
// Get the graphics context
CGContextRef context = UIGraphicsGetCurrentContext();
// Draw the first image
[pinImage drawInRect:CGRectMake(0, 0, pinImage.size.width, pinImage.size.height)];
// Get the frame of the second image
CGRect rect = CGRectMake(20.0, 10.0, user.size.width/2, user.size.height/2)
// Add the path of an ellipse to the context
// If the rect is a square the shape will be a circle
CGContextAddEllipseInRect(context, rect);
// Clip the context to that path
CGContextClip(context);
// Do the second image which will be clipped to that circle
[user drawInRect:rect];
// Get the result
UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext();
// End the image context
UIGraphicsEndImageContext();

Create a circular path and then clip to that?
CGContextAddArc(ctx, ....);
CGContextClip(ctx);

Related

Combine two images

I would like to take an image and duplicate it. Then increase it by 105% and overlay it on the original image.
What is the correct way to do this on iOS?
This is your basic code for drawing the image and then saving it as an image again:
- (UIImage *)renderImage:(UIImage *)image atSize:(CGSize)size
{
UIGraphicsBeginImageContext(size);
[image drawInRect:CGRectMake(0.0, 0.0, size.width, size.height)];
// draw anything else into the context
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Where it says "draw anything else into the context" you can draw the image at a reduced size by setting the appropriate rect to draw in. Then, call the renderImage method with whatever size you want the full image to be. You can use CGContextSetAlpha to set the transparency.

Merge two PNG UIImages in iOS without losing transparency

I have two png format images and both have transparency defined. I need to merge these together into a new png image but without losing any of the transparency in the result.
+(UIImage *) combineImage:(UIImage *)firstImage colorImage:(UIImage *)secondImage
{
UIGraphicsBeginImageContext(firstImage.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0, firstImage.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGRect rect = CGRectMake(0, 0, firstImage.size.width, firstImage.size.height);
// draw white background to preserve color of transparent pixels
CGContextSetBlendMode(context, kCGBlendModeDarken);
[[UIColor whiteColor] setFill];
CGContextFillRect(context, rect);
CGContextSaveGState(context);
CGContextRestoreGState(context);
// draw original image
CGContextSetBlendMode(context, kCGBlendModeDarken);
CGContextDrawImage(context, rect, firstImage.CGImage);
// tint image (loosing alpha) - the luminosity of the original image is preserved
CGContextSetBlendMode(context, kCGBlendModeDarken);
//CGContextSetAlpha(context, .85);
[[UIColor colorWithPatternImage:secondImage] setFill];
CGContextFillRect(context, rect);
CGContextSaveGState(context);
CGContextRestoreGState(context);
// mask by alpha values of original image
CGContextSetBlendMode(context, kCGBlendModeDestinationIn);
CGContextDrawImage(context, rect, firstImage.CGImage);
// image drawing code here
CGContextRestoreGState(context);
UIImage *coloredImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return coloredImage;
}
needed any help to improve my code in performance.
Thanks in advance
First of all, those calls to CGContextSaveGState and CGContextRestoreGState, one after the other with nothing in between, isn't doing anything for you. See this other answer for an explanation of what CGContextSaveGState and CGContextRestoreGState do: CGContextSaveGState vs UIGraphicsPushContext
Now, it's not 100% clear to me what you mean by "merging" the images. If you just want to draw one on top of the other, and blend their colors using a standard blending mode then you just need to change those blend mode calls to pass kCGBlendModeNormal (or just leave out the calls to CGContextSetBlendMode entirely. If you want to mask the second image by the first image's alpha value then you should draw the second image with the normal blend mode, then switch to kCGBlendModeDestinationIn and draw the first image.
I'm afraid I'm not really sure what you're trying to do with the image tinting code in the middle, but my instinct is that you won't end up needing it. You should be able to get most merging effects by just drawing one image, then setting the blending mode, then drawing the other image.
Also, the code you've got there under the comment "draw white background to preserve color of transparent pixels" might draw white through the whole image, but it certainly doesn't preserve the color of transparent pixels, it makes those pixels white! You should remove that code too unless you really want your "transparent" color to be white.
Used the code given in Vinay's question and Aaron's comments to develop this hybrid that overlays any number of images:
/**
Returns the images overplayed atop each other according to their array position, with the first image being bottom-most, and the last image being top-most.
- parameter images: The images to overlay.
- parameter size: The size of resulting image. Any images not matching this size will show a loss in fidelity.
*/
func combinedImageFromImages(images: [UIImage], withSize size: CGSize) -> UIImage
{
// Setup the graphics context (allocation, translation/scaling, size)
UIGraphicsBeginImageContext(size)
let context = UIGraphicsGetCurrentContext()
CGContextTranslateCTM(context, 0, size.height)
CGContextScaleCTM(context, 1.0, -1.0)
let rect = CGRectMake(0, 0, size.width, size.height)
// Combine the images
for image in images {
CGContextDrawImage(context, rect, image.CGImage)
}
let combinedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return combinedImage
}

UIView screenshot with magnificationFilter

I have a tiny qrcode UIImage set to a large UIImageView. In order to avoid any gradient from black to white when amplifying, I setted the UIImageView magnification filter to kCAFilterNearest as shown below (it works):
[QRCodeImageView layer].magnificationFilter = kCAFilterNearest;
Now I need to take a screenshot from this ImageView, but the result image is ignoring the magnification filter:
Here is my screenshot code:
UIGraphicsBeginImageContextWithOptions(CGSizeMake(QRCodeImageView.frame.size.width, QRCodeImageView.frame.size.height),YES, 2.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
[QRCodeImageView.layer renderInContext:context];
UIImage *capturedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
So, the question is, how to render in context with a given magnification filter?
Thanks in advance

Cropping ellipse using core image in ios

I want to crop an ellipse from an image in ios. Using core image framework, I know know to crop a reactangular region.
Using core graphics, I am able to clip the elliptical region. But, the size of the cropped image is same as the size of the original image as I am applying mask to area outside the ellipse.
So, the goal is to crop the elliptical region from an image and size of cropped image won't exceed the rectangular bounds of that image.
Any help would be greatly appreciated. Thanks in advance.
You have to create a context in the correct size, try the following code:
- (UIImage *)cropImage:(UIImage *)input inElipse:(CGRect)rect {
CGRect drawArea = CGRectMake(-rect.origin.x, -rect.origin.y, input.size.width, input.size.height);
UIGraphicsBeginImageContext(rect.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextAddEllipseInRect(ctx, CGRectMake(0, 0, rect.size.width, rect.size.height));
CGContextClip(ctx);
[input drawInRect:drawArea];
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
Maybe you have to adjust the drawArea to your needs as i did not test it.

How to draw an Image through Core Graphics.

I am working on a project in which user performs following tasks.
select a UIImage which he wants to draw.
After selecting an Image. User select a tool (Named as Duplicate).
And as user moved it on UIImageVIew an Selected Image will draw on
it.
For Second Part I am trying following code but it not work.
UIGraphicsBeginImageContext(frontImageView.frame.size);
[frontImageView.image drawInRect:CGRectMake(0, 0, frontImageView.frame.size.width, frontImageView.frame.size.height)];
context = UIGraphicsGetCurrentContext();
CGRect theRect = CGRectMake(touchLocation.x, touchLocation.y, eraserWidth, eraserWidth);
CGContextAddRect(context, theRect);
CGContextDrawImage(context, theRect, originalImage.CGImage);
frontImageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
where originalImage conatin selected Image, EraserWIdth is ToolWidth, FrontIMageVIew is UIImageVIEW on which image will be Draw. Please Check either this code is correct or not Because my app get crash. Thanks in advance.

Resources