I have the following code:
public static void main(String[] args) {
JFrame frm = new JFrame();
JEditorPane pane = new JEditorPane(\"text/html\", \"&l
By piecing these posts and some from other sources, I was able to get to get this to work for myself.
If I used the above paintComponent() function, it paints the image but any additional html items aren't display properly because they overwrite each other. To fix this, I tried to minimize the methods which were modified and this approach seemed to work.
Anyways, this is what I did to get it working:
1) Download the OpenJDK7 files from http://download.java.net/openjdk/jdk7/
2) Unzip the file and copy the openjdk/jdk/src/share/classes/javax/swing/text/html/ImageView.java to your project's src folder (Use a different name than ImageView.java. In the following example, we will call it Custom_ImageView.java). You will have to modify this file, so open it in your text editor and do the following:
2A) Change the class name from "ImageView" to "Custom_ImageView".
2B) Change the constructor name from "ImageView" to "Custom_ImageView".
public ImageView(Element elem) {
...to...
public Custom_ImageView(Element elem) {
2C) Change all "synchronized(ImageView.this)" to "synchronized(Custom_ImageView.this)"
2D) Change the loadImage() to this:
// 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;
}
Compared the above snippet to the original code:
// 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) Within the Custom_ImageView class, add a method called getBASE64Image(), this is used by the modified loadImage() method:
// 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()...
This finishes up the Custom_ViewImage.java modifications.
3) Now we need to create our own HTMLEditorKit which will be used by our JEditorPane. We will call this file Custom_HTMLEditorKit.java. As stated above, we will need to override the getViewFactory() method so that it knows to use our modified file (Custom_ImageView). The code should look like this:
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) Now we are ready to use the code. Within our main app, you just have to reassign the HTMLEditorKit to 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) Run the app and you should see an image of a green plus sign below the word "test".
Some things worth mentioning:
* border="1" seems to work fine. This will draw a border around the image.
* width="100px" works fine. Sets width to 100 pixels regardless of original size.
* width="100" works fine. Sets width to 100 pixels regardless of original size.
* width="50%" doesn't work. This sets the width to 50 pixels instead of 50 percent of original size.
For those interested, I posted the example on github.
https://github.com/GreenElm/expInlineImage/tree/master/src/expinlineimage
Or download repo by...
git remote add origin https://github.com/GreenElm/expInlineImage.git
I hope this help.