我正在 iOS 应用程序中动态构建 PDF 文档。我正在尝试将 HTML 格式的字符串转换为 NSAttributedString,然后将其放置在我的 PDF 文档页面上。
如果我将字符串视为普通的 NSString,我可以将其设置为框架并将其放置在页面上的任何位置(字符串中包含 html 标记)。
如果我使用 initWithString 创建一个 NSAttributedString,我还可以将生成的属性字符串放在页面上的任何位置。
如果我使用将字符串转换为 NSAttributedString
NSAttributedString initWithData:options:documentAttributes:error:
转换工作完美,标签被转换为属性。但是当我尝试将字符串的框架定位在页面上时,当我将框架从 0,0 向下和向右移动时,文本被剪裁。我可以将框架向下移动 20 点,然后逐行将文本从顶部剪掉。当所有文本从页面上消失时,我可以向右移动框架,直到原点大于宽度。
代码:
#pragma mark - === PDF BUILD Methods === -
- (void)buildPDF {
self.pdfPageSize = CGSizeMake(850.0, 1100.0);
UIFont *titleFont = [UIFont fontWithName:@"Dispatch-Bold" size:24.0];
UIFont *bodyFont = [UIFont systemFontOfSize:18.0];
// Open a new PDF dcument
[self setupPDFDocumentNamed:@"testPDF" Width:self.pdfPageSize.width Height:self.pdfPageSize.height];
//cover page
[self beginPDFPage];
NSString *title = [NSString stringWithFormat:@"How to Tie a %@", self.knot.knotName];
[self addText:title withFrame:CGRectMake(0, 10, 850, 30) font:titleFont alignment:NSTextAlignmentCenter];
[self addLineWithFrame:CGRectMake(10, 40, 830, 2) withColor:[CSCColors favoritesColor]];
NSString *imageName = [NSString stringWithFormat:@"%@_0", self.knot.knotID];
[self addImage:[UIImage imageNamed:imageName] atPoint:CGPointMake(50, 50)];
// addText method works, but addHTML method does not
//[self addText:self.knot.knotDescription withFrame:CGRectMake(400, 50, 300, 500) font:bodyFont alignment:NSTextAlignmentLeft];
[self addHTMLText:self.knot.knotDescription withFrame:CGRectMake(400, 50, 300, 500) font:bodyFont alignment:NSTextAlignmentLeft];
//close out the PDF
[self finishPDF];
}
-(void)setupPDFDocumentNamed:(NSString*)name Width:(float)width Height:(float)height {
self.pdfPageSize = CGSizeMake(width, height);
NSString *newPDFName = [NSString stringWithFormat:@"%@.pdf", name];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pdfPath = [documentsDirectory stringByAppendingPathComponent:newPDFName];
UIGraphicsBeginPDFContextToFile(pdfPath, CGRectZero, nil);
}
- (void)beginPDFPage {
UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, self.pdfPageSize.width, self.pdfPageSize.height), nil);
}
- (void)finishPDF {
UIGraphicsEndPDFContext();
}
- (void)addText:(NSString*)text withFrame:(CGRect)frame font:(UIFont*)font alignment:(NSTextAlignment)alignment{
// Set up character and paragraph attributes
UIColor * cscBlueColor = [UIColor colorWithRed:0.0 green:0.53 blue:0.8 alpha:1.0];
NSMutableParagraphStyle *paraStyle = [[NSMutableParagraphStyle alloc] init];
paraStyle.lineBreakMode = NSLineBreakByWordWrapping;
paraStyle.alignment = alignment;
//Calculate frame
NSDictionary *attr = @{NSFontAttributeName:font};
CGRect textRect = [text boundingRectWithSize:frame.size options:NSStringDrawingUsesLineFragmentOrigin attributes:attr context:nil];
CGSize stringSize = textRect.size;
float textWidth = frame.size.width;
if (textWidth < stringSize.width)
textWidth = stringSize.width;
if (textWidth > _pdfPageSize.width)
textWidth = _pdfPageSize.width - frame.origin.x;
CGRect renderingRect = CGRectMake(frame.origin.x, frame.origin.y, textWidth, stringSize.height);
NSDictionary *renderingAttr = @{NSParagraphStyleAttributeName:paraStyle, NSFontAttributeName:font, NSForegroundColorAttributeName:cscBlueColor};
[text drawInRect:renderingRect withAttributes:renderingAttr];
}
- (void)addHTMLText:(NSString*)text withFrame:(CGRect)frame font:(UIFont *)font alignment:(NSTextAlignment)alignment{
NSMutableAttributedString *myString = [[NSMutableAttributedString alloc] initWithData:[text dataUsingEncoding:NSUTF8StringEncoding]
options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: [NSNumber numberWithInt:NSUTF8StringEncoding]}
documentAttributes:nil
error:nil];
NSRange myRange;
myRange.location = 0;
myRange.length = myString.length;
// Set up character and paragraph attributes
UIColor * cscBlueColor = [UIColor colorWithRed:0.0 green:0.53 blue:0.8 alpha:1.0];
NSMutableParagraphStyle *paraStyle = [[NSMutableParagraphStyle alloc] init];
paraStyle.lineBreakMode = NSLineBreakByWordWrapping;
paraStyle.paragraphSpacing = 10.0f;
paraStyle.alignment = alignment;
NSDictionary *renderingAttr = @{NSParagraphStyleAttributeName:paraStyle, NSFontAttributeName:font, NSForegroundColorAttributeName:cscBlueColor};
[myString addAttributes:renderingAttr range:myRange];
//Calculate frame
NSStringDrawingContext *sdctx = [[NSStringDrawingContext alloc] init];
CGRect textRect = [myString boundingRectWithSize:CGSizeMake(frame.size.width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin context:sdctx];
CGSize stringSize = textRect.size;
float textWidth = frame.size.width;
if (textWidth < stringSize.width)
textWidth = stringSize.width;
if (textWidth > _pdfPageSize.width)
textWidth = _pdfPageSize.width - frame.origin.x;
CGRect renderingRect = CGRectMake(frame.origin.x, frame.origin.y, textWidth, stringSize.height);
// fill rect so we can visualize the frame
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor lightGrayColor].CGColor);
CGContextFillRect(context, renderingRect);
//[myString drawInRect:renderingRect];
[myString drawWithRect:renderingRect options:NSStringDrawingUsesLineFragmentOrigin context:sdctx];
}
- (void)addImage:(UIImage*)image atPoint:(CGPoint)point {
CGRect imageFrame = CGRectMake(point.x, point.y, image.size.width, image.size.height);
[image drawInRect:imageFrame];
}
- (void)addLineWithFrame:(CGRect)frame withColor:(UIColor*)color {
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(currentContext, color.CGColor);
// this is the thickness of the line
CGContextSetLineWidth(currentContext, 2);
CGPoint startPoint = frame.origin;
CGPoint endPoint = CGPointMake(frame.origin.x + frame.size.width, frame.origin.y);
CGContextBeginPath(currentContext);
CGContextMoveToPoint(currentContext, startPoint.x, startPoint.y);
CGContextAddLineToPoint(currentContext, endPoint.x, endPoint.y);
CGContextClosePath(currentContext);
CGContextDrawPath(currentContext, kCGPathFillStroke);
}
有任何想法吗?
屏幕截图:
对于第一个两个屏幕帽,我使用了
NSAttributedString initWithData:options:documentAttributes:error:
生成属性字符串
首先,frame 设置为 {400, 50, 300, 500} 并且文本被完全裁剪。
在第二帧是 {400, 50, 401, 500},文本出现,但第一两行文本被剪裁在顶部。如果我将框架移动到 20,则所有线条都可见。
在最后的屏幕截图中,我只是使用 initWithString 来获取属性字符串,并且一切正常,除了 HTML 没有转换为属性。
我还清理了 HTML 字符串,以确保标签和类调用没有引入一些奇怪的属性。清理后的字符串具有相同的结果:
<html><body><p>Landlubbers need not apply. The Sheet Bend is an essential knot to know and one of the first knots taught to new sailors. It is very fast to tie and is useful when joining two ropes of different diameters.</p><p>Also known as Becket bend (when made fast to an eye instead of a loop), the Sheet Bend is often considered one of the most essential knots and is related in structure to the bowline. If the two free ends are not on the same side of the knot, the result is a left-handed sheet bend of significantly reduced strength.</p></body></html>
谢谢