Adding text over an image on Xcode - iphone

I want to make an iphone application similar to some greeting cards application, where I could write text over some pre prepared background images(cards).
How can I write this text?
How to save the background image+the text on one image file ?
Thanks.

Here is a method that burns a string into an image. You can tweak the font size and other parameters to configure it to your liking.
/* Creates an image with a home-grown graphics context, burns the supplied string into it. */
- (UIImage *)burnTextIntoImage:(NSString *)text :(UIImage *)img {
UIGraphicsBeginImageContext(img.size);
CGRect aRectangle = CGRectMake(0,0, img.size.width, img.size.height);
[img drawInRect:aRectangle];
[[UIColor redColor] set]; // set text color
NSInteger fontSize = 14;
if ( [text length] > 200 ) {
fontSize = 10;
}
UIFont *font = [UIFont boldSystemFontOfSize: fontSize]; // set text font
[ text drawInRect : aRectangle // render the text
withFont : font
lineBreakMode : UILineBreakModeTailTruncation // clip overflow from end of last line
alignment : UITextAlignmentCenter ];
UIImage *theImage=UIGraphicsGetImageFromCurrentImageContext(); // extract the image
UIGraphicsEndImageContext(); // clean up the context.
return theImage;
}

Thanks Rayfleck! It worked.
To add optional compatibility with retina displays (fixes choppy letters during '#2x' version of image scale up):
replace:
UIGraphicsBeginImageContext(img.size);
with conditional:
if (UIGraphicsBeginImageContextWithOptions != NULL)
UIGraphicsBeginImageContextWithOptions(img.size,NO,0.0);
else
UIGraphicsBeginImageContext(img.size);

Update for ios7...
/* Creates an image with a home-grown graphics context, burns the supplied string into it. */
- (UIImage *)burnTextIntoImage:(NSString *)text :(UIImage *)img {
UIGraphicsBeginImageContext(img.size);
CGRect aRectangle = CGRectMake(0,0, img.size.width, img.size.height);
[img drawInRect:aRectangle];
[[UIColor redColor] set]; // set text color
NSInteger fontSize = 14;
if ( [text length] > 200 ) {
fontSize = 10;
}
UIFont *font = [UIFont fontWithName:#"Courier" size:fontSize];
NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail;
paragraphStyle.alignment = NSTextAlignmentRight;
NSDictionary *attributes = #{ NSFontAttributeName: font,
NSParagraphStyleAttributeName: paragraphStyle,
NSForegroundColorAttributeName: [UIColor whiteColor]};
[text drawInRect:aRectangle withAttributes:attributes];
UIImage *theImage=UIGraphicsGetImageFromCurrentImageContext(); // extract the image
UIGraphicsEndImageContext(); // clean up the context.
return theImage;
}

