在JSF中创建并显示缩略图(byte[])

5
我正在将图片上传到服务器,当图片上传完成后,应该显示上传图片的缩略图。缩略图未保存在硬盘上,我使用InputStream和OutputStream。上传时我使用的是tomahawk。
我的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调用了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();
  }
}

创建缩略图:

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;
}

现在我有我的缩略图,但它是以byte[]的形式存在的,请问有人能告诉我如何使用<h:graphicImage>标签显示我的缩略图吗?或者还有其他方法。谢谢!
4个回答

9
每个图像都算作一个独立的请求。您不能在单个请求/响应周期中同时处理JSF的HTML响应和图像。您需要将图像/缩略图存储在比请求寿命更长的数据存储区域中,例如服务器的本地磁盘文件系统(临时文件夹?Web内容文件夹?)或数据库(临时表?)或会话中。
首先,替换
<h:graphicImage value="#{fileUpload.thumb}" ...

by

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

以便生成如下内容:

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

“src”应指向有效的URL。

然后,创建一个映射到/thumbs/*url-pattern上的HttpServlet,并实现doGet(),大致如下:

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) {}
}

就这些了。更多有关servlet的提示可以在这篇文章中找到。


3
graphicImage标签会在HTML响应中生成一个img标签。因此,你需要在graphicImage标签的value属性中提供图像的URL,这将对应于img标签的src属性。
你可以选择以下任一方式:
  • 将缩略图写入可以通过HTTP从外部访问的filesystem路径中。然后在graphicImage标签的value属性中直接引用该图像,例如:/myapp/thumbnail/12345
  • 编写一个,在请求时服务于该图像。该可以从内存(HttpSession),文件系统或数据库中读取图像,或者每次生成图像。在这种情况下,你需要向传递一个参数,例如:/myapp/thumbnail.do?filename=12345
简而言之,你需要将byte[]缩略图存储在某个地方(会话、文件系统、数据库),以便能够作为常规资源直接或通过提供。

1

Richfaces已经为您抽象化了这个过程。请查看<a4j:mediaOutput> - 您只需将byte[]写入组件提供的OutputStream即可。


a4j:mediaOutput 包含对图像大小的限制,因为它将图像内容编码为 URL(base64 格式)。这仅适用于小图标。 - vim

0

感谢ewernli。我重复使用了您的createThumbnail实用方法。我添加了这个小改进,以便在原始图像宽度小于规定的maxDim宽度时返回原始图像。我这样做是因为我遇到了一种情况,即该方法返回一个比原始图像更大的图像,并带有黑色像素填充。

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

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

        ...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接