Add drop shadow to text written on UIIImage - iphone

I'm writing text onto an image like so:
-(UIImage *)addLabelToImage:(UIImage *)img
{
UIFont *font = [UIFont boldSystemFontOfSize:20];
UIGraphicsBeginImageContext(img.size);
[img drawInRect:CGRectMake(0, 0,img.size.width,img.size.height)];
CGRect rect = CGRectMake(60, 550, img.size.width, img.size.height);
[[UIColor whiteColor] set];
[[NSString stringWithFormat:#"%#, %#", [[NSUserDefaults standardUserDefaults] valueForKey:#"whatever"], [[NSUserDefaults standardUserDefaults] valueForKey:#"whatever2"]] drawInRect:CGRectIntegral(rect) withFont:font];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
How would I add a drop shadow to this text? I know I can just redraw the text in black shifted over a few pixels, but is there an easier way?
Cheers,
George

Before you draw your text, you can set a shadow like this:
//...
CGContextRef c = UIGraphicsGetCurrentContext();
CGSize offset = CGSizeMake(0, 1);
CGFloat blur = 2.0;
UIColor *shadowColor = [UIColor blackColor];
CGContextSetShadowWithColor(c, offset, blur, [shadowColor CGColor]);
//draw your text ...
Adjust the offset, blur and shadowColor parameters as needed to achieve the effect you want. For a sharp shadow (like on a UILabel), set blur to 0.

Related

How do I add beveled text effect in an iOS app?

Is this possible to add bevel text effect as the image shown here in an app?
I can use images to show beveled text but right now I need to do this programmatically.
You can draw text with help of
+(UIImage*) drawText:(NSString*) text
inImage:(UIImage*) image
atPoint:(CGPoint) point
{
UIFont *font = [UIFont boldSystemFontOfSize:12];
UIGraphicsBeginImageContext(image.size);
[image drawInRect:CGRectMake(0,0,image.size.width,image.size.height)];
CGRect rect = CGRectMake(point.x, point.y, image.size.width, image.size.height);
[[UIColor whiteColor] set];
[text drawInRect:CGRectIntegral(rect) withFont:font];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
but make sure you add shadow properly. If needed add more than one text with different shadow.

Draw a thick stroke to a text in label

I am trying to do this:
so I am using this code:
[self.lblRound setOutlineColor:[UIColor colorWithRed:(68/255.0) green:(82/255.0) blue:(120/255.0) alpha:1]];
self.lblRound.drawOutline = YES;
but this is what i get:
I also did try this code:
lblRound.shadowColor = [UIColor colorWithRed:(68/255.0) green:(82/255.0) blue:(120/255.0) alpha:1];
lblRound.shadowOffset = CGSizeMake(0, 0);
I also did try to make another label with the needed color and to draw it behind the text, but if I am playing with the size of the text, it influence on the width of the all text.
How can I make the stroke thicker?
I can't use an image because I have a number in this text that should be variable.
Thanks
This is the solution:
- (void)drawRect:(CGRect)rect
{
UIFont *font=[UIFont fontWithName:#"VAGRoundedStd-Bold" size:40];
CGContextRef context = UIGraphicsGetCurrentContext();
string = lblRoundnumber;
CGSize fontWidth = [string sizeWithFont:font];
CGRect tempRect=rect;
tempRect.origin.x +=160-(fontWidth.width/2);
tempRect.origin.y +=high+42;
CGContextSetRGBStrokeColor(context, 68/255.0f, 82/255.0f, 120/255.0f, 1/1.0f);
CGContextSetRGBFillColor(context, 68/255.0f, 82/255.0f, 120/255.0f, 1/1.0f);
CGContextSetTextDrawingMode(context, kCGTextStroke);
CGContextSetLineWidth(context, 11);
[string drawInRect:tempRect withFont:font];
CGContextSetRGBFillColor(context, 1,1,1,1);
CGContextSetTextDrawingMode(context, kCGTextFill);
[string drawInRect:tempRect withFont:font];
}

UILabel text color based on custom linear gradient

So I want to set the text color for a UILabel based on a gradient made in photoshop. I have the rgb values for the gradient, {211,119,95} and {199,86,56}. Is this possible? How can I do it?
Another way if you want to target iOS 6+, with a category to UIColor
You create a UIColor from a gradient:
+ (UIColor*) gradientFromColor:(UIColor*)c1 toColor:(UIColor*)c2 withHeight:(int)height
{
CGSize size = CGSizeMake(1, height);
UIGraphicsBeginImageContextWithOptions(size, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
NSArray* colors = [NSArray arrayWithObjects:(id)c1.CGColor, (id)c2.CGColor, nil];
CGGradientRef gradient = CGGradientCreateWithColors(colorspace, (CFArrayRef)colors, NULL);
CGContextDrawLinearGradient(context, gradient, CGPointMake(0, 0), CGPointMake(0, size.height), 0);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
CGGradientRelease(gradient);
CGColorSpaceRelease(colorspace);
UIGraphicsEndImageContext();
return [UIColor colorWithPatternImage:image];
}
Then with attrString as your NSMutableAttributeString:
[attrString addAttribute:NSForegroundColorAttributeName value:[UIColor gradientFromColor:[UIColor greenColor] toColor:[UIColor redColor] withHeight:labelView.height] range:defaultRange];
labelView.attributedString = attrString;
or simply set the textColor if you don't also need strokes or other styling effect
labelView.textColor = [UIColor gradientFromColor:[UIColor greenColor] toColor:[UIColor redColor] withHeight:labelView.height];
And voila, it works better with UILabel over one line, otherwise you have to calculate your line height from your font (UIFont.leading) and pass it to the method, the background will repeat vertically.
You might want to use one of these customizable labels:
FXLabel
LEffectLabel
THLabel

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

Inner Shadow in UILabel

is it possible to create such a UILabel with inner and outer shadow?
alt text http://dl.getdropbox.com/u/80699/Bildschirmfoto%202010-07-12%20um%2021.28.57.png
i only know shadowColor and shadowOffset
zoomed:
alt text http://dl.getdropbox.com/u/80699/Bildschirmfoto%202010-07-12%20um%2021.39.56.png
thanks!
The answer by dmaclach is only suitable for shapes that can easily be inverted. My solution is a custom view that works with any shape and also text. It requires iOS 4 and is resolution independent.
First, a graphical explanation of what the code does. The shape here is a circle.
The code draws text with a white dropshadow. If it's not required, the code could be refactored further, because the dropshadow needs to be masked differently. If you need it on an older version of iOS, you would have to replace the block and use an (annoying) CGBitmapContext.
- (UIImage*)blackSquareOfSize:(CGSize)size {
UIGraphicsBeginImageContextWithOptions(size, NO, 0);
[[UIColor blackColor] setFill];
CGContextFillRect(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, size.width, size.height));
UIImage *blackSquare = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return blackSquare;
}
- (CGImageRef)createMaskWithSize:(CGSize)size shape:(void (^)(void))block {
UIGraphicsBeginImageContextWithOptions(size, NO, 0);
block();
CGImageRef shape = [UIGraphicsGetImageFromCurrentImageContext() CGImage];
UIGraphicsEndImageContext();
CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(shape),
CGImageGetHeight(shape),
CGImageGetBitsPerComponent(shape),
CGImageGetBitsPerPixel(shape),
CGImageGetBytesPerRow(shape),
CGImageGetDataProvider(shape), NULL, false);
return mask;
}
- (void)drawRect:(CGRect)rect {
UIFont *font = [UIFont fontWithName:#"HelveticaNeue-Bold" size:40.0f];
CGSize fontSize = [text_ sizeWithFont:font];
CGImageRef mask = [self createMaskWithSize:rect.size shape:^{
[[UIColor blackColor] setFill];
CGContextFillRect(UIGraphicsGetCurrentContext(), rect);
[[UIColor whiteColor] setFill];
// custom shape goes here
[text_ drawAtPoint:CGPointMake((self.bounds.size.width/2)-(fontSize.width/2), 0) withFont:font];
[text_ drawAtPoint:CGPointMake((self.bounds.size.width/2)-(fontSize.width/2), -1) withFont:font];
}];
CGImageRef cutoutRef = CGImageCreateWithMask([self blackSquareOfSize:rect.size].CGImage, mask);
CGImageRelease(mask);
UIImage *cutout = [UIImage imageWithCGImage:cutoutRef scale:[[UIScreen mainScreen] scale] orientation:UIImageOrientationUp];
CGImageRelease(cutoutRef);
CGImageRef shadedMask = [self createMaskWithSize:rect.size shape:^{
[[UIColor whiteColor] setFill];
CGContextFillRect(UIGraphicsGetCurrentContext(), rect);
CGContextSetShadowWithColor(UIGraphicsGetCurrentContext(), CGSizeMake(0, 1), 1.0f, [[UIColor colorWithWhite:0.0 alpha:0.5] CGColor]);
[cutout drawAtPoint:CGPointZero];
}];
// create negative image
UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
[[UIColor blackColor] setFill];
// custom shape goes here
[text_ drawAtPoint:CGPointMake((self.bounds.size.width/2)-(fontSize.width/2), -1) withFont:font];
UIImage *negative = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGImageRef innerShadowRef = CGImageCreateWithMask(negative.CGImage, shadedMask);
CGImageRelease(shadedMask);
UIImage *innerShadow = [UIImage imageWithCGImage:innerShadowRef scale:[[UIScreen mainScreen] scale] orientation:UIImageOrientationUp];
CGImageRelease(innerShadowRef);
// draw actual image
[[UIColor whiteColor] setFill];
[text_ drawAtPoint:CGPointMake((self.bounds.size.width/2)-(fontSize.width/2), -0.5) withFont:font];
[[UIColor colorWithWhite:0.76 alpha:1.0] setFill];
[text_ drawAtPoint:CGPointMake((self.bounds.size.width/2)-(fontSize.width/2), -1) withFont:font];
// finally apply shadow
[innerShadow drawAtPoint:CGPointZero];
}
Although Steve's answer does work, it didn't scale to my particular case and so I ended up creating an inner shadow by applying a shadow to a CGPath after clipping my context:
CGContextRef context = UIGraphicsGetCurrentContext();
// clip context so shadow only shows on the inside
CGPathRef roundedRect = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:4].CGPath;
CGContextAddPath(context, roundedRect);
CGContextClip(context);
CGContextAddPath(context, roundedRect);
CGContextSetShadowWithColor(UIGraphicsGetCurrentContext(), CGSizeMake(0, 0), 3, [UIColor colorWithWhite:0 alpha:1].CGColor);
CGContextSetStrokeColorWithColor(context, [UIColor colorWithWhite:0 alpha:1].CGColor);
CGContextStrokePath(context);
Which results in:
You can change the shadow offset and blur to change the shadow style. If you need it to be darker, you can also successively add and then stroke the same CGPath, which will make the shadows pile up.
I use FXLabel for inner shadow, look here https://github.com/nicklockwood/FXLabel.
Yes, I have a blog post about it here. The short answer is to borrow the JTAInnerShadowLayer from here, subclass UILabel, and change its layerclass by overriding + (Class)layerClass so that it returns JTAInnerShadowLayer class like this:
+ (Class)layerClass
{
return [JTAInnerShadowLayer class];
}
Then in the init method for the layer set up the JTAInnerShadowLayer something like this:
[self setBackgroundColor:[UIColor clearColor]];
JTAInnerShadowLayer *innerShadow = (JTAInnerShadowLayer *)[self layer];
[innerShadow setClipForAnyAlpha:YES];
[innerShadow setOutsideShadowSize:CGSizeMake(0.0, 1.0) radius:1.0];
[innerShadow setInsideShadowSize:CGSizeMake (0.0, 4.0) radius:6.0];
/* Uncomment this to make the label also draw the text (won't work well
with black text!*/
//[innerShadow drawOriginalImage];
(or just borrow the JTAIndentLabel class).
You will have to do your own custom drawing to get an inner shadow. There's no way currently to do it with a standard UILabel.
Here's a reasonable explanation on doing inner shadow with Quartz.
Inner shadow in Core Graphics
Try PaintCode trial version! For beginners, you'll learn how to create custom drawings. It's very nice! :3 You can use it for practice or for learning, but don't use it all the time, you should also learn how to create drawings on your own.
Disclaimer: I'm not an endorser, I was just amazed by my discovery. ;)