views:

985

answers:

4

Hello

I'm uploading image to server and when image is uploaded it should show me a thumb of uploaded image. Thumbnail is not saved on hard disc I use InputStream and OutputStream. For upload i'm ustig tomahawk.

my index.jsp:

<h:form id="uploadForm" enctype="multipart/form-data">
        <t:inputFileUpload id="fileupload" accept="image/*" storage="file"
            value="#{fileUpload.uploadedFile}" styleClass="fileUploadInput"
            required="true" validator="epacient.FileUploadValidator"
            requiredMessage="Obvezna izbira datoteke." />
        <br />
        <h:message for="fileupload" infoStyle="color: green;"
            errorStyle="color: red;" />
        <br />
        <h:commandButton value="Upload" id="fileUploadButton"
            action="#{fileUpload.upload}" />
        <h:message for="uploadForm" style="color: red;" />
 <h:graphicImage value="#{fileUpload.thumb}"  rendered="#{fileUpload.uploaded}" />

    </h:form>

fileUpload.upload calls function String preview()

private  String thumb ;
public String preview() throws IOException{

        HttpServletResponse response = (HttpServletResponse)FacesContext.getCurrentInstance().getExternalContext().getResponse() 
        try {

            FacesContext context = FacesContext.getCurrentInstance();
            Map requestMap = context.getExternalContext().getApplicationMap();
            byte[] bytes =   (byte[])(requestMap.get("fileupload_bytes")); 
             // returns byte[]
            byte[] testByte = createThumbnail(bytes, 200);
           // here thumbnail is created



        } catch (Exception ex) {
            ex.printStackTrace();
        }


    }

createThumbnail:

    public static byte[] createThumbnail( byte[] orig, int maxDim) {

    try {
        ImageIcon imageIcon = new ImageIcon(orig);
         Image inImage = imageIcon.getImage();
        double scale = (double) maxDim / (double) inImage.getWidth(null);

        int scaledW = (int) (scale * inImage.getWidth(null));
        int scaledH = (int) (scale * inImage.getHeight(null));

        BufferedImage outImage = new BufferedImage(scaledW, scaledH, BufferedImage.TYPE_INT_RGB);
        AffineTransform tx = new AffineTransform();

        if (scale < 1.0d) {
            tx.scale(scale, scale);
        }

        Graphics2D g2d = outImage.createGraphics();
        g2d.drawImage(inImage, tx, null);
        g2d.dispose();  


        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(outImage, "JPG", baos);
        byte[] bytesOut = baos.toByteArray();

        return bytesOut;
    } catch (IOException e) {
        System.out.println("Erro: " + e.getMessage());
        e.printStackTrace();
    }
    return null;

}

Now I have my thumbnail but it is in byte[] can any body tell me how to show my thumb with <h:graphicImage tag? Or any other way.

Thank you !

+2  A: 

The graphicImage tag generates an img tag in the HTML response. So you need to provide the URL of an image in the value attribute of the graphicImage tag, which will correspond to the src attribute of the img tag.

You can either:

  • Write the thumbnail on the filesystem in a path that is accessible form the outside through HTTP. You can then reference the image directly in the value attribute in the graphicImage, e.g. /myapp/thumbnail/12345.
  • Write a servlet that serves the image when requested. The servlet can either read the image from memory (HttpSession), the filesystem, or a database, or generate it each time. In this case you need to pass a parameter to the servlet, e.g. /myapp/thumbnail.do?filename=12345

In short, you will need to store your byte[] thumbnail somewhere (session, filesystem, database), to be able to serve it as regular resource, either directly or through a servlet.

ewernli
+2  A: 

The images counts each as a separate request. You cannot process both the HTML response (of JSF) and the image in a single request/response cycle. You need to store the image/thumb somewhere in a datastore which lives longer than a request, e.g. the server's local disk file system (temp folder? webcontent folder?), or a database (temp table?), or in the session.

First, replace

<h:graphicImage value="#{fileUpload.thumb}" ...

by

<h:graphicImage value="thumbs/#{fileUpload.thumbId}" ...

so that it get generated as

<img src="thumbs/123" ...

(the src should namely point to a valid URL)

Then, create a HttpServlet which is mapped on an url-pattern of /thumbs/* and implement doGet() roughly like follows:

Long thumbId = Long.valueOf(request.getPathInfo().substring(1)); // 123
byte[] thumb = getItFromDiskOrDatabaseOrSessionByThumbId(thumbId);
String filename = getOriginalFilenameOfUploadedImageOrInventOne();

response.setContentType(getServletContext().getMimeType(filename));
response.setContentLength(thumb.length);
response.setHeader("Content-Disposition", "inline; filename=\"" + filename + "\"");

BufferedInputStream input = null;
BufferedOutputStream output = null;

try {
    input = new BufferedInputStream(new ByteArrayInputStream(thumb));
    output = new BufferedOutputStream(response.getOutputStream());
    byte[] buffer = new byte[8192];
    int length;
    while ((length = input.read(buffer)) > 0) {
        output.write(buffer, 0, length);
    }
} finally {
    if (output != null) try { output.close(); } catch (IOException logOrIgnore) {}
    if (input != null) try { input.close(); } catch (IOException logOrIgnore) {}
}

That's it. More servlet hints can be found in this article.

BalusC
A: 

Richfaces has abstracted this for you. Check <a4j:mediaOutput> - you just write your byte[] to an OutputStream provided by the component.

Bozho
A: 

Thanks ewernli. I've reused your createThumbnail util method. I added this little enhancement so that the original image is returned if its width is less than the stipulated maxDim width. I did this because I ran into a situation where the method returned an image that was bigger than the original, padded with black pixels.

        ImageIcon imageIcon = new ImageIcon(orig);
        Image inImage = imageIcon.getImage();

        int origWidth = inImage.getWidth(null);
        if(origWidth < maxDim) {
            return orig;
        }

        ...
Sorcha