如何以Java實現網頁截圖技術

今天看到某網友關於「如何以Java實現網頁截圖技術」的諮詢帖,因爲出現該諮詢的地點很是不適合較長回覆,故以博文形式回答。javascript

 

事實上,若是您想以Java實現網頁截圖,也就是「輸入一段網址,幾秒鐘事後就能截取一張網頁縮略圖」的效果。那麼,您至少有3種方式能夠選擇。html

 

一、最直接的方式——使用Robotjava

 

方法詳解:該方法利用Robat提供的強大桌面操做能力,硬性調用瀏覽器打開指定網頁,並將網頁信息保存到本地。web

 

優點:簡單易用,不須要任何第三方插件。windows

 

缺點:不能同時處理大量數據,技術含量太低,屬於應急型技巧。瀏覽器

 

實現方法:使用以下代碼便可。服務器

public static void main(String[] args) throws MalformedURLException,  
        IOException, URISyntaxException, AWTException {  
    //此方法僅適用於JdK1.6及以上版本  
    Desktop.getDesktop().browse(  
            new URL("http://google.com/intl/en/").toURI());  
    Robot robot = new Robot();  
    robot.delay(10000);  
    Dimension d = new Dimension(Toolkit.getDefaultToolkit().getScreenSize());  
    int width = (int) d.getWidth();  
    int height = (int) d.getHeight();  
    //最大化瀏覽器  
    robot.keyRelease(KeyEvent.VK_F11);  
    robot.delay(2000);  
    Image image = robot.createScreenCapture(new Rectangle(0, 0, width,  
            height));  
    BufferedImage bi = new BufferedImage(width, height,  
            BufferedImage.TYPE_INT_RGB);  
    Graphics g = bi.createGraphics();  
    g.drawImage(image, 0, 0, width, height, null);  
    //保存圖片  
    ImageIO.write(bi, "jpg", new File("google.jpg"));  
}

二、最常規的方式——利用JNI,調用第三方C/C++組件app

 

方法詳解:目前來說,Java領域對於網頁截圖組件的開發明顯不足(商機?),當您須要完成此種操做時,算得上碰到了Java的軟肋。可是,衆所周知Java也擁有強大的JNI能力,能夠輕易將C/C++開發的同類組件引爲己用。google

優點:實現簡單,只須要封裝對應的DLL文件,就可讓Java實現同類功能。url

 

劣勢:同其餘JNI實現同樣,在跨平臺時存在隱患,並且您的程序將再也不屬於純Java應用。

 

實現方法:可參見此用例,具體封裝何種C/C++組件請自行選擇。

 

