How to render a internal image on a swing component using html?

后端 未结 4 1270
故里飘歌
故里飘歌 2021-01-19 13:05

I have the following code:

public static void main(String[] args) {
    JFrame frm = new JFrame();
    JEditorPane pane = new JEditorPane(\"text/html\", \"&l         


        
4条回答
  •  渐次进展
    2021-01-19 13:12

    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.

提交回复
热议问题