隨筆-23  評(píng)論-0  文章-5  trackbacks-0

          今天看到某網(wǎng)友關(guān)于“如何以Java實(shí)現(xiàn)網(wǎng)頁(yè)截圖技術(shù)”的咨詢帖,由于出現(xiàn)該咨詢的地點(diǎn)非常不適合較長(zhǎng)回復(fù),故以博文形式回答。

           

          事實(shí)上,如果您想以Java實(shí)現(xiàn)網(wǎng)頁(yè)截圖,也就是“輸入一段網(wǎng)址,幾秒鐘過(guò)后就能截取一張網(wǎng)頁(yè)縮略圖”的效果。那么,您至少有3種方式可以選擇。

           

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

           

          方法詳解:該方法利用Robat提供的強(qiáng)大桌面操作能力,硬性調(diào)用瀏覽器打開(kāi)指定網(wǎng)頁(yè),并將網(wǎng)頁(yè)信息保存到本地。

           

          優(yōu)勢(shì):簡(jiǎn)單易用,不需要任何第三方插件。

           

          缺點(diǎn):不能同時(shí)處理大量數(shù)據(jù),技術(shù)含量過(guò)低,屬于應(yīng)急型技巧。

           

          實(shí)現(xiàn)方法:使用如下代碼即可


           

           

          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、最常規(guī)的方式——利用JNI,調(diào)用第三方C/C++組件

          方法詳解:目前來(lái)講,Java領(lǐng)域?qū)τ诰W(wǎng)頁(yè)截圖組件的開(kāi)發(fā)明顯不足(商機(jī)?),當(dāng)您需要完成此種操作時(shí),算得上碰到了Java的軟肋。但是,眾所周知Java也擁有強(qiáng)大的JNI能力,可以輕易將C/C++開(kāi)發(fā)的同類組件引為己用。

          優(yōu)勢(shì):實(shí)現(xiàn)簡(jiǎn)單,只需要封裝對(duì)應(yīng)的DLL文件,就可以讓Java實(shí)現(xiàn)同類功能。

           

          劣勢(shì):同其他JNI實(shí)現(xiàn)一樣,在跨平臺(tái)時(shí)存在隱患,而且您的程序?qū)⒉辉賹儆诩僇ava應(yīng)用。

           

          實(shí)現(xiàn)方法:可參見(jiàn)此用例,具體封裝何種C/C++組件請(qǐng)自行選擇。

           

          PS:示例來(lái)源于ACA HTML to Image Converter項(xiàng)目(http://www.acasystems.com/en/web-thumb-activex/faq-convert-html-to-image-in-java.htm ),這是一個(gè)收費(fèi)的HTML轉(zhuǎn)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部分的實(shí)現(xiàn):

           

           

           

          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、最扎實(shí)的方法——自行解析HTML標(biāo)記,并將其圖像化

           

          方法詳解:眾所周知,HTML之所以在瀏覽器中以具體的網(wǎng)頁(yè)格式出現(xiàn),并非服務(wù)器端傳了一整個(gè)應(yīng)用到客戶端,而是源自于瀏覽器對(duì)于客戶端自行解析的結(jié)果。因此,只要我們將對(duì)應(yīng)的解析一一實(shí)現(xiàn),那么將網(wǎng)頁(yè)圖形化,就將不是什么難事。


          優(yōu)勢(shì):純Java實(shí)現(xiàn),一勞永逸,一旦開(kāi)發(fā)完成則永遠(yuǎn)通用,而且有一定的商用價(jià)值。

           

          劣勢(shì):開(kāi)發(fā)費(fèi)時(shí),且需要針對(duì)不同語(yǔ)法做精確分析,才能保證輸出的基本正確。尤其在涉及到JavaScript解析時(shí),難度將尤其增大。

           

          實(shí)現(xiàn)方法:目前尚無(wú)具體案例可供參考。但是,由于Java有jdic之類的瀏覽器項(xiàng)目存在(https://jdic.dev.java.net/ ),而Java圖形界面又屬繪制生成。從理論上說(shuō),我們可以將所有具備Graphics的組件圖形化保存。

           

          而如果自行解析,那么您需要建立HTML解析器(或使用第三方的,萬(wàn)幸Java在這方面的組件很多),了解Java2D機(jī)制,了解何時(shí)該使用drawString繪制文字,何時(shí)又該使用drawImage插入圖片等等。

           


          補(bǔ)充:

           

          這是一個(gè)利用內(nèi)置瀏覽器截圖的示例,使用了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腳本獲得網(wǎng)頁(yè)全屏后大小   
          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組件請(qǐng)于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.             // 監(jiān)聽(tīng)加載進(jìn)度   
          69.             public void loadingProgressChanged(WebBrowserEvent e) {  
          70.                 // 當(dāng)加載完畢時(shí)   
          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.                     // 當(dāng)網(wǎng)頁(yè)超出目標(biāo)大小時(shí)   
          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組件轉(zhuǎn)Swing組件,不初始化父窗體將無(wú)法啟動(dòng)webBrowser   
          125.                 JFrame frame = new JFrame("以DJ組件保存指定網(wǎng)頁(yè)截圖");  
          126.                 // 加載指定頁(yè)面,最大保存為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 閱讀(439) 評(píng)論(0)  編輯  收藏 所屬分類: JAVA基礎(chǔ)類

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 玛多县| 富蕴县| 浦北县| 西昌市| 合山市| 五大连池市| 正蓝旗| 江永县| 拜泉县| 邵阳县| 天长市| 晋宁县| 镇安县| 荔波县| 和硕县| 乌兰浩特市| 霍林郭勒市| 鄂托克旗| 丰县| 延庆县| 伊宁市| 宁远县| 长汀县| 长治县| 育儿| 登封市| 莱州市| 河北区| 福泉市| 安溪县| 九龙城区| 建始县| 桑日县| 图们市| 越西县| 南康市| 郸城县| 吴川市| 阳泉市| 涿州市| 绩溪县|