I'm trying to create a UIImage from an NSAttributedString that's has a skewed transform. I can make a UILabel or UIImageView and skew that view, but unfortunately I need to create a UIImage after the string has been skewed. I've tried the following..
CGAffineTransform skewTransform = CGAffineTransformIdentity;
skewTransform.b = (M_1_PI / 2);
UIGraphicsBeginImageContextWithOptions(mSize, NO, 1.0);
UILabel* skewedLabel = [[UILabel alloc] init];
skewedLabel.attributedText = stringToBeSkewed;
CGContextSetTextMatrix(UIGraphicsGetCurrentContext(), skewTransform);
skewedLabel.layer.affineTransform = skewTransform;
// The following 3 calls haven't worked
// [stringToBeSkewed drawInRect:inputRectParam.rect];
// [skewedLabel.layer renderInContext:UIGraphicsGetCurrentContext()];
// [skewedLabel.layer drawInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
I get that the CALayer is CoreAnimation and CoreGraphics doesn't recognize this, but is there a way to get skewed text to be captured within the context and converted into a UIImage?
I was able to get a UIImage from text by doing the following, hope this helps someone out. Also, it's not the cleanest image, so any advice on sharpening it up would be appreciated.
UIFont* font = [UIFont fontWithName:#"(your font name)" size:60];
CTFontRef skewFont = CTFontCreateWithName((__bridge CFStringRef)font.fontName, font.pointSize, NULL);
// Create an attributed string for shadowed text
CFStringRef skewKeys[] = { kCTFontAttributeName, kCTForegroundColorAttributeName };
CFTypeRef skewValues[] = { skewFont, [UIColor colorWithRed:0 green:0 blue:0 alpha:.4].CGColor };
CFDictionaryRef skewAttributes = CFDictionaryCreate(NULL, (const void **)&skewKeys, (const void **)&skewValues,
sizeof(skewKeys) / sizeof(skewKeys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFStringRef theCFString = (__bridge CFStringRef)inputStringParam.string;
CFAttributedStringRef skewString = CFAttributedStringCreate(NULL, theCFString, skewAttributes);
CFRelease(skewAttributes);
// create skew transform
CGAffineTransform skewTransform = CGAffineTransformIdentity;
skewTransform.b = (value to be skewed);
// Draw the string
CTLineRef skewLine = CTLineCreateWithAttributedString(skewString);
CGContextSetTextMatrix(UIGraphicsGetCurrentContext(), CGAffineTransformMakeScale(1.0, -1.0));
CGContextConcatCTM(UIGraphicsGetCurrentContext(), skewTransform);
// draw and capture shadow image
CGContextSetTextPosition(UIGraphicsGetCurrentContext(), inputDrawPointParam.point.x, inputDrawPointParam.point.y);
CTLineDraw(skewLine, UIGraphicsGetCurrentContext());
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CFRelease(skewLine);
CFRelease(skewString);
CFRelease(skewFont);
Related
I am trying to place UIColor on particular (X,Y) position of UIImage,
But not able to get it,
Here, My code looks like below,
Below method return me a UIColor from particular (X,Y) position of UIImage
- (UIColor *)isWallPixel:(UIImage *)image xCoordinate:(int)x yCoordinate:(int)y {
CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage));
const UInt8* data = CFDataGetBytePtr(pixelData);
int pixelInfo = ((image.size.width * y) + x ) * 4; // The image is png
UInt8 red = data[pixelInfo]; // If you need this info, enable it
UInt8 green = data[(pixelInfo + 1)]; // If you need this info, enable it
UInt8 blue = data[pixelInfo + 2]; // If you need this info, enable it
UInt8 alpha = data[pixelInfo + 3]; // I need only this info for my maze game
CFRelease(pixelData);
UIColor* color = [UIColor colorWithRed:red/255.0f green:green/255.0f blue:blue/255.0f alpha:alpha/255.0f]; // The
return color;
}
//Original Image, I get image pixels from this image.
UIImage* image = [UIImage imageNamed:#"plus.png"];
//Need convert Image
UIImage *imagedata = [[UIImage alloc]init];
//size of the original image
int Width = image.size.width;
int height = image.size.height;
//need to get this size of another blank image
CGRect rect = CGRectMake(0.0f, 0.0f, Width, height);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
for (int i = 0; i <Width; i++) {
for (int j = 0; j < height; j++) {
//Here I got the Image pixel color from below highlighted method
UIColor *colordatra = [self isWallPixel:image xCoordinate:i yCoordinate:j];
CGContextSetFillColorWithColor(context, [colordatra CGColor]);
rect.origin.x = i;
rect.origin.y = j;
CGContextDrawImage(context, rect, imagedata.CGImage);
imagedata = UIGraphicsGetImageFromCurrentImageContext();
}
}
UIGraphicsEndImageContext();
Please note that I want to functionality like get the UIColor from particular position and placed that UIColor on another blank image at same position.
With above code I am not able to get this, Please let me know where I have done the mistake.
Hope, for favourable reply,
Thanks in Advance.
By using uiView you can do this one like that.Actually you are getting x,y,width and height
uiview *view = [uiview alloc]initwithframe:CGRectMake(x,y,width,height);
view.backgroundcolor =[UIColor colorWithRed:red/255.0f green:green/255.0f blue:blue/255.0f alpha:alpha/255.0f];
[self.YourImageView addsubview:view];
I want to add text on an image programmatically, but I can't seem to find how to do it. I've found one solution on here, but a lot of things are deprecated so it doesn't work...
Please help!
EDIT:
Here's my code:
UIImage *backgroundImage = image;
NSMutableDictionary *stringAttributes = [NSMutableDictionary dictionary];
[stringAttributes setObject: [UIFont fontWithName:#"Helvetica" size:20] forKey: NSFontAttributeName];
[stringAttributes setObject: [UIColor whiteColor] forKey: NSForegroundColorAttributeName];
[stringAttributes setObject: [NSNumber numberWithFloat: 2.0] forKey: NSStrokeWidthAttributeName];
[stringAttributes setObject: [UIColor blackColor] forKey: NSStrokeColorAttributeName];
[backgroundImage drawInRect:CGRectMake(0, 0, backgroundImage.size.width, backgroundImage.size.height)];
NSString *myString = [NSString stringWithFormat:#"Yolo"];
[myString drawInRect:CGRectMake(0, 0, 200, 50) withAttributes:stringAttributes];
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.imageView.image = result;
NEW EDIT:
I'd like to clearify some things to understand the question better. My app lets the user send a photo that they have taken themselves via text messaging or by email, and I want to add some pre-written text from strings, on the photo.
So my question is: How do I get the text from the strings, on to the photo?
It took forever, but I figured it out.
Code:
NSMutableDictionary *stringAttributes = [NSMutableDictionary dictionary];
[stringAttributes setObject: [UIFont fontWithName:#"Avenir Book" size:250] forKey: NSFontAttributeName];
[stringAttributes setObject: [UIColor whiteColor] forKey: NSForegroundColorAttributeName];
NSString *placeString = [NSString stringWithFormat:#"Text here."];
CGSize size = [placeString sizeWithAttributes:stringAttributes];
//Create a bitmap context into which the text will be rendered.
UIGraphicsBeginImageContext(size);
//Render the text.
[placeString drawAtPoint:CGPointMake(0.0, 0.0) withAttributes:stringAttributes];
//Retrieve the image.
UIImage *imagene = UIGraphicsGetImageFromCurrentImageContext();
UIImage *mergedImage = _imageView.image;
CGSize newSize = image.size;
UIGraphicsBeginImageContext(newSize);
//Use existing opacity as is.
[mergedImage drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
//Apply supplied opacity if applicable.
CGRect drawingRect = (CGRect) {.size = size};
drawingRect.origin.x = (newSize.width - size.width) * 0.01;
drawingRect.origin.y = (newSize.height - size.height) * 0.03;
[imagene drawInRect:drawingRect blendMode:kCGBlendModeNormal alpha:1];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[_imageView setImage:newImage];
self.imageView.image = newImage;
Here's a general approach, code is likely missing but it gives you the important bits.
CGContextRef ctx = CGBitmapContextCreate(...)
CGContextDrawImage (gtx, myContextRect, myimage);
CGContextSelectFont(ctx, "Helvetica", 10.0, kCGEncodingMacRoman);
CGContextSetCharacterSpacing(ctx, 1.7);
CGContextSetTextDrawingMode(ctx, kCGTextFill);
CGContextShowTextAtPoint(ctx, 100.0, 100.0, "SOME TEXT", 9);
CGImageRef imageRef = CGBitmapContextCreateImage(ctx);
UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
This will give you an image you can put in a view, or share via UIActivityViewController. I'm sure you can work out the bits.
The approach is:
1) Create bitmap context.
2) Render image
3) Add text
4) Save context to image
Simply place a UILabel on top of a UIImageView in IB and position them as desired using constraints. Then set the text into the label as desired.
EDIT:
Now that I know you want to be able to save I'd suggest using UIGraphicsBeginImageContextWithOptions to create an off-screen graphics context. I find that easier to deal with than CGContext and Core Graphics calls.
Draw into the context and the fetch and image from it.
Make the context the size of your image, and pass in a scale of 0 to use the device's native scale.
Your code might look something like this:
//Create an off-screen graphics context for drawing.
CGSize imageSize = myImage.size;
UIGraphicsBeginImageContextWithOptions(imageSize, false, 0);
//draw your image using drawAtPoint(CGPointmake(0,0));
//draw your string using one of the drawAtPoint or drawInRect methods
//available in NSString UIKit additions
//Fetch the resulting image from the context.
UIImage *maskImage = UIGraphicsGetImageFromCurrentImageContext();
//End the off-screen context
UIGraphicsEndImageContext();
In my app I'm trying to add a text on an image. I've done it using a post in stackoverflow. It's like the following.
+(UIImage *)addText:(UIImage *)img text:(NSString *)text1{
int w = img.size.width;
int h = img.size.height;
//lon = h - lon;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst);
CGContextDrawImage(context, CGRectMake(0, 0, w, h), img.CGImage);
CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1);
char* text = (char *)[text1 cStringUsingEncoding:NSASCIIStringEncoding];// "05/05/09";
CGContextSelectFont(context, "Arial", 18, kCGEncodingMacRoman);
CGContextSetTextDrawingMode(context, kCGTextFill);
CGContextSetRGBFillColor(context, 255, 255, 255, 1);
//rotate text
CGContextSetTextMatrix(context, CGAffineTransformMakeRotation( -M_PI/4 ));
CGContextShowTextAtPoint(context, 4, 52, text, strlen(text));
CGImageRef imageMasked = CGBitmapContextCreateImage(context);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
return [UIImage imageWithCGImage:imageMasked];
}
When I'm writing a text using this code, the original image's colour is changed like the following,
Original Image
Output with Text
Can anyone explain why is this happening. and how to fix this??
Thanks in Advance!!
We need to create a image context and apply drawing and get final image from this context. You can try this method. Hope this help you.
+ (UIImage *) addText:(UIImage *)img text:(NSString *)text
{
CGRect rect = [[UIScreen mainScreen] bounds];
// create a context according to image size
UIGraphicsBeginImageContext(rect.size);
// draw image
[img drawInRect:rect];
UIFont* font = [UIFont systemFontOfSize:14.0];
/// Make a copy of the default paragraph style
NSMutableParagraphStyle* paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
/// Set line break mode
paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail;
/// Set text alignment
paragraphStyle.alignment = NSTextAlignmentCenter;
NSDictionary *attributes = #{ NSFontAttributeName: font,
NSParagraphStyleAttributeName: paragraphStyle };
CGRect textRect = CGRectMake(20, 160.0, 280.0, 44);
/// draw text
[text drawInRect:textRect withAttributes:attributes];
// get as image
UIImage * image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
EDIT: This can only be run on the main thread! So it's pretty much useless.
+(UIImage *)imageFromView:(UIView *)view
{
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
Here's a new one using Core Graphics that can be used on any thread
+ (UIImage *)imageFromView:(UIView *)view
{
size_t width = view.bounds.size.width*2;
size_t height = view.bounds.size.height*2;
unsigned char *imageBuffer = (unsigned char *)malloc(width*height*8);
CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef imageContext = CGBitmapContextCreate(imageBuffer, width, height, 8, width*4, colourSpace,kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colourSpace);
CGContextTranslateCTM(imageContext, 0.0, height);
CGContextScaleCTM(imageContext, 2.0, -2.0);
[view.layer renderInContext:imageContext];
CGImageRef outputImage = CGBitmapContextCreateImage(imageContext);
UIImage *image = [[UIImage alloc] initWithCGImage:outputImage];
CGImageRelease(outputImage);
CGContextRelease(imageContext);
free(imageBuffer);
return image;
}
I am using this and it works fine for me
- (UIImage*) drawText:(NSString*) text
inImage:(UIImage*) image
atPoint:(CGPoint) point
{
UIFont *font = [UIFont fontWithName:FONT_BOLD size:20];
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);
[UIColorFromRGB(0x515151) set];
[text drawInRect:CGRectIntegral(rect) withFont:font];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
I am drawing the text on the image. text is drawn without any problem , but my text is dynamic sometimes its more characters or sometimes its less.
From below image you can see "This is long message more than 320 width of image , in that of image doesn't come .
I want all the Message to be displayed in the next line, because my Message is dynamic and i want to display it in 320 *480 size of image, here i am displaying small image just for testing purpose .
This is the Code for drawing Text :
-(UIImage *)addText:(UIImage *)img text:(NSString *)text1{
int w = img.size.width;
int h = img.size.height;
//lon = h - lon;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst);
CGContextDrawImage(context, CGRectMake(0, 0, w, h), img.CGImage);
CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1);
char* text = (char *)[text1 cStringUsingEncoding:NSASCIIStringEncoding];
CGContextSelectFont (context, // 3
"Helvetica-Bold",
15,
kCGEncodingMacRoman);
CGContextSetTextDrawingMode(context, kCGTextFill);
CGContextSetRGBFillColor(context, 255, 255, 255, 1);
CGContextShowTextAtPoint(context, 4, 52, text, strlen(text));
CGImageRef imageMasked = CGBitmapContextCreateImage(context);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
return [UIImage imageWithCGImage:imageMasked];
}
Try This code:
lblText.text=[NSString stringWithFormat:#"Put Your Text"];
lblText.font = [UIFont fontWithName:#"Helvetica" size:10.0f];
CGPoint point=lblText.center;
imgview.image =[self drawText:lblText.text inImage:imgview.image atPoint:point];
//Save it in Document directory for Checking Purpose...
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDirectory stringByAppendingPathComponent:#"savedImage.png"];
UIImage *image1 = imgview.image; // imageView is my image from camera
NSData *imageData = UIImagePNGRepresentation(image1);
[imageData writeToFile:savedImagePath atomically:NO];
-(UIImage *) drawText:(NSString*) text inImage:(UIImage*)image atPoint:(CGPoint)point
{
UIFont *font =lblText.font;;
if ([UIScreen instancesRespondToSelector:#selector(scale)]) {
UIGraphicsBeginImageContextWithOptions(imgview.frame.size, NO, 0.0f);
} else {
UIGraphicsBeginImageContext(imgview.frame.size);
}
[image drawInRect:CGRectMake(0,0,imgview.frame.size.width,imgview.frame.size.height)];
CGRect rect = CGRectMake(point.x,point.y,lblText.frame.size.width, lblText.frame.size.height);//Set Frame as per your Requirement
[lblText.textColor set];
[text drawInRect:CGRectIntegral(rect) withFont:font];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
It will Help.
Use a UIImageView to display your image and add a UILabel as the subview of UIImageView.
1.configure your UILabel first:
[yourLabel setNumberOfLines:0];
[yourLabel setLineBreakMode:NSLineBreakByWordWrapping];
2.get your label frame with the contents length
- (CGRect)labelFrameWithText:(NSString *)text
{
CGRect rect;
// the font of your text
UIFont *font = [UIFont systemFontOfSize:15.0];
NSDictionary *attributes = #{NSFontAttributeName: font};
// the first parametric CGSize is the max size that the rect's size can be
CGRect boundingRect = [title boundingRectWithSize:CGSizeMake(youImageWidth, 100.0)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:attributes
context:nil];
//the rect of the UILabel
//This method returns fractional sizes (in the size component of the returned CGRect); to use a returned size to size views, you must use raise its value to the nearest higher integer using the ceil function.
rect = CGRectMake(yourLabelOriginX,
yourLabelOriginY,
ceil(boundingRect.size.width),
ceil(boundingRect.size.height));
return rect;
}
3.change your label's frame and setText
------- old version ---------
CGSize contentSize = [content sizeWithFont:font
constrainedToSize:CGSizeMake(maxWidth, maxHeight)
lineBreakMode: NSLineBreakByWordWrapping];
I have an UILabel subclass that draws some text in drawinRect method using a pattern image. This pattern image is a gradient image I am creating.
-(void)drawRect:(CGRect)rect
{
UIColor *color = [UIColor colorWithPatternImage:[self gradientImage]];
[color set];
[someText drawInRect:rec withFont:font lineBreakMode:UILineBreakModeWordWrap alignment:someAlignment];
}
The gradient image method is
-(UIImage *)gradientImage
{
NSData *colorData = [[NSUserDefaults standardUserDefaults] objectForKey:#"myColor"];
UIColor *co = [NSKeyedUnarchiver unarchiveObjectWithData:colorData];
colors = [NSArray arrayWithObjects:co,co,[UIColor whiteColor],co,co,co,co,nil];
NSArray *gradientColors=colors;
CGFloat width;
CGFloat height;
CGSize textSize = [someText sizeWithFont:font];
width=textSize.width; height=textSize.height;
UIGraphicsBeginImageContext(CGSizeMake(width, height));
// get context
CGContextRef context = UIGraphicsGetCurrentContext();
// push context to make it current (need to do this manually because we are not drawing in a UIView)
UIGraphicsPushContext(context);
//draw gradient
CGGradientRef gradient;
CGColorSpaceRef rgbColorspace;
//set uniform distribution of color locations
size_t num_locations = [gradientColors count];
CGFloat locations[num_locations];
for (int k=0; k<num_locations; k++)
{
locations[k] = k / (CGFloat)(num_locations - 1); //we need the locations to start at 0.0 and end at 1.0, equaly filling the domain
}
//create c array from color array
CGFloat components[num_locations * 4];
for (int i=0; i<num_locations; i++)
{
UIColor *color = [gradientColors objectAtIndex:i];
NSAssert(color.canProvideRGBComponents, #"Color components could not be extracted from StyleLabel gradient colors.");
components[4*i+0] = color.red;
components[4*i+1] = color.green;
components[4*i+2] = color.blue;
components[4*i+3] = color.alpha;
}
rgbColorspace = CGColorSpaceCreateDeviceRGB();
gradient = CGGradientCreateWithColorComponents(rgbColorspace, components, locations, num_locations);
CGRect currentBounds = self.bounds;
CGPoint topCenter = CGPointMake(CGRectGetMidX(currentBounds), 0.0f);
CGPoint midCenter = CGPointMake(CGRectGetMidX(currentBounds), CGRectGetMidY(currentBounds));
CGContextDrawLinearGradient(context, gradient, topCenter, midCenter, 0);
CGGradientRelease(gradient);
CGColorSpaceRelease(rgbColorspace);
// pop context
UIGraphicsPopContext();
// get a UIImage from the image context
UIImage *gradientImage = UIGraphicsGetImageFromCurrentImageContext();
// clean up drawing environment
UIGraphicsEndImageContext();
return gradientImage;
}
Everything is working fine. The text is drawn with nice glossy effect. Now my problem is if I change the x or y position of the text inside the UILabel and then call the
[someText drawinRect:rec]... to redraw, the gloss effect is generated differently. It seems that the pattern image is changing with change of text position..
The following is the effect for the frame rec = CGRectMake(0, 10, self.frame.size.width, self.frame.size.height);
The following is the effect for the frame rec = CGRectMake(0, 40, self.frame.size.width, self.frame.size.height);
I hope I have explained my question well. Could not find any exact answer elsewhere. Thanks in advance.
You might want to look at using an existing 3rd party solution like FXLabel.