I'm using NSUserDefaults to save text entered into multiple UITextFields. I want to display the text on a PDF. Can I use the following method to handle each field and add it to the PDF? Right now in my example you can see how I am adding a "name" field. Any tips is appreciated!
+(void)drawText
{
NSUserDefaults * prefs = [NSUserDefaults standardUserDefaults];
NSString * nameString = [prefs stringForKey:#"name"];
CFStringRef stringRef = (CFStringRef)nameString;
// Prepare the text using a Core Text Framesetter
CFAttributedStringRef currentText = CFAttributedStringCreate(NULL, stringRef, NULL);
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(currentText);
CGRect frameRect = CGRectMake(30, 0, 300, 60);
CGMutablePathRef framePath = CGPathCreateMutable();
CGPathAddRect(framePath, NULL, frameRect);
// Get the frame that will do the rendering.
CFRange currentRange = CFRangeMake(0, 0);
CTFrameRef frameRef = CTFramesetterCreateFrame(framesetter, currentRange, framePath, NULL);
CGPathRelease(framePath);
// Get the graphics context.
CGContextRef currentContext = UIGraphicsGetCurrentContext();
// Put the text matrix into a known state. This ensures
// that no old scaling factors are left in place.
CGContextSetTextMatrix(currentContext, CGAffineTransformIdentity);
// Core Text draws from the bottom-left corner up, so flip
// the current transform prior to drawing.
CGContextTranslateCTM(currentContext, 0, 100);
CGContextScaleCTM(currentContext, 1.0, -1.0);
// Draw the frame.
CTFrameDraw(frameRef, currentContext);
CFRelease(frameRef);
CFRelease(stringRef);
CFRelease(framesetter);
}
Change method like given below for dynamic text in textField:
+(void)drawText:(NSString *)value index:(int)index
{
//NSUserDefaults * prefs = [NSUserDefaults standardUserDefaults];
//NSString * nameString = [prefs stringForKey:#"name"];
CFStringRef stringRef = value; //(CFStringRef)nameString;
// Prepare the text using a Core Text Framesetter
CFAttributedStringRef currentText = CFAttributedStringCreate(NULL, stringRef, NULL);
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(currentText);
CGRect frameRect = CGRectMake(30, (index*70), 300, 60); //for horizontal textfields
CGMutablePathRef framePath = CGPathCreateMutable();
CGPathAddRect(framePath, NULL, frameRect);
// Get the frame that will do the rendering.
CFRange currentRange = CFRangeMake(0, 0);
CTFrameRef frameRef = CTFramesetterCreateFrame(framesetter, currentRange, framePath, NULL);
CGPathRelease(framePath);
// Get the graphics context.
CGContextRef currentContext = UIGraphicsGetCurrentContext();
// Put the text matrix into a known state. This ensures
// that no old scaling factors are left in place.
CGContextSetTextMatrix(currentContext, CGAffineTransformIdentity);
// Core Text draws from the bottom-left corner up, so flip
// the current transform prior to drawing.
CGContextTranslateCTM(currentContext, 0, 100);
CGContextScaleCTM(currentContext, 1.0, -1.0);
// Draw the frame.
CTFrameDraw(frameRef, currentContext);
CFRelease(frameRef);
CFRelease(stringRef);
CFRelease(framesetter);
}
Use like this as i assume u have array of values for adding textfield:
for(int i=0;i>[arrOfValues count];i++)
{
[YourControllerName drawText:[arrOfValues objectAtIndex:i] index:i];
}
Related
I am porting my iOS App to MAC-OS and I am stopped because I cannot create a PDF file programmatically.
What I need to do is to create a PDF from a given .txt file
My code in ios version is this:
- (void) createPDF:(NSString *)fileName withContent:(NSString *)content forSize:(int)fontSize andFont:(NSString *)font andColor:(NSColor *)color{
CGRect a4Page = CGRectMake(0, 0, DOC_WIDTH, DOC_HEIGHT);
NSDictionary *fileMetaData = [[NSDictionary alloc] init];
if (!UIGraphicsBeginPDFContextToFile(fileName, a4Page, fileMetaData )) {
NSLog(#"error creating PDF context");
return;
}
BOOL done = NO;
CGContextRef context = UIGraphicsGetCurrentContext();
CFRange currentRange = CFRangeMake(0, 0);
CGContextSetTextDrawingMode (context, kCGTextFill);
CGContextSelectFont (context, [font cStringUsingEncoding:NSUTF8StringEncoding], fontSize, kCGEncodingMacRoman);
CGContextSetFillColorWithColor(context, [color CGColor]);
// Initialize an attributed string.
CFMutableAttributedStringRef attrString = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
CFAttributedStringReplaceString (attrString, currentRange, (CFStringRef)content);
// Create the framesetter with the attributed string.
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attrString);
do {
UIGraphicsBeginPDFPage();
CGMutablePathRef path = CGPathCreateMutable();
CGRect bounds = CGRectMake(LEFT_MARGIN,
TOP_MARGIN,
DOC_WIDTH - RIGHT_MARGIN - LEFT_MARGIN,
DOC_HEIGHT - TOP_MARGIN - BOTTOM_MARGIN);
CGPathAddRect(path, NULL, bounds);
// Create the frame and draw it into the graphics context
CTFrameRef frame = CTFramesetterCreateFrame(framesetter, currentRange, path, NULL);
if(frame) {
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0, bounds.origin.y);
CGContextScaleCTM(context, 1, -1);
CGContextTranslateCTM(context, 0, -(bounds.origin.y + bounds.size.height));
CTFrameDraw(frame, context);
CGContextRestoreGState(context);
// Update the current range based on what was drawn.
currentRange = CTFrameGetVisibleStringRange(frame);
currentRange.location += currentRange.length;
currentRange.length = 0;
CFRelease(frame);
}
// If we're at the end of the text, exit the loop.
if (currentRange.location == CFAttributedStringGetLength((CFAttributedStringRef)attrString))
done = YES;
}
while(!done);
UIGraphicsEndPDFContext();}
XCode gives to me a lot of warnings and errors:
Errors: Undefined symbols for architecture x86_64
Warnings: Implicit declaration of function 'UIGraphicsBeginPDFContextToFile' is invalid in C99 [for example]
Could someone help me to find a solution to my problem?
I tried to use CGPDFContextCreateWithURL but I didn't get any result
Thank you all
Is there any way to provide this kind of effect in a UITextView? If not, then how can I achieve this effect?
Having the same requirement, I created a UIView subclass that draws text with a drop cap. The text is drawn using core text, and as #CodaFi suggested the drop cap is drawn in a separate core text frame.
The full implementation of the class: https://gist.github.com/4596476
The meat of it looks something like this:
- (void)drawRect:(CGRect)rect {
// Create attributed strings
NSAttributedString *bodyText = [[NSAttributedString alloc] initWithString:[self.text substringWithRange:NSMakeRange(1, self.text.length -1)] attributes:_bodyAttributes];
NSAttributedString *capText = [[NSAttributedString alloc] initWithString:[[self.text substringWithRange:NSMakeRange(0, 1)] uppercaseString] attributes:_capAttributes];
CGRect capFrame = CGRectMake(0, 0, [capText size].width, [capText size].height);
// Set up graphics context
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
// Create type frames
CGMutablePathRef bodyPath = CGPathCreateMutable();
CGAffineTransform transform = CGAffineTransformTranslate(CGAffineTransformMakeScale(1, -1), 0, -self.bounds.size.height);
CGPathMoveToPoint(bodyPath, &transform, CGRectGetMaxX(capFrame), 0);
CGPathAddLineToPoint(bodyPath, &transform, self.bounds.size.width, 0);
CGPathAddLineToPoint(bodyPath, &transform, self.bounds.size.width, self.bounds.size.height);
CGPathAddLineToPoint(bodyPath, &transform, 0, self.bounds.size.height);
CGPathAddLineToPoint(bodyPath, &transform, 0, CGRectGetMaxY(capFrame));
CGPathAddLineToPoint(bodyPath, &transform, CGRectGetMaxX(capFrame), CGRectGetMaxY(capFrame));
CGPathCloseSubpath(bodyPath);
CGMutablePathRef capPath = CGPathCreateMutable();
CGPathAddRect(capPath, &transform, CGRectMake(0, 0, capFrame.size.width+10, capFrame.size.height+10));
// Draw text
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef) bodyText);
CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), bodyPath, NULL);
CFRelease(framesetter);
CTFrameDraw(frame, context);
CFRelease(frame);
framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)capText);
frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), capPath, NULL);
CFRelease(framesetter);
CTFrameDraw(frame, context);
CFRelease(frame);
}
The gist of it is you create two paths, one rectangle to contain the drop cap, and a rectangle with a notch removed for the rest of the text. The full implementation on gist allows you to control the fonts, spacing around the drop cap, and content inset of the whole view using properties.
It does not implement most of the features of a UITextView (only the features I needed) so it may not be a full solution.
Hope that helps!
I have 4 editable uitextviews, user can set its font font color etc. Now i want to draw pdf of these textviews, but using [self.view.layer renderInContext:UIGraphicsGetCurrentContext()] method causes to lose its quality, so i cannot use this method, instead i am iterating over subviews and drawing the text in pdf. Now my problem is that for some textviews text is printed correctly in pdf,but for other textviews text is not drawn in proper position.This is my code to draw pdf from textview.
NSArray *arrayOfsubviews=[self.view subviews];
for (int i=0; i<[arrayOfsubviews count]; i++) {
if ([[arrayOfsubviews objectAtIndex:i]isKindOfClass:[UITextView class]]) {
UITextView *texts=[arrayOfsubviews objectAtIndex:i];
CTFontRef ctFont = CTFontCreateWithName((__bridge CFStringRef)texts.font.fontName, texts.font.pointSize,NULL);
CGColorRef color = texts.textColor.CGColor;
NSDictionary *attributesDict = [NSDictionary dictionaryWithObjectsAndKeys:
(__bridge id)ctFont, (id)kCTFontAttributeName,
color, (id)kCTForegroundColorAttributeName,nil];
NSAttributedString *stringToDraw = [[NSAttributedString alloc] initWithString:texts.text
attributes:attributesDict];
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef) stringToDraw);
CGRect rect=CGRectMake(texts.frame.origin.x,916-texts.frame.origin.y-texts.frame.size.height, texts.frame.size.width, texts.frame.size.height);
CGMutablePathRef pathRef = CGPathCreateMutable();
CGPathAddRect(pathRef, NULL,rect);
CTFrameRef frameRef = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0),pathRef, NULL);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0,916);
CGContextScaleCTM(context, 1.0, -1.0);
CTFrameDraw(frameRef, context);
CGContextRestoreGState(context);
CGPathRelease(pathRef);
}
}
UIGraphicsEndPDFContext();
I use this to draw my text, works fairly well.. maybe it can point you in the right direction.
#define kBorderInset 20.0
#define kMarginInset 10.0
- (void) drawText{
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextSetRGBFillColor(currentContext, 0.0, 0.0, 0.0, 1.0);
NSString *textToDraw = #"Your Text Here";
UIFont *font = [UIFont systemFontOfSize:14.0];
CGSize stringSize = [textToDraw sizeWithFont:font
constrainedToSize:CGSizeMake(pageSize.width - 2*kBorderInset-2*kMarginInset, pageSize.height - 2*kBorderInset - 2*kMarginInset)
lineBreakMode:UILineBreakModeWordWrap];
CGRect renderingRect = CGRectMake(kBorderInset + kMarginInset, kBorderInset + kMarginInset + 350.0, pageSize.width - 2*kBorderInset - 2*kMarginInset, stringSize.height);
[textToDraw drawInRect:renderingRect
withFont:font
lineBreakMode:UILineBreakModeWordWrap
alignment:UITextAlignmentLeft];
}
You want to use drawInContext: instead of renderInContext:. renderInContext will rasterize the text, drawInContext write encode it as editable, resolution-independent text.
Some looses of quality or blurry views are because of the frame. The vales for locate a frame in the screen are CGFloat, so you could have a frame located in the point (0.5, 5.7), obviously this dowsn't have any sense and the point.x must be 0 or 1. Decimal values confuse the Operative System, so it's recommend to ensure that frames have always values with no decimal numbers.
You can ges some more information here: http://www.cobiinteractive.com/blog/2011/06/objective-c-blurry-uiview/ or here: http://www.markj.net/iphone-uiview-blurred-blurry-view/
I'm trying to display texts in a CGContext and I want to know how to wrap the texts. How can I make this possible?
Here's my code:
NSString *text1 = #"These three first articles describe the God in whom we believe. The pictures of the triangle represents the Triune God), of Jesus Christ and of the dove representing the Holy Spirit are grouped together in order to manifest their intimate relationships and unity.";
- (void) renderPageAtIndex:(NSUInteger)index inContext:(CGContextRef)ctx {
if(index>[images count]-1)return;
UIImage *image = [images objectAtIndex:index];
CGRect imageRect = CGRectMake(0, 0, image.size.width, image.size.height);
CGAffineTransform transform = aspectFit(imageRect,
CGContextGetClipBoundingBox(ctx));
NSString *text1 = [script objectAtIndex:index];
char* text = (char *)[text1 cStringUsingEncoding:NSASCIIStringEncoding];
CGContextSelectFont(ctx, "Arial", 30, kCGEncodingMacRoman);
CGContextConcatCTM(ctx, transform);
CGContextDrawImage(ctx, imageRect, [image CGImage]);
CGContextSetTextPosition(ctx, 0.0f, round(30 / 4.0f));
CGContextSetTextDrawingMode(ctx, kCGTextFill);
CGContextSetRGBFillColor(ctx, 0, 0, 0, 1);
CGContextShowTextAtPoint(ctx,10,10,text, strlen(text));
}
If you need more advanced text formatting (like wrapping), use Core Text instead. To display a simple string in a rectangle, use
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attrString);
CGPath p = CGPathCreateMutable();
CGPathAddRect(p, rect);
CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0,0), p, NULL);
CTFrameDraw(frame, context);
I'm having a UIView that renders some text using CoreText,everything works fine,
except for the fact that the entire view has black background color.
I've tried the most basic solutions like
[self setBackgroundColor:[UIColor clearColor]];
or
CGFloat components[] = {0.f, 0.f, 0.f, 0.f };
CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
CGColorRef transparent = CGColorCreate(rgbColorSpace, components);
CGContextSetFillColorWithColor(context, transparent);
CFRelease(transparent);
but this didn't help at all.
I'm just pounding my head on this issue, because I can't quite understand
how does really core text works and how is this pure-C layer related
with all the other objective-c stuff.
And this doesn't help very much in solving this problem,
so I'm asking you folks, if could you provide me a solution and (most important)
an explanation about it.
FIY I'm posting also the code of the CoreText view.
it's all based on 2 functions: parseText which builds up the CFAttributedString and the
drawRect that takes care of the drawing part.
-(void) parseText {
NSLog(#"rendering this text: %#", symbolHTML);
attrString = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
CFAttributedStringReplaceString (attrString, CFRangeMake(0, 0), (CFStringRef)symbolHTML);
CFStringRef fontName = (CFStringRef)#"MetaSerif-Book-Accent";
CTFontRef myFont = CTFontCreateWithName((CFStringRef)fontName, 18.f, NULL);
CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = { 1.0, 0.3f, 0.3f, 1.f };
CGColorRef redd = CGColorCreate(rgbColorSpace, components);
CFAttributedStringSetAttribute(attrString, CFRangeMake(0,0),
kCTForegroundColorAttributeName, redd);
CFRelease(redd);
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, CFStringGetLength((CFStringRef)symbolHTML)), kCTFontAttributeName, myFont);
CTTextAlignment alignment = kCTLeftTextAlignment;
CTParagraphStyleSetting settings[] = {
{kCTParagraphStyleSpecifierAlignment, sizeof(alignment), &alignment}
};
CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(settings, sizeof(settings) / sizeof(settings[0]));
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, CFStringGetLength((CFStringRef)attrString)), kCTParagraphStyleAttributeName, paragraphStyle);
[self calculateHeight];
}
and this is the DrawRect function:
- (void)drawRect:(CGRect)rect {
/* get the context */
CGContextRef context = UIGraphicsGetCurrentContext();
/* flip the coordinate system */
float viewHeight = self.bounds.size.height;
CGContextTranslateCTM(context, 0, viewHeight);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextSetTextMatrix(context, CGAffineTransformMakeScale(1.0, 1.0));
/* generate the path for the text */
CGMutablePathRef path = CGPathCreateMutable();
CGRect bounds = CGRectMake(0, 0, self.bounds.size.width-20.0, self.bounds.size.height);
CGPathAddRect(path, NULL, bounds);
/* draw the text */
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attrString);
CTFrameRef frame = CTFramesetterCreateFrame(framesetter,
CFRangeMake(0, 0), path, NULL);
CFRelease(framesetter);
CFRelease(path);
CTFrameDraw(frame, context);
CGFloat components[] = {0.f, 0.f, 0.f, 0.f };
CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
CGColorRef transparent = CGColorCreate(rgbColorSpace, components);
CGContextSetFillColorWithColor(context, transparent);
CFRelease(transparent);
}
I hope that everything is clear, but if something looks
confusing, just ask and I'll be glad to explain myself better.
thank you in advance for this hardcore issue :)
k
Here's a question. Did you remember to set view.opaque = NO? Because if not you'll get that black background regardless of what else you do.