




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
Java在多媒體中的應用9.1利用AWT繪圖
這一節中我們主要介紹如何使用Java語言提供的AWT包繪圖。java.awt包中提供了用於繪圖的API,我們通常稱之為2DAPI。不要以為只有設計繪圖程式或遊戲軟體才會用到Java2D,其實Java2D的用途可能遠比你想像的更廣泛。
其實,只要你的程式有GUI,就很可能會用到Java2D。因為AWT和Swing的組件常常無法完全適合我們,這個時候自己繪製一部分的GUI就有絕對的必要。甚至,我們還可以用Java2D來繪製自己的組件。實際上,AWT和Swing組件都是透過Java2D來進行繪製的。Java2DAPI增強了AWT的圖形、文本和圖像功能,可以開發更為強大的用戶介面和新型的Java應用程式。除了更為強大的圖形、字體和圖像API外,Java2DAPI還改進了顏色的定義與複合及對任意幾何形狀和文本的選中檢測,並為印表機和顯示設備提供了統一的繪製模式。Java2DAPI還可以創建高級圖形庫,並可創建圖像和圖形檔讀/寫篩檢程式。當與Java媒體框架(JMF)和其他Java媒體應用程式配合使用時,Java2DAPI還可用來創建和顯示動畫和其他多媒體演示稿。
到底Java2DAPI有多強大?這一點我們可以通過SUNJDK包中提供的例程來瞭解。在命令行窗口下輸入:
c:\>cd\jdk1.2\demo\jfc\Java2Dc:\jdk1.2\demo\jfc\Java2D>java-classpathJava2Demo.jarJava2Demo
或
c:\jdk1.2\demo\jfc\Java2D>appletviewer
java2demo.html
看到了嗎?Java2D神奇的威力!
下麵我們來學習如何使用Java2D繪圖。上面看到的例子雖然功能十分強大,但是它的實現非常複雜。下麵,我們先從簡單一點的入手。從java.awt.Component類(所有窗口對象的基類)繼承的類提供了一個名為paint()的方法,在需要重新繪製組件時,可調用該方法。
paint()方法只有一個參數,該參數是Graphics類的實例。如果在某個繼承了Component的類中覆蓋了該方法,那麼就可以使用該方法來控制在控制區域著何種顏色。例如,下麵的類創建了一個帶有藍背景的面板。例9.1BluePanel.javaimportjava.awt.*;classBluePanelextendsPanel{ publicstaticvoidmain(String[]args) { Framef=newFrame(); BluePanelp=newBluePanel(); f.add(p);f.setSize(300,100); f.setVisible(true);} //Invokedwhenthepanelneedstoberepainted publicvoidpaint(Graphicsg) { //Gettherectanglethatrepresentstheviewablearea //ofthepanel Rectanglerect=g.getClipBounds(); //Setthecontexttopaintinapre-definedcolor g.setColor(Color.blue);//Filltherectanglewiththecurrentcolor g.fillRect(rect.x,rect.y,rect.width,rect.height);}}
程式運行結果如圖9.1所示。圖9.19.2Graphics類的使用java.awt中提供了一系列的類用於繪製圖形。其中,Color類包含了編輯顏色的方法和常量;Font類包含了編輯字體的方法和常量;FontMetrics類包含了獲取字體資訊的方法;Polygon類包含了創建多邊形的方法;Toolkit類提供了從系統獲得圖形資訊的方法,例如可顯示的字體集和螢幕解析度等等;Graphics類包含了繪製字串、線條以及各種幾何圖形的方法。Graphics是一個抽象類,其作用是定義一個真正的工具,用來接受圖形操作。在該類中,有47個公用方法,可以用作顯示圖像和文本、繪製和填充形狀、剪貼圖像操作等等。
9.2.1繪製字串、字元和位元組用於繪製字串、字元和位元組的方法分別為●publicabstractvoiddrawString(Stringstring,intx,inty)在座標(x,y)處以當前字體和顏色繪製指定的字串string。●publicvoiddrawChars(char[]chars,intoffset,intnumber,intx,inty)
在座標(x,y)處以當前字體和顏色繪製指定的一系列字元。chars為要繪製的字元組,offset為位置的座標,number為要繪製的元素個數。●publicvoiddrawBytes(byte[]bytes,intoffset,intnumber,intx,inty)
在座標(x,y)處以當前字體和顏色繪製指定的一系列位元組。bytes為要繪製的位元組數組,offset為位置的座標,number為要繪製的元素個數。
下麵的例子展示了如何使用了drawString(),drawChars()和drawBytes()三個方法:例9.2DrawSCB.javaimportjava.awt.*;publicclassDrawSCBextendsFrame{ Strings="UsingdrawString!"; char[]c={'c','h','a','r','s','','8'}; byte[]b={'b','y','t','e',1,2,3};publicstaticvoidmain(String[]args) { DrawSCBframe=newDrawSCB(); frame.setSize(300,100); frame.setVisible(true); } publicvoidpaint(Graphicsg) { g.drawString(s,100,40); g.drawChars(c,0,7,100,65); g.drawBytes(b,0,5,100,90); }}程式運行結果如圖9.2所示。圖9.29.2.2顏色控制
Color類定義了顏色常量和方法。每種顏色都是從RGB(紅/綠/藍)值創建出來的。一個RGB值有三部分,都是從0~255的整數值,分別代表著三種顏色的含量。因此,實際上我們可以使用256×256×256種顏色,即224種顏色。這就是我們常說的24位真彩色。但不是任何電腦都可以顯示所有的顏色,就目前來說,大部分電腦都可以顯示24位甚至超過24位的彩色。顯然,我們很難記住一種顏色的RGB值,因而,Color類將一些最常用的顏色預定義為常量以方便我們使用。表9.1列出了預定義的顏色常量。表9.1Color類中定義的顏色常量
顏色常量顏色RGB值publicfinalstaticColororange橙色255,200,0publicfinalstaticColorpink粉紅色255,175,175publicfinalstaticColorcyan青色0,255,255publicfinalstaticColormagenta火紅色255,0,255publicfinalstaticColoryellow黃色255,255,0publicfinalstaticColorblack黑色0,0,0publicfinalstaticColorwhite白色255,255,255publicfinalstaticColorgray灰色128,128,128publicfinalstaticColorlightGray淺灰色192,192,192publicfinalstaticColordarkGray深灰色64,64,64publicfinalstaticColorred紅色255,0,0publicfinalstaticColorgreen綠色0,255,0publicfinalstaticColorblue藍色0,0,255Color類中常用的一些方法如下:●publicColor(intr,intg,intb):創建指定RGB值的顏色。●publicintgetRed():返回紅色含量的值。●publicintgetBlue():返回藍色含量的值。●publicintgetGreen():返回綠色含量的值。Graphics類與Color類相關的常用方法有:●publicabstactColorgetColor():返回圖形上下文的當前顏色?!駊ublicabstractvoidsetColor(Colorc):設置圖形上下文的當前顏色。下麵來看一個顏色控制的實例。例9.3ShowColor.javaimportjava.awt.*;publicclassShowColorextendsFrame{ intred,green,blue; publicstaticvoidmain(String[]args) { ShowColorframe=newShowColor(); frame.setSize(300,100); frame.setVisible(true); } publicShowColor(){ red=200; green=100; blue=0; } publicvoidpaint(Graphicsg) { g.setColor(newColor(red,green,blue)); g.drawString("Drawcolorstring.",50,40); Colorcolor=g.getColor();
g.drawString("Red:"+color.getRed(),10,70); g.drawString("Green:"+color.getGreen(),100,70); g.drawString("Blue:"+color.getBlue(),200,70); }}
程式運行結果如圖9.3所示。圖9.39.2.3繪製幾何圖形
Graphics類中用於繪製幾何圖形的方法如下:●publicabstractvoiddrawLine(intx1,inty1,intx2,inty2)
在點(x1,y1)和(x2,y2)之間用當前顏色繪製線段?!駊ublicvoiddrawRect(intx,inty,intwidth,intheight)
以點(x,y)為左上角座標,width和height為寬度和高度,用當前顏色畫矩形。●publicabstactvoidfillRect(intx,inty,intwidth,intheight)
以點(x,y)為左上角座標,width和height為寬度和高度,用當前顏色畫一個實心的矩形?!駊ublicabstactvoidclearRect(intx,inty,intwidth,intheight)
以點(x,y)為左上角座標,width和height為寬度和高度,用當前背景顏色畫一個實心的矩形。此方法用於清除某個矩形顯示區域?!駊ublicabstactvoiddrawRoundRect(intx,inty,intwidth,intheight,intarcWidth,intarcHeight)
以點(x,y)為左上角座標,width和height為寬度和高度,用當前顏色畫圓角矩形?!駊ublicabstactvoidfillRoundRect(intx,inty,intwidth,intheight,intarcWidth,intarcHeight)
以點(x,y)為左上角座標,width和height為寬度和高度,用當前顏色畫一個實心的圓角矩形?!駊ublicvoiddraw3Drect(intx,inty,intwidth,intheight,booleanb)
用指定的width和height,以當前顏色畫一個三維矩形。矩形的左上角座標為(x,y)。當b為true時,矩形為凸的;b為false時,矩形為凹的。●publicvoidfill3Drect(intx,inty,intwidth,intheight,booleanb)
用指定的width和height,以當前顏色畫一個填充的三維矩形。矩形的左上角座標為(x,y)。當b為true時,矩形為凸的;b為false時,矩形為凹的?!駊ublicabstractvoiddrawOval(intx,inty,intwidth,intheight)
用指定的width和height,以當前顏色畫橢圓。外切矩形的左上角座標為(x,y)。●publicabstractvoidfillOval(intx,inty,intwidth,intheight)
用指定的width和height,以當前顏色畫實心橢圓。外切矩形的左上角座標為(x,y)?!駊ublicabstractvoiddrawArc(intx,inty,intwidth,intheight,intstartAngle,intarcAngle)
參考外切矩形的左上角座標(x,y),用指定的width和height,以當前顏色繪製一段弧。弧段從起始角startAngle開始一直到張角arcAngle?!駊ublicabstractvoidfillArc(intx,inty,intwidth,intheight,intstartAngle,intarcAngle)
參考外切矩形的左上角座標(x,y),用指定的width和height,以當前顏色繪製一段實心的弧?;《螐钠鹗冀莝tartAngle開始一直到張角arcAngle。●publicabstractvoiddrawPolygon(int[]xPoints,int[]yPoints,intpoints)
以當前顏色畫一個具有points個頂點的多邊形。xPoint和yPoint數組分別指定了每個頂點的x和y座標。●publicvoiddrawPolygon(Polygonp)
以當前顏色畫指定的多邊形?!駊ublicabstractvoidfillPolygon(int[]xPoints,int[],yPoints,intpoints)
以當前顏色畫一個具有points個頂點的填充多邊形。xPoint和yPoint數組分別指定了每個頂點的x和y座標。下麵我們通過一個例子來學習這些方法。例9.4DrawDemo.javaimportjava.awt.*;publicclassDrawDemoextendsFrame{ publicstaticvoidmain(String[]args) { DrawDemoframe=newDrawDemo(); frame.setSize(400,500);frame.setVisible(true); } publicvoidpaint(Graphicsg){ //drawaline g.drawLine(10,30,200,40); //drawarectangle g.drawRect(10,50,100,50); //drawafilledrectangle g.fillRect(150,50,100,50); //drawaroundedrectangle g.drawRoundRect(10,120,50,50,10,20); //drawafilledroundedrectangle g.fillRoundRect(80,120,50,50,40,20); //drawaellipseg.drawRoundRect(150,130,80,20,70,70); //drawafilledsquare g.drawRoundRect(250,120,50,50,0,0); //drawacircle g.drawRoundRect(330,120,50,50,50,50); g.setColor(Color.yellow); //drawaraised3Drectangle g.draw3DRect(10,190,50,50,true); //drawasunk3Drectangle g.draw3DRect(100,190,50,50,false);//drawafilledraised3Drectangle g.fill3DRect(200,190,50,50,true); //drawafilledsunk3Drectangle g.fill3DRect(300,190,50,50,false); g.setColor(Color.black); //drawanoval g.drawOval(10,260,70,50); //drawanfilledoval g.fillOval(200,260,50,70); //drawanarc g.drawArc(10,350,60,60,0,180);//drawsolidarc g.fillArc(100,350,50,60,0,270); g.fillArc(200,350,50,60,0,-110); g.fillArc(300,350,40,60,0,-360);
//drawapolygon int[]xPoints1={10,30,40,20,10,5,10}; int[]yPoints1={430,430,440,460,460,440,430}; g.drawPolygon(xPoints1,yPoints1,7);//drawafilledpolygon int[]xPoints2={100,120,130,110,100,95,90,100}; int[]yPoints2={430,430,440,460,460,440,420,430}; g.fillPolygon(xPoints2,yPoints2,8); }}
程式運行結果如圖9.4所示。圖9.49.2.4螢幕操作本節介紹一種實現螢幕操作的Graphics方法copyArea()。copyArea()方法用於複製螢幕的一個區域,並將它放置在螢幕的另一個位置上。copyArea方法的定義如下:publicabstractvoidcopyArea(intx,inty,intwidth,intheight,intdx,intdy)其中,參數x和y指定了複製區域的左上角座標;width和height為區域的寬和高;dx和dy指定了與點(x,y)的水準和垂直偏移量,複製的區域放置在該偏移量相對於(x,y)的位置上。例9.5CopyAreaDemo.javaimportjava.awt.*;publicclassCopyAreaDemoextendsFrame{ publicstaticvoidmain(String[]args){ CopyAreaDemoframe=newCopyAreaDemo(); frame.setSize(300,200); frame.setVisible(true); } publicvoidpaint(Graphicsg){ g.drawRect(20,30,50,50); g.fillOval(50,100,50,70); g.copyArea(20,30,100,170,150,20);}}
程式運行結果如圖9.5所示。圖9.59.2.5繪圖模式繪圖模式(paintmode)用於描述如何繪圖。默認的繪圖模式是覆蓋模式(overwrite),當一個圖形畫在另一個圖形上面時,舊的圖形將被覆蓋,看到的將只是新的圖形。另外,還有一種異或繪圖模式(XOR),使用這種模式可以看到互相重疊的所有圖形。使用異或繪圖模式可以通過調用Graphics的方法:
publicabstractvoidsetXORMode(Colorc)
來實現。該方法的參數為一個Color對象。這個顏色稱作XORMode顏色。由於XOR繪圖模式實際上是對新舊兩種顏色的二進位值做異或操作,所以當重疊的部分顏色相同時,將恢復為背景顏色。這時候可以通過設置XORMode顏色,指定用某顏色來替代。例如:例9.6XORModeDemo.javaimportjava.awt.*;publicclassXORModeDemoextendsFrame{publicstaticvoidmain(String[]args) {XORModeDemoframe=newXORModeDemo();frame.setSize(300,100); frame.setVisible(true); } publicvoidpaint(Graphicsg){ //drawapinkoval g.setColor(Color.pink); g.fillOval(20,30,100,50); //drawayellowrectangleoverpartoftheoval g.setColor(Color.yellow); g.fillRect(100,30,100,50); //drawanorangerectangle g.setColor(Color.orange);g.fillOval(190,30,80,50); //setXORmodetoyellow g.setXORMode(Color.yellow); g.fillOval(180,45,60,20); //drawabluearc g.setColor(Color.blue); g.fillArc(150,40,20,20,0,360); //drawaredsquare g.setColor(Color.red); g.fillRect(120,45,20,20);}}
程式繪製了六種不同的形狀,前三種為覆蓋模式,後三種為異或模式。大家可以通過運行結果中圖形重疊部分看出兩種不同繪圖模式的效果。程式運行結果如圖9.6所示。圖9.69.3Font類的使用Java2D具有複雜文本的輸出能力。Java2D和一個重新設計的字體引擎支持使用屬性集對字串的單個字元進行操作。
9.3.1字體字體是一套具有一個點尺寸和外觀的字元類型集合,例如,所有10點Helvetica英文字元和符號組成一個字體。文本所使用的字體定義特定的外觀、大小和式樣(黑體、斜體或者普通體)。
字體如何定義特定外觀呢?字體是從字形(glyphs)創建的,一個字形是一個位映像圖像,它定義字體中的字元和符號的外觀。同一字體家族的字體都有相似的外觀,因為他們使用同一個字形創建。同樣的,不同的字體家族使用不同的字形得到相互區分的外觀。一個字體家族不但由具有相似外觀的字體組成,還包括不同的大小和式樣。Helvetica10point黑體和Helvetica12point斜體是同一家族中的兩個不同字體,而TimesRoman8point黑體和TimesRoman10point普通體是另一個家族的兩個不同字體。
為了使用一個字體,需要創建一個Font對象,而為了做到這個,則需要知道系統中有什麼字體可用以及它們的名字。字體有邏輯名、家族名和字體名。邏輯名是被映射到平臺上,可用的特定字體的名字。調用java.awt.Font.getName類可以得到一個Font對象的邏輯名。
家族名是字體家族的名字,它通過不同的外觀決定排版圖案,例如,Helvetica或者TimesNewRoman。要得到一個Font對象的家族名,須調用java.awt.Font.getFamily類。字體名代表家族中的特定字體,例如HelveticaBold。要得到一個Font對象的字體名,須調用java.awt.Font.getFontName類。要決定系統上哪些字體可用,須調用java.awt.GraphicsEnvironment.getAllFonts類。9.3.2創建和派生字體創建一個字體的最簡單的方法是指定字體名、大小和式樣。一旦你有一個Font對象,你就可以通過調用Font.deriveFont方法在存在的字體上派生任意個新Font對象,並指定新的大小、樣式、變換(位置、傾斜、縮放或者旋轉)或者屬性映射。例如
FontboldFont=newFont("Helvetica",Font.BOLD,12); FontitalicDerived=boldFont.deriveFont(Font.ITALIC,12); FontplainDerived=boldFont.deriveFont(Font.PLAIN,14);
一旦你有一個字體,你就可以用它創建一個TextLayout對象並繪製藝術字。java.awt.Font.TextLayout類可以讓你使用字元、字體和屬性集創建藝術字。一旦被創建,TextLayout對象就不可編輯,但是它的方法可以讓你訪問佈局、字體、脫字元,選擇和點擊測試資訊。下麵的代碼使用Font,TextLayout和FontRenderContext對象繪製了一個簡單的文本,使用的是24pointTimes黑體。例9.7TimesB.javaimportjava.awt.*;importjava.awt.event.*;importjava.awt.geom.*;importjava.awt.Font.*;publicclassTimesBextendsCanvas{ privateImageimg; publiccTimesB() {setBackground(Color.white); } publicvoidpaint(Graphicsg){ Graphics2Dg2; g2=(Graphics2D)g;g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
ontRenderContextfrc=g2.getFontRenderContext(); Fontf=newFont("Times",Font.BOLD,24); Strings=newString("24PointTimesBold"); TextLayouttl=newTextLayout(s,f,frc); DimensiontheSize=getSize();g2.setColor(Color.green); tl.draw(g2,theSize.width/30,theSize.height/2); } publicstaticvoidmain(Strings[]) { WindowListenerl=newWindowAdapter(){publicvoidwindowClosing(WindowEvente) {System.exit(0);} publicvoidwindowClosed(WindowEvente) {System.exit(0);} };Framef=newFrame("2DText"); f.addWindowListener(l); f.add("Center",newTimesB()); f.pack(); f.setSize(newDimension(400,300)); f.show();}}
程式運行結果如圖9.7所示。圖9.7
程式中,java.awt.Font代表系統中可用字體的一個實例;java.awt.TextLayout代表不可變的藝術字數據;java.awt.Font.FontRenderContext包含繪製文本時需要的正確測量和定位的資訊。9.4圖像處理
正如上一節所介紹的,Graphics類中確實提供了不少繪製圖形的方法,但如果用它們在Applet運行過程中即時地繪製一幅較複雜的圖形,就好比是在用斧頭和木塊去製造太空梭。因此,對於複雜圖形,一般都事先用專用的繪圖軟體將其繪製好,或者是用其他截取圖像的工具(如掃描器、視效卡等)獲取圖像的數據資訊,再將它們按一定的格式存入圖像檔中。程式運行時,只要找到圖像檔存貯的位置,將它裝載到記憶體裏,然後在適當的時機將它顯示在螢幕上就可以了。9.4.1加載和顯示圖像在AWT中,java.awt.image類用於描述圖像,它通過傳遞一個Image類對象的引用給Graphics.drawImage(Image,int,int,ImageObserver)方法,就可以將圖像在畫布(Canvas)或是其他可視組件中顯示出來。Java目前所支持的圖像檔格式只有兩種,分別是GIF和JPEG格式(帶有.GIF、.JPG、.JPEG尾碼名的檔)。因此,若圖像檔是其他格式,就須先將它們轉換為這兩種格式。
java.awt.image是一個抽象類,它定義的方法提供對圖像資訊的訪問。下麵通過一個例子來看看如何利用Image類來顯示一幅圖像。例9.8ImageTestApplication.javaimportjava.awt.*;importjava.awt.event.*;publicclassImageTestApplicationextendsFrame{ Insets insets; Image im; staticpublicvoidmain(Stringargs[]){ ImageTestApplicationapp=newImageTestApplication();app.show(); } publicImageTestApplication(){ super("ImageTest"); im=Toolkit.getDefaultToolkit().getImage("tiger.gif"); addWindowListener(newWindowAdapter(){ publicvoidwindowClosing(WindowEventevent){ dispose();System.exit(0);} }); }publicvoidaddNotify(){ super.addNotify(); //peeriscreatedhere insets=getInsets(); setBounds(100,100,217+insets.left,321+insets.top); } publicvoidpaint(Graphicsg){ g.drawImage(im,insets.left,insets.top,this); System.out.println("drawingimage..."); System.out.println(g.drawImage(im,insets.left,insets.top,this)); }}
在應用程式中加載圖像必須調用Toolkit類的靜態方法getImage(),該方法返回一個指定圖像檔的Image對象描述,然後在paint()方法中調用Graphics類的drawImage()方法,就可以將圖片顯示在當前容器中。
需要注意的是addNotify()方法,覆蓋這個方法是為了得到框架窗口空白區域的引用,並用它來設置框架窗口的大小。這樣做是因為框架窗口的左上角(0,0)座標是從標題欄開始計算的,如果將圖從(0,0)開始畫,空白區域以外(即標題欄覆蓋的部分)將會被裁減,所以必須從座標(insets.left,insets.top)的位置開始畫圖。程式的運行結果如圖9.8所示。圖9.8
在上面的例子中,查看控制臺會發現,paint()方法被調用了很多次,這是因為getImage()方法是啟動一個線程來加載圖像的,所以paint()方法被調用的時候不一定已經載入了整張圖片,每次只繪出已經加載的部分。Java這樣採用線程的做法雖然會提高性能,但是也為編程帶來了一些問題。例如,上例中的setBounds()方法中的尺寸是硬編碼(直接寫入數值)的,這種方法缺乏通用性,是明確不被推薦的做法。較好的方法是直接取圖像的尺寸,通過調用Image.getWidth()和Image.getHeight()方法可以做到。因為在圖像被完全加載以前,它們的返回值都是-1,所以要等到圖像加載完才能調用它們。
如何知道圖像有沒有被加載完呢?AWT包為此提供了MediaTracker類用於監控圖像的加載過程。使用MediaTracker類分為三步:
(1)創建MediaTracker對象。
(2)使用MediaTracker.addImage()指明要監控的圖像對象。
(3)創建try/catch塊,等待和指定與ID相關的圖像被完全加載?,F在採用MediaTracker類來改寫上面的例子。
例9.9ImageTestApplication.javaimportjava.awt.*;importjava.awt.event.*;publicclassImageTestApplicationextendsFrame{ Insetsinsets; Imageim;intwidth,height; staticpublicvoidmain(Stringargs[]){ ImageTestApplicationapp=newImageTestApplication();app.show(); } publicImageTestApplication(){ super("ImageTest"); MediaTrackertracker=newMediaTracker(this); im=Toolkit.getDefaultToolkit().getImage("tiger.gif"); tracker.addImage(im,0); try{ tracker.waitForID(0); } catch(InterruptedExceptione){ e.printStackTrace(); } width=im.getWidth(this); height=im.getHeight(this);addWindowListener(newWindowAdapter(){ publicvoidwindowClosing(WindowEventevent){ dispose(); System.exit(0);} }); } publicvoidaddNotify(){ super.addNotify(); //peeriscreatedhere insets=getInsets(); setBounds(100,100,width+insets.left,height+insets.top); }publicvoidpaint(Graphicsg){ g.drawImage(im,insets.left,insets.top,this); System.out.println("drawingimage..."); System.out.println(g.drawImage(im,insets.left,insets.top,this)); }}
再來看看控制臺,可以看到paint()方法只被執行了一次。這說明圖像是被完全加載以後才調用paint()方法顯示的。9.4.2圖像生成
AWT除了提供用於描述圖像的java.awt.image類外,還提供了用於圖像處理的java.awt.image包,這個包的所有類幾乎都和生產和消費圖像有關。圖像生產者負責產生圖像的位,而圖像消費者用於接收圖像的位。注:用於描述圖像的是java.awt包中的Image類,它為圖像提供引用,而java.awt.image包中的類則用於圖像處理,不要將它們混淆。
在java.awt.image包中,提供了圖像源生產者介面ImageProducer,以及用於像素抓取和圖像篩檢程式的消費者介面ImageConsumer。實際上,和圖像相關聯的位並不存在java.awt.image中,而是每個圖像都和一個ImageProducer介面相關聯,這個ImageProducer真正負責生產圖像的位。AWT組件除了可以顯示圖像,還可以創建圖像。要生成一幅圖像就必須調用AWT組件類提供的方法createImage(ImageProducer)或CreateImage(intwidth,intheight)。第一個方法通過給定一個提供圖像位的ImageProducer參數來創建圖像;第二個方法則通過指定圖像大小來生成圖像。
此外,java.awt.Toolkit類也擁有創建圖像的能力。它提供了三種創建圖像的方法:
①createImage(ImageProducer)②createImage(byte[]bits)③createImage(byte[]bits,intoffset,intlength)
和AWT一樣,Toolkit類在創建圖像時,也可以通過給定一個ImageProducer參數來實現。另外,它還提供了兩種方法,從一個byte數組創建圖像,該方法是使用位數組創建圖像,即我們常用的記憶體圖像。9.4.3圖像處理在AWT中,提供了大量的方法支持圖像處理,特別是在java.awt.image包中,為我們提供了一些十分有用的圖像篩檢程式。這一節將向大家介紹如何使用這些奇妙的圖像篩檢程式。前面已經提到,生產者介面ImageProducer用於產生圖像位並把它們傳遞給圖像消費者。對於每個Image對象,都有一個和它對應的圖像生產者,其作用是用來重構圖像和生產隨時需要的圖像位。
圖像生產者保持一個圖像消費者列表,他們得到的圖像數據都來自圖像生產者。ImageProducer介面提供用來在列表中增加或刪除圖像消費者的方法,而且同時還用於判斷一個消費者是否已經向生產者註冊。在java.awt.image軟體包中,有兩個類實現ImageProducer介面,它們是:FilteredImageSource類和MemoryImageSource類。
圖像消費者ImageConsumer介面用於從圖像生產者接收圖像數據,java.awt.image包中也提供了兩個類實現ImageConsumer介面,它們是:ImageFilter類和PixelGrabber類。下麵我們來介紹如何使用java.awt.image包中的圖像處理工具——
圖像篩檢程式。
java.awt.image包提供了下麵幾種圖像篩檢程式:●CorpImageFilter:從一副已知圖像中裁剪出一個特殊的矩形,要裁剪的矩形形狀由篩檢程式的構造器來決定?!馬eplicateScaleFilter:使用一個簡單的演算法縮放圖像,例如複製圖像數據的行或列進行放大;刪除圖像數據的行或列進行縮小?!馎reaAveragingScaleFilter:是ReplicateScaleFilter的一個擴展,它在縮放時採用了一個比較高級的演算法。兩者的使用方式相同,但AreaAveragingSealeFilter縮放圖像的品質要好些?!馬GBImageFilter:是一類抽象篩檢程式,其作用是傳輸專用像素到它在RGB顏色模式中的擴展,用於實現自定義圖像篩檢程式。這裏我們主要討論CorpImageFilter和RGBImageFilter的使用。我們先來看一個使用CropImageFilter實現圖像裁減的例子。例9.10CropTest.javaimportjava.awt.*;importjava.awt.image.*;import.*;publicclassCropTestextendsFrame{ privateImageim; privateImagecropped;privateInsetsinsets; privateintwidth,height; publicstaticvoidmain(String[]agrs){ CropTestframe=newCropTest(); frame.setVisible(true); } publicCropTest(){ MediaTrackermt=newMediaTracker(this); im=Toolkit.getDefaultToolkit().getImage("pic.jpg"); mt.addImage(im,0); try{ mt.waitForID(0);} catch(Exceptione){e.printStackTrace();} width=im.getWidth(this); height=im.getHeight(this);ImageFilterfilter=newCropImageFilter(110,5,100,100); FilteredImageSourcefis=newFilteredImageSource(im.getSource(),filter); cropped=createImage(fis); }
publicvoidaddNotify(){ super.addNotify(); //peeriscreatedhere insets=getInsets();
setBounds(100,100,width+insets.left+120,height+insets.top); }publicvoidpaint(Graphicsg){ g.drawImage(im,insets.left,insets.top,this); g.drawImage(cropped,width+insets.left+20,insets.top,this);}}
上面的程式中,通過創建一個CropImageFilter的對象來指定要裁減的區域為左上角是(100,5),寬和高都是100的一個矩形區域。
接下來構造一個FilteredImageSource對象,並通過Image.getSource()方法得到原圖的圖像生產者的引用,傳遞給FilteredImageSource的對象。最後,調用Component.createImage()方法生成裁減後的圖像,並將FilteredImageSource對象作為參數傳遞給該方法。這是因為FilteredImageSource實現了ImageProducer介面,所以它可以作為createImage()方法的合法參數。程式的運行結果如圖9.9所示。圖9.9
RGBImageFilter是一個抽象類,它定義了如下一個抽象方法:
intfilterRGB(intx,inty,intrgb)
改方法在缺省的RGB顏色模式中,向filterRGB()方法傳遞像素的位置和RGB顏色的一個整數表示,用於檢驗像素的RGB表示,返回相同的RGB整數表示或被修改的像素顏色表示。下麵是一個使用RGBImageFilter實現自定義的溶解篩檢程式DissolveFilter的例子。例9.11RGBImageFilter.javaimport.URL;importjava.awt.*;importjava.awt.event.*;importjava.awt.image.*;publicclassDissolveFilterTestextendsFrame{ Imageorig,dissolved; publicDissolveFilterTest(){ super("DissolveFilter"); MediaTrackermt=newMediaTracker(this); URLurl=getClass().getResource("tiger.gif"); try{ orig=createImage((ImageProducer)url.getContent()); mt.addImage(orig,0); mt.waitForID(0);} catch(Exceptione){ e.printStackTrace(); } FilteredImageSourcefis=newFilteredImageSource( orig.getSource(),newDissolveFilter(50)); dissolved=createImage(fis); } publicvoidupdate(Graphicsg){ paint(g); }
publicstaticvoidmain(Stringargs[]){ finalFramef=newDissolveFilterTest(); f.setBounds(100,100,730,380); f.setVisible(true); f.addWindowListener(newWindowAdapter(){publicvoidwindowClosing(WindowEvente){ f.dispose(); System.exit(0);}}); } publicvoidpaint(Graphicsg){ Insetsi=getInsets(); int ow=orig.getWidth(this);//ow=OriginalWidth g.drawImage(orig,i.left,i.top,this); g.drawImage(dissolved,i.left+ow+20,i.top,this);}}classDissolveFilterextendsRGBImageFilter{privateintalpha;publicDissolveFilter(){this(0);}
publicDissolveFilter(intalpha){canFilterIndexColorModel=true;if(alpha<0&&alpha>255) thrownewIllegalArgumentException("badalpha");this.alpha=alpha;}publicintfilterRGB(intx,inty,intrgb){DirectColorModelcm=(DirectColorModel)ColorModel.getRGBdefault();intalpha=cm.getAlpha(rgb);intred=cm.getRed(rgb);
intgreen=cm.getGreen(rgb);intblue=cm.getBlue(rgb);alpha=alpha==0?0:this.alpha;returnalpha<<24|red<<16|green<<8|blue;}}
這個程式實現了一個溶解篩檢程式DissolveFilter,它是通過擴展RGBImageFilter得到的。
在DissolveFilter構造器中,接收被過濾圖像中每個顏色的直接顏色模式中的alpha值(直接顏色模式即直接指明顏色值比特位)。alpha值的取值範圍是0~255。alpha值為0表示該圖像是完全透明的,而值255則表示圖像完全不透明(即原圖)。將載入的圖像中的每個點通過DissolveFilter.filterRGB()處理後,重構圖像,就得到了如圖9.10所示的運行結果。圖9.109.5動畫圖像處理9.5.1使用線程設計動畫在Java中,實現動畫有很多種辦法,但它們實現的基本原理是一樣的,即在螢幕上畫出一系列的幀來造成運動的視覺效果。在此,我們先構造一個程式的框架,再慢慢擴展,使之功能比較齊備。
為了每秒鐘多次更新螢幕,必須創建一個線程來實現動畫的迴圈,這個迴圈要跟蹤當前幀並回應週期性的螢幕更新要求。實現線程的方法有兩種:創建一個類Thread的派生類,或在當前類上實現一個Runnable介面。一個較容易犯的錯誤是將動畫迴圈放在paint()中,這樣就會佔據主AWT線程,而主線程是用於負責所有的繪圖和事件處理的,這將導致介面對事件回應遲鈍。下麵我們來看一個使用線程實現動畫的例子。例9.12Animation.javaimportjava.awt.*;publicclassAnimationextendsFrameimplementsRunnable{inttotalImages=19; intcurrentImage=0; intdelay=50; intx; Image[]spin; Threadanimator;publicstaticvoidmain(String[]args){ Animationframe=newAnimation(); frame.setSize(500,150); frame.setBackground(Color.yellow); frame.setVisible(true); }publicAnimation() { spin=newImage[totalImages]; ToolkitdefaultTk=Toolkit.getDefaultToolkit(); MediaTrackertracker=newMediaTracker(this); for(inti=0;i<totalImages;i++){ spin[i]=defaultTk.getImage("spin"+i+".gif"); tracker.addImage(spin[i],i); try{ tracker.waitForID(i);} catch(InterruptedExceptione){ e.printStackTrace(); } } x=0; animator=newThread(this); animator.start(); }publicvoidrun()
{ while(Thread.currentThread()==animator) { repaint(); try{ Thread.sleep(delay);} catch(InterruptedExceptione){ e.printStackTrace(); } } }publicvoidpaint(Graphicsg) { g.drawImage(spin[currentImage],10+x,30,this); x=(x+5)%400; currentImage=++currentImage%totalImages;}}
此程式的原理是利用
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 用電安全懲罰管理辦法
- 福州餐飲住宿管理辦法
- 工程企業合同管理辦法
- 育肥豬養殖技術課件
- 肯德基公司介紹
- 肩周炎健康知識課件
- 醫院醫廢培訓課件
- 高三第一章數學試卷
- 設備計劃管理培訓課件
- 房山八上期末數學試卷
- 使用錯誤評估報告(可用性工程)模版
- 2023年貴州公務員考試申論試題(B卷)
- 高中生物必修知識點總結(人教版復習提綱)高考基礎
- DB11T 2104-2023 消防控制室火警處置規范
- 計量工程師招聘面試題與參考回答2024年
- TwinCAT 3 以FeedTable的形式實現NCI插補
- 小學小升初英語閱讀理解練習題及答案
- 2025屆騰沖縣六年級數學第一學期期末檢測試題含解析
- 壓力容器制造質量保證手冊+程序文件+表格-符合TSG 07-2019特種設備質量保證管理體系
- 盤扣式卸料平臺施工方案
- 數據治理操作指南
評論
0/150
提交評論