Как визуализировать внутреннее изображение на компоненте swing с помощью html?

У меня есть следующий код:

public static void main(String[] args) { JFrame frm = new JFrame(); JEditorPane pane = new JEditorPane("text/html", "test
"); pane.setEditable(false); frm.getRootPane().setContentPane(pane); frm.pack(); frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frm.setVisible(true); }

Я пытаюсь сделать изображение на JEditorPane, используя кодировку base64, чтобы сохранить изображение. Он не должен быть base64, но это насколько я понял, пытаясь отобразить содержимое HTML на JEditorPane, но мне нужно использовать образ, который находится в BufferedImage (он генерируется приложением.), И, действительно предпочитают не сохранять изображение в файл на жестком диске.

Могу ли я каким-то образом отобразить BufferedImage в компоненте swing вместе с HTML (отображая его в месте, заданном тегом IMG – HTML-код также генерируется приложением)?

Я должен был переписать один из classов Java и расширить другой, но получил изображение BASE64, работающее под HTML на JEditorPane. Я отправлю свое решение в случае, если кому-то это понадобится в будущем …

Сначала создайте специальный HTMLEditorKit, который будет использовать перезаписанный class ImageView для HTML.Tag.IMG

 class BASE64HTMLEditorKit extends HTMLEditorKit { private static HTMLFactory factory = null; @Override public ViewFactory getViewFactory() { if (factory == null) { factory = new HTMLFactory() { @Override public View create(Element elem) { AttributeSet attrs = elem.getAttributes(); Object elementName = attrs.getAttribute(AbstractDocument.ElementNameAttribute); Object o = (elementName != null) ? null : attrs.getAttribute(StyleConstants.NameAttribute); if (o instanceof HTML.Tag) { HTML.Tag kind = (HTML.Tag) o; if (kind == HTML.Tag.IMG) { // HERE is the call to the special class... return new BASE64ImageView(elem); } } return super.create(elem); } }; } return factory; } } 

С помощью этого выполните специальный class, основанный на коде openjdk. Загрузите исходный код здесь и откройте файл openjdk / jdk / src / share / classes / javax / swing / text / html / ImageView.java. Поскольку у него почти все частное, мне было проще скопировать его полностью, а затем изменить метод, необходимый для загрузки BASE64 Images:

 private void loadImage() { String b64 = getBASE64Image(); BufferedImage newImage = null; try (ByteArrayInputStream bais = new ByteArrayInputStream(DatatypeConverter.parseBase64Binary(b64))) { newImage = ImageIO.read(bais); } catch (IOException ex) { ... } image = newImage; } private String getBASE64Image() { String src = (String) getElement().getAttributes().getAttribute(HTML.Attribute.SRC); if (src == null) { return null; } return src.replaceFirst("data:image/png;base64,", ""); } 

Метод getBASE64Image просто сокращает часть атрибута, отличного от BASE64. Метод loadImage – это тот, который нужно изменить, и если он будет публичным, помог бы вырезать много кода из решения …

Если у кого-то лучше и желательно меньше (у меня есть 1000 строк кода), пожалуйста, поделитесь им …

Выбирая эти сообщения и некоторые из других источников, я смог заставить это работать для себя.

Если я использовал вышеупомянутую функцию paintComponent (), она рисует изображение, но любые дополнительные элементы html отображаются неправильно, потому что они перезаписывают друг друга. Чтобы исправить это, я попытался свести к минимуму методы, которые были изменены, и этот подход, похоже, сработал.

В любом случае, это то, что я сделал, чтобы заставить его работать:
1) Загрузите файлы OpenJDK7 с http://download.java.net/openjdk/jdk7/

2) Разархивируйте файл и скопируйте файл openjdk / jdk / src / share / classes / javax / swing / text / html / ImageView.java в папку src вашего проекта (используйте другое имя, чем ImageView.java. В следующем примере мы назовет его Custom_ImageView.java). Вам придется изменить этот файл, поэтому откройте его в текстовом редакторе и выполните следующие действия:
2A) Измените имя classа с «ImageView» на «Custom_ImageView».
2B) Измените имя конструктора с «ImageView» на «Custom_ImageView».

 public ImageView(Element elem) { ...to... public Custom_ImageView(Element elem) { 

2C) Измените все синхронизированные (ImageView.this) “на” синхронизированные (Custom_ImageView.this) ”
2D) Измените loadImage () следующим образом:

 // Modified method in Custom_ImageView.java private void loadImage() { URL src = getImageURL(); Image newImage = null; if (src != null) { Dictionary cache = (Dictionary)getDocument(). getProperty(IMAGE_CACHE_PROPERTY); if (cache != null) { newImage = (Image)cache.get(src); } else { newImage = Toolkit.getDefaultToolkit().createImage(src); if (newImage != null && getLoadsSynchronously()) { // Force the image to be loaded by using an ImageIcon. ImageIcon ii = new ImageIcon(); ii.setImage(newImage); } } } else { // BEGIN: Modified code... //System.out.println("[DEBUG] Image Source: " + src); System.out.println("[DEBUG] loadImage() - newImage = null"); String b64 = getBASE64Image(); BufferedImage newBufferedImage = null; try (ByteArrayInputStream bais = new ByteArrayInputStream(DatatypeConverter.parseBase64Binary(b64))) { newBufferedImage = ImageIO.read(bais); } catch (IOException ex) { System.out.println("[ERROR] in loadImage() \n\t" + ex); } // End catch()... newImage = newBufferedImage; } // FINISH: Modified code... image = newImage; } 

Сравнив приведенный выше fragment с исходным кодом:

 // Original code from ImageView.java (OpenJDK7)... private void loadImage() { URL src = getImageURL(); Image newImage = null; if (src != null) { Dictionary cache = (Dictionary)getDocument(). getProperty(IMAGE_CACHE_PROPERTY); if (cache != null) { newImage = (Image)cache.get(src); } else { newImage = Toolkit.getDefaultToolkit().createImage(src); if (newImage != null && getLoadsSynchronously()) { // Force the image to be loaded by using an ImageIcon. ImageIcon ii = new ImageIcon(); ii.setImage(newImage); } } } image = newImage; } 

2E) В classе Custom_ImageView добавьте метод getBASE64Image (), который используется модифицированным методом loadImage ():

 // Add this method to Custom_ImageView.java private String getBASE64Image() { String src = (String) getElement().getAttributes().getAttribute(HTML.Attribute.SRC); if (src == null) { return null; } // This doesn't account for "data:image/png;charset=utf-8;base64," //return src.replaceFirst("data:image/png;base64,", ""); // So I delete all data from beginning of line (^) to ";base64" return src.replaceFirst("^.*;base64,", ""); } // End getBASE64Image()... 

Это завершает модификацию Custom_ViewImage.java.

3) Теперь нам нужно создать собственный HTMLEditorKit, который будет использоваться нашей JEditorPane. Мы будем называть этот файл Custom_HTMLEditorKit.java. Как указано выше, нам необходимо переопределить метод getViewFactory (), чтобы он знал, что мы использовали наш измененный файл (Custom_ImageView). Код должен выглядеть так:

 package my.app.package; import javax.swing.text.AbstractDocument; import javax.swing.text.AttributeSet; import javax.swing.text.Element; import javax.swing.text.StyleConstants; import javax.swing.text.View; import javax.swing.text.ViewFactory; import javax.swing.text.html.HTML; import javax.swing.text.html.HTMLEditorKit; public class Custom_HTMLEditorKit extends HTMLEditorKit { private static HTMLFactory factory = null; @Override public ViewFactory getViewFactory() { if (factory == null) { factory = new HTMLFactory() { @Override public View create(Element elem) { AttributeSet attrs = elem.getAttributes(); Object elementName = attrs.getAttribute(AbstractDocument.ElementNameAttribute); Object o = (elementName != null) ? null : attrs.getAttribute(StyleConstants.NameAttribute); if (o instanceof HTML.Tag) { HTML.Tag kind = (HTML.Tag) o; if (kind == HTML.Tag.IMG) { // HERE is the call to the special class... return new Custom_ImageView(elem); } // End if(kind == IMG)... } // End if(instance of Tag)... return super.create(elem); } // End create()... }; // End new HTMLFactory()... } // End if(factory == null)... return factory; } // End getViewFactory()... } // End Custom_HTMLEditorKit()... 

4) Теперь мы готовы использовать код. В нашем основном приложении вам нужно переназначить HTMLEditorKit для Custom_HTMLEditorKit.

 package my.app.package; import javax.swing.JEditorPane; import javax.swing.JFrame; public class ExpInlineImage { public ExpInlineImage() { JFrame jf = new JFrame(); JEditorPane jep = new JEditorPane(); jep.setEditable(false); jep.setContentType("text/html"); jep.setEditorKit(new Custom_HTMLEditorKit()); jep.setText( "test
"); jf.getRootPane().setContentPane(jep); jf.pack(); jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jf.setVisible(true); } // End constructor... public static void main(String[] args) { ExpInlineImage app = new ExpInlineImage(); } // End main()... } // End ExpInlineImage{}...

5) Запустите приложение, и вы увидите изображение зеленого плюса под словом «тест».

Некоторые вещи стоит упомянуть:
* border = “1”, похоже, работает нормально. Это создаст границу вокруг изображения.
* width = “100px” отлично работает. Устанавливает ширину до 100 пикселей независимо от исходного размера.
* width = “100” отлично работает. Устанавливает ширину до 100 пикселей независимо от исходного размера.
* width = “50%” не работает. Это устанавливает ширину до 50 пикселей вместо 50 процентов от исходного размера.

Для тех, кого это интересует, я разместил пример на github.
https://github.com/GreenElm/expInlineImage/tree/master/src/expinlineimage

Или загрузите репо …

 git remote add origin https://github.com/GreenElm/expInlineImage.git 

Надеюсь, эта помощь.

Другой способ подключить ImageView:

 public class Base64ImageView extends ImageView { private URL url; public Base64ImageView(Element elem) { super(elem); populateImage(); } private void populateImage() { Dictionary cache = (Dictionary) getDocument() .getProperty("imageCache"); if (cache == null) { cache = new Hashtable(); getDocument().putProperty("imageCache", cache); } URL src = getImageURL(); cache.put(src, loadImage()); } private Image loadImage() { String b64 = getBASE64Image(); BufferedImage newImage = null; ByteArrayInputStream bais = null; try { bais = new ByteArrayInputStream( Base64.decodeBase64(b64.getBytes())); newImage = ImageIO.read(bais); } catch (Throwable ex) { } return newImage; } private String getBASE64Image() { String src = (String) getElement().getAttributes() .getAttribute(HTML.Attribute.SRC); if (!isBase64Encoded(src)) { return null; } return src.substring(src.indexOf("base64,") + 7, src.length() - 1); } @Override public URL getImageURL() { String src = (String) getElement().getAttributes() .getAttribute(HTML.Attribute.SRC); if (isBase64Encoded(src)) { this.url = Base64ImageView.class.getProtectionDomain() .getCodeSource().getLocation(); return this.url; } return super.getImageURL(); } private boolean isBase64Encoded(String src) { return src != null && src.contains("base64,"); } } 

вы не можете отображать BufferedImage в HTML-теге!

вы можете создать BufferedImage без его сохранения, вы можете создать BufferedImage из URI / URL-адреса, и вы можете отображать HTML-код в большинстве компонентов swing, но вы не можете выполнять оба в одном;

возможно, вы можете настроить свой компонент swing, переопределив метод paintComponent и нарисуйте html, а затем изображение (возможно, вы захотите это сделать наоборот).

 private BufferedImage buffImg; //won't be stored private void readImage(){ URL url = URI.create("myUri").toURL(); buffImg = ImageIO.read(url); } @Override public void paintComponent (Graphics gr){ super(gr); //draws your html code gr.drawImage(buffImg, x, y, obs); //draweing the buffImage }