Shehbaz Khan
Shehbaz Khan

Reputation: 1990

iOS Create PDF with Dynamic Content

I want to Make PDF with Dynamic Content,like text will be dynamic,images will be dynamic so depends on content of course pages wil be dynamic as well,I have followed this tutorial http://code.tutsplus.com/tutorials/generating-pdf-documents--mobile-11265

but in this tutorial content is not dynamic.

Upvotes: 3

Views: 9947

Answers (5)

Rob
Rob

Reputation: 437372

I know this is an old question, but nowadays you would use PDFKit.

In Objective-C:

@import PDFKit;

And then:

PDFDocument *doc = [[PDFDocument alloc] init];
PDFPage *page = [[PDFPage alloc] init];
[doc insertPage:page atIndex:0];
CGRect bounds = [page boundsForBox:kPDFDisplayBoxMediaBox];
PDFAnnotation *textField = [[PDFAnnotation alloc] initWithBounds:bounds forType:PDFAnnotationSubtypeWidget withProperties:nil];
textField.widgetFieldType = PDFAnnotationWidgetSubtypeText;
textField.fontColor = UIColor.whiteColor;
textField.backgroundColor = UIColor.blueColor;
textField.font = [UIFont systemFontOfSize:14];
textField.widgetStringValue = @"WWDC 2017";
[page addAnnotation:textField];

