UIImage with alpha produces White Image - ios

I have below block of code to apply alpha on UIImage,
UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
[self drawAtPoint:CGPointZero blendMode:kCGBlendModeNormal alpha:alpha];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Following is the original Image before alpha being applied:
But after applying alpha with the above mentioned code it resulted in the following image(alpha applied with value 0.6):
I supposed to receive a transparent image instead image is getting whitened as i keep apply alpha, If i apply an alpha of 0.0 the resulted image was a pure white image, any suggestions would be appreciated.

Related

Drawing a circular image on top of another image - UIGraphicsBeginImageContextWithOptions

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);

iOS: How to get a piece of a stretched image?

The generic problem I'm facing is this:
I have a stretchable 50x50 PNG. I'm stretching it to 300x100. I want to get three UIImages of size 100x100 cut from the stretched image, A, B & C in the picture below:
I'm trying to do it like this:
// stretchedImage is the 50x50 UIImage, abcImageView is the 300x100 UIImageView
UIImage *stretchedImage = [abcImageView.image stretchableImageWithLeftCapWidth:25 topCapHeight:25];
CGImageRef image = CGImageCreateWithImageInRect(stretchedImage.CGImage, bButton.frame);
UIImage *result = [UIImage imageWithCGImage:image];
[bButton setBackgroundImage:result forState:UIControlStateSelected];
CGImageRelease(image);
I'm trying to crop the middle 100 ("B") using CGImageCreateWithImageInRect, but this is not right, since stretchedImage is 50x50, not 300x100. How do I get the 300x100 image to crop from? If the original image was 300x100 there would be no problem, but then I would lose the advantage of stretchable image.
I guess to generalize the problem even more, the question would be as simple as: if you scale or stretch an image to a bigger image view, how do you get the scaled/stretched image?
Background for the specific task I'd like to apply the solution for (if you can come up with an alternative solution):
I'm trying to implement a UI that's similar to the one you see during a call in native iPhone call application: a plate containing buttons for mute, speaker, hold, etc. Some of them are toggle type buttons with a different background color for selected state.
I have two graphics for the whole plate, for non-selected and selected states. I'm stretching both images to the desired size. For the buttons in selected state I want to get a piece of the stretched selected graphic.
You should be able to do this by rendering abcImageView to a UIImage
UIGraphicsBeginImageContextWithOptions(abcImageView.bounds.size, NO, 0.f);
[abcImageView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Then, you can crop the image like this (given cropRect):
CGImageRef cgImage = CGImageCreateWithImageInRect(image.CGImage, cropRect);
UIImage *croppedImage = [UIImage imageWithCGImage:cgImage];
// Do something with the image.
CGImageRelease(cgImage);

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

Resources