Draw text on an image in iOS 13 - ios

I am trying to draw an image and some text on a UISlider thumbnail. I have the following code that works fine on iOS 12 and below, but does not on iOS 13 and above(specifically iOS 13.2).
- (UIImage*)getSliderImageWithImage:(UIImage*)bgImage valueText:(NSString*)value {
CGFloat scale = 5.0;
//Drawing BG Image
// Where bg image is some image on top of which i need to render text.
UIGraphicsBeginImageContextWithOptions(CGSizeMake(bgImage.size.width * scale, bgImage.size.height * scale), NO, 1);
// This works
[bgImage drawInRect:CGRectMake(0, 0, bgImage.size.width * scale, bgImage.size.height * scale)];
CGRect valueBgRect;
UIColor * textColor;
UIFont * textFont;
textColor = [UIColor whiteColor];
valueBgRect = CGRectMake(18,40, bgImage.size.width,bgImage.size.height);
textFont = [UIFont fontWithName:#"Helvetica-Bold" size:50];
NSDictionary *attrsValue = #{ NSForegroundColorAttributeName : textColor,
NSFontAttributeName : textFont,
NSTextEffectAttributeName : NSTextEffectLetterpressStyle};
// This doesn't.
[value drawInRect:valueBgRect withAttributes:attrsValue];
// Though I can see the image, the text that should be on top of it is not visible.
UIImage *theImage=UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return theImage; }
I also tried setting the text on a UILabel and rendering using
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
and
[self.view drawViewHierarchyInRect:self.view.bounds afterScreenUpdates:YES];
But none of these work. Since this a very common scenario, I am surprised that I cannot find any mention of such an issue in iOS 13.2. That leads met to think that I must be looking at it the wrong way. Can anyone please help ?