NSURL *fileURL = [[[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:true error:nil] URLByAppendingPathComponent:@"test.pdf"];
if (![doc writeToURL:fileURL]) {
    NSLog(@"save failed");
}

Or, in Swift:

import PDFKit

And:

let doc = PDFDocument()
let page = PDFPage()
doc.insert(page, at: 0)
let bounds = page.bounds(for: .mediaBox)
let textField = PDFAnnotation(bounds: bounds, forType: .widget, withProperties: nil)
textField.widgetFieldType = .text
textField.fontColor = .white
textField.backgroundColor = .blue
textField.font = .systemFont(ofSize: 14.0)
textField.widgetStringValue = "WWDC 2017"
page.addAnnotation(textField)

let fileURL = try! FileManager.default
    .url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
    .appendingPathComponent("test.pdf")

if !doc.write(to: fileURL) {
    print("save failed")
}

See Introducing PDFKit on iOS, from which the above the following snippet was taken.

Upvotes: 2

iEngineer
iEngineer

Reputation: 1319

Make some custom methods and use them as per your requirement. Here are some examples,

// Create a method to draw Line of any size anywhere in the pdf,

- (void) drawLine:(CGFloat)ofWidth fromPoint:(CGPoint)from toPoint(CGPoint)to withColor:(UIColor *)color {
    //Get Current Graphics Context as a CGContextRef That Provides Graphic Environment for drawing in Quartz 2D
    CGContextRef    currentContext = UIGraphicsGetCurrentContext();

    //Sets the width of line we going to draw.
    CGContextSetLineWidth(currentContext, ofWidth);


    //Sets the strok color of context
    CGContextSetStrokeColorWithColor(currentContext, color.CGColor);

    //Starting point of line as X,Y Value
    CGPoint startPoint = from;

    //Starting point of line as X,Y Value 
    CGPoint endPoint = to;

    //Creates new empty path in given graphic context
    CGContextBeginPath(currentContext);

    //Begin a new subpath at given points
    CGContextMoveToPoint(currentContext, startPoint.x, startPoint.y);

    //Append line from the current points to the given points as parameter
    CGContextAddLineToPoint(currentContext, endPoint.x, endPoint.y);

    //Terminates the subpath of the context
    CGContextClosePath(currentContext);

    //Draw the corrunt path using drawing mode as paramete.
    CGContextDrawPath(currentContext, kCGPathFillStroke);
}  

Here is method to put text of any size, any color and any font anywhere,

- (void) drawText:(NSString *)text ofColor:(CGFloat)red Green:(CGFloat)green Blue:(CGFloat)blue withAlpha:(CGFloat)alpha withFont:(UIFont *)font atPoint:(CGRect)Point havingTextAlignment:(UITextAlignment)textAlignment{
    //Get Current Graphics Context as a CGContextRef That Provides Graphic Environment for drawing in Quartz 2D
    CGContextRef    currentContext = UIGraphicsGetCurrentContext();

    //Fill the current context with the color.
    CGContextSetRGBFillColor(currentContext,red,green,blue,alpha);


    //String to Draw
    NSString *textToDraw = text;


    [textToDraw drawInRect:Point
                  withFont:font
             lineBreakMode:UILineBreakModeWordWrap
                 alignment:textAlignment];
}

Same will go for image,

- (void) drawImage:(UIImage *)image atFrame:(CGRect)frame {
    [image drawInRect:frame];
}

Now you can create a pdf of any type using these methods,

- (void) generatePdfWithFilePath: (NSString *)thefilePath ofData:(NSDictionary *)data andPageSize:(CGSize) pageSize{

    UIGraphicsBeginPDFContextToFile(thefilePath, CGRectZero, nil);

        // For exampl
    [self drawLine:65.0 fromPoint: CGPointMake( 10, 50) toPoint:CGPointMake(pageSize.width - 100) withColor:[UIColor colorWithRed:239.0/255.0 green:239.0/255.0 blue:239.0/255.0 alpha:1.0]];

    [self drawText:@"Testing text" ofColor:0.0 Green:0.0 Blue:0.0 withAlpha:1.0 withFont:[UIFont systemFontOfSize:16.0] atPoint:CGRectMake(60,200, pageSize.width - 200,30.0) havingTextAlignment:UITextAlignmentLeft];

    UIGraphicsEndPDFContext();
}

Further you can get help from following,

http://www.raywenderlich.com/6581/how-to-create-a-pdf-with-quartz-2d-in-ios-5-tutorial-part-1
http://www.raywenderlich.com/6818/how-to-create-a-pdf-with-quartz-2d-in-ios-5-tutorial-part-2

Upvotes: 0

Vinod Pandey
Vinod Pandey

Reputation: 183

I have also used the same its working fine Hope this will be helpful for you.

Create a block:-

typedef void (^PdfCompletion)(BOOL status, NSString *filePath, NSArray *fbArr);

-(void)addData
{
    [MBProgressHUD showHUDAddedTo:self.view animated:YES];
    NSMutableDictionary *contactDict = [[NSMutableDictionary alloc] init];
    [contactDict setObject:contactTextField.text forKey:@"phonenumber"];
    [contactDict setObject:emailTextField.text forKey:@"emailid"];
    [contactDict setObject:userNameLabel.text forKey:@"displayname"];
    [self drawPdf:contactDict completion:^(BOOL status,NSString *filePath,NSArray *fbArr)
     {
         if (status)
         {
             NSMutableArray *arr;
             arr = [[NSMutableArray alloc] init];
             NSData *filedata;
             filedata = [NSData dataWithContentsOfFile:filePath];
             double locaTotalFileSize = filedata.length +498;
             totalFileSize += locaTotalFileSize;
             NSMutableDictionary *fileDict = [[NSMutableDictionary alloc] init];
             [fileDict setObject:userPicImageView.image forKey:@"image"];
             [fileDict setObject:filePath forKey:@"filePath"];
             [fileDict setObject:@"txt" forKey:@"fileType"];
             [fileDict setObject:[NSString stringWithFormat:@"%@_%@_%@",@"contact",[self getFbID],[self CurrentSystemTime]] forKey:@"fileName"];
             [fileDict setObject:@"1" forKey:@"uploadStatus"];
             [fileDict setObject:@"0 KB/0 KB" forKey:@"fileSizeStatus"];
             [fileDict setObject:@"0 KB/0 KB" forKey:@"ContentSize"];
             [arr addObject:fileDict];
             [self switchToReviewFiles:arr];
             //////NSLog(@"pdf convrt successfull");
         }
         else
         {
             //////NSLog(@"Error to convert into pdf");
         }
    }];
}


// Then Call The DrawPDF Method::--

-(void)drawPdf:(NSMutableDictionary *)drawText completion:(PdfCompletion)callback
{
    NSString* fileName = @"contact_card.txt";

    NSArray *arrayPaths =
    NSSearchPathForDirectoriesInDomains(
                                        NSDocumentDirectory,
                                        NSUserDomainMask,
                                        YES);
    NSString *path = [arrayPaths objectAtIndex:0];
    NSString* txtFileName = [path stringByAppendingPathComponent:fileName];

    NSData *data = [NSJSONSerialization dataWithJSONObject:drawText options:NSJSONWritingPrettyPrinted error:nil];
    [data writeToFile:txtFileName atomically:YES];
    callback(YES, txtFileName, nil);

Upvotes: 2

Jef
Jef

Reputation: 4728

the easiest way to handle this, like any print job in Cocoa or Cocoa-Touch, is to first make a UIView (or UIViewController) subclass to draw/layout your data as you want it printed. You should do this even if you don't intend to ever show this view on the screen in your finished app. (you still might put it on the screen in development in order to get it looking how you want it.. ) A very simple approach for a model of unknown size might be a UITableViewController. Use Autolayout or the old UIViewAutoResizingMasks so that this view will cope with resizing gracefully. Of course if it is a UIViewController subclass then you could do it with interface builder too..

Once you're in this position drawing to a PDF is trivial

-(BOOL )writePDFtoPath:(NSString *)filePath{

NSMutableData *pdfData = [NSMutableData data];
UIGraphicsBeginPDFContextToData(pdfData, CGRectZero, nil);
//note that because I've passed in CGRectZero for the size the context //comes in its default size

 /*
  default pdf..
   8.5 X 11 inch
   612 x 792
   */
//this is only 72dpi, but its the default. I have a trick where I zoom 
// out before drawing to improve resolution:

NSInteger numberPages = 3; //work out how many pages you need


for (NSInteger page = 0 : page < numberPages : page ++ ){

UIGraphicsBeginPDFPage();
CGContextRef pdfContext = UIGraphicsGetCurrentContext();
CGFloat scaleFactor = 3.0;
CGContextSaveGState(pdfContext);
CGContextScaleCTM(pdfContext, 1.0/scaleFactor, 1.0/scaleFactor);


///
/// context size is now (612.0 * 3.0 , 792.0 * 3.0) , i.e. resolution 72.0 * 3.0 dpi..

[self.pdfGeneratingView setFrame: CGRectMake( 0.0, 0.0, 612.0*scaleFactor, 792.0*scaleFactor) ]; //let autolayout make it fit 

//prepare your view for this page

[self.pdfGeneratingView.layer renderInContext:pdfContext];
CGContextRestoreGState(pdfContext);

}//page drawing loop


BOOL success = [pdfData writeToFile:filePath atomically:YES];
return success;
}

Upvotes: 2

Nikita Khandelwal
Nikita Khandelwal

Reputation: 1741

You can pass value using javaScript like this for your dynamic value

Suppose you have a key "myKey" in your HTML

<td><span class="fieldVal" id="myKey"></span></td>

And Pass value using like this

NSBundle *bundle = [NSBundle mainBundle];
NSURL *indexFileURL = [bundle URLForResource:@"name_of_your_local_html" withExtension:@"html"];
[wbView loadRequest:[NSURLRequest requestWithURL:indexFileURL]];
[wbView stringByEvaluatingJavaScriptFromString:[NSString   stringWithFormat:@"document.getElementById('myKey').innerHTML='%@'",@"myValue"]];

Now for converting HTML to PDF you can use this class

https://github.com/iclems/iOS-htmltopdf/blob/master/NDHTMLtoPDF.h

Upvotes: 2

Related Questions