Crop letter from image using Masking - iphone

What I need:
1) Choose image from library or camera
2) Write and text
3) Text is cropped with image!
Below image can clarify more on what exactly I need.
I know masking and cropping of image even I did masking with frame in emoji me app . Just I need to know how the image should be cropped according to dynamic text.
Please give your suggestions.
...
UIImage *image = [UIImage imageNamed:#"dogs.png"];
UIImage *mask = [UIImage imageNamed:#"mask.png"];
// result of the masking method
UIImage *maskedImage = [self maskImage:image withMask:mask];
...
- (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage {
CGImageRef maskRef = maskImage.CGImage;
CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
CGImageGetHeight(maskRef),
CGImageGetBitsPerComponent(maskRef),
CGImageGetBitsPerPixel(maskRef),
CGImageGetBytesPerRow(maskRef),
CGImageGetDataProvider(maskRef), NULL, false);
CGImageRef maskedImageRef = CGImageCreateWithMask([image CGImage], mask);
UIImage *maskedImage = [UIImage imageWithCGImage:maskedImageRef];
CGImageRelease(mask);
CGImageRelease(maskedImageRef);
// returns new image with mask applied
return maskedImage;
}

1) write a image with text with below code
UIImage *textedImage = [self imageFromText:#"Text to show"];
-(UIImage *)imageFromText:(NSString *)text
{
//set width for string to wrap.
CGSize maximumSize;
maximumSize = CGSizeMake(320, 300);
//set your text image font here
UIFont *font = [UIFont boldSystemFontOfSize:50];
CGSize strSize1 = [text sizeWithFont:font constrainedToSize:maximumSize lineBreakMode:UILineBreakModeWordWrap];
CGSize strSize =CGSizeMake(320, strSize1.height);
if (UIGraphicsBeginImageContextWithOptions != NULL)
UIGraphicsBeginImageContextWithOptions(strSize,NO,0.0);
else
UIGraphicsBeginImageContext(strSize);
//set your new text iamge frame here
CGRect newframe = CGRectMake(0, 0, 320, 400);
UIColor *color = [UIColor redColor];
[color set];
[text drawInRect:newframe
withFont:font
lineBreakMode:UILineBreakModeCharacterWrap
alignment:UITextAlignmentCenter];
UIImage *textImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return textImg;
}
2) after getting texture image apply image making with required image
UIImage *maskedImage = [self maskImage:finalImage withMask: textedImage];
- (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage {
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
//UIImage *maskImage = [UIImage imageNamed:#"mask.png"];
CGImageRef maskImageRef = [maskImage CGImage];
// create a bitmap graphics context the size of the image
CGContextRef mainViewContentContext = CGBitmapContextCreate (NULL, maskImage.size.width, maskImage.size.height, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast);
if (mainViewContentContext==NULL)
return NULL;
CGFloat ratio = 0;
ratio = maskImage.size.width/ image.size.width;
if(ratio * image.size.height < maskImage.size.height) {
ratio = maskImage.size.height/ image.size.height;
}
CGRect rect1 = {{0, 0}, {maskImage.size.width, maskImage.size.height}};
CGRect rect2 = {{-((image.size.width*ratio)-maskImage.size.width)/2 , -((image.size.height*ratio)-maskImage.size.height)/2}, {image.size.width*ratio, image.size.height*ratio}};
CGContextClipToMask(mainViewContentContext, rect1, maskImageRef);
CGContextDrawImage(mainViewContentContext, rect2, image.CGImage);
// Create CGImageRef of the main view bitmap content, and then
// release that bitmap context
CGImageRef newImage = CGBitmapContextCreateImage(mainViewContentContext);
CGContextRelease(mainViewContentContext);
UIImage *theImage = [UIImage imageWithCGImage:newImage];
CGImageRelease(newImage);
// return the image
return theImage;
}

Here is a CoreAnimation approach. You can use a CATextLayer to mask a layer with an image. It's a little more compact code wise:
// Create our text layer we want to use as a mask
CATextLayer *textLayer = [CATextLayer layer];
[textLayer setBounds:CGRectMake(0.0f, 0.0f, 300.0f, 300.0f)];
[textLayer setFont:#"Helvetica-Bold"];
[textLayer setFontSize:42.0f];
[textLayer setAnchorPoint:CGPointMake(0.0f, 0.0f)];
[textLayer setPosition:CGPointMake(0.0f, 0.0f)];
[textLayer setWrapped:YES];
[textLayer setAlignmentMode:kCAAlignmentCenter];
[textLayer setString:#"Hello World And Something Something!!"];
// Create our image layer
CALayer *imageLayer = [CALayer layer];
[imageLayer setBounds:CGRectMake(0.0f, 0.0f, 300.0f, 300.0f)];
[imageLayer setPosition:[[self view] center]];
[imageLayer setContents:(id)[[UIImage imageNamed:#"pp"] CGImage]];
// Set the mask
[imageLayer setMask:textLayer];
// Add the layer to the view's layer tree
[[[self view] layer] addSublayer:imageLayer];
This will yield the following:
You can mess with the font face and size. CATextLayers can wrap automatically based on the size you set them to. You can also set the text alignment on the text layer to suite your needs.
NOTE: One caveat here. If you need the output as an image, this won't work because you can't render masks using renderInContext: on the layer. This method only works if you plan to just display it in a view. Outputting an image will require the CoreGraphics approach.

Related

capture screen as it looks like

iam doing one application.In that Im using one imageview with image and add one view with sone clear holes.Means through that holes we can see the background image.So my problem is i want to capture that total screen (imageview with this holes view).Iam using below code but it's not working.
- (UIImage*)captureView:(UIView *)yourView {
CGRect rect = [[UIScreen mainScreen] bounds];
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
[yourView.layer renderInContext:context];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
but it's not working.
This IS how we do:
UIGraphicsBeginImageContextWithOptions(yourView.bounds.size, yourView.opaque, 0.0);
[yourView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *LastImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Try this to take your screeShoT
-(UIImage*)getScreenShot
{
CGSize screenSize = [[UIScreen mainScreen] applicationFrame].size;
//CGSize screenSize = CGSizeMake(1024, 768);
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
CGContextRef ctx = CGBitmapContextCreate(nil, screenSize.width, 416, 8, 4*(int)screenSize.width, colorSpaceRef, kCGImageAlphaPremultipliedLast);
CGContextTranslateCTM(ctx, 0.0, screenSize.height);
CGContextScaleCTM(ctx, 1.0, -1.0);
[(CALayer*)self.yourView.layer renderInContext:ctx];
CGImageRef cgImage = CGBitmapContextCreateImage(ctx);
UIImage *image = [UIImage imageWithCGImage:cgImage];
CGImageRelease(cgImage);
CGContextRelease(ctx);
return image;
}

Rotation and cropping an image IOS

I am performing rotation on an UIImageView and then i try to crop a part of it and save it as an UIImage. The UIImageView rotates however it always crops the same part of the photo. So the cropping does not take into account the image rotation. What am i doing wrong?
//rotate image
CGRect new = CGRectMake(0, 0, 100, 50);
CGAffineTransform rotation = CGAffineTransformMakeRotation(5);
[photo setTransform:rotation];
// crop image
CGImageRef imageRef = CGImageCreateWithImageInRect([photo.image CGImage], new);
UIImage *croppedImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
// display crop bounds
UIView* faceBounds = [[UIView alloc] initWithFrame:new];
faceBounds.layer.borderWidth = 2;
faceBounds.layer.borderColor = [[UIColor redColor] CGColor];
Use the following snippet for rotating image data.
The input data is inAngle (angle in radians) and inImage (UIImage instance).
What this does, it creates an image context, applies the transformation to it and draws the original image into that context. The resulting image data will now be stored in resultImage.
The first three lines handle the calculation of the bounding result image frame.
UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, inImage.size.width, inImage.size.height)];
rotatedViewBox.transform = CGAffineTransformMakeRotation(inAngle);
CGSize rotatedSize = rotatedViewBox.frame.size;
UIGraphicsBeginImageContext(rotatedSize);
CGContextRef bitmap = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(bitmap, rotatedSize.width / 2.0f, rotatedSize.height / 2.0f);
CGContextRotateCTM(bitmap, inAngle);
CGContextScaleCTM(bitmap, 1.0f, -1.0f);
CGContextDrawImage(bitmap, CGRectMake(-inImage.size.width / 2.0f,
-inImage.size.height / 2.0f,
inImage.size.width,
inImage.size.height),
inImage.CGImage);
UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
This is too late for now but For now someone can try this

iOS Capture screen, then crop and mask the result image

In my application, I want to do the following steps:
1 - Capture the screen, this part is no problem for me, I'm using the following code:
- (UIImage *)captureScreen {
UIGraphicsBeginImageContextWithOptions(self.view.frame.size, YES, 0.0f);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
2 - I cropped the image with this function
- (UIImage *)cropImage(UIImage *)image inRect:(CGRect)rect {
CGImageRef imageRef = CGImageCreateWithImageInRect(image.CGImage, rect);
UIImage *resultImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
return resultImage;
}
3 - Then I mask the cropped image with a pure black and white mask
- (UIImage *)maskImage:(UIImage *)image withMask:(UIImage *)maskImage {
CGImageRef maskRef = maskImage.CGImage;
CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
CGImageGetHeight(maskRef),
CGImageGetBitsPerComponent(maskRef),
CGImageGetBitsPerPixel(maskRef),
CGImageGetBytesPerRow(maskRef),
CGImageGetDataProvider(maskRef), NULL, false);
CGImageRef maskedRef = CGImageCreateWithMask([image CGImage], mask);
UIImage *resultImage = [UIImage imageWithCGImage:maskedRef];
CGImageRelease(mask);
CGImageRelease(maskedRef);
return resultImage;
}
However, the result image I got is that outside the shape of the mask, the image is in black color instead of transparent. Can anybody help me?
This Works for me. Hope it will work for you too.
- (UIImage*) doImageMask:(UIImage *)mainImage:(UIImage*)maskImage{
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGImageRef maskImageRef = [maskImage CGImage];
// create a bitmap graphics context the size of the image
CGContextRef mainViewContentContext = CGBitmapContextCreate (NULL, maskImage.size.width, maskImage.size.height, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast);
if (mainViewContentContext == NULL){
return NULL;
}
CGFloat ratio = 0;
ratio = maskImage.size.width/ mainImage.size.width;
if(ratio * mainImage.size.height < maskImage.size.height) {
ratio = maskImage.size.height/ mainImage.size.height;
}
CGRect rect1 = {{0, 0}, {maskImage.size.width, maskImage.size.height}};
CGRect rect2 = {{-((mainImage.size.width*ratio)-maskImage.size.width)/2 , -((mainImage.size.height*ratio)-maskImage.size.height)/2}, {mainImage.size.width*ratio, mainImage.size.height*ratio}};
CGContextClipToMask(mainViewContentContext, rect1, maskImageRef);
CGContextDrawImage(mainViewContentContext, rect2, mainImage.CGImage);
// Create CGImageRef of the main view bitmap content, and then
// release that bitmap context
CGImageRef newImage = CGBitmapContextCreateImage(mainViewContentContext);
CGContextRelease(mainViewContentContext);
UIImage *theImage = [UIImage imageWithCGImage:newImage];
CGImageRelease(newImage);
// return the image
return theImage;
}
I solve my problem, it is due to the alpha channel of the image to be masked. So before masking, I create another UIImage with alpha channel and continue my steps.
This is the code for creating a UIImage with alpha
- (UIImage *)imageWithAlpha {
CGImageRef imageRef = self.CGImage;
CGFloat width = CGImageGetWidth(imageRef);
CGFloat height = CGImageGetHeight(imageRef);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(nil, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedFirst);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGImageRef resultImageRef = CGBitmapContextCreateImage(context);
UIImage *resultImage = [UIImage imageWithCGImage:resultImageRef scale:self.scale orientation:self.imageOrientation];
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
CGImageRelease(resultImageRef);
return resultImage;
}

iOS: Draw NSString and border on UIImage

I am wanting to draw an NSString and a border onto a UIImage that I already have. I found a method that will draw an NSString as a UIImage, but I need it to draw on an image that I provide.
-(UIImage *)imageFromText:(NSString *)text
{
// set the font type and size
UIFont *font = [UIFont systemFontOfSize:20.0];
CGSize size = [text sizeWithFont:font];
// check if UIGraphicsBeginImageContextWithOptions is available (iOS is 4.0+)
if (UIGraphicsBeginImageContextWithOptions != NULL)
UIGraphicsBeginImageContextWithOptions(size,NO,0.0);
else
// iOS is < 4.0
UIGraphicsBeginImageContext(size);
// optional: add a shadow, to avoid clipping the shadow you should make the context size bigger
//
// CGContextRef ctx = UIGraphicsGetCurrentContext();
// CGContextSetShadowWithColor(ctx, CGSizeMake(1.0, 1.0), 5.0, [[UIColor grayColor] CGColor]);
// draw in context, you can use also drawInRect:withFont:
[text drawAtPoint:CGPointMake(0.0, 0.0) withFont:font];
// transfer image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
How would I modify this method to provide my own background image, as well as adding a border?
If you are displaying the UIImage in a UIImageView you can set the UIImageView.layer.delegate and use something like:
- (void) drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
CGContextSetFillColorWithColor(ctx, [[UIColor darkTextColor] CGColor]);
UIGraphicsPushContext(ctx);
[word drawAtPoint:CGPointMake(30.0f, 30.0f)
forWidth:200.0f
withFont:[UIFont boldSystemFontOfSize:32]
lineBreakMode:UILineBreakModeClip];
UIGraphicsPopContext();
}
Code from Add text to CALayer
The border is easy, just use the CALayer properties:
imageview.layer.borderColor = [UIColor blackColor].CGColor;
imageview.sublayer.borderWidth = 2.0;
You are looking for CALayers.
Here is very good tutorial how to create and use them.
So basically you will add new CALayer with image as a background and then draw on it text.
http://www.raywenderlich.com/2502/introduction-to-calayers-tutorial
Use this function to Draw NSString and border on UIImage
For border check CGContextSetRGBStrokeColor
-(UIImage *)imageFromText:(NSString *)text
{
// set the font type and size
UIFont *font = [UIFont systemFontOfSize:20.0];
CGSize size = [text sizeWithFont:font];
// check if UIGraphicsBeginImageContextWithOptions is available (iOS is 4.0+)
if (UIGraphicsBeginImageContextWithOptions != NULL)
UIGraphicsBeginImageContextWithOptions(size,NO,0.0);
else
// iOS is < 4.0
UIGraphicsBeginImageContext(size);
// optional: add a shadow, to avoid clipping the shadow you should make the context size bigger
//
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetShadowWithColor(ctx, CGSizeMake(1.0, 1.0), 5.0, [[UIColor brownColor] CGColor]);
// draw in context, you can use also drawInRect:withFont:
[text drawAtPoint:CGPointMake(0.0, 0.0) withFont:font];
//CGImageRef cimg = UIGraphicsGetCurrentContext();
// transfer image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
[image drawInRect:rect blendMode:kCGBlendModeNormal alpha:1.0];
//CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(ctx, 2.0, 3.5, 5.0, 1.0);
CGContextStrokeRect(ctx, rect);
UIImage *testImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return testImg;
}

Problem when masking UIImage

I took a sample code from the following URL: how to mask an image in order to mask an image.
The code is working perfectly on the iPhone simulator but works incorrectly on iPhone 4 simulator (that's when high-res images are loaded...)
Here is my code and the mask function:
- (void)someMethod {
UIImage* image = [UIImage imageNamed:#"image.png"]; // image#2x.png is loaded for high-res device
UIImage* mask = [UIImage imageNamed:#"mask.png"]; // mask#2x.png is loaded for high-res device
UIImage* maskedImage = [self maskImage:image withMask:mask];
// ... Some code here displaying maskedImage
}
- (UIImage *)maskImage:(UIImage *)image withMask:(UIImage *)maskImage {
UIImage* maskedImage = nil;
CGImageRef maskRef = maskImage.CGImage;
CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
CGImageGetHeight(maskRef),
CGImageGetBitsPerComponent(maskRef),
CGImageGetBitsPerPixel(maskRef),
CGImageGetBytesPerRow(maskRef),
CGImageGetDataProvider(maskRef), NULL, false);
CGImageRef masked = CGImageCreateWithMask([image CGImage], mask);
maskedImage = [UIImage imageWithCGImage:masked];
return maskedImage;
}
On the iPhone 4 simulator the image#2x.png and mask#2x.png are loaded and then the resulted maskedImage is cropped.
Any idea what am I doing wrong?
Use this method instead of above
- (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage {
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
//UIImage *maskImage = [UIImage imageNamed:#"mask.png"];
CGImageRef maskImageRef = [maskImage CGImage];
// create a bitmap graphics context the size of the image
CGContextRef mainViewContentContext = CGBitmapContextCreate (NULL, maskImage.size.width, maskImage.size.height, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast);
if (mainViewContentContext==NULL)
return NULL;
CGFloat ratio = 0;
ratio = maskImage.size.width/ image.size.width;
if(ratio * image.size.height < maskImage.size.height) {
ratio = maskImage.size.height/ image.size.height;
}
CGRect rect1 = {{0, 0}, {maskImage.size.width, maskImage.size.height}};
CGRect rect2 = {{-((image.size.width*ratio)-maskImage.size.width)/2 , -((image.size.height*ratio)-maskImage.size.height)/2}, {image.size.width*ratio, image.size.height*ratio}};
CGContextClipToMask(mainViewContentContext, rect1, maskImageRef);
CGContextDrawImage(mainViewContentContext, rect2, image.CGImage);
// Create CGImageRef of the main view bitmap content, and then
// release that bitmap context
CGImageRef newImage = CGBitmapContextCreateImage(mainViewContentContext);
CGContextRelease(mainViewContentContext);
UIImage *theImage = [UIImage imageWithCGImage:newImage];
CGImageRelease(newImage);
// return the image
return theImage;
}
My guess would be to not trust UIImage to deliver the highrez format to CGImageRefs etc. I think you will need to do it manually.