PS:示例來源於ACA HTML to Image Converter項目(http://www.acasystems.com/en/web-thumb-activex/faq-convert-html-to-image-in-java.htm ),這是一個收費的HTML轉Image第三方組件,但封裝方式在Java中大同小異。

 

引用JNI封裝:

import sun.awt.*;  
import java.awt.*;  
import javax.swing.*;  
import java.awt.event.*;  
import java.awt.*;  
import java.awt.peer.*;  
public class Snap  
{  
  static  
  {  
    System.loadLibrary("Snap");  
  }  
  public static void main( String[] argv )  
  {  
    Snap t_xSnap = new Snap();  
    t_xSnap.Start("http://www.google.com", "snapshot-google.png");  
  }  
  public native void Start(String pi_strURL, String pi_strImageName);  
}

CPP部分的實現:

#include <windows.h>  
#include <atlbase.h>  
#include "snap.h"  
#pragma comment(lib,"atl.lib")  
#import "./../../acawebthumb.dll" no_namespace  
JNIEXPORT void JNICALL Java_Snap_Start(JNIEnv *pEnv, jobject, jstring pi_strUrl, jstring pi_strFileName)  
{  
  CoInitialize(0);  
  _bstr_t t_strUrl = pEnv->GetStringUTFChars(pi_strUrl, 0);  
  _bstr_t t_strFileName = pEnv->GetStringUTFChars(pi_strFileName, 0);      
  IThumbMakerPtr HTML_Converter = NULL;  
  HRESULT hr = HTML_Converter.CreateInstance(L"ACAWebThumb.ThumbMaker");      
  if (SUCCEEDED(hr))  
  {   
    HTML_Converter->SetURL(t_strUrl);  
    if ( 0 == HTML_Converter->StartSnap() )  
      HTML_Converter->SaveImage(t_strFileName);  
  }  
  if (HTML_Converter)  
    HTML_Converter.Release();  
  CoUninitialize();           
}

以該組件圖像化yahoo界面的效果圖:

 

00


三、最紮實的方法——自行解析HTML標記,並將其圖像化

 

方法詳解:衆所周知,HTML之因此在瀏覽器中以具體的網頁格式出現,並不是服務器端傳了一整個應用到客戶端,而是源自於瀏覽器對於客戶端自行解析的結果。所以,只要咱們將對應的解析一一實現,那麼將網頁圖形化,就將不是什麼難事。


優點:純Java實現,一勞永逸,一旦開發完成則永遠通用,並且有必定的商用價值。

 

劣勢:開發費時,且須要針對不一樣語法作精確分析,才能保證輸出的基本正確。尤爲在涉及到JavaScript解析時,難度將尤爲增大。

 

實現方法:目前尚無具體案例可供參考。可是,因爲Java有jdic之類的瀏覽器項目存在(https://jdic.dev.java.net/),而Java圖形界面又屬繪製生成。從理論上說,咱們能夠將全部具有Graphics的組件圖形化保存。

 

而若是自行解析,那麼您須要創建HTML解析器(或使用第三方的,萬幸Java在這方面的組件不少),瞭解Java2D機制,瞭解什麼時候該使用drawString繪製文字,什麼時候又該使用drawImage插入圖片等等。

 


補充:

 

這是一個利用內置瀏覽器截圖的示例,使用了DJNativeSwing組件。

 

示例工程下載地址(Eclipse工程,含lib):http://greenvm.googlecode.com/files/Screenshot.7z

import java.awt.BorderLayout;  
import java.awt.Dimension;  
import java.awt.FlowLayout;  
import java.awt.image.BufferedImage;  
import java.io.File;  
import java.io.IOException;  
import javax.imageio.ImageIO;  
import javax.swing.JFrame;  
import javax.swing.JPanel;  
import javax.swing.SwingUtilities;  
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 Main extends JPanel {  
    /** 
     *  
     */  
    private static final long serialVersionUID = 1L;  
    // 行分隔符  
    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;");  
    }  
  //DJNativeSwing組件請於http://djproject.sourceforge.net/main/index.html下載  
    public Main(final String url, final int maxWidth, final int maxHeight) {  
        super(new BorderLayout());  
        JPanel webBrowserPanel = new JPanel(new BorderLayout());  
        final String fileName = System.currentTimeMillis() + ".jpg";  
        final JWebBrowser webBrowser = new JWebBrowser(null);  
        webBrowser.setBarsVisible(false);  
        webBrowser.navigate(url);  
        webBrowserPanel.add(webBrowser, BorderLayout.CENTER);  
        add(webBrowserPanel, BorderLayout.CENTER);  
        JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 4, 4));  
        webBrowser.addWebBrowserListener(new WebBrowserAdapter() {  
            // 監聽加載進度  
            public void loadingProgressChanged(WebBrowserEvent e) {  
                // 當加載完畢時  
                if (e.getWebBrowser().getLoadingProgress() == 100) {  
                    String result = (String) webBrowser  
                            .executeJavascriptWithResult(jsDimension.toString());  
                    int index = result == null ? -1 : result.indexOf(":");  
                    NativeComponent nativeComponent = webBrowser  
                            .getNativeComponent();  
                    Dimension originalSize = nativeComponent.getSize();  
                    Dimension imageSize = new Dimension(Integer.parseInt(result  
                            .substring(0, index)), Integer.parseInt(result  
                            .substring(index + 1)));  
                    imageSize.width = Math.max(originalSize.width,  
                            imageSize.width + 50);  
                    imageSize.height = Math.max(originalSize.height,  
                            imageSize.height + 50);  
                    nativeComponent.setSize(imageSize);  
                    BufferedImage image = new BufferedImage(imageSize.width,  
                            imageSize.height, BufferedImage.TYPE_INT_RGB);  
                    nativeComponent.paintComponent(image);  
                    nativeComponent.setSize(originalSize);  
                    // 當網頁超出目標大小時  
                    if (imageSize.width > maxWidth  
                            || imageSize.height > maxHeight) {  
                        //截圖部分圖形  
                        image = image.getSubimage(0, 0, maxWidth, maxHeight);  
                        /*此部分爲使用縮略圖 
                        int width = image.getWidth(), height = image 
                            .getHeight(); 
                         AffineTransform tx = new AffineTransform(); 
                        tx.scale((double) maxWidth / width, (double) maxHeight 
                                / height); 
                        AffineTransformOp op = new AffineTransformOp(tx, 
                                AffineTransformOp.TYPE_NEAREST_NEIGHBOR); 
                        //縮小 
                        image = op.filter(image, null);*/  
                    }  
                    try {  
                        // 輸出圖像  
                        ImageIO.write(image, "jpg", new File(fileName));  
                    } catch (IOException ex) {  
                        ex.printStackTrace();  
                    }  
                    // 退出操做  
                    System.exit(0);  
                }  
            }  
        }  
        );  
        add(panel, BorderLayout.SOUTH);  
    }  
    public static void main(String[] args) {  
        NativeInterface.open();  
        SwingUtilities.invokeLater(new Runnable() {  
            public void run() {  
                // SWT組件轉Swing組件,不初始化父窗體將沒法啓動webBrowser  
                JFrame frame = new JFrame("以DJ組件保存指定網頁截圖");  
                // 加載指定頁面,最大保存爲640x480的截圖  
                frame.getContentPane().add(  
                        new Main("http://blog.csdn.net/cping1982", 640, 480),  
                        BorderLayout.CENTER);  
                frame.setSize(800, 600);  
                // 僅初始化,但不顯示  
                frame.invalidate();  
                frame.pack();  
                frame.setVisible(false);  
            }  
        });  
        NativeInterface.runEventPump();  
    }  
}
相關文章
相關標籤/搜索