Presenting file (pdf / tiff / png) content in wicket 1.5 - pdf

So I've run in to a problem that I can't seem to solve on my own.
I want to present a file in an iFrame. The file can either be pdf, png or tiff, and I don't know which on beforehand.
The pdfs and tiffs should be presented with different actions (printing, saving to disk etc) - I rely on browser plug-ins for this.
What I do is this;
Java:
public ContentPanel(String id, final Atatchment attachment) {
super(id);
ResourceReference rr = new ResourceReference(attachment.getName()) {
private static final long serialVersionUID = 1L;
#Override
public IResource getResource() {
return new ByteArrayResource(attachment.getMimeType(), attachment.getByteArray());
}
};
WebMarkupContainer wmc = new WebMarkupContainer("myIframe");
wmc.add(new AttributeModifier("src", (String) urlFor(rr, null)));
add(wmc);
}
HTML:
<body>
<wicket:panel>
<iframe wicket:id="myIframe" src=""></iframe>
</wicket:panel>
</body>
This results in a 404 ("The requested resource is not availible"). The thing is, when I had some of the files cached they were presented the way I want them to be.
Thanks in advance!
Olle

The problem was the the resource was not registered in the application. Just added:
if (rr.canBeRegistered()) {
getApplication().getResourceReferenceRegistry().registerResourceReference(rr);
}
And it works!

Related

JSF2.0: Show certain pdf page on load

