Java HTML转换为图片
Java HTML转换为图片
核桃白果 发表于3年前
Java HTML转换为图片
  • 发表于 3年前
  • 阅读 268
  • 收藏 1
  • 点赞 0
  • 评论 0

腾讯云 新注册用户 域名抢购1元起>>>   

第一次尝试:用awt 包将HTML源码转换为图片

优点:不依赖任何外部JAR包,缺点:对CSS的支持比较差,复杂点的样式就无法展示,且不支持外部引入的CSS和写在style中的CSS,只能写在标签上

Eg:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.ArrayList;
import java.util.UUID;

import javax.swing.JTextPane;
import javax.swing.border.EmptyBorder;
import javax.swing.plaf.basic.BasicEditorPaneUI;

import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGEncodeParam;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

public class GraphUtils {

    private final static Log log                  = LogFactory.getLog(GraphUtils.class);
    public static int        DEFAULT_IMAGE_WIDTH  = 1000;
    //默认值最好设置大点,因为我们再导之前,不知道这个流有多大,如果过小,则生成的图片后面的为黑色,因为流没有读取完整
    public static int        DEFAULT_IMAGE_HEIGHT = 200;

    public static boolean paintPage(Graphics g, int hPage, int pageIndex, JTextPane panel) {
        Graphics2D g2 = (Graphics2D) g;
        Dimension d = ((BasicEditorPaneUI) panel.getUI()).getPreferredSize(panel);
        double panelHeight = d.height;
        double pageHeight = hPage;
        int totalNumPages = (int) Math.ceil(panelHeight / pageHeight);
        g2.translate(0f, -(pageIndex - 1) * pageHeight);
        panel.paint(g2);
        boolean ret = true;
        if (pageIndex >= totalNumPages) {
            ret = false;
            return ret;
        }
        return ret;
    }

    /**
     * 将BufferedImage转换为图片的信息
     */
    public static String toJpeg(BufferedImage image) {
        // 获取图片文件的在服务器的路径
        String imageName = "G:\\" + UUID.randomUUID().toString() + ".jpg";
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(baos);
            JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(image);
            param.setQuality(1.0f, false);
            encoder.setJPEGEncodeParam(param);
            encoder.encode(image);
            byte[] buff = baos.toByteArray();
            baos.close();
            // 将字节流写入文件保存为图片
            FileUtils.writeByteArrayToFile(new File(imageName), buff);
        } catch (Exception ex) {
            log.error("保存删除图片失败:" + ex.getMessage());
        }
        return imageName;
    }

    /**
     * html转换为jpeg文件
     * @param bgColor 图片的背景色
     * @param html html的文本信息
     * @param width 显示图片的Text容器的宽度
     * @param height 显示图片的Text容器的高度
     * @param eb 設置容器的边框
     * @return
     * @throws Exception
     */
    private static ArrayList<String> html2jpeg(Color bgColor, String html, int width, int height, EmptyBorder eb)
            throws Exception {
        ArrayList<String> ret = new ArrayList<String>();
        try {
            JTextPane tp = new JTextPane();
            tp.setSize(width, height);
            if (eb == null) {
                eb = new EmptyBorder(0, 50, 0, 50);
            }
            if (bgColor != null) {
                tp.setBackground(bgColor);
            }
            if (width <= 0) {
                width = DEFAULT_IMAGE_WIDTH;
            }
            if (height <= 0) {
                height = DEFAULT_IMAGE_HEIGHT;
            }

            tp.setBorder(eb);
            tp.setContentType("text/html");
            tp.setText(html);

            int pageIndex = 1;
            boolean bcontinue = true;
            while (bcontinue) {
                BufferedImage image = new java.awt.image.BufferedImage(width, height,
                        java.awt.image.BufferedImage.TYPE_INT_RGB);
                Graphics g = image.getGraphics();
                g.setClip(0, 0, width, height);
                bcontinue = paintPage(g, height, pageIndex, tp);
                g.dispose();
                String path = toJpeg(image);
                ret.add(path);
                pageIndex++;
            }
        } catch (Exception ex) {
            throw ex;
        }
        return ret;
    }

    /**
     * 将一個html转换为图片
     * @param htmls
     * @return
     * @throws Exception
     */
    public static ArrayList<String> toImages(String html) throws Exception {
        return html2jpeg(Color.white, html, DEFAULT_IMAGE_WIDTH, DEFAULT_IMAGE_HEIGHT, new EmptyBorder(0, 0, 0, 0));
    }

