Отображение base64-закодированного изображения - PullRequest
0 голосов
/ 10 декабря 2018

У меня проблема с интеграцией изображения в текстовый / html JTextPane.JTextPane инициализируется следующим текстом:

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

Я вставляю текст с:

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

Весь текст, вставленный таким образом, отображается правильно, но когда я попытался вставить base64-закодированное изображение с:

kit.insertHTML(doc,doc.getLength(), "<img src=\"data:image/jpeg;base64," + base64Code + "\"/>", 0, 0, HTML.Tag.IMG);

Я получил только изображение-заполнитель.При попытке с нормальным исходным путем это работало.Тем не менее, когда я получил код base64 онлайн и использовал его, я тоже получил изображение-заполнитель, в то время как тот же самый код работал на HTML-редакторе w3school.com.

1 Ответ

0 голосов
/ 11 декабря 2018

Когда JTextPane видит тег <img>, он проверяет, существует ли изображение в кэше, и если нет, он пытается прочитать изображение с URL-адреса.Библиотека html, используемая JTextPane, не поддерживает данные изображения в кодировке base64 в теге <img>, поэтому нам нужно будет сделать это по-другому.

Оказывается, мы можем вручную добавлять изображения вкеш изображений.Это может быть использовано, чтобы выбрать какой-то неверный URL и присвоить ему изображение.


Давайте добавим изображение в кеш и покажем его в 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;
}

Обратите внимание, что я подавляю некоторые предупреждения о параметрах типа в Dictionary и Hashtable.Обычно этого следует избегать, но в этом случае мы имеем дело с бессмыслицей Swing таким образом, чтобы можно было подавлять предупреждения.

Этот метод по сути выбирает некоторый недействительный URL-адрес и сохраняет изображение по этому URL-адресу.

Обратите внимание на аргумент name.Это будет частью URL, и если вы попытаетесь сохранить изображение в кэш с тем же именем, что и у предыдущего изображения, это заменит это предыдущее изображение.Избегайте использования сумасшедших символов в этом имени, так как new Url(url) может выдать MalformedURLException, если это недопустимый URL.


Теперь мы можем использовать его с 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, чтобы гарантировать, что изображения будут добавлены до того, как это понадобится Swing.

Если изображение в кэше изменяется с помощью 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.

...