Indesign scripting to get all textframes of a page in order - scripting

I am trying to get all the text frames for a single page in order but I was always getting them in random order when using the
myDoc.pages[1] //assuming the 1st index page
>> [object Page]
myDoc.pages[eachPage].textFrames //get all the text frames on that page.
>> [object TextFrames] //able to get the textframes but they are not in the order if they are linked textframes
Is there a way to get them in order if they are linked text frames? (not sure how they will come up if they are unlinked)
If not at least how to know the first text frame on the page so I can get the other frames with . nextTextFrame.

Basically you will have to start with any text frame and from this find all linked text frames and then in a third step collect just those that are on your page. Here is how you could go about it:
// get your document and your page somehow
var doc = app.activeDocument;
var myPage = doc.pages[1];
// get any text frame on your page and from its parent story get the
// text containers which is an array of all text frames that contain
// the linked text story
var someTextFrame = myPage.textFrames[0];
var textContainers = someTextFrame.parentStory.textContainers;
// loop over all text containers in order and collect those that are
// on your page
var textFramesInOrder = [];
for (var i = 0; i < textContainers.length; i++) {
if(textContainers[i].parentPage === myPage) {
textFramesInOrder.push(textContainers[i]);
}
}
// now textFramesInOrder holds all the text frames of the page in correct order

Related

Is there a way to tell which page number the textframe exists in?

I am trying to find out whether a particular text exists and perfectly fits in the text frame and when the text flows to the next text frame, then upon calculating the coordinates(baseline) of the next frame iam increasing the size of the existing frame and trying to fit the text but when the text frame is in the next page then the baseline it's giving me a negative value so I would like to know if there is any way I could understand that the next text frame is in next page so as to avoid negative value while calculating.
Is there a way to tell which page number the textframe exists in?
Yes, each TextFrame class has a parentPage property that returns a reference to the Page that the text frame is on.
Each Page class has a name property that essentially returns a string of the page number
Therefore, the following code snippet logs to the console the page number that the documents first text frame is on.
var doc = app.activeDocument;
var firstTextFramesPageNumber = doc.textFrames[0].parentPage.name;
$.writeln(firstTextFramesPageNumber)
I would like to know if there is any way I could understand that the next text frame is in next page so as to avoid negative value while calculating.
For this you'll need to:
Ascertain whether the text frame has an associated next text frame. You can achieve this by utilizing the nextTextFrame property of the TextFrame class. It will either:
Return null if there is no associated next text frame.
Or, a reference to the next text frame when there is an associated next text frame.
Once you know there is an associated next text frame, you can check parentPage.name for the referenced next text frame to get its page number.
To check whether the text frame and it's associated next text frame are on the same page check using the === equality operator.
Demo Gist
Below is a somewhat contrived example gist. It loops through all text frames in a document and logs to the console the following:
The page number that the current text frame is on.
Whether the current text frame has an associated next text frame.
When the current text does have an associated next text frame it tells you which page number it is on.
#target indesign
var doc = app.activeDocument;
var textFrames = doc.textFrames;
for (var i = 0, max = textFrames.length; i < max; i++) {
var currentTextFrame = textFrames[i];
// 1. Get the current text frames page number
var currentTextFramePageNumber = currentTextFrame.parentPage.name
$.writeln('The current text frame is on page ' + currentTextFramePageNumber)
// 2. Get the current text frames associated next text frame.
var hasNextTextFrame = currentTextFrame.nextTextFrame;
if (hasNextTextFrame) {
// 3. Let's get the page number of the associated next text frame?
var nextTextFramePageNumber = currentTextFrame.nextTextFrame.parentPage.name
// 4. Is the associated next text frame on the same page number as the current text frame?
if (currentTextFramePageNumber === nextTextFramePageNumber) {
$.writeln('This text frame DOES have a next text frame. It\'s also on on page '
+ nextTextFramePageNumber)
} else {
$.writeln('This text frame DOES have a next text frame. However it\'s on a different page, it\'s on page '
+ nextTextFramePageNumber)
}
} else {
$.writeln('This text frame DOES NOT have a next text frame.')
}
$.writeln('--------------')
}

