国产成人精品亚洲777人妖,欧美日韩精品一区视频,最新亚洲国产,国产乱码精品一区二区亚洲

您的位置:首頁技術(shù)文章
文章詳情頁

捕獲屏幕-編寫一個(gè)基于Java Robot類的屏幕捕獲工具

瀏覽:97日期:2024-06-05 17:05:22
內(nèi)容: 摘要Java Fun and Games(Java娛樂和游戲)提供了通過Java的Robot類捕獲主屏幕設(shè)備的功能,并且可以將整個(gè)屏幕或者選定的一部分保存為jpeg文件。注意:現(xiàn)在你可以使用在線開發(fā)工具DevSquare編譯和運(yùn)行Java Fun and Games中提供的applet。DevSquare入門請(qǐng)閱讀資源中提供的用戶向?qū)Аava.awt.Robot類為娛樂功能提供了一些有用的方法。其中一個(gè)包括了建立屏幕捕獲工具的功能。Java Fun and Games給出了一個(gè)使用Robot捕獲主屏幕設(shè)備內(nèi)容的工具。這一部分從我以前的幾部分中分離出來了,因?yàn)樗⒉皇羌性赼pplet實(shí)現(xiàn)上。這篇文章以Swing應(yīng)用的形式實(shí)現(xiàn)了屏幕捕獲工具。從GUI觀點(diǎn)介紹完這個(gè)應(yīng)用之后,我將解釋實(shí)現(xiàn)的關(guān)鍵部分。版權(quán)聲明:任何獲得Matrix授權(quán)的網(wǎng)站,轉(zhuǎn)載時(shí)請(qǐng)務(wù)必保留以下作者信息和鏈接作者:Jeff Friesen;mydeman原文:http://www.javaworld.com/javaworld/jw-04-2006/jw-0424-funandgames.htmlMatrix:http://www.matrix.org.cn/resource/article/2006-09-15/Java+Robot_f9598e5e-445b-11db-af0b-0f766c077b58.html關(guān)鍵字:Java Robot;捕獲屏幕應(yīng)用程序GUI我的Capture程序提供了一個(gè)圖形用戶界面(GUI,Graphic User Interface),通過它你可以選擇捕獲圖像的一部分,修剪圖像到選擇內(nèi)容,以及將結(jié)果圖像保存為jpeg文件。圖1顯示了包含一個(gè)捕獲示例的Capture的GUI。 圖 1. 紅白相間的虛線所形成的矩形表示了當(dāng)前選中的區(qū)域Capture的GUI由菜單欄和顯示捕獲圖像的可滾動(dòng)窗口組成。如圖1所示,選擇矩形(通過拖拽鼠標(biāo))表示了捕獲圖形的一個(gè)矩形區(qū)域。菜單欄提供了File和Capture菜單:---File提供Save As…(另存為)和Exit(退出)菜單項(xiàng),可以通過文件選擇器保存當(dāng)前捕獲為一個(gè)jpeg文件,和退出Capture。盡管你可以直接選擇這些菜單項(xiàng),但是你會(huì)發(fā)現(xiàn)使用它們的快捷鍵Alt-S和Alt-X會(huì)更加方便。---Capture提供Capture(捕獲)和Crop(修剪)菜單項(xiàng),可以捕獲當(dāng)前主屏幕設(shè)備的內(nèi)容和修剪一個(gè)圖像為選擇矩形的內(nèi)容。和File菜單項(xiàng)一樣,這些菜單項(xiàng)也有它們自己的方便的快捷鍵:Capture(Alt-C)和Crop(Alt-K)。應(yīng)用實(shí)現(xiàn)有三個(gè)源文件來描述Capture的GUI:Capture.java(啟動(dòng)應(yīng)用程序和構(gòu)造GUI)、ImageArea.java( 描述了一個(gè)用來顯示捕獲的內(nèi)容的組件,你也可以在其中選擇捕獲的一部分或修剪捕獲的內(nèi)容)和ImageFileFilter.java(限制文件選擇器的選擇是文件夾和jpeg文件)。在這一部分下面,我從這些源文件中摘錄了一些代碼片斷來說明Capture的工作過程。機(jī)器人屏幕捕獲為了使用Robot類捕獲屏幕,Capture必須先創(chuàng)建一個(gè)Robot對(duì)象。Capture類的public static void main(String [] args)方法嘗試調(diào)用Robot的public Robot()構(gòu)造函數(shù)來創(chuàng)建這個(gè)對(duì)象。如果創(chuàng)建成功,就會(huì)返回一個(gè)針對(duì)主屏幕設(shè)備坐標(biāo)系的Robot引用。如果平臺(tái)不支持低級(jí)控制(在沒有屏幕設(shè)備的環(huán)境這是成立的),將會(huì)拋出java.awt.AWTException。如果平臺(tái)不允許創(chuàng)建Robot對(duì)象就會(huì)拋出java.lang.SecurityException。但愿你不會(huì)再遇到其他異常。假設(shè)Robot對(duì)象已被創(chuàng)建,main()調(diào)用Capture類的構(gòu)造函數(shù)創(chuàng)建一個(gè)GUI。作為GUI創(chuàng)建的一部分,Capture通過調(diào)用dimScreenSize = Toolkit.getDefaultToolkit().getScreenSize();獲得主屏幕設(shè)備的尺寸。因?yàn)橛脕盹@示屏幕捕獲的內(nèi)容的Robot的public BufferedImage createScreenCapture(Rectangle screenRect)方法,需要一個(gè)java.awt.Rectangle參數(shù),所以構(gòu)造函數(shù)通過rectScreenSize = new Rectangle(dimScreenSize);將java.awt.Dimension對(duì)象轉(zhuǎn)換為一個(gè)Rectangle對(duì)象。當(dāng)Capture菜單項(xiàng)的動(dòng)作監(jiān)聽器被調(diào)用時(shí),下面摘錄的Capture.java片斷就會(huì)調(diào)用createScreenCapture()。// Hide Capture's main window so that it does not appear in// the screen capture.setVisible (false);// Perform the screen capture.BufferedImage biScreen;biScreen = robot.createScreenCapture (rectScreenSize);// Show Capture's main window for continued user interaction.setVisible (true);// Update ImageArea component with the new image and adjust// the scrollbars.ia.setImage (biScreen);jsp.getHorizontalScrollBar ().setValue (0);jsp.getVerticalScrollBar ().setValue (0);你不希望Capture的GUI遮住你想要捕獲的任何內(nèi)容。這就是為什么代碼中隱藏Capture GUI優(yōu)先級(jí)高于完成捕獲。在獲取了包含屏幕像素copy的java.awt.image.BufferedImage后,代碼片斷顯示出GUI,并且通過圖像區(qū)域組件顯示出BufferedImage的內(nèi)容。子圖像選擇當(dāng)從一個(gè)捕獲的圖像中獲取子圖像時(shí)需要一個(gè)選擇矩形。ImageArea類提供代碼來創(chuàng)建、操作和繪制選擇矩形。如下面摘錄的ImageArea.java所示,這個(gè)類的構(gòu)造函數(shù)以一個(gè)Rectangle實(shí)例創(chuàng)建選擇矩形,創(chuàng)建java.awt.BasicStoke和java.awt.GradientPaint對(duì)象定義了矩形的輪廓外觀(保持它與底層圖像分離),注冊(cè)鼠標(biāo)和鼠標(biāo)動(dòng)作監(jiān)聽器讓你能夠操作選擇矩形。// Create a selection Rectangle. It's better to create one Rectangle// here than a Rectangle each time paintComponent() is called, to reduce// unnecessary object creation.rectSelection = new Rectangle ();// Define the stroke for drawing selection rectangle outline.bs = new BasicStroke (5, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 0, new float [] { 12, 12 }, 0);// Define the gradient paint for coloring selection rectangle outline.gp = new GradientPaint (0.0f, 0.0f, Color.red, 1.0f, 1.0f, Color.white, true);// Install a mouse listener that sets things up for a selection drag.MouseListener ml;ml = new MouseAdapter () { public void mousePressed (MouseEvent e) { // When you start Capture, there is no captured image. // Therefore, it makes no sense to try and select a sub-image. // This is the reason for the if (image == null) test. if (image == null) return; destx = srcx = e.getX (); desty = srcy = e.getY (); repaint (); } };addMouseListener (ml);// Install a mouse motion listener to update the selection rectangle// during drag operations.MouseMotionListener mml;mml = new MouseMotionAdapter () { public void mouseDragged (MouseEvent e) { // When you start Capture, there is no captured image. // Therefore, it makes no sense to try and select a // sub-image. This is the reason for the if (image == null) // test. if (image == null) return; destx = e.getX (); desty = e.getY (); repaint (); } };addMouseMotionListener (mml);當(dāng)按下鼠標(biāo)時(shí),鼠標(biāo)事件處理器對(duì)相同的橫向鼠標(biāo)坐標(biāo)設(shè)置destx和srcx,對(duì)于縱向鼠標(biāo)坐標(biāo)亦是如此。源變量和目標(biāo)變量同樣表示哪些顯示的選擇矩形應(yīng)該被移除了。它通過調(diào)用repaint(),導(dǎo)致public void paintComponent(Graphics g)被調(diào)用。這個(gè)方法將srcx和srcy分別與destx和desty相比較,如果他們不同,就繪制一個(gè)選擇矩形:// Draw the selection rectangle if present.if (srcx != destx || srcy != desty){ // Compute upper-left and lower-right coordinates for selection // rectangle corners. int x1 = (srcx < destx) ? srcx : destx; int y1 = (srcy < desty) ? srcy : desty; int x2 = (srcx> destx) ? srcx : destx; int y2 = (srcy> desty) ? srcy : desty; // Establish selection rectangle origin. rectSelection.x = x1; rectSelection.y = y1; // Establish selection rectangle extents. rectSelection.width = (x2-x1)+1; rectSelection.height = (y2-y1)+1; // Draw selection rectangle. Graphics2D g2d = (Graphics2D) g; g2d.setStroke (bs); g2d.setPaint (gp); g2d.draw (rectSelection);}在選擇矩形繪制以前,它的左上和右下角必須對(duì)標(biāo)示出來,用來確定矩形的原點(diǎn)和范圍。以至于你可以在不同的方向拖拽出選擇矩形(例如右下或者左上方向),srcx/destx和srcy/desty的最小值表示左上角,相似地,它們的最大值表示右下角。圖像修剪在選擇子圖像后,你想要修剪捕獲的圖像得到子圖像。圖像修剪啟動(dòng)Crop中的菜單項(xiàng)的動(dòng)作監(jiān)聽器,它請(qǐng)求ImageArea將捕獲的圖像修剪為選擇的子圖像。若操作成果,監(jiān)聽器則重置ImageArea的滾動(dòng)條。反之,監(jiān)聽器通過對(duì)話框給出一個(gè)“Out of bounds錯(cuò)誤信息。// Crop ImageArea component and adjust the scrollbars if// cropping succeeds.if (ia.crop ()){ jsp.getHorizontalScrollBar ().setValue (0); jsp.getVerticalScrollBar ().setValue (0);}else showError ('Out of bounds.');因?yàn)樾藜舨僮鞑恢刂肅apture GUI的大小,所以可以同時(shí)看到主窗口的背景和結(jié)果圖像(初始修剪后的)。圖2顯示了選擇圖像的一部分時(shí)還可能選中背景的一部分。 圖 2. 嘗試選擇多于這個(gè)圖像主窗口的背景像素不是捕獲的圖像的一部分;就不可能把它們包含在修剪的圖片內(nèi)。因此,無論何時(shí)把背景像素包含在修剪區(qū)域內(nèi),操作都會(huì)失敗,并且會(huì)給出一個(gè)“Out of bounds錯(cuò)誤信息。修剪操作由ImageArea的public Boolean crop()方法處理。如果完成了修剪或者沒有選擇子圖像(當(dāng)沒有選中內(nèi)容時(shí)調(diào)用這個(gè)方法是非常方便的)該方法(如下所示)返回true。如果在選擇區(qū)域中包含了背景像素則返回false。public boolean crop (){ // There is nothing to crop if the selection rectangle is only a single // point. if (srcx == destx && srcy == desty) return true; // Assume success. boolean succeeded = true; // Compute upper-left and lower-right coordinates for selection rectangle // corners. int x1 = (srcx < destx) ? srcx : destx; int y1 = (srcy < desty) ? srcy : desty; int x2 = (srcx> destx) ? srcx : destx; int y2 = (srcy> desty) ? srcy : desty; // Compute width and height of selection rectangle. int width = (x2-x1)+1; int height = (y2-y1)+1; // Create a buffer to hold cropped image. BufferedImage biCrop = new BufferedImage (width, height, BufferedImage.TYPE_INT_RGB); Graphics2D g2d = biCrop.createGraphics (); // Perform the crop operation. try { BufferedImage bi = (BufferedImage) image; BufferedImage bi2 = bi.getSubimage (x1, y1, width, height); g2d.drawImage (bi2, null, 0, 0); } catch (RasterFormatException e) { succeeded = false; } g2d.dispose (); if (succeeded) setImage (biCrop); // Implicitly remove selection rectangle. else { // Prepare to remove selection rectangle. srcx = destx; srcy = desty; // Explicitly remove selection rectangle. repaint (); } return succeeded;}crop()方法調(diào)用BufferedImage的public BufferedImage getSubimage(int x, int y, int w, int h)方法摘取選擇區(qū)域內(nèi)的子圖像。如果該方法的參數(shù)沒有指定BufferedImage內(nèi)的圖像,它就會(huì)拋出一個(gè)java.awt.image.RasterFormatException,因此就會(huì)返回false。圖像保存Capture允許你把捕獲的圖像保存為一個(gè)jpeg文件。你通過一個(gè)保存文件選擇器指定文件名,選擇器由Capture類的構(gòu)造函數(shù)創(chuàng)建:// Construct a save file-chooser. Initialize the starting directory to// the current directory, do not allow the user to select the 'all files'// filter, and restrict the files that can be selected to those ending// with .jpg or .jpeg extensions.final JFileChooser fcSave = new JFileChooser ();fcSave.setCurrentDirectory (new File (System.getProperty ('user.dir')));fcSave.setAcceptAllFileFilterUsed (false);fcSave.setFileFilter (new ImageFileFilter ());為了限制文件選擇器的選擇是文件夾或者是以.jpg或.jpeg為后綴的文件,就使用了ImageFileFilter類的一個(gè)實(shí)例作為保存時(shí)文件選擇器的文件過濾器。該方法對(duì)于任何非文件夾和后綴名非.jpg/.jpeg的文件都返回false:public boolean accept (File f){ // Allow the user to select directories so that the user can navigate the // file system. if (f.isDirectory ()) return true; // Allow the user to select files ending with a .jpg or a .jpeg // extension. String s = f.getName (); int i = s.lastIndexOf ('.'); if (i> 0 && i < s.length ()-1) { String ext = s.substring (i+1).toLowerCase (); if (ext.equals ('jpg') || ext.equals ('jpeg')) return true; } // Nothing else can be selected. return false;}當(dāng)你選擇了Save As…菜單項(xiàng)時(shí),它的監(jiān)聽器就會(huì)顯示一個(gè)保存文件選擇器。假定你沒有退出選擇器,監(jiān)聽器就會(huì)確保你選擇的文件名是以.jpg或.jpeg為后綴名。繼續(xù),監(jiān)聽器會(huì)確定文件是否存在,這樣你就不會(huì)無意中覆蓋一個(gè)存在的文件。// Present the 'save' file-chooser without any file selected.// If the user cancels this file-chooser, exit this method.fcSave.setSelectedFile (null);if (fcSave.showSaveDialog (Capture.this) != JFileChooser.APPROVE_OPTION) return;// Obtain the selected file. Validate its extension, which // must be .jpg or .jpeg. If extension not present, append// .jpg extension.File file = fcSave.getSelectedFile ();String path = file.getAbsolutePath ().toLowerCase ();if (!path.endsWith ('.jpg') && !path.endsWith ('.jpeg')) file = new File (path += '.jpg');// If the file exists, inform the user, who might not want// to accidentally overwrite an existing file. Exit method// if the user specifies that it is not okay to overwrite// the file. if (file.exists ()){ int choice = JOptionPane. showConfirmDialog (null,'Overwrite file?','Capture',JOptionPane.YES_NO_OPTION); if (choice == JOptionPane.NO_OPTION) return;}如果文件不存在或者你允許覆蓋已經(jīng)存在的文件,監(jiān)聽器就會(huì)將捕獲的內(nèi)容保存為一個(gè)選擇的文件。為了完成這個(gè)任務(wù),監(jiān)聽器使用Java的ImageIO框架選擇一個(gè)jpeg writer,指定文件作為writer的目標(biāo),設(shè)置writer的壓縮品質(zhì)為95%,然后把圖像寫入到文件中。ImageWriter writer = null;ImageOutputStream ios = null;try{ // Obtain a writer based on the jpeg format. Iterator iter; iter = ImageIO.getImageWritersByFormatName ('jpeg'); // Validate existence of writer. if (!iter.hasNext ()) { showError ('Unable to save image to jpeg file type.'); return; } // Extract writer. writer = (ImageWriter) iter.next(); // Configure writer output destination. ios = ImageIO.createImageOutputStream (file); writer.setOutput (ios); // Set jpeg compression quality to 95%. ImageWriteParam iwp = writer.getDefaultWriteParam (); iwp.setCompressionMode (ImageWriteParam.MODE_EXPLICIT); iwp.setCompressionQuality (0.95f); // Write the image. writer.write (null, new IIOImage ((BufferedImage)ia.getImage (), null, null), iwp);}catch (IOException e2){ showError (e2.getMessage ());}finally{ try { // Cleanup. if (ios != null) { ios.flush (); ios.close (); } if (writer != null) writer.dispose (); } catch (IOException e2) { }}讓代碼自己清理一直是一個(gè)不錯(cuò)的主意。我把ImageIO的清理代碼放在了finally子句中,以至于無論是正常結(jié)束還是拋出異常,它都可以執(zhí)行。總結(jié)Capture限制了捕獲的內(nèi)容只能在主屏幕設(shè)備內(nèi)。你可能想增強(qiáng)Capture來捕獲所有附加屏幕設(shè)備(或許是一個(gè)巨大的虛擬屏幕)的內(nèi)容。增強(qiáng)之一,你需要包含下面的代碼,它捕獲所有屏幕的內(nèi)容,將它和Capture.java已經(jīng)存在的代碼集成。GraphicsEnvironment graphenv = GraphicsEnvironment.getLocalGraphicsEnvironment ();GraphicsDevice [] screens = graphenv.getScreenDevices ();BufferedImage [] captures = new BufferedImage [screens.length];for (int i = 0; i < screens.length; i++){ DisplayMode mode = screens [i].getDisplayMode (); Rectangle bounds = new Rectangle (0, 0, mode.getWidth (), mode.getHeight ()); captures [i] = new Robot (screens [i]).createScreenCapture (bounds);}把以上代碼放到Capture菜單項(xiàng)的動(dòng)作監(jiān)聽器內(nèi)。然后先引入代碼創(chuàng)建一個(gè)bigScreen要引用的足夠大的BufferedImage,它可以保存被captures數(shù)組引用的所有BufferedImage內(nèi)容;接著引入代碼把它們的繪制到bigScreen中。Capture現(xiàn)在成為了多屏幕捕獲器就好像是一個(gè)單屏幕捕獲器。關(guān)于作者Jeff Friesen是一個(gè)自由軟件開發(fā)者和教育家,特別是在C、C++和Java技術(shù)領(lǐng)域。資源Matrix中文Java社區(qū):http://www.matrix.org.cn下載文中的代碼文件:http://www.javaworld.com/javaworld/jw-04-2006/games/jw-0424-funandgames.zip你可以使用在線開發(fā)工具DevSquare編譯和運(yùn)行Java Fun And Games中提供的Applet。工具入門請(qǐng)閱讀這篇用戶向?qū)В篽ttp://www.javaworld.com/javaworld/jw-12-2005/jw-devsquare.htmlDevSquare:http://www.devsquare.com/index.html Java, java, J2SE, j2se, J2EE, j2ee, J2ME, j2me, ejb, ejb3, JBOSS, jboss, spring, hibernate, jdo, struts, webwork, ajax, AJAX, mysql, MySQL, Oracle, Weblogic, Websphere, scjp, scjd 摘要Java Fun and Games(Java娛樂和游戲)提供了通過Java的Robot類捕獲主屏幕設(shè)備的功能,并且可以將整個(gè)屏幕或者選定的一部分保存為jpeg文件。注意:現(xiàn)在你可以使用在線開發(fā)工具DevSquare編譯和運(yùn)行Java Fun and Games中提供的applet。DevSquare入門請(qǐng)閱
標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 崇明县| 宝山区| 施甸县| 德兴市| 友谊县| 灵丘县| 偏关县| 宁明县| 河北区| 东平县| 封开县| 灵宝市| 隆昌县| 同江市| 赫章县| 瑞昌市| 左云县| 丽水市| 沂南县| 东平县| 崇阳县| 玛沁县| 南乐县| 迁安市| 龙江县| 迁西县| 莎车县| 沂源县| 青岛市| 南昌县| 修武县| 界首市| 阿尔山市| 泰顺县| 修武县| 合阳县| 博湖县| 夏津县| 佛坪县| 古浪县| 修水县|