pdfOutline of PDFKit in Objective-C - objective-c

i try badly to extend (im a beginner with Objective-C) a pdf-viewer with PDF-included Outlines. The viewer is based on Apples PDFKit. (https://developer.apple.com/documentation/pdfkit/pdfoutline)
Thats what i have done so far:
PDFPage *page = [_pdfDocument pageAtIndex:_pdfDocument.pageCount-1];
PDFOutline *pdfOutline = [_pdfDocument outlineRoot];
NSLog(#"LOG of pdfOutline");
NSLog(#"%#", pdfOutline);
NSLog(#"%i", pdfOutline.numberOfChildren);
Thats gives me the following Output:
[3685:9776989] LOG of pdfOutline
[3685:9776989] <PDFOutline: 0x60c000203370>
[3685:9776989] 4
So far so good, but I need somehow the labels and the page numbers in an jsonObject (its necessary cause of using it later in a react-native callback). Im even not sure what the output of "pdfOutline" is.
I really have no idea how to start. The goal is clear, generate an json-object from the outlines.

That's just given you a pointer to the object. You need to use the pdfOutline.label method to get the text of the outline's label.
Outlines don't contain a page number, but a Destination object, which you can read using the .destination method; or an Action object. A Destination is a page number, page co-ordinates, and optional zoom level. An Action may be "Go to page", or a URL, or other.
Don't forget that page numbers in PDFKit start at 0, not 1. !!

Related

iText's Alt-Text adding sample code not working for PDFs tagged using Acrobat

I'm working on a PDF accessibility assignment, which is to add alternative text in a tagged PDF. I got the sample code for the same at: Add alternative text for an image in tagged pdf (PDF/UA) using iText
Very much excited about that my task is going to end in a very short time, without much R&D.
Created a Java project based on the code, and when I executed it, it worked perfectly for the input PDF used in iText.
Unfortunately, the same source code is not working with PDFs tagged using Acrobat.
Sample Inputs: iText PDF: no_alt_attribute.pdf   &   My PDF: SARO_Sample_v1.7.pdf
Issue:
// This line works and returns RootElement
PdfDictionary structTreeRoot = catalog.getAsDict(PdfName.STRUCTTREEROOT);
// --> This line always returns NULL,
// Instead of returning the child elements of RootElement
PdfArray kids = structTreeRoot.getAsArray(PdfName.K);
// --> As per the structure Kids are present
Compared the structure of both PDFs and the following are my observations:
Tagging Structure - exactly same in both PDFs Tagging Structure
Content Structure - almost same, but a few additions are available in the PDF created by me. Content Structure
Tag Tree Structure - almost same respective to Tags, but with a major difference: iText's PDF tags are marked with /T:StructElem whereas that's not found in MY-PDF Even re-tagging doesn't help. Tag Tree Structure
Verified with various tagged PDFs available with us and all are similar (without /T:StructElem). These PDFs are validated and have passed accessibility compliance.
Need some thoughts on how to make this source code work with the PDFs we have. Alternatively, I need a way to ADD the missing /T:StructElem automatically in the PDFs while tagging in Acrobat.
Any help will be much appreciated!
Please do let me know if any further information is needed.
Note: I'm still not sure adding this /T:StructElem will work, since the PDFs were passed in PAC.
If this is really an issue, then those PDFs wont be passed the validations, right? But this is the only difference I found between those two PDFs.
PS: The Acrobat version I'm using is "Adobe Acrobat (Pro) DC."
-- Thanks,SaRaVaNaN
Bruno's code in the referenced answer does not walk the whole structure tree because he did not implement all cases of the K contents. The structure element K entry is specified like this:
The children of this structure element. The value of this entry may be one of the following objects or an array consisting of one or more of the following objects in any combination: [...]
(ISO 32000-2, Table 355 — Entries in a structure element dictionary)
Bruno's code, though, always assumes the value to be an array:
PdfArray kids = element.getAsArray(PdfName.K);
(Most likely he implemented that code with just the structure tree of the PDF in question there in mind.)
Thus, replace
PdfArray kids = element.getAsArray(PdfName.K);
if (kids == null) return;
for (int i = 0; i < kids.size(); i++)
manipulate(kids.getAsDict(i));
by something like
PdfObject kid = element.getDirectObject(PdfName.K);
if (kid instanceof PdfDictionary) {
manipulate((PdfDictionary)kid);
} else if (kid instanceof PdfArray) {
PdfArray kids = (PdfArray)kid;
for (int i = 0; i < kids.size(); i++)
manipulate(kids.getAsDict(i));
}
As you did not share an example document, I could not test the code. If there are problems, please share an example PDF.

looping a sprite vertically objective C sprite builder

Note: for this I am using a program called spritebuilder, which allows me to create a game with less code than would normally be needed. If you know a solution that's just all code, then by all means feel free to share it :)
Also, for this question, I followed a tutorial at this link: Build Your Own Flappy Bird Clone. Just scroll down to the part that says: "Loop the Ground"
So here's my problem. Im currently working on a game, and I created a camera which scrolls vertically long with the character sprite i created, however i need a certain image to loop. When the image leaves the bottom part of the screen I would like it to loop around to the top of the screen, infinitely. For this i created two identical images (in this case its the bark of a tree). One will be on screen, while the other will be offscreen, so as the first image leaves the screen, the second will replace it (seamlessly). I created two objects for the images, and assigned them the name _ground1, and _ground2, and I also created an NSArray in which to store them in. (Please refer to the link above if it is somewhat confusing)
Here is the code that I have:
CCNode *_ground1;
CCNode *_ground2;
NSArray *_grounds;
for (CCNode *ground in _grounds) {
// get the world position of the ground
CGPoint groundWorldPosition = [_physicsNode convertToWorldSpace:ground.position];
// get the screen position of the ground
CGPoint groundScreenPosition = [self convertToNodeSpace:groundWorldPosition];
// if the left corner is one complete width off the screen, move it to the right
if (groundScreenPosition.y <(-1 * ground.contentSize.height)) {
ground.position = ccp(ground.position.x , ground.position.y + 2 * ground.contentSize.height);
}
For some reason when I try this, it doesnt seem to work. what happens is that, the camera will travel vertically as it is meant to do, but the images do not loop. Once the two images leave the bottom of the screen, no new images replace them.
i also done this project as above tutorials. it work fine but you have some mistake to set variable in spritebuilder. in your above code replce code as and try it. you only put less than may be it issue.
if (groundScreenPosition.y <=(-1 * ground.contentSize.height)) {
ground.position = ccp(ground.position.x , ground.position.y + 2 * ground.contentSize.height);
}
You are using CCNode objects as _ground1and _ground2.
CCNode objects usually do not have a contentSize, they will return 0 unless you explicitly set them inSpriteBuilder`.
Make sure that you are using CCSprite objects in SpriteBuilder and in your code.
Also, as a friendly hint you should also consider refactoring (renaming) your sprites with more meaningful names for your use case like _treeBark1 and treeBark2 for example.

How to add text to an existing pdf at a fixed position?

I must insert a number at a fix position in an existing A4 pdf.
I've tried the following as a first test, but that doesn't work(not text is added).
What goes wrong?
Here's my code:
byte[] omrMarks = omrFrame.getOmrImage();
Jpeg img = new Jpeg(omrMarks);
PdfImportedPage page = stamper.getImportedPage(source, pageNum);
PdfContentByte pageContent = stamper.getOverContent(pageNum);
pageContent.addImage(
img, img.getWidth(), 0, 0, img.getHeight(), 15f, (page.getHeight() - 312));
pageContent.moveTo(10, 200);
pageContent.beginText();
pageContent.setLiteral("Test");
pageContent.endText();
There are many issues with this question.
This is certainly wrong:
pageContent.moveTo(10, 200);
pageContent.beginText();
pageContent.setLiteral("Test");
pageContent.endText();
The moveTo() method doesn't make sense; it has no effect on the text state object.
The text state object is illegal because there's no setFontAndSize() (it's very odd that this doesn't throw a RuntimeException, are you using an obsolete version of iText?)
The setLiteral() method should only be used to add some literal PDF syntax to a content stream.
For instance, something like:
pageContent.setLiteral("\n100 100 m\n100 200 l\nS\n");
should only be used if you understand that the following PDF syntax draws a line:
100 100 m
100 200 l
S
It's clear from your question that you don't understand PDF syntax, so you shouldn't use these methods. Instead you should use convenience methods such as the showTextAligned() method, which hide the complexity of PDF and save you a couple of lines.
Maybe you have a good reason to opt for the "hard way", but in that case, you should read the documentation, otherwise you'll continue using methods such as setLiteral() instead of showText(), moveTo() instead of moveText(), and so on, resulting in code you don't want your employer to see.
Furthermore, you're making the assumption that the lower left corner of the page has the coordinates (0,0). That's probably true for the majority of PDF documents found in the wild, but that's not true for all PDF documents. The MediaBox doesn't have to be [0 0 595 842], it could as well be [595 842 1190 1684]. Moreover: what if there's a CropBox? Maybe you're adding content that isn't visible because it's cropped away...

how to properly debug in xCode and Objective-C

I was wondering if there is an effective way to debug problems in xcode while coding in Objective-C. I create webpages constantly and code in jquery and javascript where you can set various alert boxes in different places in your code to determine if your script is properly executing sections. Can you do something like that in xcode to make sure that your script is executing methods properly and creating variables properly?
Thanks
Use the debugger - that's what it is there for! Set breakpoints by clicking in the grey are next to the line of code you want to break on. When this line of code is going to be excuted, the debugger will kick in and highlight the current place in execution. You can hover the cursor over variables in the IDE to examine their values, view the current call-stack (to see here this code has been called from) and get a list of local variables to help track program state. You can modify variable properties here too which often makes debugging simpler.
Execute code line by line by 'Stepping Over' (cmd+shift+o), which executes the current line, 'Stepping Into' (cmd_shift+i) which steps into the current line of code (if it is a function), or 'Stepping Out' to return back up the call stack.
If you want to stick to 'old-school' printf style debugging, go with NSLoging output to console.
NSLog(#"this text appears");
prints the following to the console:
this text appears
To print some basic variable values:
CGFloat pi = 3.14;
NSString *aFloatString = [NSString stringWithFormat:#"%.2f", pi];
NSLog(#"pi is equal to: %#", aFloatString);
Prints:
pi is equa to: 3.14
Standard c formatters can be used in NSLog i.e %d for int, %.2f for a float to 2 decimal places etc. Use %# for NSString*s.
Remember that NSLog will remain in production code unless you #IFDEF it out of release builds (or something similar), so if you don't want a performance hit, or embarrassing console logs to accompany the app you will want to remove them.
I've been known to litter functions that dump the following to console - and it isn't good:
OUTPUT:
Number of vertices is: 1200
<Requested reduction>
Can I kick it?
....
....
YES. I. CAN!
Number of vertices is: 800
Could have done with removing things like that :|
yes, the debugger can do all the things you want to do (just set some breakpoints - right click where you want them - then build&debug)
You can try writing to the console.
NSLog(#"Some status message here");
NSLog(#"The value of myObject is:%#", myObject);
To view the output of your application, while running with Xcode, click Run->Console and you will see all of the output from your application.

Co-ordinates of a element in a pdf file using iText

I'm creating a pdf file using BIRT reporting library. Later I need to digitally sign these files. I'm using iText to digitally sign the document.
The issue I'm facing is, I need to place the signature in different places in different reports. I already have the code to digitally sign the document, now I'm always placing the signature at the bottom of last page in every report.
Eventually I need each report to say where I need to place the signature. Then I've to read the location using iText and then place the signature at that location.
Is this possible to achieve using BIRT and iText
Thanks
If you're willing to cheat a bit, you can use a link... which BIRT supports according to my little dive into their docs just now.
A link is an annotation. Sadly, iText doesn't support examining annotations at a high level, only generating them, so you'll have to use the low-level object calls.
The code to extract it might look something like this:
// getPageN is looking for a page number, not a page index
PdfDictionary lastPageDict = myReader.getPageN(myReader.getNumberOfPages());
PdfArray annotations = lastPageDict.getAsArray( PdfName.ANNOTS );
PdfArray linkRect = null;
if (annotations != null) {
int numAnnots = annotations.size();
for (int i = 0; i < numAnnots; ++i) {
PdfDictionary annotDict = annotations.getAsDict( i );
if (annotDict == null)
continue; // it'll never happen, unless you're dealing with a Really Messed Up PDF.
if (PdfName.LINK.equals( annotDict.getAsName( PdfName.SUBTYPE ) )) {
// if this isn't the only link on the last page, you'll have to check the URL, which
// is a tad more work.
linkRect = annotDict.getAsArray( PdfName.RECT );
// a little sanity check here wouldn't hurt, but I have yet to come across a PDF
// that was THAT screwed up, and I've seen some Really Messed Up PDFs over the years.
// and kill the link, it's just there for a placeholder anyway.
// iText doesn't maintain any extra info on links, so no need for other calls.
annotations.remove( i );
break;
}
}
}
if (linkRect != null) {
// linkRect is an array, thusly: [ llx, lly, urx, ury ].
// you could use floats instead, but I wouldn't go with integers.
double llx = linkRect.getAsNumber( 0 ).getDoubleValue();
double lly = linkRect.getAsNumber( 1 ).getDoubleValue();
double urx = linkRect.getAsNumber( 2 ).getDoubleValue();
double ury = linkRect.getAsNumber( 3 ).getDoubleValue();
// make your signature
magic();
}
If BIRT generates some text in the page contents under the link for its visual representation, that's only a minor issue. Your signature should cover it completely.
You're definitely better of if you can generate the signature directly from BIRT in the first place, but my little inspection of their docs didn't exactly fill me with confidence in their PDF customization abilities... despite sitting on top of iText themselves. It's a report generator that happens to be able to produce PDFs... I shouldn't expect too much.
`
Edit: If you need to look for the specific URL, you'll want to look at section "12.5.6.5 Link Annotations" of the PDF Reference, which can be found here:
http://www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/PDF32000_2008.pdf
I don't know anything about BIRT, and have only a little familiarity with iText. But maybe this works...
Can BIRT generate the signature box's outline as a regular form field with a given field name? If so, then you should be able to:
Lookup that field by name in iText's AcroFields hashmap, using getField;
Create a new signature using the pdf stamper, and set its geometry based on the values of the old field object; and
Delete the old field using removeField.