Splitting at a specific point in PDFBox

I would like to split to generate a new pdf by concatenating certain individual pages, but the last page has to be split at a certain point (i.e. all content above a limit to be included and everything below to be excluded - I only care about the ones having their upper left corner above a line). Is that possible using PDFbox?
One way to achieve the task, i.e. to split a page at a certain point (i.e. all content above a limit to be included and everything below to be excluded) would be to prepend a clip path.
You can use this method:
void clipPage(PDDocument document, PDPage page, BoundingBox clipBox) throws IOException
{
PDPageContentStream pageContentStream = new PDPageContentStream(document, page, true, false);
pageContentStream.addRect(clipBox.getLowerLeftX(), clipBox.getLowerLeftY(), clipBox.getWidth(), clipBox.getHeight());
pageContentStream.clipPath(PathIterator.WIND_NON_ZERO);
pageContentStream.close();
COSArray newContents = new COSArray();
COSStreamArray contents = (COSStreamArray) page.getContents().getStream();
newContents.add(contents.get(contents.getStreamCount()-1));
for (int i = 0; i < contents.getStreamCount()-1; i++)
{
newContents.add(contents.get(i));
}
page.setContents(new PDStream(new COSStreamArray(newContents)));
}
to clip the given page along the given clipBox. (It first creates a new content stream defining the clip path and then arranges this stream to be the first one of the page.)
E.g. to clip the content of a page along the horizontal line 650 units above the bottom, do this:
PDPage page = ...
PDRectangle cropBox = page.findCropBox();
clipPage(document, page, new BoundingBox(
cropBox.getLowerLeftX(),
cropBox.getLowerLeftY() + 650,
cropBox.getUpperRightX(),
cropBox.getUpperRightY()));
For a running example look here: ClipPage.java.

Sitefinity get current dynamiccontent item from code

I'm currently writing a site using Sitefinity CMS. Can someone please explain how to get the current dynamic content item from server side code on page_load?
I have written a user control to display a custom gallery of sliding images. There are multiple content types in my dynamic module. The user control will sit as part of the masterpage template rather than on every page. On each page load I would like to fetch the current dynamiccontent item that is associated with the page and examine whether it has a property with the name 'Gallery'. If so I would then extract the images and render them via the usercontrol.
Thanks,
Brian.
I'm assuming your images are related content. This gets every published content item of your type.
var dynamicModuleManager = DynamicModuleManager.GetManager();
var moduleType = TypeResolutionService.ResolveType("Telerik.Sitefinity.DynamicTypes.Model.YOURTYPEHERE");
var dcItems = dynamicModuleManager.GetDataItems(moduleType)
.Where(l => l.Status == ContentLifecycleStatus.Master);
foreach (var dcItem in dcItems)
{
//pass the dynamic content item to a model constructor or populate here, then
// get your image this way:
var image = dcItem.GetRelatedItems<Image>("Images").SingleOrDefault();
if (image != null)
{
ImageUrl = image.MediaUrl;
}
}

Cannot stamp certain PDFs

