Monday, September 17, 2012

Creating PDF file from simple Texts/NSStrings/UIImages in iOS App

Hi Guyz, In this section i will write you a bunch of custom methods that can be used for generating PDF files from your simple texts and NSStrings in iOS app. In this section, we will be using core Graphics functions of Objective-C, No frameworks are used. You can have your own design customization  beside what i have designed here. I hope this blog will help you to start generating PDF as per your requirements. Lets start coding!!!

Lets define some variables and constants in .h file:
    #define kBorderInset            20.0
    #define kBorderWidth            1.0
    #define kMarginInset            12.0
    #define kLineWidth              1.0
    CGSize pageSize;

-(IBAction)generatePdfButtonPressed:(id)sender; //UIButton method for generating PDF
Now, in .m file : (lets have some custom methods)
- (void) drawBorder{
    /***get the current context, select a color for the border, specify a rect for the border, which has an inset of 20 pixels, and then just stroke the rect using normal Core Graphics.***/
    CGContextRef    currentContext = UIGraphicsGetCurrentContext();
    UIColor *borderColor = [UIColor brownColor];
    CGRect rectFrame = CGRectMake(kBorderInset, kBorderInset, pageSize.width-kBorderInset*2, pageSize.height-kBorderInset*2);
    CGContextSetStrokeColorWithColor(currentContext, borderColor.CGColor);
    CGContextSetLineWidth(currentContext, kBorderWidth);
    CGContextStrokeRect(currentContext, rectFrame);
}


- (void)drawPageNumber:(NSInteger)pageNumber{

     /***indicating the current page number *****/
       NSString* pageNumberString = [NSString stringWithFormat:@"Page %d", pageNumber];
       UIFont* theFont = [UIFont systemFontOfSize:12];
    CGSize pageNumberStringSize = [pageNumberString sizeWithFont:theFont constrainedToSize:pageSize     

                                                          lineBreakMode:UILineBreakModeWordWrap];
    CGRect stringRenderingRect = CGRectMake(kBorderInset, pageSize.height - 40.0,pageSize.width - 2*kBorderInset, 

                                                        pageNumberStringSize.height);
    [pageNumberString drawInRect:stringRenderingRect withFont:theFont lineBreakMode:UILineBreakModeWordWrap alignment:UITextAlignmentCenter];
}

- (void) drawHeader{
      /*** drawing header format for PDF  *****/
    CGContextRef    currentContext = UIGraphicsGetCurrentContext();
    CGContextSetRGBFillColor(currentContext, 0.3, 0.7, 0.2, 1.0);
    NSString *textToDraw = @"Pdf Demo – Title";
    UIFont *font = [UIFont systemFontOfSize:24.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, pageSize.width - 2*kBorderInset - 2*kMarginInset, stringSize.height);
    [textToDraw drawInRect:renderingRect withFont:font lineBreakMode:UILineBreakModeWordWrap alignment:UITextAlignmentLeft];
}

- (void) drawText{
    /***calculate the size of the NSString/Texts we need to draw ***/
    CGContextRef    currentContext = UIGraphicsGetCurrentContext();
    CGContextSetRGBFillColor(currentContext, 0.0, 0.0, 0.0, 1.0);
    NSString *textToDraw = @"Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.\n Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.";
    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 + 50.0, pageSize.width - 2*kBorderInset - 2*kMarginInset, stringSize.height);
    [textToDraw drawInRect:renderingRect withFont:font lineBreakMode:UILineBreakModeWordWrap alignment:UITextAlignmentLeft];
}
- (void) drawLine{
   
/***get the current context, set the line width and stroke color, specify the start and end points, move to the start point, add a line to the end point, and finally draw the path.***/
   CGContextRef currentContext = UIGraphicsGetCurrentContext();
    CGContextSetLineWidth(currentContext,kLineWidth);
    CGContextSetStrokeColorWithColor(currentContext,[UIColor blueColor].CGColor);   
    CGPoint startPoint = CGPointMake(kMarginInset+kBorderInset, kMarginInset+kBorderInset+40.0);
    CGPoint endPoint = CGPointMake(pageSize.width - 2*kMarginInset -2*kBorderInset, kMarginInset + kBorderInset + 40.0);
    CGContextBeginPath(currentContext);
    CGContextMoveToPoint(currentContext, startPoint.x, startPoint.y);
    CGContextAddLineToPoint(currentContext, endPoint.x, endPoint.y);
    CGContextClosePath(currentContext);   
    CGContextDrawPath(currentContext, kCGPathFillStroke);
}