It's working in iOS 13
_imgView.image = [self drawFront:[UIImage imageNamed:#"chain_image.jpeg"] text:#"SANKET VAGHELA" atPoint:CGPointMake(50, 50)];
Call this function.
-(UIImage*)drawFront:(UIImage*)image text:(NSString*)text atPoint:
(CGPoint)point
{
UIFont *font = [UIFont systemFontOfSize:20];
UIGraphicsBeginImageContext(image.size);
[image drawInRect:CGRectMake(0,0,image.size.width,image.size.height)];
CGRect rect = CGRectMake(point.x, (point.y - 5), image.size.width, image.size.height);
[[UIColor whiteColor] set];
NSMutableAttributedString* attString = [[NSMutableAttributedString alloc] initWithString:text];
NSRange range = NSMakeRange(0, [attString length]);
[attString addAttribute:NSFontAttributeName value:font range:range];
[attString addAttribute:NSForegroundColorAttributeName value:[UIColor whiteColor] range:range];
NSShadow* shadow = [[NSShadow alloc] init];
shadow.shadowColor = [UIColor darkGrayColor];
shadow.shadowOffset = CGSizeMake(1.0f, 1.5f);
[attString addAttribute:NSShadowAttributeName value:shadow range:range];
[attString drawInRect:CGRectIntegral(rect)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}

Related

NSString drawInRect with stroke cause incorrect new line in IOS 13

I need draw string with stroke ,then convert to a UIImage, but in ios 13.7, the "stroke" 's new line not match to "fill" 's new line,
error in ios 13.7:
correct in ios 14 ,16:
after some test ,i find if i don't set NSParagraphStyleAttributeName in attributes, new line is right in ios 13.7 ,it's a bug in ios 13.7?
my code:
- (void)viewDidLoad {
[super viewDidLoad];
UIImage *img = [[self class] drawTextWithStroke];
UIImageView* imageView = [[UIImageView alloc] initWithImage:img];
[self.view addSubview:imageView];
}
+ (UIImage*)drawTextWithStroke
{
NSString* string = #"The operation couldn’t be completed. completed";
CGRect rect = CGRectMake(0, 0, 362, 42);
CGSize size = CGSizeMake(rect.size.width, rect.size.height);
UIFont *font = [UIFont fontWithName:#"Arial-BoldMT" size:18];
// retina display, double resolution
if ([UIScreen instancesRespondToSelector:#selector(scale)] && [[UIScreen mainScreen] scale] == 2.0f) {
UIGraphicsBeginImageContextWithOptions(size, NO, 2.0f);
} else {
UIGraphicsBeginImageContext(size);
}
CGContextRef context = UIGraphicsGetCurrentContext();
NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init];
//
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
[style setAlignment: NSTextAlignmentCenter];
attributes[ NSParagraphStyleAttributeName ] = style;
// draw stroke
[attributes setObject:font forKey:NSFontAttributeName];
[attributes setObject:[NSNumber numberWithFloat:3] forKey:NSStrokeWidthAttributeName];
[attributes setObject:[UIColor redColor] forKey:NSStrokeColorAttributeName];
[string drawInRect:rect withAttributes:attributes];
// draw fill
[attributes removeObjectForKey:NSStrokeWidthAttributeName];
[attributes removeObjectForKey:NSStrokeColorAttributeName];
[attributes setObject:[UIColor blackColor] forKey:NSForegroundColorAttributeName];
[string drawInRect:rect withAttributes:attributes];
// convert to image and return
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
The best solution is to draw the text just once specifying both the stroke and the fill attributes together.
But here's the trick - you need to specify a negative stroke width in order to get both the stroke and fill. If you go to the documentation for the NSStrokeWidthAttributeName key you will see the following (emphasis mine):
The value of this attribute is an NSNumber object containing a floating-point value. This value represents the amount to change the stroke width and is specified as a percentage of the font point size. Specify 0 (the default) for no additional changes. Specify positive values to change the stroke width alone. Specify negative values to stroke and fill the text. For example, a typical value for outlined text would be 3.0.
So changing your stroke width to a negative number gives you the desired effect.
Here's an updated version of your code with lots of little cleanup.
+ (UIImage*)drawTextWithStroke {
NSString* string = #"The operation couldn’t be completed. completed";
CGRect rect = CGRectMake(0, 0, 362, 42);
// Added in iOS 4.0 - no need to check for it any more
UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init];
//
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
[style setAlignment: NSTextAlignmentCenter];
attributes[ NSParagraphStyleAttributeName ] = style;
UIFont *font = [UIFont fontWithName:#"Arial-BoldMT" size:18];
attributes[NSFontAttributeName] = font;
attributes[NSStrokeWidthAttributeName] = #(-3); // Use negative value for both stroke and fill
attributes[NSStrokeColorAttributeName] = UIColor.redColor;
attributes[NSForegroundColorAttributeName] = UIColor.blackColor;
[string drawInRect:rect withAttributes:attributes];
// convert to image and return
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}

Drawing rotated text in a image

My application insert a label and has two sliders rotate and scale the text. After I want to draw this text in a image. See the code of the sliders and method to draw the text.
- (IBAction)angleSliderDidChange:(id)sender {
CGAffineTransform transform = CGAffineTransformMakeRotation(angleSlider.value * M_PI / 180.0);
[myNewLabel setTransform:transform];
}
- (IBAction)scaleSliderDidChange:(id)sender {
[myNewLabel setFont:[UIFont fontWithName:#"HelveticaNeue" size:21*scaleSlider.value]];
[myNewLabel sizeToFit];
[myNewLabel setFont:[UIFont fontWithName:#"HelveticaNeue" size:17*scaleSlider.value]];
}
- (IBAction)editionDidFinish:(id)sender {
UIFont *font = [UIFont fontWithName:#"HelveticaNeue" size:17*scaleSlider.value];
NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
paragraphStyle.alignment = NSTextAlignmentRight;
NSDictionary *attributes = #{ NSFontAttributeName:font, NSParagraphStyleAttributeName: paragraphStyle};
UIGraphicsBeginImageContext(bigImageView.frame.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGPoint contextCenter = CGPointMake(CGRectGetMidX(myNewLabel.frame), CGRectGetMidY(myNewLabel.frame));
CGContextTranslateCTM(ctx, contextCenter.x, contextCenter.y);
CGContextRotateCTM(ctx, angleSlider.value * M_PI / 180);
CGContextScaleCTM(ctx, scaleSlider.value, scaleSlider.value);
[myNewLabel.text drawInRect:(CGRect){-myNewLabel.frame.size.width/2, -myNewLabel.frame.size.height/2, myNewLabel.frame.size} withAttributes:attributes];
finalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
bigImageView.image = finalImage;
}
It is a simple procedure but my text is not being drawing in the same place of the added label. I believe I am forgoting some details but I can't see it. And the result is shown on the image below. So, please, help me to fix it.

How to rotate String and saved this String as UIImage in swift

I need to rotate the String and save this rotating string as UIImage.
Let say my given String is = HELLO WORLD
Now i need to first rotate(say 45 degree) it and than saved as UIImage so i can show this UIImage into my UIImageView
Please help me . So i can rotate the String and save this rotating string as UIImage in Swift?.
I found this answer Drawing rotated text with NSString drawInRect. But not able to achieve the result.
May be the below code helps u,I achieved the same result of rotating the string in 45 degree
-(UIImage*) drawText:(NSString*) text
atPoint:(CGPoint) point
{
UIGraphicsBeginImageContextWithOptions(CGSizeMake(65, 65),NO,0.0);
CGRect rect = CGRectMake(point.x, point.y, 50, 30);
[[UIColor whiteColor] set];
CGContextConcatCTM(UIGraphicsGetCurrentContext(), CGAffineTransformMakeTranslation(32.5, 32.5));
CGContextConcatCTM(UIGraphicsGetCurrentContext(), CGAffineTransformMakeRotation(M_PI / 4));
CGContextConcatCTM(UIGraphicsGetCurrentContext(), CGAffineTransformMakeTranslation(-32.5, -32.5));
//[text drawInRect:CGRectIntegral(rect) withFont:font ];
NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
[paragraphStyle setLineBreakMode:NSLineBreakByWordWrapping];
[paragraphStyle setAlignment:NSTextAlignmentCenter];
NSDictionary *attributes = #{ NSFontAttributeName: [UIFont fontWithName:#"HelveticaNeue-CondensedBold" size:12],
NSForegroundColorAttributeName: [UIColor blackColor],
NSParagraphStyleAttributeName:paragraphStyle};
[text drawInRect:CGRectIntegral(rect) withAttributes:attributes];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Below is screenshot where i achieved the result

iOS - UIImage creating a blurry image

I am creating an image with UIImage, and overlaying some text on top.
The end result is coming out blurry, and I want it to be clear
UIImage* DrawTextOnImage(NSString *text, UIImage *image)
{
UIGraphicsBeginImageContextWithOptions(image.size, YES, 0.0);
[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
CGRect rect = CGRectMake(10, 50, image.size.width-20, image.size.height-60);
NSMutableParagraphStyle *paragraph = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
paragraph.lineBreakMode = NSLineBreakByWordWrapping;
paragraph.alignment = NSTextAlignmentCenter;
NSShadow *shadow = [NSShadow.alloc init];
shadow.shadowColor = [UIColor clearColor];
NSDictionary *attributes = #{NSForegroundColorAttributeName:[UIColor whiteColor], NSFontAttributeName:[UIFont systemFontOfSize:18], NSParagraphStyleAttributeName:paragraph, NSShadowAttributeName:shadow};
[text drawInRect:CGRectIntegral(rect) withAttributes:attributes];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
I have seen others having problems when setting the scale wrong, but changing it doesn't affect mine.
Anyone else having similar issues?

Changing the text color for UIImage or UIGraphics

I am going to implement the module for adding the numbers in WHITE color onto the arrow heads of the UIImage being drawn onto the ios apps. When it comes to the execution, it shows that only black color is set on the the numbers. I have added
CGContextSetFillColorWithColor(UIGraphicsGetCurrentContext(), [UIColor whiteColor].CGColor);
but to no avail. Would you please tell which is the better way to do so ?
The below is my working
-(UIImage*) drawText:(NSString*) text
inImage:(UIImage*) image
atPoint:(CGPoint) point
{
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];
UIFont *font = [UIFont boldSystemFontOfSize:24];
if([text respondsToSelector:#selector(drawInRect:withAttributes:)])
{
//IOS 7
NSDictionary *att = #{NSFontAttributeName:font};
[text drawInRect:rect withAttributes:att];
}
else
{
[text drawInRect:CGRectIntegral(rect) withFont:font];
}
CGContextSetFillColorWithColor(UIGraphicsGetCurrentContext(), [UIColor whiteColor].CGColor);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Depending on how far back in time you want to go, pick any of these 3 solutions.
The 6+ and 7+ versions make use of NSForegroundColorAttributeName to select the color. These are the preferred methods.
iOS 7+
// (add the color to the attribute)
NSDictionary *att = #{NSFontAttributeName :font,
NSForegroundColorAttributeName:[UIColor whiteColor]};
[#"test" drawInRect:rect withAttributes:att];
iOS 6+ (works in iOS 7 too)
// (add the color to the attribute, using NSAttributedString)
NSDictionary *att = #{NSFontAttributeName :font,
NSForegroundColorAttributeName:[UIColor whiteColor]};
NSAttributedString * text = [[NSAttributedString alloc] initWithString:#"test"
attributes:att];
[text drawInRect:rect];
iOS 5 (does not work on iOS 7)
// No attributes involved
[[UIColor whiteColor] set];
[#"test" drawInRect:CGRectIntegral(rect) withFont:font];

Resources