This approach takes in account the screen's scale and it's super intuitive
UIImage * img = ...
UIImageView * iV = [[UIImageView alloc] initWithImage:img];
UILabel * l = [[UILabel alloc] initWithFrame:iV.bounds];
l.textAlignment = ...;
l.adjustsFontSizeToFitWidth = YES;
l.textColor = ...;
l.font = ...;
l.text = ...;
[iV addSubview:l];
UIGraphicsBeginImageContextWithOptions(iV.bounds.size, NO, 0);
[iV.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * finalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return finalImage

Related

Adding text to image, trying to change the color of text

I am adding text to image using the code mentioned below. But the problem am facing is that the color and font size not changing. I am trying to change the font size, not happening and don't know how to change color.
-(UIImage *)imageFromText:(NSString *)text
{
// set the font type and size
//UIFont *font = [UIFont systemFontOfSize:txtView.font];
//CGSize size = [text sizeWithFont:[UIFont fontWithName:#"Arial" size:13.0f]]; // label or textview
NSDictionary *attributes = #{
NSFontAttributeName: [UIFont fontWithName:#"Arial" size:14]
};
CGSize size = [text sizeWithAttributes:#{
NSFontAttributeName: [UIFont fontWithName:#"Helvetica" size:14]
}];
// check if UIGraphicsBeginImageContextWithOptions is available (iOS is 4.0+)
if (UIGraphicsBeginImageContextWithOptions != NULL)
UIGraphicsBeginImageContextWithOptions(size,NO,0.0);
else
// iOS is < 4.0
UIGraphicsBeginImageContext(size);
//[text drawInRect:CGRectMake(0,0,size.width,size.height) withFont:[UIFont fontWithName:#"Arial" size:15.0f]];
CGRect drawRect = CGRectMake(0.0, 0.0, size.width,size.height);
NSStringDrawingContext *drawingContext = [[NSStringDrawingContext alloc] init];
drawingContext.minimumScaleFactor = 1.5;
[text drawWithRect:drawRect options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:drawingContext];
UIImage *testImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return testImg;
}
Please guide, why font size not changing, what is wrong in the code nad how to change color of this text also.
Finally i got myself.
[theText drawAtPoint:CGPointMake(x, y)
withAttributes:#{NSFontAttributeName:[UIFont fontWithName:#"Helvetica" size:8], NSForegroundColorAttributeName:[UIColor whiteColor] }];

fetching image from url is not sharp & clear

I am working on one application where i have to load images from server.
I am trying to load application screenshots from a link of appstore.
I am getting the image but not so sharp & clear. I am fetching the image in background & everything works fine.But the resulted image looks a little blurry. I am testing this image in retina display. Anyone has any idea why it is happening. Any solution will be helpful.
Thanks,
Here is my code for image loading :
// This will create the imageview with required frame & use the url to load the image
-(void)loadAppsScreenShots:(int)i Frame:(CGRect)frame withImageUrl:(NSString *)urlStr
{
UIImageView *appImageView = [[UIImageView alloc] init];
frame.origin.x = 0;
appImageView.frame = frame;
appImageView.tag = i;
sharedImageCache = [ImageCache sharedImageCacheInstance];
UIImage *image1 = [sharedImageCache getCachedImage:[NSString stringWithFormat:#"%#",urlStr]];
if (image1==nil)
{
// Show indicator till image loads
UIActivityIndicatorView *indiView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
indiView.center = CGPointMake(appImageView.frame.size.width/2, appImageView.frame.size.height/2);
[appImageView addSubview:indiView];
[indiView startAnimating];
indiView.hidden = FALSE;
// Show label indicating image loading process
UILabel *loadingLbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 25)];
loadingLbl.text = #"";//#"Please wait...";
loadingLbl.center = CGPointMake(appImageView.frame.size.width/2 + 5, appImageView.frame.size.height/2 + 23);
loadingLbl.font = [UIFont fontWithName:#"Helvetica-Bold" size:15.0f];
loadingLbl.textAlignment = UITextAlignmentCenter;
loadingLbl.backgroundColor = [UIColor clearColor];
loadingLbl.textColor = [UIColor whiteColor];
[appImageView addSubview:loadingLbl];
[appImageView sendSubviewToBack:loadingLbl];
loadingLbl.hidden = FALSE;
// Dictionalry to get all objects & pass it to method where we load the data
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject:appImageView forKey:#"imageView"];
if (urlStr != nil) {
[dict setObject:urlStr forKey:#"url"];
}
[dict setObject:indiView forKey:#"indi"];
[dict setObject:loadingLbl forKey:#"loadingLbl"];
[self performSelectorInBackground:#selector(loadImageFromURLAndSaveInDocDir:) withObject:dict];
}
else
{
appImageView.image = image1;
}
[[appView viewWithTag:i] addSubview:appImageView];
[appView bringSubviewToFront:appImageView];
appImageView.contentMode = UIViewContentModeScaleAspectFit;
appImageView=nil;
}
-(void)loadImageFromURLAndSaveInDocDir:(NSMutableDictionary *)dict
{
#autoreleasepool
{
UIImageView *cellImageViewObj = [dict objectForKey:#"imageView"];
NSString *url;
UIActivityIndicatorView *indiview = [dict objectForKey:#"indi"];
UILabel *Lbl = [dict objectForKey:#"loadingLbl"];
if ([dict objectForKey:#"url"])
{
url = [dict objectForKey:#"url"];
// fetch the data
NSURL *imgURL = [NSURL URLWithString:url];
NSData *imgData = [NSData dataWithContentsOfURL:imgURL];
NSString *filename = [Utils getFileNameFromURL:url];
// Cache the image
[sharedImageCache cacheImage:[NSString stringWithFormat:#"%#",filename] :imgData];
UIImage *image1 = [[UIImage alloc] initWithData:imgData];
cellImageViewObj.image = image1;
image1=nil;
}
else {
url = #"";
}
// set the content mode & hide the indicator & label
cellImageViewObj.contentMode = UIViewContentModeScaleAspectFit;
[indiview stopAnimating];
indiview.hidden = TRUE;
Lbl.hidden = TRUE;
dict = nil;
}
}
What is wrong am i doing.
The problem is that you are showing the image at its natural size. On a retina device, you need images which are twice as wide and twice as tall as the view they get drawn into.
Say the image is 200x200 and you are going to show it in a 100x100 view. The proper way to do this is:
get a CGImageRef of the data
create a UIImage using the below method and a scale of 2 (for retina)
(UIImage *)imageWithCGImage:(CGImageRef)imageRef scale:(CGFloat)scale orientation:(UIImageOrientation)orientation
The result is an image sized 100x100 but with a scale of two.
That said, since you specify 'UIViewContentModeScaleAspectFit', you may be able to just take the 200x200 image and had it off to the UIImageView, but in this case you must force the imageView to have a frame.size of 100x100.
If the image size is different than imageview, then you can proportionally scale the server image as per your view.
- (UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize;
- (UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize {
UIImage *sourceImage = self;
UIImage *newImage = nil;
CGSize imageSize = sourceImage.size;
CGFloat width = imageSize.width;
CGFloat height = imageSize.height;
CGFloat targetWidth = targetSize.width;
CGFloat targetHeight = targetSize.height;
CGFloat scaleFactor = 0.0;
CGFloat scaledWidth = targetWidth;
CGFloat scaledHeight = targetHeight;
CGPoint thumbnailPoint = CGPointMake(0.0,0.0);
if (CGSizeEqualToSize(imageSize, targetSize) == NO) {
CGFloat widthFactor = targetWidth / width;
CGFloat heightFactor = targetHeight / height;
if (widthFactor < heightFactor)
scaleFactor = widthFactor;
else
scaleFactor = heightFactor;
scaledWidth = width * scaleFactor;
scaledHeight = height * scaleFactor;
// center the image
if (widthFactor < heightFactor) {
thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
} else if (widthFactor > heightFactor) {
thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
}
}
// this is actually the interesting part:
UIGraphicsBeginImageContext(targetSize);
CGRect thumbnailRect = CGRectZero;
thumbnailRect.origin = thumbnailPoint;
thumbnailRect.size.width = scaledWidth;
thumbnailRect.size.height = scaledHeight;
[sourceImage drawInRect:thumbnailRect];
newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
if(newImage == nil) NSLog(#"could not scale image");
return newImage ;
}

Add drop shadow to text written on UIIImage

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.

UITableViewCell with stretchable background image

I have cells in UITableView, I have made custom frame for the label on cell and this frame is resize according to the text.
But my problem is that how I can show those texts inside the bubble (image) as the text size increase the bubble image size also increases.
Try this code for image you use :
- (UIImage *)stretchableImageWithLeftCapWidth:(NSInteger)leftCapWidth topCapHeight:(NSInteger)topCapHeight
Try this:
In Custom Cell.m file :
bgImageView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 30, 80, 40)];
[self.contentView addSubview:bgImageView];
messageContentView = [[UITextView alloc] init];
messageContentView.backgroundColor = [UIColor clearColor];
messageContentView.editable = NO;
messageContentView.scrollEnabled = NO;
[messageContentView sizeToFit];
[self.contentView addSubview:messageContentView];
And in tableView:cellForRowAtindexPath method:
static CGFloat padding = 20.0;
CGSize textSize = {260.0 , 10000.0};
CGSize size = [message sizeWithFont:[UIFont boldSystemFontOfSize:13] constrainedToSize:textSize lineBreakMode:UILineBreakModeWordWrap];
size.width += (padding/2);
UIImage *bgImage = nil;
if([sender isEqualToString:#"you"])
{
bgImage = [[UIImage imageNamed:#"orange.png"] stretchableImageWithLeftCapWidth:24 topCapHeight:15];
[cell.messageContentView setFrame: CGRectMake(padding, padding*2, size.width, size.height)];
[cell.bgImageView setFrame:CGRectMake(cell.messageContentView.frame.origin.x - padding/2,cell.messageContentView.frame.origin.y - padding/2,size.width+padding, size.height+padding)];
}
else
{
bgImage = [[UIImage imageNamed:#"aqua.png"] stretchableImageWithLeftCapWidth:24 topCapHeight:15];
[cell.messageContentView setFrame:CGRectMake(320 - size.width - padding,padding*2,size.width, size.height)];
[cell.bgImageView setFrame:CGRectMake(cell.messageContentView.frame.origin.x - padding/2, cell.messageContentView.frame.origin.y - padding/2,size.width+padding,size.height+padding)];
}
cell.bgImageView.image = bgImage;
you can stretch the image with caps, depending on your image shape it could work
You can use this code
//Your image view
UIImageView *imageView;
//Your image
UIImage *image;
//Left cap is the space you dont wanna stretch on the left side and right side of the image
int leftCap = 20;
//Left cap is the space you dont wanna stretch on the top side and bottom side of the image
int topCap = 20;
//this will only stretch the inner side of the image
imageView.image = [image stretchableImageWithLeftCapWidth:leftCap topCapHeight:topCap];
for more information check this tutorial

How to change an UILabel/UIFont's letter spacing?

I've searched loads already and couldn't find an answer.
I have a normal UILabel, defined this way:
UILabel *totalColors = [[[UILabel alloc] initWithFrame:CGRectMake(5, 7, 120, 69)] autorelease];
totalColors.text = [NSString stringWithFormat:#"%d", total];
totalColors.font = [UIFont fontWithName:#"Arial-BoldMT" size:60];
totalColors.textColor = [UIColor colorWithRed:221/255.0 green:221/255.0 blue:221/255.0 alpha:1.0];
totalColors.backgroundColor = [UIColor clearColor];
[self addSubview:totalColors];
And I wanted the horizontal spacing between letters, to be tighter, whilst mantaining the font size.
Is there a way to do this? It should be a pretty basic thing to do.
Cheers guys,
Andre
UPDATE:
So I was forced to do it like this:
- (void) drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSelectFont (context, "Arial-BoldMT", 60, kCGEncodingMacRoman);
CGContextSetCharacterSpacing (context, -10);
CGContextSetTextDrawingMode (context, kCGTextFill);
CGContextSetRGBFillColor(context, 221/255.0, 221/255.0, 221/255.0, 221/255.0);
CGAffineTransform xform = CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0, 0.0);
CGContextSetTextMatrix(context, xform);
char* result = malloc(17);
sprintf(result, "%d", totalNumber);
CGContextShowTextAtPoint (context, 0, 54, result, strlen(result));
}
But I need to align this to the right.
I could do that manually if I knew the width of the drawn text, but it's proving near impossible to find that.
I've read about ATSU, but I couldn't find any examples.
This sucks :/
From iOS 6 you can use NSAttributedString in UILabel.
In attributed string you can use attribute NSKernAttributeName to set letter spacing
NSMutableAttributedString* attrStr = [[NSMutableAttributedString alloc] initWithString: #"Test test test test "];
[attrStr addAttribute:NSKernAttributeName value:#(4.0) range:NSMakeRange(0, attrStr.length)];
UILabel* label = [[UILabel alloc] initWithFrame:CGRectMake(0, 300, 300, 100)];
label.attributedText = attrStr;
I've extended UILabel to change the character spacing. This should work out the box and pulls font, text, color etc from the UILabel itself (proper coding!).
You may notice I draw the text twice, first with clear color. This is to auto center the text in the label. Whilst this may be inefficient - isn't it nice to be auto centered?
Enjoy!
#interface RALabel : UILabel {
}
#end
#implementation RALabel
- (void) drawRect:(CGRect)rect
{
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSelectFont (context, [self.font.fontName cStringUsingEncoding:NSASCIIStringEncoding], self.font.pointSize, kCGEncodingMacRoman);
CGContextSetCharacterSpacing(context, 1);
CGContextSetFillColorWithColor(context, [[UIColor clearColor] CGColor]);
CGAffineTransform myTextTransform = CGAffineTransformScale(CGAffineTransformIdentity, 1.f, -1.f );
CGContextSetTextMatrix (context, myTextTransform);
// draw 1 but invisbly to get the string length.
CGPoint p =CGContextGetTextPosition(context);
float centeredY = (self.font.pointSize + (self.frame.size.height- self.font.pointSize)/2)-2;
CGContextShowTextAtPoint(context, 0, centeredY, [self.text cStringUsingEncoding:NSASCIIStringEncoding], [self.text length]);
CGPoint v =CGContextGetTextPosition(context);
// calculate width and draw second one.
float width = v.x - p.x;
float centeredX =(self.frame.size.width- width)/2;
CGContextSetFillColorWithColor(context, [self.textColor CGColor]);
CGContextShowTextAtPoint(context, centeredX, centeredY, [self.text cStringUsingEncoding:NSASCIIStringEncoding], [self.text length]);
}
I've come up with a solution for the letter spacing and the alignment to the right.
Here it goes:
NSString *number = [NSString stringWithFormat:#"%d", total];
int lastPos = 85;
NSUInteger i;
for (i = number.length; i > 0; i--)
{
NSRange range = {i-1,1};
NSString *n = [number substringWithRange:range];
UILabel *digit = [[[UILabel alloc] initWithFrame:CGRectMake(5, 10, 35, 50)] autorelease];
digit.text = n;
digit.font = [UIFont fontWithName:#"Arial-BoldMT" size:60];
digit.textColor = [UIColor colorWithRed:221/255.0 green:221/255.0 blue:221/255.0 alpha:1.0];
digit.backgroundColor = [UIColor clearColor];
[self addSubview:digit];
CGSize textSize = [[digit text] sizeWithFont:[digit font]];
CGFloat textWidth = textSize.width;
CGRect rect = digit.frame;
rect.origin.x = lastPos - textWidth;
digit.frame = rect;
lastPos = rect.origin.x + 10;
}
The letter spacing is the "10" on the last line.
The alignment comes from the lastPos.
Hope this helps anyone out there.
In Swift:
let myTitle = "my title"
let titleLabel = UILabel()
let attributes: NSDictionary = [
NSFontAttributeName:UIFont(name: "HelveticaNeue-Light", size: 20),
NSForegroundColorAttributeName:UIColor.whiteColor(),
NSKernAttributeName:CGFloat(2.0)
]
let attributedTitle = NSAttributedString(string: myTitle, attributes: attributes as? [String : AnyObject])
titleLabel.attributedText = attributedTitle
titleLabel.sizeToFit()
Not in any publicly available version of iPhone OS. ;-) If you are a current iPhone Developer, you can get an idea of where iPhone OS is going by looking through the "What's New" notes for iPhone OS 3.2.
Update: iOS v3.2, which added support for kerning, was still under NDA when I posted this. For an update-to-date answer, see How to set kerning in iPhone UILabel.