I'm trying to add a page to an existing PDF-Document that I'm performing multiple different actions on before and after the page is supposed to be added.
Currently I open the page at the beginning of the document and write stuff on the first and second page of it. On the second page I add some images aswell. The Stuff that's written on the PDFs is different per PDF and sometimes it's so much stuff that two pages (or sometimes even 3) aren't enough. Now I'm trying to add a third or even fourth page once a certain amount of written text/printed images is on the second page.
Somehow no matter what I do, the third page I want to add doesn't show up in the final document. Here's my code to add the page:
if(doc.getNumberOfPages() < p+1){
PDDocument emptyDoc = PDDocument.load("./data/EmptyPage.pdf");
PDPage emptyPage = (PDPage)emptyDoc.getDocumentCatalog().getAllPages().get(0);
doc.addPage(emptyPage);;
emptyDoc.close();
}
When I check doc.getNumberOfPages() before, it says 2. Afterwards it says 3. The final document still just has 2 pages. The code after the if-clause contains multiple contentStreams that are supposed to write text on the new page (and on the first and second page).
contentStream = new PDPageContentStream(doc, (PDPage) allPages.get((int)p), true, true);
In the end, I save the document via
doc.save(tarFolder+nr.get(i)+".pdf");
doc.close();
I've created a whole new project with a class that's supposed to do the exact same thing - add a page to another PDF. This code works perfectly fine and the third page shows up - so it seems like I'm just missing something. My code works perfectly fine for page 1 + 2, we just had the new case that we need a third/fourth page sometimes lately, so I want to integrate that into my main project.
Here's the new project that works:
PDDocument doc = PDDocument.load("D:\\test.pdf");
PDDocument doc2 = PDDocument.load("D:\\EmptyPage.pdf");
List<PDPage> allPages = doc2.getDocumentCatalog().getAllPages();
PDPage page = (PDPage) allPages.get(pageNumber);
doc.addPage(page);
doc.save("D:\\testoutput.pdf");
What's weird in my main project is that the third page I add gets counted by
"getNumberOfPages()"
but doesn't show up in the final product. The program throws an error if I don't add the page because it tries to write content on the third page.
Any idea what I'm doing wrong?
Thanks in advance!
Edit:
If I add the page at the beginning, when my document is loaded the first time, the page gets added and exists in my final document - like this:
doc = PDDocument.load(config.getFolder("template"));
PDDocument emptyDoc = PDDocument.load("./data/EmptyPage.pdf");
PDPage emptyPage = (PDPage)emptyDoc.getDocumentCatalog().getAllPages().get(0);
doc.addPage(emptyPage);
However, since some documents don't need that extra page, it gets unnecessarily complicated - and I feel like removing the page if it isn't needed isn't really pretty, since I'd like to avoid adding it in the first place. Maybe somebody has an idea now?
I found an answer thanks to Tilman Hausherr.
If I move the
emptyDoc.close()
to the end of my code, right after:
doc.save(tarFolder+nr.get(i)+".pdf");
doc.close();
the page shows up in the final document without any issues.
Related
I'm trying to go to the next page on an aspx form using JSoup.
I can find the next button itself. I just don't know what to do with it.
The idea is that, for that particular form, if the next button exists, we would simulate a click and go to the next page. But any other solution other than simulating a click would be fine, as long as we get to the next page.
I also need to update the results once we go to the next page.
// Connecting, entering the data and making the first request
...
// Submitting the form
Document searchResults = form.submit().cookies(resp.cookies()).post();
// reading the data. Everything up to this point works as expected
...
// finding the next button (this part also works as expected)
Element nextBtn = searchResults.getElementById("ctl00_MainContent_btnNext");
if (nextBtn != null) {
// click? I don't know what to do here.
searchResults = ??? // updating the search results to include the results from the second page
}
The page itself is www.somePage.com/someForm.aspx, so I can't use the solution stated here:
Android jsoup, how to select item and go to next page
I was unable to find any other suggestions.
Any ideas? What am I missing? Is simulating a click even possible with JSoup? The documentation says nothing about it. But I'm sure people are able to navigate these type of forms.
Also, I'm working with Android, so I can't use HtmlUnit, as stated here:
importing HtmlUnit to Android project
Thank you.
This is not Jsoup work! Jsoup is a parser with a nice DOM API that allows you to deal with wild HTML as if it were well-formed and not crippled with errors and nonsenses.
In your specific case you may be able to scrape the target site directly from your app by finding links and retrieving HTML pages recursively. Something like
private void scrape(String url) {
Document doc = Jsoup.connect(url).get();
// Analyze current document content here...
// Then continue
for (Element link : doc.select(".ctl00_MainContent_btnNext")) {
scrape(link.attr("href"));
}
}
But in the general case what you want to do requires far more functionality that Jsoup provides: a user agent capable of interpreting HTML, CSS and Javascript with a scriptable API that you can call from your app to simulate a click. For example Selenium:
WebDriver driver = new FirefoxDriver();
driver.findElement(By.name("next_page")).click();
Selenium can't be bundled in an Android app, so I suggest you put your Selenium code on a server and make it accessible with some REST API.
Pagination on ASPX can be a pain. The best thing you can do is to use your browser to see the data parameters it sends to the server, then try to emulate this in code.
I've written a detailed tutorial on how to handle it here but it uses the univocity HTML parser (which is commercial closed source) instead of JSoup.
In short, you should try to get a <form> element with id="aspnetForm", and read the form elements to generate a POST request for the next page. The form data usually comes out with stuff such as this:
__EVENTTARGET =
__EVENTARGUMENT =
__VIEWSTATE = /wEPDwUKMTU0OTkzNjExNg8WBB4JU29ydE9yZ ... a very long string
__VIEWSTATEGENERATOR = 32423F7A
... and other gibberish
Then you need to look at each one of these and compare with what your browser sends. Sometimes you need to get values from other elements of the page to generate a similar POST request. You may have to REMOVE some of the parameters you get - again, make your code behave exactly the same as your browser
After some (frustrating) trial and error you will get it working. The server should return a pipe-delimited result, which you can break down and parse. Something like:
25081|updatePanel|ctl00_ContentPlaceHolder1_pnlgrdSearchResult|
<div>
<div style="font-weight: bold;">
... more stuff
|__EVENTARGUMENT||343908|hiddenField|__VIEWSTATE|/wEPDwU... another very long string ...1Pni|8|hiddenField|__VIEWSTATEGENERATOR|32423F7A| other gibberish
From THAT sort of response you need to generate new POST requests for the subsequent pages, for example:
String viewState = substringBetween(ajaxResponse, "__VIEWSTATE|", "|");
Then:
request.setDataParameter("__VIEWSTATE", viewState);
There are will be more data parameters to get from each response. But a lot depends on the site you are targeting.
Hope this helps a little.
I have been trying to automate a search using Selenium. I simply want to search terms (say Pink Floyd) but the file type should be pdf. Here is what I have done so far:
//Query term
WebElement element = driver.findElement(By.name("as_q"));
String finalQuery = "pink floyd";
element.sendKeys(finalQuery);
//File type selection
WebElement elem = driver.findElement(By.id("as_filetype_button"));
elem.sendKeys("Adobe Acrobat pdf (.pdf)");
driver.findElement(By.xpath("/html/body/div[1]/div[4]/form/div[5]/div[9]/div[2]/input[#type='submit']")).click();
This puts the term in the appropriate place and the drop down for file types are expanded but pdf option is not selected. Any help?
I am using Selenium 2.53.0.
EDIT
The following code segment perfectly worked as per the accepted answer for this question. However, all on a sudden the code segment is not working. I am a bit surprised to find this out. Previously, I was able to select PDF automatically with the following code segment but now, nothing gets selected.
WebElement element = driver.findElement(By.name("as_q"));
String finalQuery = "pink floyd";
element.sendKeys(finalQuery);
driver.findElement(By.id("as_filetype_button")).click();
driver.findElement(By.xpath("//li[#class=class-name][#value='pdf']")).click();
This is how i do it, find the li that matches the class='goog-menuitem' and value='pdf', i inspected the element. You can go directly with value='pdf' but just to make sure we are looking at the file type dropdown we added the class.
driver.findElement(By.id("as_filetype_button")).click();
driver.findElement(By.xpath("//li[#class='goog-menuitem'][#value='pdf']")).click();
You can still declare it with WebElement, i just prefer it shorthand. Hope this helps.
I am using aspose-words-15.6.0 api for java. I want to change the page orientation to portrait or landscape based on the page number.
Scenario:
I've a doc having 3 pages in it, I want page orientation as follow:
1st Page : Portrait.
2nd Page : Landscape.
3rd Page : Portrait.
EDIT:
I have tried with DocumentBuilder, there is a way to achieve this but I am missing something, please refer the screenshot I've attached with this question.
Any help would be greatly appreciated.
There is no concept of Page in MS Word documents. Pages are created by Microsoft Word on the fly and unfortunately there is no straight forward way that you can use to set orientation per Page. However, you can specify orientation settings for a whole Section using Section.PageSetup.Orientation property and a Section may contain more than just one Page.
Alternatively, you may be able create a separate Section for each page in word document using Aspose.Words and then specify page orientation for each Section corresponding to a particular page. Please report this requirement in Aspose.Words forum, we will then develop code for this requirement and provide you more information.
EDIT:
If you want to build document from scratch, please use the following code:
Document doc = new Document();
DocumentBuilder builder = new DocumentBuilder(doc);
builder.writeln("Content on first page");
builder.getPageSetup().setOrientation(Orientation.PORTRAIT);
builder.insertBreak(BreakType.SECTION_BREAK_NEW_PAGE);
builder.writeln("Content on second page");
builder.getPageSetup().setOrientation(Orientation.LANDSCAPE);
builder.insertBreak(BreakType.SECTION_BREAK_NEW_PAGE);
builder.writeln("Content on third page");
builder.getPageSetup().setOrientation(Orientation.PORTRAIT);
doc.save(getMyDir() + "15.10.0.docx");
I work with Aspose as Developer Evangelist.
i am new to Htmlunit and trying to extract data from a website http://capitaline.com/new/index.asp. I have logged into the website successfully. When we log into website there are three frames.
One on the top to search for the company(like ACC ltd.) for which we are extracting data.
2nd frame has a tree which provide links to various data we want to look at.
3rd frame has the resulted data outcome on the basis of link you clicked in frame.
I managed to get the frame i need below:
HtmlPage companyAtGlanceTopWindow =(HtmlPage)companyAtGlanceLink.click().getEnclosingWindow().getTopWindow().getEnclosedPage();
HtmlPage companyAtGlanceFrame = (HtmlPage)companyAtGlanceTopWindow.getFrameByName("mid2").getEnclosedPage();
System.out.println(companyAtGlanceFrame.toString()); // This line returns the frame URL as i can see in my browser.
Output of print statement is
HtmlPage(http://capitaline.com/user/companyatglance.asp?id=CGO&cocode=6)#1194282974
Now i want my code to navigate down to the table inside this frame and for that i am using getByXPath() but it gives me nullPointerException. Here is the code for that.
HtmlTable companyGlanceTable1 = companyAtGlanceFrame.getFirstByXPath("/html/body/table[4]/tbody/tr/td/table/tbody/tr/td[1]/table");
My XPath for the current webpage(after i clicked the link)from which i am trying to extract table is seems correct, as it is copied from chrome element inspect. Please suggest some way to extract the table. I have done this type of extraction before but there i had id of table so, i used it.
Here is the HTML code for the table in the webpage.
<table width="100%" class = "tablelines" border = "0" >
I want to know that can you see the inner contents of each iframes in console (print asXml()), are they nested iframes?
well try this
List<WebWindow> windows = webClient.getWebWindows();
for(WebWindow w : windows){
HtmlPage hpage = (HtmlPage) w.getEnclosedPage();
System.out.println(hpage.asXml());
}
once you can see the contents,
HtmlPage hpage = (HtmlPage)webClient.getWebWindowByName(some_name).getEnclosedPage();
then using xpath grab your table contents(make sure your xpath is correct). It will work.(worked for me)
Thank you RDD for your feedback.
I solved the problem. Actually issue was not with the frame but with the XPath provided by chrome.
XPath Provided by chrome is:
/html/body/**table[4]**/tbody/tr/td/table/tbody/tr/td[1]/table
But the XPath worked for me is:
/html/body/**table[3]**/tbody/tr/td/table/tbody/tr/td[1]/table
It seems as, XPath provided by chrome has some glitch when there is a table within the path(Or may be some bug in htmlunit itself). I did many experiments and found that chrome always gives ../../table[row+1]/.. as XPath, while working XPath for htmlunit is ../../table[row]/..
SO, this code is working fine for me
HtmlTable companyGlanceTable1 = companyAtGlanceFrame.getFirstByXPath("/html/body/table[3]/tbody/tr/td/table/tbody/tr/td[1]/table");
I want to add an index page to existing PDF file. And add page numbers to the page of the pdf file.
All the suggested solutions point towards creating a new pdf and merging the existing pdf file with the new one.
Is there any other way for this ??
Also I dont want to use itext since its not free for commercial uses.
According to your comments to the original question, you think in PDFBox
for adding a new page & content, you need to create a new pdf add new content and then merge the existing pdf. I wanted to avoid the merging step. Renaming is not the issue
You might want to try something like this:
PDDocument doc = PDDocument.load(new FileInputStream(new File("original.pdf")));
PDPage page = new PDPage();
// fill page
doc.addPage(page);
doc.save("original-plus-page.pdf");
EDIT: In a comment to the answer the question arose how to insert a new page at specific index(page number). To do this, obviously the doc.addPage(page) has to be changed somehow.
Originally this PDDocument method is defined like this:
/**
* This will add a page to the document. This is a convenience method, that
* will add the page to the root of the hierarchy and set the parent of the
* page to the root.
*
* #param page The page to add to the document.
*/
public void addPage( PDPage page )
{
PDPageNode rootPages = getDocumentCatalog().getPages();
rootPages.getKids().add( page );
page.setParent( rootPages );
rootPages.updateCount();
}
We merely need a similar function which merely does not simply add the page to the kids but instead adds it at a given index. Thus a helper method like the following in our code will do:
public static void addPage(PDDocument doc, int index, PDPage page)
{
PDPageNode rootPages = doc.getDocumentCatalog().getPages();
rootPages.getKids().add(index, page);
page.setParent(rootPages);
rootPages.updateCount();
}
If you now replace the line
doc.addPage(page);
in the code of the original answer by
addPage(doc, page, 0);
the empty page is added up front.