9

私は最近、優れた PDF チュートリアルやドキュメントなどをよく探しています。

最終的にこのコードを使用しましたが、問題はほとんどありません。

シナリオ

ラベル、textView、および imageView を含むビューがあります。ここで、 label name、 textView description、および imageView を呼び出しimageます。

名前はヘッダーとして機能します。

説明は非常に変更可能で、2 行から数ページまで可能です。

画像は説明テキストの最後に配置する必要があります。

私はこのコードを使用しています:

- (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];
}

ページの最後、説明の直後の画像の描き方を教えてください。

このようにヘッダーを描画しました:

-(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];
}

そしてそれはすべてのページの最初に表示されています。

内容(説明)のあとの画像の描き方がわからない!

4

4 に答える 4

5

コンテキスト内で PDF を描画することは、キャンバスに描画するようなものです。

本質的に動的なテキストと画像を描画する最良の方法は、描画するメソッドを作成して使用することです。これは、ページでの描画に使用される高さを返し、返された値をインクリメントすることで次の描画元の位置を計算する変数を保持するだけです。価値。また、別のオフセット変数を配置して、ページ フレームをチェックします。

画像を pdf コンテキストに描画するには、次のサンプルを使用できますCGImage。Core Graphics を介してレンダリングすることもできますが、キャンバスの回転を考慮する必要がありますCGContext(反転)。 Core Graphics の原点は右下にあります。

UIImage *gymLogo=[UIImage imageNamed:@"logo.png"];
CGPoint drawingLogoOrigin = CGPointMake(5,5);
[gymLogo drawAtPoint:drawingLogoOrigin];
于 2013-01-24T12:30:05.413 に答える
1

UIViewこれがあなたが望むことをするサブクラスです...

に配置できますUIScrollView-sizeThatFits:スーパービューの実行中に正しいフレーム サイズを取得するために呼び出します-layoutSubviews。(囲んでいるスクロールビューのcontentSizeにも。)

に適切なサイズを返す 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

ページ番号フッターが必要な場合は、同じパターンに従って、下部に別の UILabel を追加できます。

于 2013-01-27T05:39:58.180 に答える
1

pdf_tutorialViewController.hまず、ファイルにカスタムメソッドを作成します

- (void)drawImage:(UIImage *)img  atRect:(CGRect)rect inContext:(CGContextRef)ctx;

/////////////// pdf_tutorialViewController.mファイル //////////

Your methodの最後に 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;
  ////////////////////////////////////////////////////////////////////////////////////
} 

そしてコードを追加

- (void)drawImage:(UIImage *)img  atRect:(CGRect)rect inContext:(CGContextRef)ctx
{
    UIImage *myImage = (UIImage *)img;
    [myImage drawInRect:rect];
    //[myImage release];
}
于 2013-01-26T21:17:28.803 に答える
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();
于 2013-01-31T06:48:16.067 に答える