I have two images, one is a mask that is transparent with some edges / borders and the other is the actual image. I want to merge both of them.
I have used the following code to mask and combine the image:
- (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage {
// create a bitmap graphics context the size of the image
CGFloat dim = MIN(image.size.width, image.size.height);
CGSize size = CGSizeMake(dim, dim);
UIGraphicsBeginImageContextWithOptions(size, NO, .0);
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithOvalInRect:(CGRect){ CGPointZero, size }];
[bezierPath fill];
[bezierPath addClip];
CGPoint offset = CGPointMake((dim - image.size.width) * 0.5, (dim - image.size.height) * 0.5);
[image drawInRect:(CGRect){ offset, image.size }];
UIImage *ret = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return ret;
}
The result:
In the result image, the border of the image used as a mask is missing. Can someone please help me with this?
I wrote a masking category for ios (well it is basically cross platform because CoreImage is on both platforms anyway:
github project
the core functionality boils down to this (for your example)
UIImage *person = ...
UIImage *circle = ...
UIImage *result = [person imageMaskedWith:circle];
UIImageView *redbox = [[UIImageView alloc] initWithImage:result];
redbox.backgroundColor = [UIColor redColor]; //this can be a gradient!
the main part of the code from the category:
CGImageRef imageReference = image.CGImage;
CGImageRef maskReference = mask.CGImage;
CGRect rect = CGRectMake(0, 0, CGImageGetWidth(imageReference), CGImageGetHeight(imageReference));
// draw with Core Graphics
UIGraphicsBeginImageContext(rect.size);
CGContextRef bitmap = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(bitmap, 0.0, rect.size.height);
CGContextScaleCTM(bitmap, 1.0, -1.0);
CGContextClipToMask(bitmap, rect, maskReference);
CGContextDrawImage(bitmap, rect, imageReference);
newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Related
I'm looking for a way to add a solid border with Core Image. I have implement custom camera for taking pictures of rectangle shape documents. Now I am getting that documents four coordinates but problem to draw border on CIImage. Please help me.
CIImage *overlay = [CIImage imageWithColor:[CIColor colorWithRed:0 green:1 blue:0 alpha:0.6]];
overlay = [overlay imageByCroppingToRect:image.extent];
overlay = [overlay imageByApplyingFilter:#"CIPerspectiveTransformWithExtent" withInputParameters:#{#"inputExtent":[CIVector vectorWithCGRect:image.extent],#"inputTopLeft":[CIVector vectorWithCGPoint:topLeft],#"inputTopRight":[CIVector vectorWithCGPoint:topRight],#"inputBottomLeft":[CIVector vectorWithCGPoint:bottomLeft],#"inputBottomRight":[CIVector vectorWithCGPoint:bottomRight]}];
return [overlay imageByCompositingOverImage:image];
You can use this methods :
- (UIImage *)addBorderToImage:(UIImage *)image {
CGImageRef bgimage = [image CGImage];
float width = CGImageGetWidth(bgimage);
float height = CGImageGetHeight(bgimage);
// Create a temporary texture data buffer
void *data = malloc(width * height * 4);
// Draw image to buffer
CGContextRef ctx = CGBitmapContextCreate(data,
width,
height,
8,
width * 4,
CGImageGetColorSpace(image.CGImage),
kCGImageAlphaPremultipliedLast);
CGContextDrawImage(ctx, CGRectMake(0, 0, (CGFloat)width, (CGFloat)height), bgimage);
//Set the stroke (pen) color
CGContextSetStrokeColorWithColor(ctx, [UIColor greenColor].CGColor);
//Set the width of the pen mark
CGFloat borderWidth = (float)width*0.05;
CGContextSetLineWidth(ctx, borderWidth);
//Start at 0,0 and draw a square
CGContextMoveToPoint(ctx, 0.0, 0.0);
CGContextAddLineToPoint(ctx, 0.0, height);
CGContextAddLineToPoint(ctx, width, height);
CGContextAddLineToPoint(ctx, width, 0.0);
CGContextAddLineToPoint(ctx, 0.0, 0.0);
//Draw it
CGContextStrokePath(ctx);
// write it to a new image
CGImageRef cgimage = CGBitmapContextCreateImage(ctx);
UIImage *newImage = [UIImage imageWithCGImage:cgimage];
CFRelease(cgimage);
CGContextRelease(ctx);
// auto-released
return newImage;
}
Calling this method:
UIImage *updatedIMG = [self addBorderToImage:[[UIImage alloc] initWithCIImage:overlay]]
Hi in my iOS application I want to rotate the UIImage data in 90 Degrees.
I used the below code for 180 degree rotation - and it works fine.
- (UIImage*)upsideDownBunny:(UIImage *)img {
CGSize imgSize = [img size];
UIGraphicsBeginImageContext(imgSize);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextRotateCTM(context, M_PI);
CGContextTranslateCTM(context, -imgSize.width, -imgSize.height);
[img drawInRect:CGRectMake(0, 0, imgSize.width, imgSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
But when I try to rotate in 90 degree it is not working - please correct me
- (UIImage *)upsideDownBunny:(UIImage *)img {
CGSize imgSize = [img size];
UIGraphicsBeginImageContext(imgSize);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextRotateCTM(context, M_PI_2);
CGContextTranslateCTM(context, -imgSize.width, -imgSize.height);
[img drawInRect:CGRectMake(0, 0, imgSize.width, imgSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Try this...
UIImage * LandscapeImage = [UIImage imageNamed: imgname];
UIImage * PortraitImage = [[UIImage alloc] initWithCGImage: LandscapeImage.CGImage
scale: 1.0
orientation: UIImageOrientationLeft];
hope this helps you!
Try this
- (UIImage *)upsideDownBunny:(UIImage *)image {
// Rotate in degrees
CGFloat degrees = M_PI_2;
// Calculate the size of the rotated view's containing box for our drawing space
UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0, 0, image.size.width, image.size.height)];
CGAffineTransform transform = CGAffineTransformMakeRotation(degrees);
rotatedViewBox.transform = transform;
CGSize rotatedSize = rotatedViewBox.frame.size;
// Create image context
UIGraphicsBeginImageContext(rotatedSize);
CGContextRef context = UIGraphicsGetCurrentContext();
// Move the origin to the middle of the image.
CGContextTranslateCTM(context, rotatedSize.width * 0.5f, rotatedSize.height * 0.5f);
// Rotate the image context
CGContextRotateCTM(context, degrees);
// Now, draw the rotated/scaled image into the context
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawImage(context, CGRectMake(-image.size.width * 0.5f, -image.size.height * 0.5f, image.size.width, image.size.height), [image CGImage]);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
The problem is your context is being rotated around (0,0) which is the top left corner and after 90 degrees rotate it will go out of bounds. So you need to move the origin of the context to middle.
How can I fill the non-transparent areas of a PNG UIImage with a linear gradient? I'd like to reuse a PNG shape for MKAnnotationViews, but change the gradient per annotation's properties.
To use an image as a mask for a gradient (i.e. to have a gradient in the shape of the non-transparent pixels of your image), you can:
create a simple view with a gradient (you can either create a simple UIView and use the addGradientLayerToView shown below to give it a gradient or you can create the gradient PNG in advance and add it to your bundle).
apply your PNG as a mask to that gradient view:
UIImage *mask = [UIImage imageNamed:#"mask.png"];
CALayer *maskLayer = [CALayer layer];
maskLayer.frame = CGRectMake(0, 0, mask.size.width, mask.size.height);
maskLayer.contents = (id)[mask CGImage];
gradientViewToMask.layer.mask = maskLayer;
To apply a gradient to the transparent pixels, you can either:
Create a new image with a gradient:
- (UIImage *)imageWithGradient:(UIImage *)image
{
UIGraphicsBeginImageContextWithOptions(image.size, NO, 1.0);
CGContextRef context = UIGraphicsGetCurrentContext();
size_t locationCount = 2;
CGFloat locations[2] = { 0.0, 1.0 };
CGFloat components[8] = { 0.0, 0.8, 0.8, 1.0, // Start color
0.9, 0.9, 0.9, 1.0 }; // End color
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents (colorspace, components, locations, locationCount):
CGPoint startPoint = CGPointMake(0.0, 0.0);
CGPoint endPoint = CGPointMake(0.0, image.size.height);
CGContextDrawLinearGradient (context, gradient, startPoint, endPoint, 0);
CGContextTranslateCTM(context, 0, image.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawImage(context, CGRectMake(0.0, 0.0, image.size.width, image.size.height), [image CGImage]);
UIImage *gradientImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGGradientRelease(gradient);
CGColorSpaceRelease(colorspace);
return gradientImage;
}
You can also add a CAGradientLayer to a view and then add the UIImageView as a subview of that view.
- (void)addGradientLayerToView:(UIView *)view
{
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = view.bounds;
gradient.colors = #[(id)[[UIColor colorWithRed:0.0 green:0.8 blue:0.8 alpha:1.0] CGColor],
(id)[[UIColor colorWithRed:0.9 green:0.9 blue:0.9 alpha:1.0] CGColor]];
[view.layer insertSublayer:gradient atIndex:0];
}
Note, you have to #import <QuartzCore/QuartzCore.h> as well as add the QuartzCore framework to your project.
I ended up hacking together some bits of Rob's code and an extension to UIImage I found at http://coffeeshopped.com/2010/09/iphone-how-to-dynamically-color-a-uiimage
+ (UIImage *)imageNamed:(NSString *)name withGradient:(CGGradientRef)gradient
{
// load the image
UIImage *img = [UIImage imageNamed:name];
// begin a new image context, to draw our colored image onto
UIGraphicsBeginImageContextWithOptions(img.size, NO, [[UIScreen mainScreen] scale]);
// get a reference to that context we created
CGContextRef context = UIGraphicsGetCurrentContext();
// translate/flip the graphics context (for transforming from CG* coords to UI* coords
CGContextTranslateCTM(context, 0, img.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
// set the blend mode to overlay, and the original image
CGContextSetBlendMode(context, kCGBlendModeOverlay);
CGRect rect = CGRectMake(0, 0, img.size.width, img.size.height);
// set a mask that matches the shape of the image, then draw (overlay) a colored rectangle
CGContextClipToMask(context, rect, img.CGImage);
CGContextAddRect(context, rect);
//gradient
CGPoint startPoint = CGPointMake(0.0, img.size.height);
CGPoint endPoint = CGPointMake(0.0, 0.0);
CGContextDrawLinearGradient (context, gradient, startPoint, endPoint, 0);
// generate a new UIImage from the graphics context we drew onto
UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGGradientRelease(gradient);
//return the color-burned image
return coloredImg;
}
I want to crop a part of an uiimageview that on my view controller. I'm creating a rectangle on top of it:
UIGraphicsBeginImageContext(self.view.bounds.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextMoveToPoint(context, newPoint1.x, newPoint1.y);
CGContextAddLineToPoint(context, newPoint1.x, newPoint2.y);
CGContextAddLineToPoint(context, newPoint2.x, newPoint2.y);
CGContextAddLineToPoint(context, newPoint2.x, newPoint1.y);
CGContextAddLineToPoint(context, newPoint1.x, newPoint1.y);
CGContextClosePath(context);
UIColor *blue = [UIColor colorWithRed: (0.0/255.0 ) green: (0.0/255.0) blue: (255.0/255.0) alpha:0.4];
CGContextSetFillColorWithColor(context, blue.CGColor);
CGContextDrawPath(context, kCGPathFillStroke);
I can't figure out how to crop it right. I'm able to retrieve a capture of the screen : entirely blank with my rectangle on it:
UIImage *cropImage = UIGraphicsGetImageFromCurrentImageContext();
rectImage = cropImage;
UIGraphicsEndImageContext();
UIImageCrop *rectImageView = [[UIImageCrop alloc]initWithImage:rectImage];
[self.view addSubview:rectImageView];
So I'm aware that there is something I've missed about it, any help?
- (UIImage *)captureScreenInRect:(CGRect)captureFrame
{
CALayer *layer;
layer = self.view.layer;
UIGraphicsBeginImageContext(self.view.frame.size);
CGContextClipToRect (UIGraphicsGetCurrentContext(),captureFrame);
[layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *screenImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return screenImage;
}
this is just for reference change this code according to your requirement
hope this will help you
You can get cropped image using :
- (UIImage*) getCroppedImage {
CGRect rect = PASS_YOUR_RECT;
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
// translated rectangle for drawing sub image
CGRect drawRect = CGRectMake(-rect.origin.x, -rect.origin.y, your_image.size.width, your_image.size.height);
// clip to the bounds of the image context
// not strictly necessary as it will get clipped anyway?
CGContextClipToRect(context, CGRectMake(0, 0, rect.size.width, rect.size.height));
// draw image
[your_image drawInRect:drawRect];
// grab image
UIImage* croppedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return croppedImage;
}
Hope it helps you.
I'm trying to generate an image that is lozenge-shaped and shows some percentage finished versus unfinished. The way I implemented this was as follows:
Generate 2 rectangles - one the size of the filled region, the other the size of the empty rectange
Invoke UIGrapicsBeginImageContext() with the size of the rectangle I am interested in
Draw the 2 rectangles in the context side-by side
Grab the image from the context and end the context
Create a new masked image by using CGImageMaskCreate() followed by CGImageCreateWithMask() and extracting the masked image
I generate the filled and empty bitmaps using category extensions to UIImage, and then apply a static mask image to them.
The Problem: This works fine in the simulator, but the masking doesn't work on a real device.
Instead of including the code here, I'm including a link to a project that has the code. The relevant files are:
UIImage.h/UIImage.m: The category extension to UIImage that adds both the "create an image with a specified color" and "create a masked image using the supplied mask".
TLRangeDisplay.h/TLRangeDisplay.m: the code for my lozenge-shaped status display. The routine of interest there is fillWithRect().
Here is the code I added to UIImage (via a category):
+ (UIImage *)imageWithColor:(UIColor *)color {
CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
+ (UIImage *)imageWithColor:(UIColor *)color andSize:(CGSize)size {
CGRect rect = CGRectMake(0.0f, 0.0f, size.height, size.width);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
- (UIImage*) maskWith:(UIImage *)maskImage {
CGImageRef maskRef = maskImage.CGImage;
CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef), CGImageGetHeight(maskRef),
CGImageGetBitsPerComponent(maskRef),
CGImageGetBitsPerPixel(maskRef), CGImageGetBytesPerRow(maskRef), CGImageGetDataProvider(maskRef), NULL, false);
CGImageRef masked = CGImageCreateWithMask([self CGImage], mask);
UIImage* image = [UIImage imageWithCGImage:masked];
CFRelease(mask);
CFRelease(masked);
return image;
}
And here is the routine that does the masking:
-(void)fillWithRect {
CGRect f = self.frame;
CGFloat width = f.size.width;
CGFloat fullRange = maxValue_ - minValue_;
CGFloat filledRange = currentValue_ - minValue_;
CGRect fillRect = CGRectMake(0, 0, (filledRange * width) / fullRange, f.size.height);
CGRect emptyRect = CGRectMake(fillRect.size.width, 0, width - fillRect.size.width, f.size.height);
UIImage *fillImage = nil;
UIImage *emptyImage = nil;
if(fillRect.size.width > 0) {
fillImage = [UIImage imageWithColor:fillColor_ andSize:fillRect.size];
}
if(emptyRect.size.width > 0) {
emptyImage = [UIImage imageWithColor:emptyColor_ andSize:emptyRect.size];
}
// Build the 2-color image
UIGraphicsBeginImageContext(f.size);
[fillImage drawInRect:fillRect];
[emptyImage drawInRect:emptyRect];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// Mask it
if(nil != maskImage_)
image = [image maskWith:maskImage_];
CGRect fullRect = CGRectMake(0, 0, f.size.width, f.size.height);
// Merge ith with the shape
UIGraphicsBeginImageContext(f.size);
[image drawInRect:fullRect];
[shapeImage_ drawInRect:fullRect];
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[shownView_ removeFromSuperview];
shownView_ = [[UIImageView alloc] initWithImage:image];
[self addSubview:shownView_];
if(nil != shownView_)
[self bringSubviewToFront:shownView_];
}
The project can be downloaded from http://dl.dropbox.com/u/5375467/ColorPlayOS4.zip
Thanks for any insights on this problem!