Find page of interactive form field in PDF - objective-c

I am trying to build a PDF parser that gives me all the locations and types of interactive form fields. I run through the entries of the AcroForm dictionary and get the right number, types and coordinates of the form fields. But how can I find the page on which a particular field is meant to be drawn? This is the revelant snippet:
NSURL* pdfURL = [openPanel URL];
CGPDFDocumentRef pdfDocument = CGPDFDocumentCreateWithURL((CFURLRef)pdfURL);
CFRelease((CFURLRef)pdfURL);
CGPDFDictionaryRef pdfCatalog = CGPDFDocumentGetCatalog(pdfDocument);
CGPDFDictionaryRef acroForm;
CGPDFDictionaryGetDictionary(pdfCatalog,"AcroForm",&acroForm);
CGPDFArrayRef formFieldsArray;
CGPDFDictionaryGetArray(acroForm,"Fields", &formFieldsArray);
long formFieldsCount = CGPDFArrayGetCount(formFieldsArray);
for (int j = 0; j < formFieldsCount; j++){
CGPDFDictionaryRef formFieldDictionary;
CGPDFArrayGetDictionary(formFieldsArray, j, &formFieldDictionary);

Related

How to combine two pdfs without losing any information?

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])

UICollection View images from url

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

SOAP in iOS - Extracting multiple strings from XML

In an iOS program I am making, I am requesting a list of courses with SOAP. This is the reply format
<ListCoursesResponse>
<statusMessage xmlns="xxx">string</statusMessage>
<courseID xmlns="xxx">string</courseID>
<courseTitle xmlns="xxx">string</courseTitle>
</ListCoursesResponse>
<ListCoursesResponse>
<statusMessage xmlns="xxx">string</statusMessage>
<courseID xmlns="xxx">string</courseID>
<courseTitle xmlns="xxx">string</courseTitle>
</ListCoursesResponse>
I am using something along the lines of extrating each separate course as an element in an array, than stepping through the array for each and extracting what is between the Course ID. However, I can't figure out how to extract more than one, as when I return it, it only shows the first course. If I explained this in a bad way, please do tell me so I can try to explain better.
My question is, what's the best way to approach a large list of courses (200+) returned in an XML reponse ?
Edit: Snippet of the code I am using, which only returns 1 ID.
NSString *tag1Open = #"<ListCoursesResponse>";
NSString *tag1Close = #"</ListCoursesResponse>";
NSString *courseIDOpen = #"<courseID xmlns=\"http://drm.mediuscorp.com/\">";
NSString *courseIDClose = #"</courseID>";
result = #"";
NSArray *XMLarray1 = [XMLResult componentsSeparatedByString:tag1Open];
if ([XMLarray1 count] > 1) {
for (int i = 0; i < [XMLarray1 count]; i++) {
NSString *courseIDString = [[[XMLarray1 objectAtIndex:1]componentsSeparatedByString:tag1Close]objectAtIndex:0];
NSArray *courseID = [XMLResult componentsSeparatedByString:courseIDOpen];
if ([courseID count] > 1) {
for (int i = 0; i < [courseID count]; i++) {
courseIDString = [[[courseID objectAtIndex:1]componentsSeparatedByString:courseIDClose]objectAtIndex:0];
}
}
NSLog(#"Course ID: %#",courseIDString);
}
[persArray addObject:result];
for (int i = 0; i < [persArray count]; i++) {
NSLog(#"%#",[persArray objectAtIndex:i]);
}
}
Rather than try to parse the SOAP XML response response yourself using NSString methods, you would be much better off using an XML Parser to handle this task. iOS has a built-in XML Parser called NSXMLParser that is available to you. (There are also numerous third-party XML Parser components available, of both SAX and DOM varieties)
Here is a tutorial that gives an example of using NSXMLParser.

iOS asset path from Core Data used in HTML img tag

I'm creating an app that lets users take and store photos in a Core Data graph, then email these photos in a table from within the app.
I've been able to save the photos within the SQlite database by converting the asset paths to NSURL values and referencing them - to stop the database from suffering from memory issues.
My last task is to allow users to email their photos in a nicely laid out table, complete with a description of the photo. This is automatically generated from the UITableView that the images are displayed in.
I'm using the following to generate the HTML email:
- (NSString *)generateHTMLBody {
NSString *res = #"<HTML><body><table border=""1"">\n";
for (int i=0; i < [self.fetchedResultsController.fetchedObjects count]; i++) {
NSString *rowCount = [NSString stringWithFormat:#"%d.", i+1];
NSString *tmp = (NSString *)[imageList objectAtIndex:0];
NSString *imageString = [NSString stringWithFormat:#"<img src=""%#"" />",tmp];
res = res = [res stringByAppendingString:#"<tr><td>"];
res = res = [res stringByAppendingString:rowCount];
res = res = [res stringByAppendingString:#"</td>\n"];
res = res = [res stringByAppendingString:#"<td>"];
res = res = [res stringByAppendingString:imageString];
res = res = [res stringByAppendingString:#"</td>\n"];
res = res = [res stringByAppendingString:#"<td>"];
res = res = [res stringByAppendingString:tmp];
res = res = [res stringByAppendingString:#"</td></tr>\n"];
}
res = [res stringByAppendingString:#"</table></body></html>\n"];
return res;
}
What I'm trying to do is load the images from the Core Data graph into an HTML img tag. I'm pulling the following asset path into the var tmp:
assets-library://asset/asset.JPG?id=2F62642E-00B3-4D85-82D2-A6A1F064F2CE&ext=JPG
However, this isn't working. How would I load these photos into the email?
How are you sending the email? Via a MFMailComposeViewController? I would have thought that you'd be attaching files via addAttachmentData:mimeType:fileName:. That's probably easiest.
Alternatively, if you want to build a custom, pretty html body with images included in there, you probably want to pursue a base64 encoding of your images. You then put something like <img src="data:image/gif;base64,XXX"> in your html, where XXX is the base64 encoding of your image. When I did this, I encoded using Google GTMBase64 in GTM:
http://code.google.com/p/google-toolbox-for-mac/
There are also articles here about base64 libraries, e.g.
How do I do base64 encoding on iphone-sdk?

PDF Packages in iOS

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.