Display p:fileupload image in p:graphicImage preview without saving it
Asked Answered
A

1

7

I am using PrimeFaces 5.3 <p:fileUpload> to upload a PNG image and I would like to show a preview of it in <p:graphicImage> before saving in database.

Here's a MCVE:

<h:form enctype="multipart/form-data">
    <p:fileUpload value="#{bean.uploadedFile}" mode="simple" />
    <p:graphicImage value="#{bean.image}" />
    <p:commandButton action="#{bean.preview}" ajax="false" value="Preview" />
</h:form>

private UploadedFile uploadedFile;

public UploadedFile getUploadedFile() {
    return uploadedFile;
}

public void setUploadedFile(UploadedFile uploadedFile) {
    this.uploadedFile = uploadedFile;
}

public void preview() {
    // NOOP for now.
}

public StreamedContent getImage() {
    if (uploadedFile == null) {
        return new DefaultStreamedContent(); 
    } else {
        return new DefaultStreamedContent(new ByteArrayInputStream(uploadedFile.getContents()), "image/png"); 
    }
}

No error occurring on the backing bean, and the image won't be load and display at front-end. The client mentions that the image returned a 404 not found error.

Archenemy answered 7/8, 2016 at 18:16 Comment(12)
You say the upload works so how is this issue file-upload related and not graphic-imageChancy
because the byte[] source is come from the upload content, so i had obtained the upload content byte[], but when i use the upload content to be display on the web page, its not gonna display and saying that the resource is not foundArchenemy
So you mean that if you manually put a byte[] in the database, not via the file-upload, it works?Chancy
Sorry sir, you misunderstood my question, I have not tried database yet, as it is not working via the file-uploadArchenemy
The flow are suppose to be like "Upload Image -> Preview Image -> Store into Database" in expecting, but for now I cannot Preview Image because the content from Image Upload cannot be displayArchenemy
@BalusC please review my updated question, the issue is exactly sameArchenemy
I did not save the uploaded file, I stored in variable and reuse as soon as I submitting to display for previewArchenemy
yes correct, i wonder it is an "Unsaved" uploaded file, as I had assign into a variable for temporary use, only perform permanent saving after a final confirmation for user.Archenemy
So I must perform storing the file somewhere else in the file system or database? there are no way to display the image without saving?Archenemy
sure there is, in a longer scoped bean... But would you want to?Chancy
longer scoped bean? Pardon me, I am not well understanding in scoped bean concept, please guide meArchenemy
#7032385Chancy
L
13

Your problem is two-fold. It failed because the uploaded file contents is request scoped and because the image is requested in a different HTTP request. To better understand the inner working, carefully read the answers on following closely related Q&A:

To solve the first problem, you need to read the uploaded file contents immediately in the action method associated with the form submit. In your specific case, that would look like:

private UploadedFile uploadedFile;
private byte[] fileContents;

public void preview() {
    fileContents = uploadedFile.getContents();
}

// ...

To solve the second problem, your best bet is to use the data URI scheme. This makes it possible to render the image directly in the very same response and therefore you can safely use a @ViewScoped bean without facing "context not active" issues or saving the byte[] in session or disk in order to enable serving the image in a different request. Browser support on data URI scheme is currently pretty good. Replace the entire <p:graphicImage> with below:

<ui:fragment rendered="#{not empty bean.uploadedFile}">
    <img src="data:image/png;base64,#{bean.imageContentsAsBase64}" />
</ui:fragment>

public String getImageContentsAsBase64() {
    return Base64.getEncoder().encodeToString(imageContents);
}

Note: I assume that Java 8 is available to you as java.util.Base64 was only introduced in that version. In case you're using an older Java version, use DatatypeConverter.printBase64Binary(imageContents) instead.

In case you happen to use JSF utility library OmniFaces, you can also just use its <o:graphicImage> component instead which is on contrary to <p:graphicImage> capable of directly referencing a byte[] and InputStream bean property and rendering a data URI.

<o:graphicImage value="#{bean.imageContents}" dataURI="true" rendered="#{not empty bean.imageContents}">
Lichter answered 8/8, 2016 at 7:46 Comment(3)
Thank you @Lichter the issue now has been totally verified and had resolved according to your solution approach, very thanks to your effortArchenemy
@Lichter why in my case didn't works? Repository github.com/zaknafein83/uploadimage-primefaces-tutorial.git When i start, io get a nullpointer exception on method to convert byte[] content into String (Base64). If i add a null pointer control, i never get the preview of the imageGrovergroves
is there a way, when the user choose the file, the image is displayed?Hurst

© 2022 - 2024 — McMap. All rights reserved.