- (void) drawImage{

   /** Draw Image on the PDF file if you needed, give frame for UIImage to redraw **/
    UIImage * demoImage = [UIImage imageNamed:@"demo.jpg"];
    [demoImage drawInRect:CGRectMake( (pageSize.width - demoImage.size.width/2)/2, 350, demoImage.size.width/2, demoImage.size.height/2)];
}

- (void) generatePdfWithFilePath: (NSString *)thefilePath{
  /*** Now generating the pdf  and storing it to the documents directory of device on selected path. Customize do-while loop to meet your pdf requirements like number of page, Size of NSstrings/texts you want to fit. Basically just call all the above methods depending on your requirements from do-while loop or you can recustomize it. ****/
    UIGraphicsBeginPDFContextToFile(thefilePath, CGRectZero, nil);
    NSInteger currentPage = 0;
    BOOL done = NO;
    do
    {
        //Start a new page.
        UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, pageSize.width, pageSize.height), nil);
        //Draw a page number at the bottom of each page.
        currentPage++;
        [self drawPageNumber:currentPage];
        //Draw a border for each page.
        [self drawBorder];
        //Draw text fo your header.
        [self drawHeader];
        //Draw a line below the header.
        [self drawLine];
        //Draw some text for the page.
        [self drawText];
        //Draw an image
        [self drawImage];        
        done = YES;
    }
    while (!done);
    // Close the PDF context and write the contents out.
    UIGraphicsEndPDFContext();
}
-(IBAction)generatePdfButtonPressed:(id)sender{
     /*** This is the method called by your "PDF generating" Button. Just give initial PDF page frame, Name for your PDF file to be saved as, and the path for storing it to documnets directory ***/
    pageSize = CGSizeMake(612, 792);
    NSString *fileName = @"Demo.pdf";
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *pdfFilePath = [documentsDirectory stringByAppendingPathComponent:fileName];
    [self generatePdfWithFilePath:pdfFilePath];

// The PDF file will be stored on the Path "pdfFilePath", read it from there and view in your UIWebView
   /*****
    NSURL *url = [NSURL fileURLWithPath:pdfFilePath];
    NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
    [yourWebView setUserInteractionEnabled:YES];
    [yourWebView setDelegate:self];
    yourWebView.scalesPageToFit = YES;
    [yourWebView loadRequest:requestObj];
    ****/
}

Finally, this is just a simple format for generating PDF file in Objective C, Now you can customize it on your own way to make it look better and efficient. Good Luck !!!

6 comments:

  1. Can this be used to draw multiple NSStrings to a PDF? I need some assistance in figuring this out.

    Send me a tweet @thelukeirvin

    Thanks!

    ReplyDelete
    Replies
    1. If you need multiple NSStrings to be drawn to PDF then replace the method - (void) drawText{} with something like - (void) drawTextWithString:(NSString *) yourString{} and call this method as in blog with diffrenet NSString (probably from loop) and manage the page number as per your requirement.

      Delete
  2. Hi, Great Tutorial helped me a lot.
    How can I display Multiple Pages....

    Thanks.......

    ReplyDelete
  3. For multiple page , you just have to work on - (void) generatePdfWithFilePath: (NSString *)thefilePath{ } method. Take care of do while loop as per your requirement.

    ReplyDelete
  4. Sameer, the problem is that iOS 7 has some new things and I can't modify your code to the new one,. They are mort much and I tried browsing everywhere and no one explains it the way you do. Can you help with this one

    ReplyDelete