iOS - Generating pdf from multiple files - ios

I am attempting to convert some text files into a pdf. Now the easiest thing in the world right now is to simply combine all of the text from the files into a single string and then use the iOS documentation here to render it into a single pdf. The trouble is, these are large text files; together they can equal well over 90 pages. Therefore I will need to add in some hyperlinks so I can create a table of contents at the top and the user can quickly move to the beginning of each text file rather than have to scroll through 60 pages to get to where they want to go.
Problem is, if I combine the txt files into a single string, I have no way of knowing when each file will end while it is paginating, therefore I wanted to add the files separately to the pdf before finally publishing it. Problem is, at best only the last txt file will show up rendered, most likely because it is overwriting the previous ones. Below is my code, any ideas?
- (void)savePDFFile:(NSString *)file_Name
{
// NSArray *filePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *homeDir = NSHomeDirectory();
NSString *saveDirectory = [NSString stringWithFormat: #"%#/%#", homeDir, #"Documents/"];
NSArray *fileAr = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:saveDirectory error:nil];
// NSString *text = #"";
// NSMutableArray *textArray = [[NSMutableArray alloc] init];
NSInteger currentPage = 0;
NSString *completeString = #"";
for (NSString *string in fileAr) {
if([string hasSuffix:#"txt"]){
NSString *file = [NSString stringWithFormat: #"%#/%#", saveDirectory, string];
NSString *text =[NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil];
completeString = [NSString stringWithFormat:#"%#%#", completeString, text];
}
}
for (NSString *string in fileAr) {
if([string hasSuffix:#"txt"]){
NSString *file = [NSString stringWithFormat: #"%#/%#", saveDirectory, string];
NSString *text =[NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil];
// Prepare the text using a Core Text Framesetter
CFAttributedStringRef currentText = CFAttributedStringCreate(NULL, (CFStringRef)text, NULL);
if (currentText) {
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)currentText);
// CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(currentText);
if (framesetter) {
NSString* pdfFileName = file_Name;
// Create the PDF context using the default page size of 612 x 792.
UIGraphicsBeginPDFContextToFile(pdfFileName, CGRectZero, nil);
CFRange currentRange = CFRangeMake(0, 0);
BOOL done = NO;
do {
// Mark the beginning of a new page.
UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, 612, 792), nil);
// 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);
// Release the framewetter.
CFRelease(framesetter);
CFRelease(currentText);
}
}
// Close the PDF context and write the contents out.
UIGraphicsEndPDFContext();
} else {
NSLog(#"Could not create the framesetter needed to lay out the atrributed string.");
}
// Release the attributed string.
}
}
// Use Core Text to draw the text in a frame on the page.
- (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(72, 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, 792);
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;
}

I made progress and ran into another problem, so I asked an additional question here.
Eventually, with my own testing and a little bit of help, I solved the issue.

Related

Can't Create PDF and PRINT more than 60 Pages ( memory Raises & crashes) [duplicate]

This question already has answers here:
Cannot create PDF document with 400+ pages on iOS
(4 answers)
Closed 6 years ago.
I need to generate PDF more than 60 pages and need to Print it, but in iPhone & iPad memory Ram raises to 350.50MB-500.00MB and Crashes .
For Reducing memory->Running in dispatch queues also that doesn't help
Can't find the solution for this . Plz help me in this ...
and referred below link but doesn't help
Cannot create PDF document with 400+ pages on iOS
-(NSData*)getPdfFullLineSheetiPhone:(UIScrollView *)tableView GridCount:(NSInteger)count{
// -- first page height, rest pages height: adjust to get it right
#define FIRST_PAGE_HEIGHT_FULLSON 1040
#define REST_PAGES_HEIGHT_FULLSON 1090//1420
#define WIDTH_FULLSO_PORTRAITN 400
CGSize fittedSize;
CGRect priorBounds = tableView.frame;
// - the '200' is the cell height for estimating how many pages, and 200/3 is ROw calculation(How many rows in GMGridView)
fittedSize =CGSizeMake(WIDTH_FULLSO_PORTRAITN, count * 200/3);
tableView.bounds = CGRectMake(0, 0, fittedSize.width, fittedSize.height);
Generating Pages Code Starts
CGRect pdfPageBounds;
// Standard US Letter dimensions 8.5" x 11"
pdfPageBounds = CGRectMake(0, 0, 768/1.8, REST_PAGES_HEIGHT_FULLSON/1.79);
NSMutableData *pdfData = [[NSMutableData alloc] init];
UIGraphicsBeginPDFContextToData(pdfData, pdfPageBounds, nil);
int pageno=0;
{
// do page1
CGRect pdfPageBoundsPage1;
pdfPageBoundsPage1 = CGRectMake(0,0,768/1.8, FIRST_PAGE_HEIGHT_FULLSON/1.7);
UIGraphicsBeginPDFPageWithInfo(pdfPageBoundsPage1, nil);
{
CGContextTranslateCTM(UIGraphicsGetCurrentContext(), 10, 0);
[tableView.layer renderInContext:UIGraphicsGetCurrentContext()];
pageno ++;
}
//Rest of Pages
for (CGFloat pageOriginY = FIRST_PAGE_HEIGHT_FULLSON/1.7; pageOriginY < fittedSize.height; pageOriginY += REST_PAGES_HEIGHT_FULLSON/1.79)
{
#autoreleasepool {
UIGraphicsBeginPDFPageWithInfo(pdfPageBounds, nil);
{
CGContextTranslateCTM(UIGraphicsGetCurrentContext(), 10, -pageOriginY);
[tableView.layer renderInContext:UIGraphicsGetCurrentContext()];
pageno ++;
}
}
}
}
UIGraphicsEndPDFContext();
tableView.bounds = priorBounds;
return pdfData;
}
Memory Raises in iPad4 whereas in iPad Mini 180-240MB nd crashes
you have to construct your code some thing like this:
UIGraphicsBeginPDFContextToFile( pdfPath, CGRectZero, nil );// as per rMaddy
UIGraphicsBeginPDFPageWithInfo();
CGContextRef pdfContext = UIGraphicsGetCurrentContext();
[tableView.layer renderInContext:pdfContext];
UIGraphicsEndPDFContext();
here:
file namecan be like this:
NSString *newPDFName = [NSString stringWithFormat:#”%#.pdf”, #"whatEverNameYouWant"];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pdfPath = [documentsDirectory stringByAppendingPathComponent:newPDFName];
NSLog(#”%#”,pdfPath);
basically the main benefit of this approach will be reduce NSData which is creating memory pressure.
over all code will look some thing this:
// Set up we the pdf we're going to be generating is
UIGraphicsBeginPDFContextToFile(pdfPath, CGRectZero, nil);
int i = 0;
for ( ; i < pages; i++)
{
#autoreleasepool{
// Specify the size of the pdf page
UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, kDefaultPageWidth, kDefaultPageHeight), nil);
CGContextRef currentContext = UIGraphicsGetCurrentContext();
// Move the context for the margins
CGContextTranslateCTM(currentContext, kMargin, kMargin);
// draw the layer to the pdf, ignore the "renderInContext not found" warning.
[tableView.layer.layer renderInContext:currentContext];
}
}
// all done with making the pdf
UIGraphicsEndPDFContext();
Thats it !! you can take care of your calculation
It is not the answer for above question , it is another Code which was tried for to generate PDf using
UIGraphicsBeginPDFPageWithInfo. This approach also crashes for more than 500 rows nothing but it comes around 56 Pages
After this approach after returning PDF Data when i assign that PDF Data to UIPrinterInteractionController Action -
It shows , SO i am unable to calculate Pages
Print-Job failed: Printer exists.
2016-05-27 00:37:26.131 APPName[9078:2952235] \032Send\032to\032Mac\032#\032macminiB._ipp._tcp.local.: startJob not called.
Note :
whereas this Printer error doesn't shows in Above code which i posted above with UIGraphicsBeginPDFContextToData
-(NSData *)getPdfSimpleSOTr:(UITableView *)tableView{
#define FIRST_PAGE_HEIGHT 1188
#define REST_PAGES_HEIGHT 1176.5
CGSize fittedSize;
CGRect priorBounds;
// 140208 dan - Comment: save the WIDTH
CGRect savedFrame = tableView.frame;
// 140207 dan - force portrait width
priorBounds = tableView.frame;
priorBounds.size.width=768; // put into Portrait
tableView.frame = priorBounds;
fittedSize = [tableView sizeThatFits:CGSizeMake(priorBounds.size.width, ([tableView numberOfRowsInSection:0] * 49) + 529)];
tableView.bounds = CGRectMake(0, 0, fittedSize.width, fittedSize.height);
CGRect pdfPageBounds;
pdfPageBounds = CGRectMake(0, -12, 768, REST_PAGES_HEIGHT);
File Name & Path
NSString *newPDFName = [NSString stringWithFormat:#"%#.pdf", #"AppName"];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pdfPath = [documentsDirectory stringByAppendingPathComponent:newPDFName];
NSLog(#"%#",pdfPath);
Generating Pages
// Set up we the pdf we're going to be generating is
UIGraphicsBeginPDFContextToFile(pdfPath, CGRectZero, nil);
int pageno=0;
{
CGRect pdfPageBoundsPage1 = CGRectMake(0,0,768, FIRST_PAGE_HEIGHT+15);//15
UIGraphicsBeginPDFPageWithInfo(pdfPageBoundsPage1, nil);
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 10, 0);
[tableView.layer renderInContext:context];
pageno ++;
}
for (CGFloat pageOriginY = FIRST_PAGE_HEIGHT; pageOriginY < fittedSize.height; pageOriginY += REST_PAGES_HEIGHT)
{
#autoreleasepool{
// Specify the size of the pdf page
UIGraphicsBeginPDFPageWithInfo(pdfPageBounds, nil);
CGContextRef context = UIGraphicsGetCurrentContext();
// Move the context for the margins
CGContextTranslateCTM(context, 10, -pageOriginY);
// draw the layer to the pdf, ignore the "renderInContext not found" warning.
[tableView.layer renderInContext:context];
}
}
}
// all done with making the pdf
UIGraphicsEndPDFContext();
After GraphicsEnd retrieving NSData from FilePath
NSData *pdfData;
if([[NSFileManager defaultManager] fileExistsAtPath:pdfPath])
{
pdfData = [[NSFileManager defaultManager] contentsAtPath:pdfPath];
}
else
{
NSLog(#"File not exits");
}
tableView.bounds = priorBounds;
// 140208 dan - Comment: restored the saved WIDTH
tableView.frame=savedFrame ;
return pdfData;
}

Set color CFAttributedStringRef

I have this methods for draw a table ant populated . What i want is to change the color for one word from each column , but i dont know how can i do it . Can somebeday help me ,please ? Any help will be appreciate .
in my app the user can select some attributes from segmente control... I want to export what he chosen in a pdf , like a table .So on each line a word will be selected
-(void)drawTableDataAt:(CGPoint)origin
withRowHeight:(int)rowHeight
andColumnWidth:(int)columnWidth
andRowCount:(int)numberOfRows
andColumnCount:(int)numberOfColumns
{
int padding = 1;
NSArray* headers = [NSArray arrayWithObjects:#"Grand", #"Taile ok", #"Petit", nil];
NSArray* invoiceInfo1 = [NSArray arrayWithObjects:#"Extra", #"Bon", #"Ordi", nil];
NSArray* invoiceInfo2 = [NSArray arrayWithObjects:#"Gras", #"Etat", #"Maigre", nil];
NSArray* invoiceInfo3 = [NSArray arrayWithObjects:#"Cru", #"Propre", #"Sale", nil];
NSArray* invoiceInfo4 = [NSArray arrayWithObjects:#"PLourd", #"PMoyen", #"PLeger", nil];
NSArray* invoiceInfo5 = [NSArray arrayWithObjects:#"CSup", #"CEgal", #"CInf", nil];
NSArray* allInfo = [NSArray arrayWithObjects:headers, invoiceInfo1, invoiceInfo2, invoiceInfo3, invoiceInfo4, invoiceInfo5,nil];
for(int i = 0; i < [allInfo count]; i++)
{
NSArray* infoToDraw = [allInfo objectAtIndex:i];
for (int j = 0; j < numberOfColumns; j++)
{
int newOriginX = origin.x + (j*columnWidth);
int newOriginY = origin.y + ((i+1)*rowHeight);
CGRect frame = CGRectMake(newOriginX + padding, newOriginY + padding, columnWidth, rowHeight);
[self drawText:[infoToDraw objectAtIndex:j] inFrame:frame];
}
}
}
-(void)drawText:(NSString*)textToDraw inFrame:(CGRect)frameRect
{
CFStringRef stringRef = (__bridge CFStringRef)textToDraw;
// Prepare the text using a Core Text Framesetter
CFAttributedStringRef currentText = CFAttributedStringCreate(NULL, stringRef, NULL);
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(currentText);
CGMutablePathRef framePath = CGPathCreateMutable();
CGPathAddRect(framePath, NULL, frameRect);
// Get the frame that will do the rendering.
CFRange currentRange = CFRangeMake(0, 0);
CTFrameRef frameRef = CTFramesetterCreateFrame(framesetter, currentRange, framePath, NULL);
CGPathRelease(framePath);
// 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);
// Core Text draws from the bottom-left corner up, so flip
// the current transform prior to drawing.
CGContextTranslateCTM(currentContext, 0, frameRect.origin.y*2);
CGContextScaleCTM(currentContext, 1.0, -1.0);
// Draw the frame.
CTFrameDraw(frameRef, currentContext);
CGContextScaleCTM(currentContext, 1.0, -1.0);
CGContextTranslateCTM(currentContext, 0, (-1)*frameRect.origin.y*2);
CFRelease(frameRef);
CFRelease(stringRef);
CFRelease(framesetter);
}
Based on the comments on the question, you mentioned that the words will never change. You could potentially create a whole bunch of if/else statements checking every word selected against every word in an array. I have put this down as a more efficient alternative and it should hopefully work. It may need some tweaking or even a loop to go through your chosen words, but this should hopefully put you in the right direction:
//declare your textToDraw as a new NSString
NSString *str = textToDraw;
//Make an Array of the str by adding objects that are separated by whitespace
NSArray *words = [str componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
//create a BOOL to check if your selected word exists in the array
BOOL wordExists = [words containsObject: #"%#", yourSelectedWord];
CTFramesetterRef framesetter = null;
//if the word exists, make it red
if(wordExists){
NSUInteger indexOfTheString = [words indexOfObject: #"%#", yourSelectedWord];
CFAttributedStringRef currentText = CFAttributedStringCreate(NULL,str, NULL);
[currentText addAttribute:NSForegroundColorAttributeName
value:[UIColor redColor]
range:NSMakeRange(indexOfTheString, yourSelectedWord.length)];
framesetter = CTFramesetterCreateWithAttributedString(currentText);
}
This will match your selected word found against the right word in your array and highlight it red.

How to find the touch point of PDF present in UIWebView?

I am working on document based application. I will load the PDF in UIWebView. For my requirement, i have to add an image in my touch/tap point. I have found the touch point(CGPoint) in UIWebview. But i want to get the same touch point of PDF that was loaded in PDF.
In detail, UIWebView show the contents of PDF document in varied size(Small size). So the touchpoint(CGPoint) of UIWebView will differ with the PDF.
I am not rendering the content of UIWebView to PDF due to decrease in page clarity. I will render the content of PDF directly.
Below code will explain the how i am rendering the PDF.
Code for PDF render:
NSString *tessdataPath = [[NSBundle mainBundle] pathForResource:#"input" ofType:#"pdf"];
NSURL *url = [NSURL fileURLWithPath:tessdataPath];
CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL((CFURLRef)url);
const size_t numberOfPages = CGPDFDocumentGetNumberOfPages(pdf);
NSMutableData* data = [NSMutableData data];
UIGraphicsBeginPDFContextToData(data, CGRectZero, nil);
for(size_t page = 1; page <= numberOfPages; page++)
{
// Get the current page and page frame
CGPDFPageRef pdfPage = CGPDFDocumentGetPage(pdf, page);
const CGRect pageFrame = CGPDFPageGetBoxRect(pdfPage, kCGPDFMediaBox);
UIGraphicsBeginPDFPageWithInfo(pageFrame, nil);
// Draw the page (flipped)
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);
CGContextScaleCTM(ctx, 1, -1);
CGContextTranslateCTM(ctx, 0, -pageFrame.size.height);
CGContextDrawPDFPage(ctx, pdfPage);
CGContextRestoreGState(ctx);
if(page == 1)
{
for (UIView *subview in [self.pdfView.scrollView subviews]) {
if([subview isKindOfClass:[UIImageView class]])
{
UIImageView *img = (UIImageView*)subview;
[subview removeFromSuperview];
CGPoint point1 = CGPointMake(img.frame.origin.x, img.frame.origin.y);
[self drawCustomPDFContent:img.image point1:point1];
}
}
}
}
UIGraphicsEndPDFContext();
CGPDFDocumentRelease(pdf);
pdf = nil;
NSArray* documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
NSString* documentDirectory = [documentDirectories objectAtIndex:0];
NSString *filePath = [documentDirectory stringByAppendingPathComponent:#"output.pdf"];
//bool fileCopied = [[NSFileManager defaultManager]copyItemAtURL:url toURL:toUrl error:nil];
[data writeToFile:filePath atomically:YES];
In this, i am rendering the input pdf with an image in page 1. Image was successfully rendered with input.pdf. But i need to add the image at exact point in pdf. See the above image for touch point difference. Can anyone provide the solution to find the exact touch point in PDF?

PDF First Page doesn't show in iOS

I have to show PDF First Page in UITableViewCell's ImageView.
My PDF Documents are located in document directory of app.
Here is my code in CellForRowAtIndexPath
NSURL* url =[self.arrayOfBooks objectAtIndex:indexPath.row];
UIImage *cellImage = [self buildThumbnailImage:MyGetPDFDocumentRef(url.absoluteString)];
cell.imageView.image = cellImage;
And Here is buildThumbnailImage Method.
- (UIImage *)buildThumbnailImage:(CGPDFDocumentRef)pdfDocument
{
BOOL hasRetinaDisplay = FALSE; // by default
CGFloat pixelsPerPoint = 1.0; // by default (pixelsPerPoint is just the "scale" property of the screen)
if ([UIScreen instancesRespondToSelector:#selector(scale)]) // the "scale" property is only present in iOS 4.0 and later
{
// we are running iOS 4.0 or later, so we may be on a Retina display; we need to check further...
if ((pixelsPerPoint = [[UIScreen mainScreen] scale]) == 1.0)
hasRetinaDisplay = FALSE;
else
hasRetinaDisplay = TRUE;
}
else
{
// we are NOT running iOS 4.0 or later, so we can be sure that we are NOT on a Retina display
pixelsPerPoint = 1.0;
hasRetinaDisplay = FALSE;
}
size_t imageWidth = 320; // width of thumbnail in points
size_t imageHeight = 460; // height of thumbnail in points
if (hasRetinaDisplay)
{
imageWidth *= pixelsPerPoint;
imageHeight *= pixelsPerPoint;
}
size_t bytesPerPixel = 4; // RGBA
size_t bitsPerComponent = 8;
size_t bytesPerRow = bytesPerPixel * imageWidth;
void *bitmapData = malloc(imageWidth * imageHeight * bytesPerPixel);
// in the event that we were unable to mallocate the heap memory for the bitmap,
// we just abort and preemptively return nil:
if (bitmapData == NULL)
return nil;
// remember to zero the buffer before handing it off to the bitmap context:
bzero(bitmapData, imageWidth * imageHeight * bytesPerPixel);
CGContextRef theContext = CGBitmapContextCreate(bitmapData, imageWidth, imageHeight, bitsPerComponent, bytesPerRow,
CGColorSpaceCreateDeviceRGB(), kCGImageAlphaPremultipliedLast);
//CGPDFDocumentRef pdfDocument = MyGetPDFDocumentRef(); // NOTE: you will need to modify this line to supply the CGPDFDocumentRef for your file here...
CGPDFPageRef pdfPage = CGPDFDocumentGetPage(pdfDocument, 1); // get the first page for your thumbnail
CGAffineTransform shrinkingTransform =
CGPDFPageGetDrawingTransform(pdfPage, kCGPDFMediaBox, CGRectMake(0, 0, imageWidth, imageHeight), 0, YES);
CGContextConcatCTM(theContext, shrinkingTransform);
CGContextDrawPDFPage(theContext, pdfPage); // draw the pdfPage into the bitmap context
CGPDFDocumentRelease(pdfDocument);
//
// create the CGImageRef (and thence the UIImage) from the context (with its bitmap of the pdf page):
//
CGImageRef theCGImageRef = CGBitmapContextCreateImage(theContext);
free(CGBitmapContextGetData(theContext)); // this frees the bitmapData we malloc'ed earlier
CGContextRelease(theContext);
UIImage *theUIImage;
// CAUTION: the method imageWithCGImage:scale:orientation: only exists on iOS 4.0 or later!!!
if ([UIImage respondsToSelector:#selector(imageWithCGImage:scale:orientation:)])
{
theUIImage = [UIImage imageWithCGImage:theCGImageRef scale:pixelsPerPoint orientation:UIImageOrientationUp];
}
else
{
theUIImage = [UIImage imageWithCGImage:theCGImageRef];
}
CFRelease(theCGImageRef);
return theUIImage;
}
CGPDFDocumentRef MyGetPDFDocumentRef(NSString *inputPDFFile)
{
//NSString *inputPDFFile = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:#"test.pdf"];
const char *inputPDFFileAsCString = [inputPDFFile cStringUsingEncoding:NSASCIIStringEncoding];
//NSLog(#"expecting pdf file to exist at this pathname: \"%s\"", inputPDFFileAsCString);
CFStringRef path = CFStringCreateWithCString(NULL, inputPDFFileAsCString, kCFStringEncodingUTF8);
CFURLRef url = CFURLCreateWithFileSystemPath(NULL, path, kCFURLPOSIXPathStyle, 0);
CFRelease (path);
CGPDFDocumentRef document = CGPDFDocumentCreateWithURL(url);
CFRelease(url);
if (CGPDFDocumentGetNumberOfPages(document) == 0)
{
printf("Warning: No pages in pdf file \"%s\" or pdf file does not exist at this path\n", inputPDFFileAsCString);
return NULL;
}
return document;
}
And Here is how i load pdf file list from document directory.
- (NSMutableArray *)loadBookFromDocumentDirectory
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [NSString stringWithFormat:#"%#",[paths objectAtIndex:0]];
NSFileManager *manager = [NSFileManager defaultManager];
NSError *error;
NSArray *files = [manager contentsOfDirectoryAtURL:[NSURL fileURLWithPath:documentsDirectory]
includingPropertiesForKeys:[NSArray arrayWithObject:NSURLContentModificationDateKey]
options:NSDirectoryEnumerationSkipsHiddenFiles
error:&error];
NSArray* sortArray = [files sortedArrayUsingComparator:
^(NSURL *file1, NSURL *file2)
{
NSDate *file1Date;
[file1 getResourceValue:&file1Date forKey:NSURLContentModificationDateKey error:nil];
NSDate *file2Date;
[file2 getResourceValue:&file2Date forKey:NSURLContentModificationDateKey error:nil];
// Ascending:
//return [file1Date compare: file2Date];
// Descending:
return [file2Date compare: file1Date];
}];
NSMutableArray *sortedContents = [[NSMutableArray alloc] initWithArray:sortArray];
return sortedContents;
}
When i run my app , it doesn't show anything at Cell ImageView and showing this message.
file:///Users/MacUser/Library/Application%20Support/iPhone%20Simulator/7.1-64/Applications/08BE9071-6251-44ED-A8E0-55CD478380FC/Documents/CGPDFDocument.pdf" or pdf file does not exist at this path
I am sure i have that pdf and even showing PDF Name in TableView.
Where am i wroning?
Okay. I think I understand what's going on here.
You've "added your PDF files via iTunes". I have NO idea how that is supposed to actually work.
But it's clear to me that the PDF files in your simulator folder are zero bytes in size.
The code you have right now should work, you just need to get valid PDF files into there to start with.
In Terminal, you can open that folder using the command
open ~/Library/Application\ Support/iPhone\ Simulator/7.1-64/Applications/08BE9071-6251-44ED-A8E0-55CD478380FC/Documents
And when it opens in the Macintosh Finder, you'll see that all the PDF files in there are zero bytes in size. Manually copy in your correct PDF files and your app should begin to magically work in the simulator.
Now, for production code, you need to write code to REALLY copy the PDF files into the documents folder. Where do the PDF files come from originally? Do you download them or are they built into the app somewhere?

Add a signature image to a pdf without showing the pdf data to user in iOS

I want to add the signature on existing pdf. I have done this in following way:
1) Load existing pdf on UIView say mainView.
2) Add a signature image on mainView.
3) Call a following function
-(NSMutableData *)getPDFDatafromUIView
{
DebugLog(#"");
// Creates a mutable data object for updating with binary data, like a byte array
NSMutableData *pdfData = [NSMutableData data];
// Points the pdf converter to the mutable data object and to the UIView to be converted
UIGraphicsBeginPDFContextToData(pdfData, mainView.bounds, nil);
UIGraphicsBeginPDFPage();
CGContextRef pdfContext = UIGraphicsGetCurrentContext();
// draws rect to the view and thus this is captured by UIGraphicsBeginPDFContextToData
mainView.layer renderInContext:pdfContext];
// remove PDF rendering context
UIGraphicsEndPDFContext();
return pdfData;
}
4) This function block your UI for a while, so call it on new thread
[NSThread detachNewThreadSelector:#selector(launchExportViewForExportDrawing) toTarget:self withObject:nil];
Using above method I get a pdf data with signature which contain the old pdf data too.
But for above method I must need to show the pdf in UIView. If I want do the above thing without loading on UIView, without showing pdf to user, How do I do that?
I am able to add a Image on pdf with creating the new pdf page. How do I add a image on existing pdf?
I have solved by creating the new PDF and drawing the pdf data and signature on it. Please refer following code:
// For adding the Siganture we need to wite the content on new PDF
-(void) addSignature:(UIImage *) imgSignature onPDFData:(NSData *)pdfData {
NSMutableData* outputPDFData = [[NSMutableData alloc] init];
CGDataConsumerRef dataConsumer = CGDataConsumerCreateWithCFData((CFMutableDataRef)outputPDFData);
CFMutableDictionaryRef attrDictionary = NULL;
attrDictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(attrDictionary, kCGPDFContextTitle, CFSTR("My Doc"));
CGContextRef pdfContext = CGPDFContextCreate(dataConsumer, NULL, attrDictionary);
CFRelease(dataConsumer);
CFRelease(attrDictionary);
CGRect pageRect;
// Draw the old "pdfData" on pdfContext
CFDataRef myPDFData = (__bridge CFDataRef) pdfData;
CGDataProviderRef provider = CGDataProviderCreateWithCFData(myPDFData);
CGPDFDocumentRef pdf = CGPDFDocumentCreateWithProvider(provider);
CGDataProviderRelease(provider);
CGPDFPageRef page = CGPDFDocumentGetPage(pdf, 1);
pageRect = CGPDFPageGetBoxRect(page, kCGPDFMediaBox);
CGContextBeginPage(pdfContext, &pageRect);
CGContextDrawPDFPage(pdfContext, page);
// Draw the signature on pdfContext
pageRect = CGRectMake(0, 0,imgSignature.size.width , imgSignature.size.height);
CGImageRef pageImage = [imgSignature CGImage];
CGContextDrawImage(pdfContext, pageRect, pageImage);
// release the allocated memory
CGPDFContextEndPage(pdfContext);
CGPDFContextClose(pdfContext);
CGContextRelease(pdfContext);
// write new PDFData in "outPutPDF.pdf" file in document directory
NSString *docsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *pdfFilePath =[NSString stringWithFormat:#"%#/outPutPDF.pdf",docsDirectory];
[outputPDFData writeToFile:pdfFilePath atomically:YES];
}
Rohit Answer is working perfectly,But it works only single page so i just Added some code for all pages displaying with image(image shown in single page reaming pages are looks same).Thanks #Rohit
NSString *path = [[NSBundle mainBundle] pathForResource:#"PartB" ofType:#"pdf"];
NSURL *docURL = [NSURL fileURLWithPath:path];
NSString *pdfName = [NSString stringWithFormat:#"%#",docURL];
NSLog(#"pdfName: %#", pdfName);
NSData *pdfData = [NSData dataWithContentsOfFile:path];
NSURL *pdfURL = [[NSBundle mainBundle] URLForResource:#"PartB.pdf" withExtension:nil];
CGPDFDocumentRef pdf1 = CGPDFDocumentCreateWithURL((CFURLRef)pdfURL);
long pageCount = CGPDFDocumentGetNumberOfPages(pdf1);
NSLog(#"the page count %ld",pageCount);
NSMutableData* outputPDFData = [[NSMutableData alloc] init];
CGDataConsumerRef dataConsumer = CGDataConsumerCreateWithCFData((CFMutableDataRef)outputPDFData);
CFMutableDictionaryRef attrDictionary = NULL;
attrDictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(attrDictionary, kCGPDFContextTitle, CFSTR("My Doc"));
CGContextRef pdfContext = CGPDFContextCreate(dataConsumer, NULL, attrDictionary);
CFRelease(dataConsumer);
CFRelease(attrDictionary);
CGRect pageRect;
// Draw the old "pdfData" on pdfContext
CFDataRef myPDFData = (__bridge CFDataRef) pdfData;
CGDataProviderRef provider = CGDataProviderCreateWithCFData(myPDFData);
CGPDFDocumentRef pdf = CGPDFDocumentCreateWithProvider(provider);
CGDataProviderRelease(provider);
for (int k=1; k<=pageCount; k++) {
CGPDFPageRef page3 = CGPDFDocumentGetPage(pdf, k);
pageRect = CGPDFPageGetBoxRect(page3, kCGPDFMediaBox);
CGContextBeginPage(pdfContext, &pageRect);
CGContextDrawPDFPage(pdfContext, page3);
if (k==pageSelect) {
pageRect = CGRectMake(0, 0,100 , 100);
CGImageRef pageImage = [mainImage.image CGImage];
CGContextDrawImage(pdfContext, pageRect, pageImage);
}
CGPDFContextEndPage(pdfContext);
}
CGPDFContextClose(pdfContext);
CGContextRelease(pdfContext);
// write new PDFData in "outPutPDF.pdf" file in document directory
NSString *docsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *pdfFilePath =[NSString stringWithFormat:#"%#/outPutPDF.pdf",docsDirectory];
[outputPDFData writeToFile:pdfFilePath atomically:YES];
NSLog(#"save the pdf %#",pdfFilePath);
I'm not sure I understand your problem completely. From what I can tell you have a UIView that you're rendering onto a PDF document, and you want to add a signature image and not show it to the user.
If you're trying to add a "signature image" to your pdf, you can add a UIImageView to the UIView that you're rendering to the pdf.
If you don't want the user to see the UIView in the mean time, you could change it's origin to somewhere off bounds, for example:
CGRect originalFrame = mainView.frame;
CGRect newFrame = mainView.frame;
newFrame.origin.x = -newFrame.size.width;
newFrame.origin.y = -newFrame.size.height;
mainView.frame = newFrame;
//do all your PDF stuff here
mainView.frame = originalFrame;
I hope that helps. If it doesn't, please clarify the problem :)

Resources