显示base64编码的图像

时间:2018-12-10 19:34:42

标签: java html jtextpane

我在text / html JTextPane中集成图像时遇到问题。 JTextPane用以下文本初始化:

var bpm = 60;             // Beats per minute
var div = 4;              // "4/4 division" (the pattern length)
var s = 0;
var tickTimeout = null;

var loop = [{
  name: "kick",           // it's a sound/file name
  pattern: [1, 0, 0, 0],  // can be expressed using 0 and 1
  volume: 1               // volume goes from 0.0 to 1.0, remember?
},{
  name: "snare",
  pattern: [0, 1, 0, 1],
  volume: 1 
},{
  name: "hihat",
  pattern: [1, 1, 1, 1],
  volume: 1 
}];

// Preload sounds
loop.map(function(obj){
  obj.audio = new Audio("../audio/drumset-rock/"+ obj.name +".mp3");
  obj.audio.volume = obj.volume;
});

// Play tick
function play(){ 
  var names = "";                     // Demo only
  loop.forEach(function(obj) {        
    if (obj.pattern[s]) {
      obj.audio.play();               // Play sound if in pattern
      names += " "+ obj.name          // Demo only
    }
  });
  console.log(s +': '+ names);        // Demo only

  s = ++s % div;                      // Increment and loopback
  tickTimeout = setTimeout(play, 1000 * 60 / bpm);  // Next tick at bpm
}

function stop() {
  clearTimeout(tickTimeout);
}

play();         // Start loop
// stop();      // Use to immediately stop drum machine

我插入以下文字:

<html>
  <head>
    <style type="text/css">
    </style>
  </head>
  <body>
  </body>
</html>

以这种方式插入的所有文本都可以正确显示,但是当我尝试插入具有以下内容的base64编码的图像时:

kit.insertHTML(doc, doc.getLength(), "<b>" + string + "</b><br>" , 0, 0, HTML.Tag.B);

我只有一个占位符图像。尝试使用正常的源路径时,它可以工作。但是,在线获取base64代码并使用它也得到了一个占位符图像,而完全相同的代码在w3school.com的HTML tryit编辑器上起作用。

1 个答案:

答案 0 :(得分:4)

JTextPane看到<img>标签时,它将检查图像是否在缓存中,如果不存在,它将尝试从URL中读取图像。 JTextPane使用的html库不支持<img>标签中的base64编码图像数据,因此我们将需要采用其他方式。

事实证明,我们可以手动将图像添加到图像缓存中。可以利用它来选择一些其他无效的网址并为其分配图片。


让我们将图像添加到缓存中并在JTextPane中显示!

首先,您要将图像转换为BufferedImage。这可以使用ImageIO类来完成。

byte[] imgBytes = decodeBase64(base64Code);
BufferedImage img = ImageIO.read(new ByteArrayInputStream(imgBytes));

请注意,这里我们需要原始图像字节,而不是base64编码。如果您正在从文件中读取图像,则可以将File传递给read函数,而不是输入流。


现在我们将图像作为BufferedImage,我们可以编写一个将其添加到缓存的函数。

@SuppressWarnings({ "rawtypes", "unchecked" })
public static String saveImageToCache(JTextPane pane, BufferedImage img, String name) throws MalformedURLException {
    Dictionary cache = (Dictionary) pane.getDocument().getProperty("imageCache");
    if (cache == null) {
        // No cache exists, so create a new one.
        cache = new Hashtable();
        pane.getDocument().putProperty("imageCache", cache);
    }
    String url = "http:\\buffered/" + name;
    cache.put(new URL(url), img);
    return url;
}

请注意,我取消了有关DictionaryHashtable上的类型参数的一些警告。通常应该避免这种情况,但是在这种情况下,我们以一种可以抑制警告的方式来处理Swing废话。

此方法本质上会选择一些无效的URL并将图像存储在该URL。

注意name参数。这将是url的一部分,如果您尝试使用与先前图像相同的名称将图像存储到缓存中,它将替换先前的图像。避免使用该名称作为疯狂字符,因为new Url(url)如果不是有效的网址,则可能会抛出MalformedURLException


我们现在可以将其与JTextPane一起使用。

BufferedImage img = ...;

JTextPane pane = new JTextPane();
pane.setContentType("text/html");

String url = saveImageToCache(pane, img, "image1");

pane.setText("<html><body><img src=\"" + url + "\"></body></html>");

JFrame frame = new JFrame("image test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(pane);
frame.setSize(img.getWidth(), img.getHeight());
frame.setLocationRelativeTo(null);
frame.setVisible(true);

请注意,在将图像添加到缓存之前,您必须先调用setContentType,因为该方法会清除缓存。此外,重要的是在调用setText之前将图像添加到缓存中,以确保在摆动需要之前添加图像。

如果通过使用具有先前已知名称的saveImageToCache更改了缓存中的图像,则需要以某种方式更新JTextPane,例如调用setText


如果有很多图像,可能需要在不再需要它们时将它们从缓存中删除,以避免过多的内存使用。一种方法是将以下函数定义为一个函数,该函数将从缓存中删除图像。

@SuppressWarnings({ "rawtypes" })
public static void removeImageFromCache(JTextPane pane, String name) throws MalformedURLException {
    Dictionary cache = (Dictionary) pane.getDocument().getProperty("imageCache");
    if (cache == null) {
        // There is no cache, so the image is not in the cache.
        return;
    }
    String url = "http:\\buffered/" + name;
    cache.remove(new URL(url));
}

您还可以通过调用setContentType或用新对象替换JTextPane来清除缓存。这是因为缓存存储在JTextPane中。