隨筆-23  評論-0  文章-5  trackbacks-0

          今天看到某網友關于“如何以Java實現網頁截圖技術”的咨詢帖,由于出現該咨詢的地點非常不適合較長回復,故以博文形式回答。

           

          事實上,如果您想以Java實現網頁截圖,也就是“輸入一段網址,幾秒鐘過后就能截取一張網頁縮略圖”的效果。那么,您至少有3種方式可以選擇。

           

          1、最直接的方式——使用Robot

           

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

           

          優勢:簡單易用,不需要任何第三方插件。

           

          缺點:不能同時處理大量數據,技術含量過低,屬于應急型技巧。

           

          實現方法:使用如下代碼即可


           

           

          1. public static void main(String[] args) throws MalformedURLException,  
          2.         IOException, URISyntaxException, AWTException {  
          3.     //此方法僅適用于JdK1.6及以上版本   
          4.     Desktop.getDesktop().browse(  
          5.             new URL("http://google.com/intl/en/").toURI());  
          6.     Robot robot = new Robot();  
          7.     robot.delay(10000);  
          8.     Dimension d = new Dimension(Toolkit.getDefaultToolkit().getScreenSize());  
          9.     int width = (int) d.getWidth();  
          10.     int height = (int) d.getHeight();  
          11.     //最大化瀏覽器   
          12.     robot.keyRelease(KeyEvent.VK_F11);  
          13.     robot.delay(2000);  
          14.     Image image = robot.createScreenCapture(new Rectangle(00, width,  
          15.             height));  
          16.     BufferedImage bi = new BufferedImage(width, height,  
          17.             BufferedImage.TYPE_INT_RGB);  
          18.     Graphics g = bi.createGraphics();  
          19.     g.drawImage(image, 00, width, height, null);  
          20.     //保存圖片   
          21.     ImageIO.write(bi, "jpg"new File("google.jpg"));  
          22. }  

           

           

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

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

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

           

          劣勢:同其他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封裝:

           

           

           

          1. import sun.awt.*;  
          2. import java.awt.*;  
          3. import javax.swing.*;  
          4. import java.awt.event.*;  
          5. import java.awt.*;  
          6. import java.awt.peer.*;  
          7. public class Snap  
          8. {  
          9.   static  
          10.   {  
          11.     System.loadLibrary("Snap");  
          12.   }  
          13.   public static void main( String[] argv )  
          14.   {  
          15.     Snap t_xSnap = new Snap();  
          16.     t_xSnap.Start("http://www.google.com""snapshot-google.png");  
          17.   }  
          18.   public native void Start(String pi_strURL, String pi_strImageName);  
          19. }  

           

           

          CPP部分的實現:

           

           

           

          1. #include <windows.h>  
          2. #include <atlbase.h>  
          3. #include "snap.h"  
          4. #pragma comment(lib,"atl.lib")  
          5. #import "./../../acawebthumb.dll" no_namespace  
          6. JNIEXPORT void JNICALL Java_Snap_Start(JNIEnv *pEnv, jobject, jstring pi_strUrl, jstring pi_strFileName)  
          7. {  
          8.   CoInitialize(0);  
          9.   _bstr_t t_strUrl = pEnv->GetStringUTFChars(pi_strUrl, 0);  
          10.   _bstr_t t_strFileName = pEnv->GetStringUTFChars(pi_strFileName, 0);      
          11.   IThumbMakerPtr HTML_Converter = NULL;  
          12.   HRESULT hr = HTML_Converter.CreateInstance(L"ACAWebThumb.ThumbMaker");      
          13.   if (SUCCEEDED(hr))  
          14.   {   
          15.     HTML_Converter->SetURL(t_strUrl);  
          16.     if ( 0 == HTML_Converter->StartSnap() )  
          17.       HTML_Converter->SaveImage(t_strFileName);  
          18.   }  
          19.   if (HTML_Converter)  
          20.     HTML_Converter.Release();  
          21.   CoUninitialize();           
          22. }  

           

           

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

           

          00


          3、最扎實的方法——自行解析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

           

           

           

           

          1. import java.awt.BorderLayout;  
          2. import java.awt.Dimension;  
          3. import java.awt.FlowLayout;  
          4. import java.awt.image.BufferedImage;  
          5. import java.io.File;  
          6. import java.io.IOException;  
          7. import javax.imageio.ImageIO;  
          8. import javax.swing.JFrame;  
          9. import javax.swing.JPanel;  
          10. import javax.swing.SwingUtilities;  
          11. import chrriis.dj.nativeswing.swtimpl.NativeComponent;  
          12. import chrriis.dj.nativeswing.swtimpl.NativeInterface;  
          13. import chrriis.dj.nativeswing.swtimpl.components.JWebBrowser;  
          14. import chrriis.dj.nativeswing.swtimpl.components.WebBrowserAdapter;  
          15. import chrriis.dj.nativeswing.swtimpl.components.WebBrowserEvent;  
          16. public class Main extends JPanel {  
          17.     /** 
          18.      *  
          19.      */  
          20.     private static final long serialVersionUID = 1L;  
          21.     // 行分隔符   
          22.     final static public String LS = System.getProperty("line.separator""/n");  
          23.     // 文件分割符   
          24.     final static public String FS = System.getProperty("file.separator""http://");  
          25.     //以javascript腳本獲得網頁全屏后大小   
          26.     final static StringBuffer jsDimension;  
          27.       
          28.     static {  
          29.         jsDimension = new StringBuffer();  
          30.         jsDimension.append("var width = 0;").append(LS);  
          31.         jsDimension.append("var height = 0;").append(LS);  
          32.         jsDimension.append("if(document.documentElement) {").append(LS);  
          33.         jsDimension.append(  
          34.                         "  width = Math.max(width, document.documentElement.scrollWidth);")  
          35.                 .append(LS);  
          36.         jsDimension.append(  
          37.                         "  height = Math.max(height, document.documentElement.scrollHeight);")  
          38.                 .append(LS);  
          39.         jsDimension.append("}").append(LS);  
          40.         jsDimension.append("if(self.innerWidth) {").append(LS);  
          41.         jsDimension.append("  width = Math.max(width, self.innerWidth);")  
          42.                 .append(LS);  
          43.         jsDimension.append("  height = Math.max(height, self.innerHeight);")  
          44.                 .append(LS);  
          45.         jsDimension.append("}").append(LS);  
          46.         jsDimension.append("if(document.body.scrollWidth) {").append(LS);  
          47.         jsDimension.append(  
          48.                 "  width = Math.max(width, document.body.scrollWidth);")  
          49.                 .append(LS);  
          50.         jsDimension.append(  
          51.                 "  height = Math.max(height, document.body.scrollHeight);")  
          52.                 .append(LS);  
          53.         jsDimension.append("}").append(LS);  
          54.         jsDimension.append("return width + ':' + height;");  
          55.     }  
          56.   //DJNativeSwing組件請于http://djproject.sourceforge.net/main/index.html下載   
          57.     public Main(final String url, final int maxWidth, final int maxHeight) {  
          58.         super(new BorderLayout());  
          59.         JPanel webBrowserPanel = new JPanel(new BorderLayout());  
          60.         final String fileName = System.currentTimeMillis() + ".jpg";  
          61.         final JWebBrowser webBrowser = new JWebBrowser(null);  
          62.         webBrowser.setBarsVisible(false);  
          63.         webBrowser.navigate(url);  
          64.         webBrowserPanel.add(webBrowser, BorderLayout.CENTER);  
          65.         add(webBrowserPanel, BorderLayout.CENTER);  
          66.         JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 44));  
          67.         webBrowser.addWebBrowserListener(new WebBrowserAdapter() {  
          68.             // 監聽加載進度   
          69.             public void loadingProgressChanged(WebBrowserEvent e) {  
          70.                 // 當加載完畢時   
          71.                 if (e.getWebBrowser().getLoadingProgress() == 100) {  
          72.                     String result = (String) webBrowser  
          73.                             .executeJavascriptWithResult(jsDimension.toString());  
          74.                     int index = result == null ? -1 : result.indexOf(":");  
          75.                     NativeComponent nativeComponent = webBrowser  
          76.                             .getNativeComponent();  
          77.                     Dimension originalSize = nativeComponent.getSize();  
          78.                     Dimension imageSize = new Dimension(Integer.parseInt(result  
          79.                             .substring(0, index)), Integer.parseInt(result  
          80.                             .substring(index + 1)));  
          81.                     imageSize.width = Math.max(originalSize.width,  
          82.                             imageSize.width + 50);  
          83.                     imageSize.height = Math.max(originalSize.height,  
          84.                             imageSize.height + 50);  
          85.                     nativeComponent.setSize(imageSize);  
          86.                     BufferedImage image = new BufferedImage(imageSize.width,  
          87.                             imageSize.height, BufferedImage.TYPE_INT_RGB);  
          88.                     nativeComponent.paintComponent(image);  
          89.                     nativeComponent.setSize(originalSize);  
          90.                     // 當網頁超出目標大小時   
          91.                     if (imageSize.width > maxWidth  
          92.                             || imageSize.height > maxHeight) {  
          93.                         //截圖部分圖形   
          94.                         image = image.getSubimage(00, maxWidth, maxHeight);  
          95.                         /*此部分為使用縮略圖 
          96.                         int width = image.getWidth(), height = image 
          97.                             .getHeight(); 
          98.                          AffineTransform tx = new AffineTransform(); 
          99.                         tx.scale((double) maxWidth / width, (double) maxHeight 
          100.                                 / height); 
          101.                         AffineTransformOp op = new AffineTransformOp(tx, 
          102.                                 AffineTransformOp.TYPE_NEAREST_NEIGHBOR); 
          103.                         //縮小 
          104.                         image = op.filter(image, null);*/  
          105.                     }  
          106.                     try {  
          107.                         // 輸出圖像   
          108.                         ImageIO.write(image, "jpg"new File(fileName));  
          109.                     } catch (IOException ex) {  
          110.                         ex.printStackTrace();  
          111.                     }  
          112.                     // 退出操作   
          113.                     System.exit(0);  
          114.                 }  
          115.             }  
          116.         }  
          117.         );  
          118.         add(panel, BorderLayout.SOUTH);  
          119.     }  
          120.     public static void main(String[] args) {  
          121.         NativeInterface.open();  
          122.         SwingUtilities.invokeLater(new Runnable() {  
          123.             public void run() {  
          124.                 // SWT組件轉Swing組件,不初始化父窗體將無法啟動webBrowser   
          125.                 JFrame frame = new JFrame("以DJ組件保存指定網頁截圖");  
          126.                 // 加載指定頁面,最大保存為640x480的截圖   
          127.                 frame.getContentPane().add(  
          128.                         new Main("http://blog.csdn.net/cping1982"640480),  
          129.                         BorderLayout.CENTER);  
          130.                 frame.setSize(800600);  
          131.                 // 僅初始化,但不顯示   
          132.                 frame.invalidate();  
          133.                 frame.pack();  
          134.                 frame.setVisible(false);  
          135.             }  
          136.         });  
          137.         NativeInterface.runEventPump();  
          138.     }  
          139. }  

           

           

           

          posted on 2015-01-21 12:00 ForMeBlog 閱讀(443) 評論(0)  編輯  收藏 所屬分類: JAVA基礎類

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 太保市| 德化县| 郁南县| 新晃| 故城县| 阳信县| 广水市| 延安市| 庄浪县| 通化市| 舟曲县| 馆陶县| 海丰县| 民乐县| 游戏| 屏边| 新密市| 安丘市| 浠水县| 桐城市| 田林县| 九江县| 临沭县| 廊坊市| 迁西县| 勐海县| 秭归县| 海林市| 龙井市| 右玉县| 天水市| 修水县| 莎车县| 濉溪县| 南木林县| 淄博市| 尉犁县| 兴隆县| 南宁市| 山阳县| 庐江县|