PDF stamping works for nearly every document I have tried. However, a client scanned some pages and his computer generated a PDF document that is resistant to stamping. The embedded image files are in JBIG2 format, but I am not sure if that is important. I have debugged the PDF with Apache's pdfbox, and I can see the text is embedded. It just doesn't show up.
Here is the PDF that won't stamp: http://demo.clearvillageinc.com/plans.pdf
And my code:
static void Main(string[] args) {
string stamp = "<div style=\"color:#F00;\">Reviewed for Code Compliance</div>";
string fileName = #"C:\temp\source.pdf";
string outputFileName = #"C:\temp\source-output.pdf";
// Open a destination stream.
using (var destStream = new System.IO.MemoryStream()) {
using (var sourceReader = new PdfReader(fileName)) {
// Convert the HTML into a stamp.
using (var stampData = FromHtml(stamp)) {
using (var stampReader = new PdfReader(stampData)) {
using (var stamper = new PdfStamper(sourceReader, destStream)) {
stamper.Writer.CloseStream = false;
// Add the stamp stream to the source document.
var stampPage = stamper.GetImportedPage(stampReader, 1);
// Process all of the pages in the source document.
for (int i = 1; i <= sourceReader.NumberOfPages; i++) {
var canvas = stamper.GetOverContent(i);
canvas.AddTemplate(stampPage, 0, -50);
}
}
}
}
}
// Finished. Save the file.
using (var fs = new System.IO.FileStream(outputFileName, FileMode.Create)) {
destStream.Position = 0;
destStream.CopyTo(fs);
}
}
}
public static System.IO.Stream FromHtml(string html) {
var ms = new System.IO.MemoryStream();
// Convert html to pdf.
using (var document = new iTextSharp.text.Document()) {
var writer = iTextSharp.text.pdf.PdfWriter.GetInstance(document, ms);
writer.CloseStream = false;
document.Open();
using (var sr = new System.IO.StringReader(html)) {
XMLWorkerHelper.GetInstance().ParseXHtml(writer, document, sr);
}
}
ms.Position = 0; // Reset for reading.
return ms;
}
One part of a page definition is the "MediaBox" which controls the page's size. This property takes two locations that specify the coordinates of two opposite corners of a rectangle. Although not required, most PDFs specify the lower left corner first followed by the upper right corner. Also, most PDF use 0x0 for the lower left and then whatever the page's width and height for the top corner. So an 8.5x11 inch PDF would be 0,0 and 612,792 (8.5 * 72 = 612 and 11 * 72 = 792) and this would be written as 0,0,612,792.
Your scanned PDF, however, has for whatever reason decided to treat 0,7072 as the lower left corner and 614,7864 as the top right corner. That still gives us (almost) an 8.5x11 page size but if you try to draw something at 0,0 it will be 7,072 pixels below the actual page. You can see this in Acrobat Pro by zooming out very far (1% for me), picking Tools, Edit Object and then doing a Select All. You should see something way far down selected, too.
To get around this, you need to respect the page's boundaries.
for (int i = 1; i <= sourceReader.NumberOfPages; i++) {
//Get the page to be stamped
var pageToBeStamped = sourceReader.GetPageSize(i);
var canvas = stamper.GetOverContent(i);
//Offset our new page by 50 pixels off of the destination page's bottom
canvas.AddTemplate(stampPage, pageToBeStamped.Left, pageToBeStamped.Bottom - 50);
}
The code above gets the rectangle for the imported page and uses bottom offset by 50 pixels (from your original code). Also, although not a problem in your case, we use the imported page's actual left edge instead of just zero.
This code can still break, however. The math in the first paragraph uses 72 which is the default for PDFs but this can be changed. Most people don't change it but most people also don't change 0,0. Currently your -50 assumes the 72 which gives the visual perception of moving the stamp about seven-tenths of an inch from the top edge. If you run into this scenario you'll want to look into retrieving the user unit.
Also, as I said in the first paragraph, most applications use lower left upper right but this isn't a hard rule. Someone could specify upper right and bottom left or even top left and bottom right. This is a hard one to take into account but it is something that you should at least be aware of.

Need alternative to local or remote goto/destinations with merged documents