TestCase:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(locations = { "classpath*:spring/application.xml", "classpath*:spring/plugin-*.xml" })
public class GraphUtilsTest extends TestCase {

    @Autowired
    private TaskService            taskService;

    @Autowired
    private VelocitySimpleRelolver velocitySimpleRelolver;

    @Test
    public void testHtml2Image() {
        try {
            String imageTemplateFile = "mail/weekly/mile_schedule_task.vm";
            //邮件内容
            Map<String, Object> velocityData = new HashMap<String, Object>();
            String projId = "6a9fb54e3439453e86e819a4d46fdafb";
            MileSchedule mileSchedule = taskService.getMileSchedule(projId);
            velocityData.put("mileSchedule", mileSchedule);

            String htmlstr = velocitySimpleRelolver.relolve(imageTemplateFile, velocityData);

            Assert.assertNotNull(htmlstr);
            GraphUtils.toImages(htmlstr);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Second: 利用html2image组件

优点:方便,代码简单  缺点:CSS支持极差,比不上Java自身的转化

maven引入:

<dependency> 
    <groupId>gui.ava</groupId> 
    <artifactId>html2image</artifactId> 
    <version>0.9</version> 
</dependency>
TestCase:
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(locations = { "classpath*:spring/application.xml", "classpath*:spring/plugin-*.xml" })
public class Html2ImageTest extends TestCase {

    @Autowired
    private TaskService            taskService;

    @Autowired
    private VelocitySimpleRelolver velocitySimpleRelolver;

    @Test
    public void testHtml2Image() {
        try {
            String imageTemplateFile = "mail/weekly/mile_schedule_task.vm";
            //邮件内容
            Map<String, Object> velocityData = new HashMap<String, Object>();
            String projId = "6a9fb54e3439453e86e819a4d46fdafb";
            MileSchedule mileSchedule = taskService.getMileSchedule(projId);
            velocityData.put("mileSchedule", mileSchedule);

            String htmlstr = velocitySimpleRelolver.relolve(imageTemplateFile, velocityData);
            System.out.println(htmlstr);
            Assert.assertNotNull(htmlstr);
            String imageName = "G:/weekly_mile_" + projId + ".png";

            HtmlImageGenerator imageGenerator = new HtmlImageGenerator();
            imageGenerator.setSize(new Dimension(1000, 200));
            imageGenerator.loadHtml(htmlstr);
            imageGenerator.getBufferedImage();
            imageGenerator.saveAsImage(imageName);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testImage() {
        HtmlImageGenerator imageGenerator = new HtmlImageGenerator();
        imageGenerator.setSize(new Dimension(1000, 200));
        imageGenerator.loadUrl("http://www.baidu.com");
        imageGenerator.getBufferedImage();
        imageGenerator.saveAsImage("G:/aaa.png");
    }
}
Third:DJNativeSwing

参考:http://blog.csdn.net/cping1982/article/details/5353049

其中:JAR包下载地址:

http://sourceforge.net/projects/djproject/?source=navbar  此地址下down DJNativeSwing.jar 和DJNativeSwing-SWT.jar

http://maven-repository.com/artifact/org.eclipse.swt.org.eclipse.swt.win32.win32.x86_64.4.3.swt/org.eclipse.swt.win32.win32.x86_64/4.3

此地址下down org.eclipse.swt 包,选择适合你的开发环境

注意:swt 包针对不同的环境有不同的要求,windows与Linux下的不同,使用maven引入时采用properties方式,将下载的包放入你的maven库,然后在POM中进行maven引入

eg:

<!-- DJNativeSwing -->
		<dependency> 
		    <groupId>chrriis.dj.nativeswing</groupId> 
		    <artifactId>DJNativeSwing</artifactId> 
		    <version>1.0.2</version> 
		</dependency> 
		<dependency> 
		    <groupId>chrriis.dj.nativeswing.swt</groupId> 
		    <artifactId>DJNativeSwing-SWT</artifactId> 
		    <version>1.0.2</version> 
		</dependency>
		<dependency>
		  <groupId>${swt.groupId}</groupId>
		  <artifactId>${swt.artifactId}</artifactId>
		  <version>4.3</version>
		</dependency>


import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.Semaphore;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

import chrriis.dj.nativeswing.swtimpl.NativeComponent;
import chrriis.dj.nativeswing.swtimpl.NativeInterface;
import chrriis.dj.nativeswing.swtimpl.components.JWebBrowser;
import chrriis.dj.nativeswing.swtimpl.components.WebBrowserAdapter;
import chrriis.dj.nativeswing.swtimpl.components.WebBrowserEvent;

public class DJNativeSwingUtils extends JPanel {

    private static final long  serialVersionUID = 8675106494733722832L;
    // 行分隔符  
    final static public String     LS = System.getProperty("line.separator", "/n");
    // 文件分割符  
    final static public String     FS = System.getProperty("file.separator", "//");
    //以javascript脚本获得网页全屏后大小  
    final static StringBuffer      jsDimension;

    static {
        jsDimension = new StringBuffer();
        jsDimension.append("var width = 0;").append(LS);
        jsDimension.append("var height = 0;").append(LS);
        jsDimension.append("if(document.documentElement) {").append(LS);
        jsDimension.append("  width = Math.max(width, document.documentElement.scrollWidth);").append(LS);
        jsDimension.append("  height = Math.max(height, document.documentElement.scrollHeight);").append(LS);
        jsDimension.append("}").append(LS);
        jsDimension.append("if(self.innerWidth) {").append(LS);
        jsDimension.append("  width = Math.max(width, self.innerWidth);").append(LS);
        jsDimension.append("  height = Math.max(height, self.innerHeight);").append(LS);
        jsDimension.append("}").append(LS);
        jsDimension.append("if(document.body.scrollWidth) {").append(LS);
        jsDimension.append("  width = Math.max(width, document.body.scrollWidth);").append(LS);
        jsDimension.append("  height = Math.max(height, document.body.scrollHeight);").append(LS);
        jsDimension.append("}").append(LS);
        jsDimension.append("return width + ':' + height;");
    }


    public static JPanel createContent(String htmlStr, final String fileName, final Semaphore semp) {
        //浏览器面板
        JPanel webBrowserPanel = new JPanel(new BorderLayout());
        //swing的内嵌浏览器
        final JWebBrowser webBrowser = new JWebBrowser();
        //隐藏所有的栏
        webBrowser.setBarsVisible(false);
        //向浏览器写入html内容
        webBrowser.setHTMLContent(htmlStr);
        //将浏览器嵌入浏览器面板
        webBrowserPanel.add(webBrowser, BorderLayout.CENTER);
        //向浏览器增加监听事件
        webBrowser.addWebBrowserListener(new WebBrowserAdapter() {
            // 监听加载进度  
            public void loadingProgressChanged(WebBrowserEvent e) {
                // 当加载完毕时  
                if (e.getWebBrowser().getLoadingProgress() == 100) {
                    try {
                        //执行JS获取图片的宽度,高度
                        String result = (String) webBrowser.executeJavascriptWithResult(jsDimension.toString());
                        int index = result == null ? -1 : result.indexOf(":");

                        NativeComponent nativeComponent = webBrowser.getNativeComponent();
                        //获取图片的原始尺寸
                        Dimension originalSize = nativeComponent.getSize();
                        //根据JS返回结果设定新的图片尺寸
                        Dimension imageSize = new Dimension(Integer.parseInt(result.substring(0, index)), Integer
                                .parseInt(result.substring(index + 1)));
                        //计算图片的新尺寸
                        imageSize.width = Math.max(originalSize.width, imageSize.width);
                        imageSize.height = Math.max(originalSize.height, imageSize.height);
                        nativeComponent.setSize(imageSize);

                        //创建一个不带透明色的BufferedImage对象
                        BufferedImage image = new BufferedImage(imageSize.width, imageSize.height,
                                BufferedImage.TYPE_INT_RGB);
                        //对浏览器中图片进行绘色
                        nativeComponent.paintComponent(image);
                        //截图
                        image = image.getSubimage(0, 0, imageSize.width - 25, imageSize.height);

                        try {
                            // 输出图像  
                            ImageIO.write(image, "jpg", new File(fileName));

                        } catch (IOException ex) {
                            ex.printStackTrace();
                        }

                    } finally {
                        //  退出操作  :释放线程
                        NativeInterface.close();
                        semp.release();
                    }

                }
            }
        });
        return webBrowserPanel;
    }
}
service调用:
private String createImage(final String htmlStr, final Semaphore semaphore) {
        
        final String fileName = FileUtils.getNewFileName("jpg");
        
        NativeInterface.open();
        UIUtils.setPreferredLookAndFeel();
        SwingUtilities.invokeLater(new Runnable() {

            public void run() {
                    // SWT组件转Swing组件,不初始化父窗体将无法启动webBrowser  
                    JFrame frame = new JFrame();
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    // 加载指定页面
                frame.getContentPane().add(DJNativeSwingUtils.createContent(htmlStr, fileName, semaphore),
                        BorderLayout.CENTER);
                    // 仅初始化,但不显示  
                    frame.invalidate();
                    frame.pack();
                    frame.setVisible(false);
            }
        });
        // 在MAC上使用时,因为MAC不支持双进程,仅支持进程内模式,调用此方法进行事件调度。windows和Linux可以忽略此事件调度
        //NativeInterface.runEventPump();
        return new File(fileName).getAbsolutePath();
    }
 private int fillPicture(HSSFSheet sheet, Report report, int startRow) throws IOException {
        if(null == weekly.getMileSchedule()){
            return startRow + 1;
        }
        // 将高度设置为图片的高度
        HSSFRow pictureRow = sheet.getRow(startRow);
        pictureRow.setHeightInPoints(162);
        String htmlStr = this.createHtml(report);
        String imagePath = null;
        final Semaphore semp = new Semaphore(1);//设置信号量
       try {
            semp.acquire();
            // 子线程生成图片
            imagePath = this.createImage(htmlStr, semp);
            // 等待子线程释放信号量
            semp.acquire();
        } catch (InterruptedException e) {
            LOG.error("", e);
        } finally {
            semp.release();
        }

        try {
            ExcelExportUtils.insertPicture(sheet, startRow, (short) 0, (short) 15, imagePath);
        } catch (Exception e) {
            e.printStackTrace();
       } finally {
            // delete 文件
            new File(imagePath).delete();
        }
        return ++startRow;
    }

windows 下截图正常,Linux下异常,Linux下必须安装Mollizia内核的浏览器,在服务器上安装了一个Firefox后,也必须安装图形界面,刚开始采用安装虚拟x-server,但是在CentOS 下安装各种依赖,尝试安装图形界面后tomcat也必须在图形界面下启动才能正常截图,后废弃此种方式,采用java原生绘图方式,下一篇博文介绍




共有 人打赏支持
粉丝 8
博文 49
码字总数 30643
×
核桃白果
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: