My goal is to combine two PDFs. One has 10 pages, and another has 6 pages, so the output should be 16 pages. My approach is to load both PDFs into two NSData stored in an NSMutableArray.
Here is my saving method:
NSMutableData *toSave = [NSMutableData data];
for(NSData *pdf in PDFArray){
[toSave appendData:pdf];
}
[toSave writeToFile:path atomically:YES];
However the output PDF only has the second part, which only contains 6 pages. So I don't know what did I miss. Can anyone give me some hints?
PDF is a file format which describes a single document. You cannot concatenate to PDF files to get the concatenated document.
But might achieve this with PDFKit:
Create both documents with initWithData:.
Insert all pages of the second document into the first one with insertPage:atIndex:.
This should look like:
PDFDocument *theDocument = [[PDFDocument alloc] initWithData:PDFArray[0]]
PDFDocument *theSecondDocument = [[PDFDocument alloc] initWithData:PDFArray[1]]
NSInteger theCount = theDocument.pageCount;
NSInteger theSecondCount = theSecondDocument.pageCount;
for(NSInteger i = 0; i < theSecondCount; ++i) {
PDFPage *thePage = [theSecondDocument pageAtIndex:i];
[theDocument insertPage:thePage atIndex:theCount + i];
}
[theDocument writeToURL:theTargetURL];
You have to add either #import <PDFKit/PDFKit.h> or #import PDFKit; to your source file, and you should add PDFKit.framework to the Linked Frameworks and Libraries of the build target in Xcode.
I've made a Swift command line tool to combine any number of PDF files. It takes the output path as the first argument and the input PDF files as the other arguments. There's no error handling whatsoever, so you can add that if you want to. Here's the full code:
import PDFKit
let args = CommandLine.arguments.map { URL(fileURLWithPath: $0) }
let doc = PDFDocument(url: args[2])!
for i in 3..<args.count {
let docAdd = PDFDocument(url: args[i])!
for i in 0..<docAdd.pageCount {
let page = docAdd.page(at: i)!
doc.insert(page, at: doc.pageCount)
}
}
doc.write(to: args[1])
Related
Recently i'm trouble in some problems about html convert to PDF files.
I find use the followed method to convert is not quickly enough and the PDF files created are big (the file size is about 2M - 5M / 7 pages ) . And some html pages are inconsistent with the converted PDF files.
Are there any methods to control the pdf size?
Are there any methods can convert it more quickly?
Are there any methods can solve the pdf files be inconsistent with the html pages in webview ?
I would very much appreciate your help. Thank you.
- (NSData*) printToPDF
{
NSMutableData *pdfData = [NSMutableData data];
UIGraphicsBeginPDFContextToData( pdfData, CGRectZero, nil );
[self prepareForDrawingPages: NSMakeRange(0, self.numberOfPages)];
CGRect bounds = UIGraphicsGetPDFContextBounds();
for ( int i = 0 ; i < self.numberOfPages ; i++ )
{
UIGraphicsBeginPDFPage();
[self drawPageAtIndex: i inRect: bounds];//
}
UIGraphicsEndPDFContext();
return pdfData;
}
I have followed this tutorial to make a UICollectionView custom layout: http://skeuo.com/uicollectionview-custom-layout-tutorial#section4
I got through it and I got it working. But when I try to use it with my own pictures I cannot get them show in the app.
Here's the code to get the pictures
self.albums = [NSMutableArray array];
NSURL *urlPrefix =
[NSURL URLWithString:#"https://raw.github.com/ShadoFlameX/PhotoCollectionView/master/Photos/"];
NSInteger photoIndex = 0;
for (NSInteger a = 0; a < 12; a++) {
BHAlbum *album = [[BHAlbum alloc] init];
album.name = [NSString stringWithFormat:#"Photo Album %d",a + 1];
NSUInteger photoCount = 1;
for (NSInteger p = 0; p < photoCount; p++) {
// there are up to 25 photos available to load from the code repository
NSString *photoFilename = [NSString stringWithFormat:#"thumbnail%d.jpg",photoIndex % 25];
NSURL *photoURL = [urlPrefix URLByAppendingPathComponent:photoFilename];
BHPhoto *photo = [BHPhoto photoWithImageURL:photoURL];
[album addPhoto:photo];
photoIndex++;
}
[self.albums addObject:album];
}
So the problem comes when I change the url string to the one with my pictures. I want to use a public website for hosting images like Flickr, but I also tried Imageshak.us and postimage.org and it didn't work.
I have the photo names as it says the string: thumbnail%d.jpd so that is not the problem. Any ideas?
UPDATE:
I tried using this
[NSURL URLWithString:#"http://www.flickr.com/photos/93436974#N06/"];
That's the url to the gallery, but it doesn't show anything. If I can't use Flickr, is there any other websites similar that could be used?
For your thumbnails you're naming them "thumbnail0.jpg" "thumbnail1.jpg" etc right? The %d means insert the number from outside the quotes here, for the code you posted it takes whichever number photo you're on and adds it into your string (up to a maximum of 25 at which point it will restart , ie photo 27 would return thumbnail2.jpg
Just quickly googling it looks like flickr doesn't keep the source file name so it wouldn't work with the code you posted. I would recommend photobucket I beilieve they keep the source file name and urls are easy to work with
in my ios app i am listing out some data in scroll view. When a button is clicked the datas in the page are been generated in pdf file format. Following is the bit of code.
- (void)createPDFfromUIView:(UIView*)aView saveToDocumentsWithFileName:(NSString*)aFilename{
// 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, aView.bounds, nil);
UIGraphicsBeginPDFPage();
CGContextRef pdfContext = UIGraphicsGetCurrentContext();
// draws rect to the view and thus this is captured by UIGraphicsBeginPDFContextToData
[aView.layer renderInContext:pdfContext];
// remove PDF rendering context
UIGraphicsEndPDFContext();
// Retrieves the document directories from the iOS device
NSArray* documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
NSString* documentDirectory = [documentDirectories objectAtIndex:0];
NSString* documentDirectoryFilename = [documentDirectory stringByAppendingPathComponent:aFilename];
// instructs the mutable data object to write its context to a file on disk
[pdfData writeToFile:documentDirectoryFilename atomically:YES];
NSLog(#"documentDirectoryFileName: %#",documentDirectoryFilename);
}
From the above code, i am able to generate a pdf file, but i am facing the following issue.
If i have more than 50 data, in my app i am able to see only the first 10 data and to see the others i need to scroll them. In this case when the pdf file gets generated it is taking only the data of first 10 and not the others. How to get the other data too
renderInContext: will only render what you currently see - UIScrollView is smart and will only have the views in the hierarchy that you need right now. You need a for-loop to manually scroll and redraw. This might be tricky to get right, maybe call [aView layoutSubviews] manually after scrolling to force the scrollView to rearrange the subviews instantly.
as steipete said, you can use loop to renderIncontext
- You need to calculate num of loop
numOfLoop = webview.ScrollView.ContentSize.Height/weview.frame.size.height
use loop to renderInContext
for(int i = 0; i < numOfLopp; i ++)
1.UIGraphicsBeginPDFPage()
get current context
renderIncontext
This way run correct in my app but I am getting with BIG issue when the numOfLoop lager
- you will get slow to renderInContext
- Memory will be increase -> Close app
In this way, How can I remove/release context when I am in once loop ?
Other way, you can use https://github.com/iclems/iOS-htmltopdf/blob/master/NDHTMLtoPDF.h
to generate to PDF
#steipete, #all Hi i tried the below code it generate multipage PDF, but the visible area in view is repeated for all the pages. please add any further ideas to improve the result.
-(void)createPDFfromUIView:(UIWebView*)aView saveToDocumentsWithFileName:(NSString*)aFilename
{
NSString *oldFilePath= [[NSBundle mainBundle] pathForResource:#"ABC" ofType:#"pdf"];
NSMutableData *pdfData = [NSMutableData data];
UIGraphicsBeginPDFContextToData(pdfData, aView.bounds, nil);
CFURLRef url = CFURLCreateWithFileSystemPath (NULL, (CFStringRef)oldFilePath, kCFURLPOSIXPathStyle, 0);
CGPDFDocumentRef templateDocument = CGPDFDocumentCreateWithURL(url);
CFRelease(url); size_t count = CGPDFDocumentGetNumberOfPages(templateDocument);
for (size_t pageNumber = 1; pageNumber <= count; pageNumber++)
{
UIGraphicsBeginPDFPage();
CGContextRef pdfContext = UIGraphicsGetCurrentContext();
[aView.layer renderInContext:pdfContext];
}
CGPDFDocumentRelease(templateDocument);
// remove PDF rendering context UIGraphicsEndPDFContext();
// Retrieves the document directories from the iOS device
NSArray* documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString* documentDirectory = [documentDirectories objectAtIndex:0];
NSString* documentDirectoryFilename = [documentDirectory stringByAppendingPathComponent:aFilename];
[pdfData writeToFile:documentDirectoryFilename atomically:YES];
NSLog(#"documentDirectoryFileName: %#",documentDirectoryFilename);
}
Check ScrollViewToPDF example
It uses same scrollview's layer renderInContext but here PDF is created according to your requirement such as one page PDF or multiple page PDF
Note : It captures all visible as well as invisible part of scrollView
I've been trying for a while to be able to extract the pdf documents contained in a PDF package with no success. I've found no documentation or example code anywhere, but I know it's not impossible because the Adobe Reader app and the PDFExpert app support it. It is possible that they have their own parser, I hope it doesn't come to that...
Any hint that will point me in the right direction will be greatly appreciated
Edit: after a long time I went back to working on this and finally figured it out.
Special thanks to iPDFDev for pointing me in the right direction!!
Here's the code on how to obtain each inner CGPDFDocumentRef:
NSURL *url = [NSURL fileURLWithPath:filePath isDirectory:NO];
CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL((__bridge CFURLRef)url);
CGPDFDictionaryRef catalog = CGPDFDocumentGetCatalog(pdf);
CGPDFDictionaryRef names = NULL;
if (CGPDFDictionaryGetDictionary(catalog, "Names", &names)) {
CGPDFDictionaryRef embFiles = NULL;
if (CGPDFDictionaryGetDictionary(names, "EmbeddedFiles", &embFiles)) {
// At this point you know this is a Package/Portfolio
CGPDFArrayRef nameArray = NULL;
CGPDFDictionaryGetArray(embFiles, "Names", &nameArray);
// nameArray contains the inner documents
// it brings the name and then a dictionary from where you can extract the pdf
for (int i = 0; i < CGPDFArrayGetCount(nameArray); i+=2) {
CGPDFStringRef name = NULL;
CGPDFDictionaryRef dict = NULL;
if (CGPDFArrayGetString(nameArray, i, &name) &&
CGPDFArrayGetDictionary(nameArray, i+1, &dict)) {
NSString *_name = [self convertPDFString:name];
CGPDFDictionaryRef EF;
if (CGPDFDictionaryGetDictionary(dict, "EF", &EF)) {
CGPDFStreamRef F;
if (CGPDFDictionaryGetStream(EF, "F", &F)) {
CFDataRef data = CGPDFStreamCopyData(F, NULL);
CGDataProviderRef provider = CGDataProviderCreateWithCFData(data);
CGPDFDocumentRef _doc = CGPDFDocumentCreateWithProvider(provider);
if (_doc) {
// save the docRef somewhere (_doc)
// save the pdf name somewhere (_name)
}
CFRelease(data);
CGDataProviderRelease(provider);
}
}
}
}
}
}
- (NSString *)convertPDFString:(CGPDFStringRef)string {
CFStringRef cfString = CGPDFStringCopyTextString(string);
NSString *result = [[NSString alloc] initWithString:(__bridge NSString *)cfString];
CFRelease(cfString);
return result;
}
By PDF packages I assume you refer to PDF portfolios. The files in a PDF portfolio are basically document attachments with some extended attributes and they are located in the EmbeddedFiles tree. You start with the document catalog dictionary. From the document catalog dictionary you retrieve the /Names dictionary. From the /Names dictionary, if exists (it is optional), you retrieve the /EmbeddedFiles dictionary. If it exists, it represents the head of the embedded files tree (a name tree in the PDF specification). The PDF specification (available here: http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/PDF32000_2008.pdf) describes in section 7.9.6 the name trees and you'll get the idea how to parse the tree.
The tree maps string identifiers to file specification dictionaries (section 7.11.3). From the file specification dictionary you retrieve the value of the /EF key which is the embedded file stream (section 7.11.4). The stream associated with this object is the file content you're looking for.
I need to view data from NSMutableArray in NSTableView. There is the code:
- (IBAction)StartReconstruction:(id)sender
{
NSMutableArray *ArrayOfFinals = [[NSMutableArray alloc] initWithObjects:nil]; //Array of list with final images
NSString *FinalPicture;
NSString *PicNum;
int FromLine = [TextFieldFrom intValue]; //read number of start line
int ToLine = [TextFieldTo intValue]; //read number of finish line
int RecLine;
for (RecLine = FromLine; RecLine < ToLine; RecLine++) //reconstruct from line to line
{
//Start(RecLine); //start reconstruction
//Create path of final image
FinalPicture = #"FIN/final";
PicNum = [NSString stringWithFormat: #"%d", RecLine];
FinalPicture = [FinalPicture stringByAppendingString:PicNum];
FinalPicture = [FinalPicture stringByAppendingString:#".bmp"];
[ArrayOfFinals addObject:FinalPicture]; // add path to array
}
NSBeep(); //make some noise
}
I need to set ArrayOfFinals as data source for my tableview in my app. I'm noob in cocoa, and I don't know where I need to make connections :(
I saw tutorial on youtube, but it didn't hepl me.
SO is really not a place for step-by-step tutorials.
But on this subject there're many you can find online. Personally, I've found apple tutorial very informative (even if a bit verbose).
You can't really use an array directly as a data source, but you can use an NSArrayController in between and then use bindings to hook them up.
You won't need to write a single line of code for a basic set up.
There are plenty of step-by-step tutorials on the net for this.