将byte[]转换为Base64字符串以用于数据URI

38

我知道这个问题可能被问过10000次,然而,我似乎找不到一个直接回答我的问题的答案。

我在我的数据库中有一个LOB(大型对象)表示一张图片;我从数据库获取该图像,并希望通过HTML IMG标签在网页上显示它。虽然这不是我的首选方案,但这是一个权宜之计,直到我找到更好的解决方案。

我正在尝试使用Apache Commons Codec将byte[]转换为Base64,方法如下:

String base64String = Base64.encodeBase64String({my byte[]});

然后,我想这样在页面上展示我的图片:

<img src="data:image/jpg;base64,{base64String from above}"/>

它正在显示浏览器的默认“找不到此图像”的图像。

有人有任何想法吗?

谢谢。


你能发布完整的代码吗?我需要它作为参考。我也遇到了同样的问题,但是我不知道代码会是什么样子。 - Lucky
5个回答

43

我使用了这个方法,它运行良好(与被接受的答案相反,该答案使用了一个在这种情况下不推荐的格式):

StringBuilder sb = new StringBuilder();
sb.append("data:image/png;base64,");
sb.append(StringUtils.newStringUtf8(Base64.encodeBase64(imageByteArray, false)));
contourChart = sb.toString();

2
这是正确的答案,如果没有UTF8编码,浏览器会给你带来各种麻烦。 - phamductri
2
你用了哪些导入? - kozla13
1
StringUtils未定义。 - Christine
@Hill 这是来自 Apache Commons 的。看看吧,你可能会在每个项目中都用到它。 - WhyNotHugo
@Hill 我猜我太习惯于在几乎每个项目中看到它了,以至于开始视为理所当然 :) - WhyNotHugo
显示剩余3条评论

13

1
维基百科文章中的PNG示例表明使用+和/是可以的。 - Daniel Trebbien
1
有人实际尝试过使用Base64.encodeBase64URLSafeString()的输出在浏览器中是否有效吗?encodeBase64URLSafeString()似乎不能生成有效/标准的base64编码。为使base64编码的字符串符合URI规范,您应该对其应用标准的URI字符转义。我认为上述函数不是您想要的。 - Keeth
这个答案实际上没有为我生成正确的字符串。Hugo的答案包含了缺失的编码,使其能够正常工作。 - ryber

3

2
你也可以考虑将图片流式传输到浏览器,而不是将其编码在页面上。
下面是通过servlet将文件中的图像流式传输到浏览器的示例,可以轻松地采用这种方法来流式传输BLOB的内容,而不是文件:
  public void doGet(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
  {
    ServletOutputStream sos = resp.getOutputStream();
    try {
      final String someImageName = req.getParameter(someKey);

      // encode the image path and write the resulting path to the response
      File imgFile = new File(someImageName);

      writeResponse(resp, sos, imgFile);
    }
    catch (URISyntaxException e) {
      throw new ServletException(e);
    }
    finally {
      sos.close();
    }
  }

  private void writeResponse(HttpServletResponse resp, OutputStream out, File file)
    throws URISyntaxException, FileNotFoundException, IOException
  {
    // Get the MIME type of the file
    String mimeType = getServletContext().getMimeType(file.getAbsolutePath());
    if (mimeType == null) {
      log.warn("Could not get MIME type of file: " + file.getAbsolutePath());
      resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
      return;
    }

    resp.setContentType(mimeType);
    resp.setContentLength((int)file.length());

    writeToFile(out, file);
  }

  private void writeToFile(OutputStream out, File file)
    throws FileNotFoundException, IOException
  {
    final int BUF_SIZE = 8192;

    // write the contents of the file to the output stream
    FileInputStream in = new FileInputStream(file);
    try {
      byte[] buf = new byte[BUF_SIZE];
      for (int count = 0; (count = in.read(buf)) >= 0;) {
        out.write(buf, 0, count);
      }
    }
    finally {
      in.close();
    }
  }

我正在使用Spring Web MVC,并且整个页面都是使用tiles构建的,等等... 我真的不想经历创建另一个控制器并单独调用每个图像的麻烦,但还是谢谢! - El Guapo

1

如果您不想从Servlet流式传输,则将文件保存到Web根目录中的目录中,然后创建指向该位置的src。这样,Web服务器就会承担提供文件的工作。如果您感到特别聪明,可以通过时间戳/ inode / crc32检查现有文件,并仅在DB中更改时写入它,这可以为您带来性能提升。此文件方法还将自动支持ETag和if-modified-since头,以便浏览器可以正确缓存文件。


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