I'd like to open a PDF in a new Page from JSF2, and display a certain page in this pdf on load. I have a kind of TOC in my jsf page, and want to jump from there to the page in the PDF directly.
What I know (this is not, what I need, just an example of giving adobe reader and other pdf readers the page I want to jump to):
Something like this will open the page (chose something from the internet):
https://www.cdc.gov/diabetes/pdfs/data/statistics/national-diabetes-statistics-report.pdf#page=10
The #page=10 makes the pdf plugin of the browser display page 10.
Requirements for selecting the PDF:
PDF is dynamically downloaded from a webservice according to an ID that must only reside in the ManagedBeans, since it's secret, and should not be passed to others (like Session ID...) (below given anser by me passes the ID in the GET-Parameter, which should not be done)
PDF should not reside in the Filesystem, sinc I don't want the handling of temporary files (below given answer by me actually utilizes PDFs on FS, with stream only it does not work)
Now my real problem: I have to change the URL beeing displayed/used in JSF, but can't use the normal way with and includeViewParams, because this will insert a "?", and not a "#" in the URL.
Also, I have a backing bean, that gets the content of the PDF from a backend service, based on some other parameters I'm giving, so a solution with would be cool, but I'm aware that this is probably not possible...
Does anyone have an idea, how to solve this?
I didn't include any code, since it doesn't work anyways, and I probably need a completely new way to solve this anyways...
Turns out, Primefaces has this already implemented (although the implementation has it's restrictions):
<p:media player="pdf" value="#{viewerBean.media}" width="100%" height="100%">
<f:param name="#page" value="#{viewerBean.pageNumber}"/>
<f:param name="toolbar" value="1"/>
<!--<f:param name="search" value="#{viewerBean.queryText}"/>-->
</p:media>
https://www.primefaces.org/showcase/ui/multimedia/media.xhtml
Restriction: Can't read from a stream, at least not very stable. Save your energy, and write a stream to a temp file, and set this filename dynamically. Not sure, whether this is complete, but you should get the idea:
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;
import java.io.*;
import javax.annotation.PostConstruct;
import java.nio.file.Files;
import java.nio.file.Paths;
#ManagedBean
#RequestScoped
public class ViewerBean implements Serializable {
#ManagedProperty(value = "#{param.page}")
private String pageNumber;
private File media;
#PostConstruct
public void init() {
try {
media = Files.createTempFile("car", ".pdf").toFile();
try (FileOutputStream outputStream = new FileOutputStream(media)) {
IOUtils.copy(getStreamedContent().getStream(), outputStream);
}
} catch (IOException e) {
LOGGER.error(e);
throw new RuntimeException("Error creating temp file", e);
}
}
public StreamedContent getMedia() {
try {
return new DefaultStreamedContent(new FileInputStream(media), "application/pdf");
} catch (FileNotFoundException e) {
String message = "Error reading file " + media.getAbsolutePath();
LOGGER.error(message, e);
throw new RuntimeException(message, e);
}
}
}
If the pagename is not needed, you could use this:
http://balusc.omnifaces.org/2006/05/pdf-handling.html
Maybe if you can utilize outputLink for this you'll be lucky, but I ran out of time to test this option.
Found the (THE) solution; above answher mentions , but this cannot cope with #ViewScope beans, and sends many requests to the underlying bean for reading only one InputStream. I found this not acceptable for load reasons.
So here we go:
Create JSF page with <f:event type="preRenderView" listener="#{documentDownloadBean.writeIntpuStreamToResponseOutputStream}"/>
Put neccessary data for dynamic retrieval of the PDF into flash scope
redirect to above JSF page like so: return "document_search/view_pdf.xhtml?faces-redirect=true#page=" + page;
#ManagedBean
#ViewScoped
public class DocumentDownloadBean implements Serializable {
#ManagedProperty(value = "#{documentSearchBean}")
private DocumentSearchBean documentSearchBean;
public String activeDocumentToFlashScope(String page) {
Document document = documentSearchBean.getSelectedDocument();
FacesContext.getCurrentInstance().getExternalContext().getFlash().put("document", document);
// everything preapared now, redirect to viewing JSF page, with page=xxx parameter in URL, which will be evaluated by adobe pdf reader (and other readers, too)
return "document_search/view_pdf.xhtml?faces-redirect=true#page=" + page;
}
public void download() {
Document document = (Document) FacesContext.getCurrentInstance().getExternalContext().getFlash().get("document");
InputStream inputStream = getInputstreamFromBackingWebserviceSomehow(document);
FacesUtils.writeToResponseStream(FacesContext.getCurrentInstance().getExternalContext(), inputStream, document.getFileName());
}
}
Calling JSF Page:
<p:commandLink id="outputText" action="#{documentDownloadBean.activeDocumentToFlashScope(selectedDocument, page)}"
target="_blank" ajax="false">
<h:outputText value="View PDF"/>
</p:commandLink>

Wicket Deployment mode map resources wrong way

I have Page
getRootRequestMapperAsCompound().add(new NoVersionMapper("/card/${cardId}", CardPage.class));.
On this page there is TinyMCE4 editor. Which try to load images using relative path "images/1.jpg"
I've added resource mapping to allow images successfuly loaded.
mountResource("/card/image/${imageId}", imageResourceReference);
In DEVELOPMENT mode everything work nice, image are loaded in to editor, but in DEPLOYMENT mode, Page has been called twice, first time for /card/1 and second time for /card/image/1.jpg.
How to correctly mount resources for DEPLOYMENT mode?
UPDATE look like found the reason
public int getCompatibilityScore(Request request)
{
return 0; // pages always have priority over resources
}
, but then the question is: "Why it is working nice in development mode"?
Update 2 I haven't find better solution then add my own Resource Mapper with overrided getCompatibilityScore()
public class ImageResourceMapper extends ResourceMapper {
private String[] mountSegments;
public ImageResourceMapper(String path, ResourceReference resourceReference) {
super(path, resourceReference);
mountSegments = getMountSegments(path);
}
public ImageResourceMapper(String path, ResourceReference resourceReference, IPageParametersEncoder encoder) {
super(path, resourceReference, encoder);
mountSegments = getMountSegments(path);
}
#Override
public int getCompatibilityScore(Request request) {
if (urlStartsWith(request.getUrl(), mountSegments)) {
return 10;
}
return 0;
}
}

Read a file from the cache in CEFSharp

I need to navigate to a web site that ultimately contains a .pdf file and I want to save that file locally. I am using CEFSharp to do this. The nature of this site is such that once the .pdf appears in the browser, it cannot be accessed again. For this reason, I was wondering if once you have a .pdf displayed in the browser, is there a way to access the source for that file in the cache?
I have tried implementing IDownloadHandler and that works, but you have to click the save button on the embedded .pdf. I am trying to get around that.
OK, here is how I got it to work. There is a function in CEFSharp that allows you to filter an incoming web response. Consequently, this gives you complete access to the incoming stream. My solution is a little on the dirty side and not particularly efficient, but it works for my situation. If anyone sees a better way, I am open for suggestions. There are two things I have to assume in order for my code to work.
GetResourceResponseFilter is called every time a new page is downloaded.
The PDF is that last thing to be downloaded during the navigation process.
Start with the CEF Minimal Example found here : https://github.com/cefsharp/CefSharp.MinimalExample
I used the WinForms version. Implement the IRequestHandler and IResponseFilter in the form definition as follows:
public partial class BrowserForm : Form, IRequestHandler, IResponseFilter
{
public readonly ChromiumWebBrowser browser;
public BrowserForm(string url)
{
InitializeComponent();
browser = new ChromiumWebBrowser(url)
{
Dock = DockStyle.Fill,
};
toolStripContainer.ContentPanel.Controls.Add(browser);
browser.BrowserSettings.FileAccessFromFileUrls = CefState.Enabled;
browser.BrowserSettings.UniversalAccessFromFileUrls = CefState.Enabled;
browser.BrowserSettings.WebSecurity = CefState.Disabled;
browser.BrowserSettings.Javascript = CefState.Enabled;
browser.LoadingStateChanged += OnLoadingStateChanged;
browser.ConsoleMessage += OnBrowserConsoleMessage;
browser.StatusMessage += OnBrowserStatusMessage;
browser.TitleChanged += OnBrowserTitleChanged;
browser.AddressChanged += OnBrowserAddressChanged;
browser.FrameLoadEnd += browser_FrameLoadEnd;
browser.LifeSpanHandler = this;
browser.RequestHandler = this;
The declaration and the last two lines are the most important for this explanation. I implemented the IRequestHandler using the template found here:
https://github.com/cefsharp/CefSharp/blob/master/CefSharp.Example/RequestHandler.cs
I changed everything to what it recommends as default except for GetResourceResponseFilter which I implemented as follows:
IResponseFilter IRequestHandler.GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
{
if (request.Url.EndsWith(".pdf"))
return this;
return null;
}
I then implemented IResponseFilter as follows:
FilterStatus IResponseFilter.Filter(Stream dataIn, out long dataInRead, Stream dataOut, out long dataOutWritten)
{
BinaryWriter sw;
if (dataIn == null)
{
dataInRead = 0;
dataOutWritten = 0;
return FilterStatus.Done;
}
dataInRead = dataIn.Length;
dataOutWritten = Math.Min(dataInRead, dataOut.Length);
byte[] buffer = new byte[dataOutWritten];
int bytesRead = dataIn.Read(buffer, 0, (int)dataOutWritten);
string s = System.Text.Encoding.UTF8.GetString(buffer);
if (s.StartsWith("%PDF"))
File.Delete(pdfFileName);
sw = new BinaryWriter(File.Open(pdfFileName, FileMode.Append));
sw.Write(buffer);
sw.Close();
dataOut.Write(buffer, 0, bytesRead);
return FilterStatus.Done;
}
bool IResponseFilter.InitFilter()
{
return true;
}
What I found is that the PDF is actually downloaded twice when it is loaded. In any case, there might be header information and what not at the beginning of the page. When I get a stream segment that begins with %PDF, I know it is the beginning of a PDF so I delete the file to discard any previous contents that might be there. Otherwise, I just keep appending each segment to the end of the file. Theoretically, the PDF file will be safe until you navigate to another PDF, but my recommendation is to do something with the file as soon as the page is loaded just to be safe.

Tess4J doOCR() for *First Page* of pdf / tif

Is there a way to tell Tess4J to only OCR a certain amount of pages / characters?
I will potentially be working with 200+ page PDF's, but I really only want to OCR the first page, if that!
As far as I understand, the common sample
package net.sourceforge.tess4j.example;
import java.io.File;
import net.sourceforge.tess4j.*;
public class TesseractExample {
public static void main(String[] args) {
File imageFile = new File("eurotext.tif");
Tesseract instance = Tesseract.getInstance(); // JNA Interface Mapping
// Tesseract1 instance = new Tesseract1(); // JNA Direct Mapping
try {
String result = instance.doOCR(imageFile);
System.out.println(result);
} catch (TesseractException e) {
System.err.println(e.getMessage());
}
}
}
Would attempt to OCR the entire, 200+ page into a single String.
For my particular case, that is way more than I need it to do, and I'm worried it could take a very long time if I let it do all 200+ pages and then just substring the first 500 or so.
The library has a PdfUtilities class that can extract certain pages of a PDF.

Unable to show PDF in p:media generated from streamed content in Primefaces

I'm trying to show inline PDF which is opened in new browser window. I have following scenario:
In some ActionListen which is called by ajax I generate PDF content, put data in session, and send Javascript to be executed (window.open to open new page to show PDF)
On opened page I just have p:media tag inside h:body with value pointing to StreamedContent:
Now, on that page my PDF is not generated. In log I can see these two lines:
org.primefaces.application.PrimeResourceHandler handleResourceRequest
SEVERE: Error in streaming dynamic resource. Expression cannot be null
I started to debug and find out a few things.
First, I added breakpoint to #PostConstruct method of my RequestScoped bean. What is interesting is that breakpoint is reached twice, and to my big surprise after that PDF is shown perfectly?!
After some debugging through PrimeResourceHandler I figure out that in some cases ValueExpression is not calculated, in fact it throws NullPointerException, and again while debugging I saw that two requests are sent, and second request fails because dynamicContentId is removed in first request, and second call to handleResourceRequest doesn't have sense.
Through Firebug I can see two requests, first which is good with PDF data, and second which is also with content-type application/pdf but empty, with size 0.
xhtml page:
<html>
<h:head></h:head>
<h:body>
<p:media value="#{reportBean.streamedContent}" player="pdf" width="500" height="500"/>
</h:body>
</html>
backing bean:
#RequestScoped
public class StampaListeBackingBean implements Serializable {
private static final long serialVersionUID = 1L;
private StreamedContent streamedContent;
#PostConstruct
public void init() {
Map<String, Object> session = FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
byte[] b = (byte[]) session.get("reportBytes");
if (b != null) {
streamedContent = new DefaultStreamedContent(new ByteArrayInputStream(b), "application/pdf");
}
}
public StreamedContent getStreamedContent() {
if (FacesContext.getCurrentInstance().getRenderResponse()) {
return new DefaultStreamedContent();
} else {
return streamedContent;
}
}
public void setStreamedContent(StreamedContent streamedContent) {
this.streamedContent = streamedContent;
}
}
I need to understand why two requests are sent on page with p:media tag, and to figure out how to make this work. Backing bean is request scoped, it creates StreamedContent in #PostConstruct method, and has getter and setter for that field. Primefaces version is 3.4.2, with Mojarra 2.1.14.
ADDED:
It is easy to reproduce my problem. If code in init method is replaced with following:
FileInputStream fis = new FileInputStream(new File("C:\\samplexxx.pdf"));
streamedContent = new DefaultStreamedContent(fis, "application/pdf");
problem can be reproduced.
I can reproduce your problem. It indeed doesn't work in Firefox (nor in IE9, but it works in Chrome). PrimeFaces lead Cagatay has also mentioned that several times.
I'm not sure if this is a bug in the PrimeFaces resource handler or in the browser. I'll leave it in the middle.
In the meanwhile, your best bet is a simple web servlet for the job. Just create this class:
#WebServlet("/report.pdf")
public class PdfReportServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
byte[] content = (byte[]) request.getSession().getAttribute("reportBytes");
response.setContentType("application/pdf");
response.setContentLength(content.length);
response.getOutputStream().write(content);
}
}
And invoke it as follows:
<p:media value="/report.pdf" ... />
That's it. No XML config necessary. It works for me in all browsers. Depending on the functional requirements, you may want to further finetune response headers related to browser caching.
It is not a browser or primefaces problem, just a funny getter problem.
The getter is called twice by p:media (or if you refresh page than more times), but only the 1st call gets the correct data. StreamedContent encapsulates an InputStream, which has the property that it will give no bytes if the stream is at the end of the file. First time it is read to its end (data is ok), but every next call will get no data. :)
javadoc of inputStream.read():
If no byte is available because the stream is at the end of the file, the value -1 is returned; otherwise, at least one byte is read and stored into b.
Solution:
private StreamedContent streamedContent;
private InputStream stream;
public void somewhere(){
byte[] b = ...
stream = new ByteArrayInputStream( b );
stream.mark(0); //remember to this position!
streamedContent = new DefaultStreamedContent(stream, "application/pdf");
}
public StreamedContent getStreamedContent() {
if (streamedContent != null)
streamedContent.getStream().reset(); //reset stream to the start position!
return streamedContent;
}
I hope my little contribution can help anyone who can't display pdf preview in Firefox. I was using Primefaces 6 + Spring and I had the same problem but maybe not due the same reason. Indeed, I tried the proposed solution by Balus C. It helped me to display the pdf in Chrome and IE11 but it still was not working in Firefox 52.
I noticed an error in the Firefox console: Load denied by X-Frame-Options: http://localhost:8080/myapp/ does not permit framing
In my case, it was because spring-security configuration and the solution was edit spring-context.xml in this way:
<sec:http ...>
...
<sec:headers>
<sec:frame-options policy="SAMEORIGIN" />
</sec:headers>
...
</sec:http>