I've been searching a lot lately for a good PDF tutorial, documentation, etc.
我最近一直在寻找一个很好的PDF教程,文档等等。
I ended up using this code, but there are few problems.
我最终使用了这段代码,但问题很少。
Scenario
I have a view which contains a label, a textView and an imageView. Now, we'll call the label name
, the textView description
and the imageView image
.
我有一个包含标签,textView和imageView的视图。现在,我们将调用标签名称,textView描述和imageView图像。
The name works as header.
该名称作为标题。
The description is very very mutable, it can be from 2 lines to some pages.
描述非常非常可变,它可以是从2行到某些页面。
Image should go at the end of the description text.
图像应该放在描述文本的末尾。
I'm using this code:
我正在使用此代码:
- (void)generatePDF{
NSString *fileName = [NSString stringWithFormat:@"%@.pdf",nameString];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pdfFileName = [documentsDirectory stringByAppendingPathComponent:fileName];
CFAttributedStringRef currentText = CFAttributedStringCreate(NULL,
(CFStringRef)descriptionString, NULL);
if (currentText) {
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(currentText);
if (framesetter) {
// Create the PDF context using the default page: currently constants at the size
// of 612 x 792.
UIGraphicsBeginPDFContextToFile(pdfFileName, CGRectZero, nil);
CFRange currentRange = CFRangeMake(0, 0);
NSInteger currentPage = 0;
BOOL done = NO;
do {
// Mark the beginning of a new page.
UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, kDefaultPageWidth,
kDefaultPageHeight), nil);
[self drawHeader]
// Draw a page number at the bottom of each page
currentPage++;
[self drawPageNumber:currentPage];
// Render the current page and update the current range to
// point to the beginning of the next page.
currentRange = [self renderPage:currentPage withTextRange:
currentRange andFramesetter:framesetter];
// If we're at the end of the text, exit the loop.
if (currentRange.location == CFAttributedStringGetLength
((CFAttributedStringRef)currentText))
done = YES;
} while (!done);
// Close the PDF context and write the contents out.
UIGraphicsEndPDFContext();
// Release the framewetter.
CFRelease(framesetter);
} else {
NSLog(@"Could not create the framesetter needed to lay out the atrributed string.");
}
// Release the attributed string.
CFRelease(currentText);
} else {
NSLog(@"Could not create the attributed string for the framesetter");
}
}
- (CFRange)renderPage:(NSInteger)pageNum withTextRange:(CFRange)currentRange
andFramesetter:(CTFramesetterRef)framesetter
{
// 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);
// Create a path object to enclose the text. Use 72 point
// margins all around the text.
CGRect frameRect = CGRectMake(22,72, 468, 648);
CGMutablePathRef framePath = CGPathCreateMutable();
CGPathAddRect(framePath, NULL, frameRect);
// Get the frame that will do the rendering.
// The currentRange variable specifies only the starting point. The framesetter
// lays out as much text as will fit into the frame.
CTFrameRef frameRef = CTFramesetterCreateFrame(framesetter, currentRange, framePath, NULL);
CGPathRelease(framePath);
// Core Text draws from the bottom-left corner up, so flip
// the current transform prior to drawing.
CGContextTranslateCTM(currentContext, 0, kDefaultPageHeight);
CGContextScaleCTM(currentContext, 1.0, -1.0);
// Draw the frame.
CTFrameDraw(frameRef, currentContext);
// Update the current range based on what was drawn.
currentRange = CTFrameGetVisibleStringRange(frameRef);
currentRange.location += currentRange.length;
currentRange.length = 0;
CFRelease(frameRef);
return currentRange;
}
- (void)drawPageNumber:(NSInteger)pageNum
{
NSString* pageString = [NSString stringWithFormat:NSLocalizedString(@"Page", nil), pageNum];
UIFont* theFont = [UIFont systemFontOfSize:12];
CGSize maxSize = CGSizeMake(kDefaultPageWidth, 72);
CGSize pageStringSize = [pageString sizeWithFont:theFont
constrainedToSize:maxSize
lineBreakMode:UILineBreakModeClip];
CGRect stringRect = CGRectMake(((kDefaultPageWidth - pageStringSize.width) / 2.0),
720.0 + ((72.0 - pageStringSize.height) / 2.0) ,
pageStringSize.width,
pageStringSize.height);
[pageString drawInRect:stringRect withFont:theFont];
}
I would like to know how to draw the image at the end of the page, right after the end of the description.
我想知道如何在描述结束后立即在页面末尾绘制图像。
I've drawn the header this way:
我用这种方式绘制了标题:
-(void)drawHeader{
NSString *headerString = nameString;
UIFont* theFont = [UIFont boldSystemFontOfSize:15];
CGSize maxSize = CGSizeMake(kDefaultPageWidth, 72);
CGSize pageStringSize = [headerString sizeWithFont:theFont constrainedToSize:maxSize lineBreakMode:UILineBreakModeClip];
CGRect stringRect = CGRectMake(22,22,pageStringSize.width,pageStringSize.height);
[headerString drawInRect:stringRect withFont:theFont];
}
and it's being shown at the beginning of every page.
它会显示在每个页面的开头。
Now I don't know how to draw the image after the contents (description)!
现在我不知道如何在内容之后绘制图像(描述)!
Any help highly appreciated!
任何帮助高度赞赏!
4 个解决方案
#1
4
Well Drawing a pdf in the context is like drawing in a canvas.
在上下文中绘制pdf就像在画布中绘制一样。
The best way to draw text and images which are dynamic in nature is to create and use methods to draw, which returns the height used to draw in the page and simply keeping a variable to calculate the next drawing orgin y position by incrementing with the returned value.Also put a separate offset variable to check the page frame.
绘制动态文本和图像的最佳方法是创建和使用绘制方法,返回用于在页面中绘制的高度,并简单地保留变量以通过递增返回来计算下一个绘图orgin y位置value。还要放置一个单独的偏移量变量来检查页面框架。
To draw an image into pdf context you can make use of the following sample.You can also render CGImage
via Core Graphics,but you have to consider rotation of the canvas(CGContext
) since those will appear in the upside down way(flipped) since the coordinate origin in Core Graphics is on the bottom right .
要将图像绘制到pdf上下文中,您可以使用以下示例。您还可以通过Core Graphics渲染CGImage,但您必须考虑画布的旋转(CGContext),因为这些将以颠倒的方式显示(翻转),因为Core Graphics中的坐标原点位于右下角。
UIImage *gymLogo=[UIImage imageNamed:@"logo.png"];
CGPoint drawingLogoOrigin = CGPointMake(5,5);
[gymLogo drawAtPoint:drawingLogoOrigin];
Happy coding :)
快乐编码:)
#2
1
First You create custom Method in pdf_tutorialViewController.h
file
首先在pdf_tutorialViewController.h文件中创建自定义方法
- (void)drawImage:(UIImage *)img atRect:(CGRect)rect inContext:(CGContextRef)ctx;
/////////////// pdf_tutorialViewController.m file //////////
/////////////// pdf_tutorialViewController.m文件//////////
and Add UIImage
and call drawImage:atRect:inContext:
Method at the end of Your method.
并添加UIImage并调用drawImage:atRect:inContext:方法结束时的方法。
- (CFRange)renderPage:(NSInteger)pageNum withTextRange:(CFRange)currentRange
andFramesetter:(CTFramesetterRef)framesetter
{
////////////////////////////////////////////////////////////////////////////////////
UIImage *logoimg = [UIImage imageNamed:@"1.png"];
[self drawImage:logoimg atRect:CGRectMake("Your Size") inContext:currentContext];
return currentRange;
////////////////////////////////////////////////////////////////////////////////////
}
And Add code of
并添加代码
- (void)drawImage:(UIImage *)img atRect:(CGRect)rect inContext:(CGContextRef)ctx
{
UIImage *myImage = (UIImage *)img;
[myImage drawInRect:rect];
//[myImage release];
}
This Code might be helpful for You :)
本代码可能对您有所帮助:)
Thanks
#3
1
Here's a subclass of UIView
that does what you want...
这是UIView的子类,可以做你想要的......
You can place it in a UIScrollView
. Call -sizeThatFits:
to get the correct frame size during your superview's -layoutSubviews
. (also for your enclosing scroll view's contentSize.)
您可以将其放在UIScrollView中。调用-sizeThatFits:在superview的-layoutSubviews中获取正确的帧大小。 (也用于封闭滚动视图的contentSize。)
Note that I included a category on UILabel that returns a reasonable size to -sizeThatFits:
, you may want to provide your own implementation.
请注意,我在UILabel上添加了一个类别,该类别返回-sizeThatFits:的合理大小,您可能希望提供自己的实现。
View.h
#import <UIKit/UIKit.h>
@interface View : UIView
@property ( nonatomic, strong, readonly ) UILabel * descriptionLabel ;
@property ( nonatomic, strong, readonly ) UILabel * nameLabel ;
@property ( nonatomic, strong, readonly ) UIImageView * pdfImageView ;
@property ( nonatomic ) CGPDFDocumentRef pdf ;
@end
View.m
#import "View.h"
@implementation UILabel (SizeThatFits)
-(CGSize)sizeThatFits:(CGSize)fitSize
{
return [ self.text sizeWithFont:self.font constrainedToSize:fitSize ] ;
}
@end
@interface View ()
@property ( nonatomic, strong, readonly ) UIImage * pdfImage ;
@end
@implementation View
@synthesize descriptionLabel = _descriptionLabel ;
@synthesize nameLabel = _nameLabel ;
@synthesize pdfImageView = _pdfImageView ;
@synthesize pdfImage = _pdfImage ;
-(void)dealloc
{
CGPDFDocumentRelease( _pdf ) ;
}
-(CGSize)sizeThatFits:(CGSize)size
{
CGSize fitSize = (CGSize){ size.width, CGFLOAT_MAX } ;
CGSize result = { size.width, 0 } ;
result.height = [ self.headerLabel sizeThatFits:fitSize ].height
+ [ self.label sizeThatFits:fitSize ].height
+ self.pdfImage.size.height * fitSize.width / self.pdfImage.size.width ;
return result ;
}
-(void)layoutSubviews
{
CGRect bounds = self.bounds ;
CGRect slice ;
CGRectDivide( bounds, &slice, &bounds, [ self.headerLabel sizeThatFits:bounds.size ].height, CGRectMinYEdge ) ;
self.headerLabel.frame = slice ;
CGRectDivide( bounds, &slice, &bounds, [ self.label sizeThatFits:bounds.size ].height, CGRectMinYEdge ) ;
self.label.frame = slice ;
self.pdfImageView.frame = bounds ;
}
-(void)setPdf:(CGPDFDocumentRef)pdf
{
CGPDFDocumentRelease( _pdf ) ;
_pdf = CGPDFDocumentRetain( pdf ) ;
_pdfImage = nil ;
}
-(UILabel *)descriptionLabel
{
if ( !_descriptionLabel )
{
UILabel * label = [[ UILabel alloc ] initWithFrame:CGRectZero ] ;
label.numberOfLines = 0 ;
//
// ... configure label here
//
[ self addSubview:label ] ;
_descriptionLabel = label ;
}
return _descriptionLabel ;
}
-(UILabel *)nameLabel
{
if ( !_nameLabel )
{
UILabel * label = [[ UILabel alloc ] initWithFrame:CGRectZero ] ;
label.numberOfLines = 0 ;
//
// ... configure label here
//
[ self addSubview:label ] ;
_nameLabel = label ;
}
return _nameLabel ;
}
-(UIView *)pdfImageView
{
if ( !_pdfImageView )
{
UIImageView * imageView = [[ UIImageView alloc ] initWithFrame:CGRectZero ] ;
[ self addSubview:imageView ] ;
_pdfImageView = imageView ;
}
return _pdfImageView ;
}
-(UIImage *)pdfImage
{
if ( !_pdfImage )
{
CGPDFPageRef page = CGPDFDocumentGetPage( self.pdf, 1 ) ; // 1 indexed
CGRect mediaBox = CGPDFPageGetBoxRect( page, kCGPDFMediaBox ) ;
UIGraphicsBeginImageContextWithOptions( mediaBox.size, NO, self.window.screen.scale ) ;
CGContextRef c = UIGraphicsGetCurrentContext() ;
CGContextScaleCTM( c, 1.0f, -1.0f ) ;
CGContextTranslateCTM( c, 0.0, -mediaBox.size.height ) ;
CGContextDrawPDFPage( c, page ) ;
_pdfImage = UIGraphicsGetImageFromCurrentImageContext() ;
self.pdfImageView.image = _pdfImage ;
UIGraphicsEndImageContext() ;
}
return _pdfImage ;
}
@end
If you need a page number footer, you can add another UILabel at the bottom, following the same pattern.
如果您需要页码页脚,可以在底部添加另一个UILabel,遵循相同的模式。
#4
0
NSString *fileName = @"myInfo.pdf";
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pdfFileName = [documentsDirectory stringByAppendingPathComponent:fileName];
if ([passwordString length]) {
NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:passwordString, kCGPDFContextOwnerPassword, passwordString, kCGPDFContextUserPassword, kCFBooleanFalse, kCGPDFContextAllowsCopying, kCFBooleanFalse, kCGPDFContextAllowsPrinting, nil]; // Providing Password Protection for PDF File
UIGraphicsBeginPDFContextToFile(pdfFileName, CGRectZero, dictionary);
[dictionary release];
} else {
UIGraphicsBeginPDFContextToFile(pdfFileName, CGRectZero, nil);
}
UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, 612.0, heightOfView), nil); //612,792 Width & Height of the pdf page which we want to generate.
NSString *pngPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%d.png", 123]];
UIImage *pngImage = [UIImage imageWithContentsOfFile:pngPath];
[pngImage drawInRect:CGRectMake((612 - self.frame.size.width) / 2, 0, self.frame.size.width, heightOfView)]; // Size of the image we want to draw in pdf file.
UIGraphicsEndPDFContext();
#1
4
Well Drawing a pdf in the context is like drawing in a canvas.
在上下文中绘制pdf就像在画布中绘制一样。
The best way to draw text and images which are dynamic in nature is to create and use methods to draw, which returns the height used to draw in the page and simply keeping a variable to calculate the next drawing orgin y position by incrementing with the returned value.Also put a separate offset variable to check the page frame.
绘制动态文本和图像的最佳方法是创建和使用绘制方法,返回用于在页面中绘制的高度,并简单地保留变量以通过递增返回来计算下一个绘图orgin y位置value。还要放置一个单独的偏移量变量来检查页面框架。
To draw an image into pdf context you can make use of the following sample.You can also render CGImage
via Core Graphics,but you have to consider rotation of the canvas(CGContext
) since those will appear in the upside down way(flipped) since the coordinate origin in Core Graphics is on the bottom right .
要将图像绘制到pdf上下文中,您可以使用以下示例。您还可以通过Core Graphics渲染CGImage,但您必须考虑画布的旋转(CGContext),因为这些将以颠倒的方式显示(翻转),因为Core Graphics中的坐标原点位于右下角。
UIImage *gymLogo=[UIImage imageNamed:@"logo.png"];
CGPoint drawingLogoOrigin = CGPointMake(5,5);
[gymLogo drawAtPoint:drawingLogoOrigin];
Happy coding :)
快乐编码:)
#2
1
First You create custom Method in pdf_tutorialViewController.h
file
首先在pdf_tutorialViewController.h文件中创建自定义方法
- (void)drawImage:(UIImage *)img atRect:(CGRect)rect inContext:(CGContextRef)ctx;
/////////////// pdf_tutorialViewController.m file //////////
/////////////// pdf_tutorialViewController.m文件//////////
and Add UIImage
and call drawImage:atRect:inContext:
Method at the end of Your method.
并添加UIImage并调用drawImage:atRect:inContext:方法结束时的方法。
- (CFRange)renderPage:(NSInteger)pageNum withTextRange:(CFRange)currentRange
andFramesetter:(CTFramesetterRef)framesetter
{
////////////////////////////////////////////////////////////////////////////////////
UIImage *logoimg = [UIImage imageNamed:@"1.png"];
[self drawImage:logoimg atRect:CGRectMake("Your Size") inContext:currentContext];
return currentRange;
////////////////////////////////////////////////////////////////////////////////////
}
And Add code of
并添加代码
- (void)drawImage:(UIImage *)img atRect:(CGRect)rect inContext:(CGContextRef)ctx
{
UIImage *myImage = (UIImage *)img;
[myImage drawInRect:rect];
//[myImage release];
}
This Code might be helpful for You :)
本代码可能对您有所帮助:)
Thanks
#3
1
Here's a subclass of UIView
that does what you want...
这是UIView的子类,可以做你想要的......
You can place it in a UIScrollView
. Call -sizeThatFits:
to get the correct frame size during your superview's -layoutSubviews
. (also for your enclosing scroll view's contentSize.)
您可以将其放在UIScrollView中。调用-sizeThatFits:在superview的-layoutSubviews中获取正确的帧大小。 (也用于封闭滚动视图的contentSize。)
Note that I included a category on UILabel that returns a reasonable size to -sizeThatFits:
, you may want to provide your own implementation.
请注意,我在UILabel上添加了一个类别,该类别返回-sizeThatFits:的合理大小,您可能希望提供自己的实现。
View.h
#import <UIKit/UIKit.h>
@interface View : UIView
@property ( nonatomic, strong, readonly ) UILabel * descriptionLabel ;
@property ( nonatomic, strong, readonly ) UILabel * nameLabel ;
@property ( nonatomic, strong, readonly ) UIImageView * pdfImageView ;
@property ( nonatomic ) CGPDFDocumentRef pdf ;
@end
View.m
#import "View.h"
@implementation UILabel (SizeThatFits)
-(CGSize)sizeThatFits:(CGSize)fitSize
{
return [ self.text sizeWithFont:self.font constrainedToSize:fitSize ] ;
}
@end
@interface View ()
@property ( nonatomic, strong, readonly ) UIImage * pdfImage ;
@end
@implementation View
@synthesize descriptionLabel = _descriptionLabel ;
@synthesize nameLabel = _nameLabel ;
@synthesize pdfImageView = _pdfImageView ;
@synthesize pdfImage = _pdfImage ;
-(void)dealloc
{
CGPDFDocumentRelease( _pdf ) ;
}
-(CGSize)sizeThatFits:(CGSize)size
{
CGSize fitSize = (CGSize){ size.width, CGFLOAT_MAX } ;
CGSize result = { size.width, 0 } ;
result.height = [ self.headerLabel sizeThatFits:fitSize ].height
+ [ self.label sizeThatFits:fitSize ].height
+ self.pdfImage.size.height * fitSize.width / self.pdfImage.size.width ;
return result ;
}
-(void)layoutSubviews
{
CGRect bounds = self.bounds ;
CGRect slice ;
CGRectDivide( bounds, &slice, &bounds, [ self.headerLabel sizeThatFits:bounds.size ].height, CGRectMinYEdge ) ;
self.headerLabel.frame = slice ;
CGRectDivide( bounds, &slice, &bounds, [ self.label sizeThatFits:bounds.size ].height, CGRectMinYEdge ) ;
self.label.frame = slice ;
self.pdfImageView.frame = bounds ;
}
-(void)setPdf:(CGPDFDocumentRef)pdf
{
CGPDFDocumentRelease( _pdf ) ;
_pdf = CGPDFDocumentRetain( pdf ) ;
_pdfImage = nil ;
}
-(UILabel *)descriptionLabel
{
if ( !_descriptionLabel )
{
UILabel * label = [[ UILabel alloc ] initWithFrame:CGRectZero ] ;
label.numberOfLines = 0 ;
//
// ... configure label here
//
[ self addSubview:label ] ;
_descriptionLabel = label ;
}
return _descriptionLabel ;
}
-(UILabel *)nameLabel
{
if ( !_nameLabel )
{
UILabel * label = [[ UILabel alloc ] initWithFrame:CGRectZero ] ;
label.numberOfLines = 0 ;
//
// ... configure label here
//
[ self addSubview:label ] ;
_nameLabel = label ;
}
return _nameLabel ;
}
-(UIView *)pdfImageView
{
if ( !_pdfImageView )
{
UIImageView * imageView = [[ UIImageView alloc ] initWithFrame:CGRectZero ] ;
[ self addSubview:imageView ] ;
_pdfImageView = imageView ;
}
return _pdfImageView ;
}
-(UIImage *)pdfImage
{
if ( !_pdfImage )
{
CGPDFPageRef page = CGPDFDocumentGetPage( self.pdf, 1 ) ; // 1 indexed
CGRect mediaBox = CGPDFPageGetBoxRect( page, kCGPDFMediaBox ) ;
UIGraphicsBeginImageContextWithOptions( mediaBox.size, NO, self.window.screen.scale ) ;
CGContextRef c = UIGraphicsGetCurrentContext() ;
CGContextScaleCTM( c, 1.0f, -1.0f ) ;
CGContextTranslateCTM( c, 0.0, -mediaBox.size.height ) ;
CGContextDrawPDFPage( c, page ) ;
_pdfImage = UIGraphicsGetImageFromCurrentImageContext() ;
self.pdfImageView.image = _pdfImage ;
UIGraphicsEndImageContext() ;
}
return _pdfImage ;
}
@end
If you need a page number footer, you can add another UILabel at the bottom, following the same pattern.
如果您需要页码页脚,可以在底部添加另一个UILabel,遵循相同的模式。
#4
0
NSString *fileName = @"myInfo.pdf";
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pdfFileName = [documentsDirectory stringByAppendingPathComponent:fileName];
if ([passwordString length]) {
NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:passwordString, kCGPDFContextOwnerPassword, passwordString, kCGPDFContextUserPassword, kCFBooleanFalse, kCGPDFContextAllowsCopying, kCFBooleanFalse, kCGPDFContextAllowsPrinting, nil]; // Providing Password Protection for PDF File
UIGraphicsBeginPDFContextToFile(pdfFileName, CGRectZero, dictionary);
[dictionary release];
} else {
UIGraphicsBeginPDFContextToFile(pdfFileName, CGRectZero, nil);
}
UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, 612.0, heightOfView), nil); //612,792 Width & Height of the pdf page which we want to generate.
NSString *pngPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%d.png", 123]];
UIImage *pngImage = [UIImage imageWithContentsOfFile:pngPath];
[pngImage drawInRect:CGRectMake((612 - self.frame.size.width) / 2, 0, self.frame.size.width, heightOfView)]; // Size of the image we want to draw in pdf file.
UIGraphicsEndPDFContext();