BACKGROUND
I have a java program that analyzes data and creates a pdf report using itext 5.
I recently had to add a summary of major problems at the start of the document so a user would not have to read over a hundred pages to find problems. Problems are only discovered when serially looking through the data.
I solved the problem by creating 3 pdf documents and then merging them, a start/title pdf, the summary of problems pdf, and the body or analysis pdf. (Basically splitting the original document at the point I wanted to insert the summary)
I use PdfReader and PdfCopy to combine the documents. I am able to keep the chapter bookmarks OK.
THE PROBLEM
As I encounter a significant problem I add it to the 'summary' document. I want to add a link in the summary to point to the problem in the body.
I tried to use Chunk.setLocalDestination and setLocalGoto but realized why that did not work, so I tried using setLocalDestination and setRemoteGoto (with and without 'file://'), but that did not work either. (Also, I used the final pdf document name in the RemoteGoto, not the temporary pdf document name.)
I do not want to use bookmarks because that seems wrong and would not look right.
I am hoping someone could suggest an alternate method or make a suggestion.
To recap, in my current code a create a Chunk with setLocalDestination and that chunk goes into the 'body' document. At the same time I create a setRemoteGoto which is put into the summary document. I was hoping when they were combined the link would work, but when the link is clicked, you go to the first page of the combined document.
Thanks.....
PS I have both iText in action books
CLARIFICATION 3/5/2014
What I was calling 'bookmarks' are really Chapter class entities that are inserted into sections of the 3 documents as they are being created.
After saving the 3 documents, PdfReader is used to open each and PdfCopy is used to put them into a new, final document.
I get the data from the Chapters, which creates the 'bookmarks' on the left side of the Pdf reader used by the user, e.g. Acrobat Reader.
int thisPdfPages = reader.getNumberOfPages();
reader.consolidateNamedDestinations();
java.util.List<HashMap<String, Object>> bookmarks = SimpleBookmark.getBookmark(reader);
if (bookmarks != null) {
if (pageOffset != 0) {
if (debug3) auditLogger.log("Shifting pages by " + pageOffset );
SimpleBookmark.shiftPageNumbers(bookmarks, pageOffset, null);
}
masterBookmarks.addAll(bookmarks);
}
for (int i = 0; i < thisPdfPages;) {
page = copy.getImportedPage(reader, ++i);
stamp = copy.createPageStamp(page);
// add page numbers
ColumnText.showTextAligned(stamp.getUnderContent(), Element.ALIGN_CENTER, new Phrase(String.format("page %d of %d", start + i, totalPages)), 297.5f, 28, 0);
stamp.alterContents();
copy.addPage(page);
}
PRAcroForm form = reader.getAcroForm();
if (form != null) {
copy.copyAcroForm(reader);
}
When analyzing the data I have 2 documents open, a base document which contains all the details and a summary document which contains notable events over some thresholds.
//NOTE section is part of the 'body' document
//NOTE summaryPhrase is a part of the 'summary' document
String linkName = "summaryPf_" + networkid ;
//create Link target
section.add(new Chunk("CHANGE TO EMPTY STRING WHEN WORKING").setLocalDestination( linkName ));
//create Link
Chunk linkChunk = new Chunk( "[Link] " );
Font linkFont = new Font( regularFont );
linkFont.setColor(BaseColor.BLUE);
linkFont.setStyle( Font.UNDERLINE );
linkChunk.setFont( linkFont );
boolean useLocal = true;
// both local and remote goto's fail
if (useLocal) {
linkChunk.setLocalGoto( linkName);
} else {
// all permutations of setting filename fail,
// but it does bring up a permissions dialog when the link is clicked.
//String remotePdfName = "file://./" + pdfReportName ;
//String remotePdfName = "file://" + pdfReportName ;
//String remotePdfName = "file:" + pdfReportName ;
String remotePdfName = pdfReportName ;
linkChunk.setRemoteGoto( remotePdfName, linkName);
}
// add link to summary document
summaryPhrase.add( linkChunk );
summaryPhrase.add( String.format("There were %d devices with ping failures", summaryCount));
summaryPhrase.add( Chunk.NEWLINE );
}
If I use setLocalGoto, when you click the link in the final document you goto the first page.
If I use setRemoteGoto, a dialog ask permission to go to a document, but the document fails to open, tried several permutations on filename.