Java在多媒體中的應用_第1頁
Java在多媒體中的應用_第2頁
Java在多媒體中的應用_第3頁
Java在多媒體中的應用_第4頁
Java在多媒體中的應用_第5頁
已閱讀5頁,還剩118頁未讀 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第9章Java在多媒體中的應用9.1利用AWT繪圖9.2Graphics類的使用9.3Font類的使用9.4圖像處理9.5動畫圖像處理9.1利用AWT繪圖這一節(jié)中我們主要介紹如何使用Java語言提供的AWT包繪圖。java.awt包中提供了用于繪圖的API,我們通常稱之為2DAPI。不要以為只有設計繪圖程序或游戲軟件才會用到Java2D,其實Java2D的用途可能遠比你想象的更廣泛。其實,只要你的程序有GUI,就很可能會用到Java2D。因為AWT和Swing的組件常常無法完全適合我們,這個時候自己繪制一局部的GUI就有絕對的必要。甚至,我們還可以用Java2D來繪制自己的組件。實際上,AWT和Swing組件都是透過Java2D來進行繪制的。Java2DAPI增強了AWT的圖形、文本和圖像功能,可以開發(fā)更為強大的用戶接口和新型的Java應用程序。除了更為強大的圖形、字體和圖像API外,Java2DAPI還改進了顏色的定義與復合及對任意幾何形狀和文本的選中檢測,并為打印機和顯示設備提供了統(tǒng)一的繪制模式。Java2DAPI還可以創(chuàng)立高級圖形庫,并可創(chuàng)立圖像和圖形文件讀/寫過濾器。當與Java媒體框架(JMF)和其他Java媒體應用程序配合使用時,Java2DAPI還可用來創(chuàng)立和顯示動畫和其他多媒體演示稿。到底Java2DAPI有多強大?這一點我們可以通過SUNJDK包中提供的例程來了解。在命令行窗口下輸入: c:\>cd\jdk1.2\demo\jfc\Java2Dc:\jdk1.2\demo\jfc\Java2D>java-classpathJava2Demo.jarJava2Demo或c:\jdk1.2\demo\jfc\Java2D>appletviewerjava2demo.html看到了嗎?Java2D神奇的威力!下面我們來學習如何使用Java2D繪圖。上面看到的例子雖然功能十分強大,但是它的實現(xiàn)非常復雜。下面,我們先從簡單一點的入手。從java.awt.Component類(所有窗口對象的基類)繼承的類提供了一個名為paint()的方法,在需要重新繪制組件時,可調用該方法。paint()方法只有一個參數(shù),該參數(shù)是Graphics類的實例。如果在某個繼承了Component的類中覆蓋了該方法,那么就可以使用該方法來控制在控制區(qū)域著何種顏色。例如,下面的類創(chuàng)立了一個帶有藍背景的面板。例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類包含了創(chuàng)立多邊形的方法;Toolkit類提供了從系統(tǒng)獲得圖形信息的方法,例如可顯示的字體集和屏幕分辨率等等;Graphics類包含了繪制字符串、線條以及各種幾何圖形的方法。Graphics是一個抽象類,其作用是定義一個真正的工具,用來接受圖形操作。在該類中,有47個公用方法,可以用作顯示圖像和文本、繪制和填充形狀、剪貼圖像操作等等。9.2.1繪制字符串、字符和字節(jié)用于繪制字符串、字符和字節(jié)的方法分別為●publicabstractvoiddrawString(Stringstring,intx,inty)在坐標(x,y)處以當前字體和顏色繪制指定的字符串string?!駊ublicvoiddrawChars(char[]chars,intoffset,intnumber,intx,inty)在坐標(x,y)處以當前字體和顏色繪制指定的一系列字符。chars為要繪制的字符組,offset為位置的坐標,number為要繪制的元素個數(shù)?!駊ublicvoiddrawBytes(byte[]bytes,intoffset,intnumber,intx,inty)在坐標(x,y)處以當前字體和顏色繪制指定的一系列字節(jié)。bytes為要繪制的字節(jié)數(shù)組,offset為位置的坐標,number為要繪制的元素個數(shù)。下面的例子展示了如何使用了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所示。圖顏色控制Color類定義了顏色常量和方法。每種顏色都是從RGB(紅/綠/藍)值創(chuàng)立出來的。一個RGB值有三局部,都是從0~255的整數(shù)值,分別代表著三種顏色的含量。因此,實際上我們可以使用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):創(chuàng)立指定RGB值的顏色?!駊ublicintgetRed():返回紅色含量的值?!駊ublicintgetBlue():返回藍色含量的值?!駊ublicintgetGreen():返回綠色含量的值。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所示。圖繪制幾何圖形Graphics類中用于繪制幾何圖形的方法如下:●publicabstractvoiddrawLine(intx1,inty1,intx2,inty2)在點(x1,y1)和(x2,y2)之間用當前顏色繪制線段?!駊ublicvoiddrawRect(intx,inty,intwidth,intheight)以點(x,y)為左上角坐標,width和height為寬度和高度,用當前顏色畫矩形?!駊ublicabstactvoidfillRect(intx,inty,intwidth,intheight)以點(x,y)為左上角坐標,width和height為寬度和高度,用當前顏色畫一個實心的矩形。●publicabstactvoidclearRect(intx,inty,intwidth,intheight)以點(x,y)為左上角坐標,width和height為寬度和高度,用當前背景顏色畫一個實心的矩形。此方法用于去除某個矩形顯示區(qū)域?!駊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時,矩形為凹的?!駊ublicvoidfill3Drect(intx,inty,intwidth,intheight,booleanb)用指定的width和height,以當前顏色畫一個填充的三維矩形。矩形的左上角坐標為(x,y)。當b為true時,矩形為凸的;b為false時,矩形為凹的?!駊ublicabstractvoiddrawOval(intx,inty,intwidth,intheight)用指定的width和height,以當前顏色畫橢圓。外切矩形的左上角坐標為(x,y)?!駊ublicabstractvoidfillOval(intx,inty,intwidth,intheight)用指定的width和height,以當前顏色畫實心橢圓。外切矩形的左上角坐標為(x,y)?!駊ublicabstractvoiddrawArc(intx,inty,intwidth,intheight,intstartAngle,intarcAngle)參考外切矩形的左上角坐標(x,y),用指定的width和height,以當前顏色繪制一段弧?;《螐钠鹗冀莝tartAngle開始一直到張角arcAngle?!駊ublicabstractvoidfillArc(intx,inty,intwidth,intheight,intstartAngle,intarcAngle)參考外切矩形的左上角坐標(x,y),用指定的width和height,以當前顏色繪制一段實心的弧?;《螐钠鹗冀莝tartAngle開始一直到張角arcAngle。●publicabstractvoiddrawPolygon(int[]xPoints,int[]yPoints,intpoints)以當前顏色畫一個具有points個頂點的多邊形。xPoint和yPoint數(shù)組分別指定了每個頂點的x和y坐標?!駊ublicvoiddrawPolygon(Polygonp)以當前顏色畫指定的多邊形?!駊ublicabstractvoidfillPolygon(int[]xPoints,int[],yPoints,intpoints)以當前顏色畫一個具有points個頂點的填充多邊形。xPoint和yPoint數(shù)組分別指定了每個頂點的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所示。圖屏幕操作本節(jié)介紹一種實現(xiàn)屏幕操作的Graphics方法copyArea()。copyArea()方法用于復制屏幕的一個區(qū)域,并將它放置在屏幕的另一個位置上。copyArea方法的定義如下:publicabstractvoidcopyArea(intx,inty,intwidth,intheight,intdx,intdy)其中,參數(shù)x和y指定了復制區(qū)域的左上角坐標;width和height為區(qū)域的寬和高;dx和dy指定了與點(x,y)的水平和垂直偏移量,復制的區(qū)域放置在該偏移量相對于(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所示。圖繪圖模式繪圖模式(paintmode)用于描述如何繪圖。默認的繪圖模式是覆蓋模式(overwrite),當一個圖形畫在另一個圖形上面時,舊的圖形將被覆蓋,看到的將只是新的圖形。另外,還有一種異或繪圖模式(XOR),使用這種模式可以看到互相重疊的所有圖形。使用異或繪圖模式可以通過調用Graphics的方法:publicabstractvoidsetXORMode(Colorc)來實現(xiàn)。該方法的參數(shù)為一個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)創(chuàng)立的,一個字形是一個位映像圖像,它定義字體中的字符和符號的外觀。同一字體家族的字體都有相似的外觀,因為他們使用同一個字形創(chuàng)立。同樣的,不同的字體家族使用不同的字形得到相互區(qū)分的外觀。一個字體家族不但由具有相似外觀的字體組成,還包括不同的大小和式樣。Helvetica10point黑體和Helvetica12point斜體是同一家族中的兩個不同字體,而TimesRoman8point黑體和TimesRoman10point普通體是另一個家族的兩個不同字體。為了使用一個字體,需要創(chuàng)立一個Font對象,而為了做到這個,那么需要知道系統(tǒng)中有什么字體可用以及它們的名字。字體有邏輯名、家族名和字體名。邏輯名是被映射到平臺上,可用的特定字體的名字。調用java.awt.Font.getName類可以得到一個Font對象的邏輯名。家族名是字體家族的名字,它通過不同的外觀決定排幅員案,例如,Helvetica或者TimesNewRoman。要得到一個Font對象的家族名,須調用java.awt.Font.getFamily類。字體名代表家族中的特定字體,例如HelveticaBold。要得到一個Font對象的字體名,須調用java.awt.Font.getFontName類。要決定系統(tǒng)上哪些字體可用,須調用java.awt.GraphicsEnvironment.getAllFonts類。9.3.2創(chuàng)立和派生字體創(chuàng)立一個字體的最簡單的方法是指定字體名、大小和式樣。一旦你有一個Font對象,你就可以通過調用Font.deriveFont方法在存在的字體上派生任意個新Font對象,并指定新的大小、樣式、變換(位置、傾斜、縮放或者旋轉)或者屬性映射。例如 FontboldFont=newFont("Helvetica",Font.BOLD,12); FontitalicDerived=boldFont.deriveFont(Font.ITALIC,12); FontplainDerived=boldFont.deriveFont(Font.PLAIN,14);一旦你有一個字體,你就可以用它創(chuàng)立一個TextLayout對象并繪制藝術字。java.awt.Font.TextLayout類可以讓你使用字符、字體和屬性集創(chuàng)立藝術字。一旦被創(chuàng)立,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代表系統(tǒng)中可用字體的一個實例;java.awt.TextLayout代表不可變的藝術字數(shù)據(jù);java.awt.Font.FontRenderContext包含繪制文本時需要的正確測量和定位的信息。9.4圖像處理正如上一節(jié)所介紹的,Graphics類中確實提供了不少繪制圖形的方法,但如果用它們在Applet運行過程中實時地繪制一幅較復雜的圖形,就好比是在用斧頭和木塊去制造航天飛機。因此,對于復雜圖形,一般都事先用專用的繪圖軟件將其繪制好,或者是用其他截取圖像的工具(如掃描儀、視效卡等)獲取圖像的數(shù)據(jù)信息,再將它們按一定的格式存入圖像文件中。程序運行時,只要找到圖像文件存貯的位置,將它裝載到內存里,然后在適當?shù)臅r機將它顯示在屏幕上就可以了。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類的靜態(tài)方法getImage(),該方法返回一個指定圖像文件的Image對象描述,然后在paint()方法中調用Graphics類的drawImage()方法,就可以將圖片顯示在當前容器中。需要注意的是addNotify()方法,覆蓋這個方法是為了得到框架窗口空白區(qū)域的引用,并用它來設置框架窗口的大小。這樣做是因為框架窗口的左上角(0,0)坐標是從標題欄開始計算的,如果將圖從(0,0)開始畫,空白區(qū)域以外(即標題欄覆蓋的局部)將會被裁減,所以必須從坐標(insets.left,insets.top)的位置開始畫圖。程序的運行結果如圖9.8所示。圖9.8在上面的例子中,查看控制臺會發(fā)現(xiàn),paint()方法被調用了很屢次,這是因為getImage()方法是啟動一個線程來加載圖像的,所以paint()方法被調用的時候不一定已經載入了整張圖片,每次只繪出已經加載的局部。Java這樣采用線程的做法雖然會提高性能,但是也為編程帶來了一些問題。例如,上例中的setBounds()方法中的尺寸是硬編碼(直接寫入數(shù)值)的,這種方法缺乏通用性,是明確不被推薦的做法。較好的方法是直接取圖像的尺寸,通過調用Image.getWidth()和Image.getHeight()方法可以做到。因為在圖像被完全加載以前,它們的返回值都是-1,所以要等到圖像加載完才能調用它們。如何知道圖像有沒有被加載完呢?AWT包為此提供了MediaTracker類用于監(jiān)控圖像的加載過程。使用MediaTracker類分為三步:(1)創(chuàng)立MediaTracker對象。(2)使用MediaTracker.addImage()指明要監(jiān)控的圖像對象。(3)創(chuàng)立try/catch塊,等待和指定與ID相關的圖像被完全加載?,F(xiàn)在采用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()方法只被執(zhí)行了一次。這說明圖像是被完全加載以后才調用paint()方法顯示的。9.4.2圖像生成AWT除了提供用于描述圖像的java.awt.image類外,還提供了用于圖像處理的java.awt.image包,這個包的所有類幾乎都和生產和消費圖像有關。圖像生產者負責產生圖像的位,而圖像消費者用于接收圖像的位。注:用于描述圖像的是java.awt包中的Image類,它為圖像提供引用,而java.awt.image包中的類那么用于圖像處理,不要將它們混淆。在java.awt.image包中,提供了圖像源生產者接口ImageProducer,以及用于像素抓取和圖像過濾器的消費者接口ImageConsumer。實際上,和圖像相關聯(lián)的位并不存在java.awt.image中,而是每個圖像都和一個ImageProducer接口相關聯(lián),這個ImageProducer真正負責生產圖像的位。AWT組件除了可以顯示圖像,還可以創(chuàng)立圖像。要生成一幅圖像就必須調用AWT組件類提供的方法createImage(ImageProducer)或CreateImage(intwidth,intheight)。第一個方法通過給定一個提供圖像位的ImageProducer參數(shù)來創(chuàng)立圖像;第二個方法那么通過指定圖像大小來生成圖像。此外,java.awt.Toolkit類也擁有創(chuàng)立圖像的能力。它提供了三種創(chuàng)立圖像的方法:①createImage(ImageProducer)②createImage(byte[]bits)③createImage(byte[]bits,intoffset,intlength)和AWT一樣,Toolkit類在創(chuàng)立圖像時,也可以通過給定一個ImageProducer參數(shù)來實現(xiàn)。另外,它還提供了兩種方法,從一個byte數(shù)組創(chuàng)立圖像,該方法是使用位數(shù)組創(chuàng)立圖像,即我們常用的內存圖像。9.4.3圖像處理在AWT中,提供了大量的方法支持圖像處理,特別是在java.awt.image包中,為我們提供了一些十分有用的圖像過濾器。這一節(jié)將向大家介紹如何使用這些奇妙的圖像過濾器。前面已經提到,生產者接口ImageProducer用于產生圖像位并把它們傳遞給圖像消費者。對于每個Image對象,都有一個和它對應的圖像生產者,其作用是用來重構圖像和生產隨時需要的圖像位。圖像生產者保持一個圖像消費者列表,他們得到的圖像數(shù)據(jù)都來自圖像生產者。ImageProducer接口提供用來在列表中增加或刪除圖像消費者的方法,而且同時還用于判斷一個消費者是否已經向生產者注冊。在java.awt.image軟件包中,有兩個類實現(xiàn)ImageProducer接口,它們是:FilteredImageSource類和MemoryImageSource類。圖像消費者ImageConsumer接口用于從圖像生產者接收圖像數(shù)據(jù),java.awt.image包中也提供了兩個類實現(xiàn)ImageConsumer接口,它們是:ImageFilter類和PixelGrabber類。下面我們來介紹如何使用java.awt.image包中的圖像處理工具——圖像過濾器。java.awt.image包提供了下面幾種圖像過濾器:●CorpImageFilter:從一副圖像中裁剪出一個特殊的矩形,要裁剪的矩形形狀由過濾器的構造器來決定。●ReplicateScaleFilter:使用一個簡單的算法縮放圖像,例如復制圖像數(shù)據(jù)的行或列進行放大;刪除圖像數(shù)據(jù)的行或列進行縮小?!馎reaAveragingScaleFilter:是ReplicateScaleFilter的一個擴展,它在縮放時采用了一個比較高級的算法。兩者的使用方式相同,但AreaAveragingSealeFilter縮放圖像的質量要好些?!馬GBImageFilter:是一類抽象過濾器,其作用是傳輸專用像素到它在RGB顏色模式中的擴展,用于實現(xiàn)自定義圖像過濾器。這里我們主要討論CorpImageFilter和RGBImageFilter的使用。我們先來看一個使用CropImageFilter實現(xiàn)圖像裁減的例子。例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);}}上面的程序中,通過創(chuàng)立一個CropImageFilter的對象來指定要裁減的區(qū)域為左上角是(100,5),寬和高都是100的一個矩形區(qū)域。接下來構造一個FilteredImageSource對象,并通過Image.getSource()方法得到原圖的圖像生產者的引用,傳遞給FilteredImageSource的對象。最后,調用Component.createImage()方法生成裁減后的圖像,并將FilteredImageSource對象作為參數(shù)傳遞給該方法。這是因為FilteredImageSource實現(xiàn)了ImageProducer接口,所以它可以作為createImage()方法的合法參數(shù)。程序的運行結果如圖9.9所示。圖9.9RGBImageFilter是一個抽象類,它定義了如下一個抽象方法:intfilterRGB(intx,inty,intrgb)改方法在缺省的RGB顏色模式中,向filterRGB()方法傳遞像素的位置和RGB顏色的一個整數(shù)表示,用于檢驗像素的RGB表示,返回相同的RGB整數(shù)表示或被修改的像素顏色表示。下面是一個使用RGBImageFilter實現(xiàn)自定義的溶解過濾器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;}}這個程序實現(xiàn)了一個溶解過濾器DissolveFilter,它是通過擴展RGBImageFilter得到的。在DissolveFilter構造器中,接收被過濾圖像中每個顏色的直接顏色模式中的alpha值(直接顏色模式即直接指明顏色值比特位)。alpha值的取值范圍是0~255。alpha值為0表示該圖像是完全透明的,而值255那么表示圖像完全不透明(即原圖)。將載入的圖像中的每個點通過DissolveFilter.filterRGB()處理后,重構圖像,就得到了如圖9.10所示的運行結果。圖9.109.5動畫圖像處理9.5.1使用線程設計動畫在Java中,實現(xiàn)動畫有很多種方法,但它們實現(xiàn)的根本原理是一樣的,即在屏幕上畫出一系列的幀來造成運動的視覺效果。在此,我們先構造一個程序的框架,再慢慢擴展,使之功能比較齊備。為了每秒鐘屢次更新屏幕,必須創(chuàng)立一個線程來實現(xiàn)動畫的循環(huán),這個循環(huán)要跟蹤當前幀并響應周期性的屏幕更新要求。實現(xiàn)線程的方法有兩種:創(chuàng)立一個類Thread的派生類,或在當前類上實現(xiàn)一個Runnable接口。一個較容易犯的錯誤是將動畫循環(huán)放在paint()中,這樣就會占據(jù)主AWT線程,而主線程是用于負責所有的繪圖和事件處理的,這將導致界面對事件響應遲鈍。下面我們來看一個使用線程實現(xiàn)動畫的例子。例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;}}此程序的原理是利用一系列的圖片的更替來實現(xiàn)動畫,run()方法中不斷的調用repaint()方法,repaint()方法又會導致paint()方法被調用,每次調用paint()方法都會繪制一副圖片,并且將currentImage指針移動到下一幅圖片的位置,橫坐標也隨之平移。這樣的效果就是出現(xiàn)一個不斷移動的小人,如圖9.11所示。圖防止閃爍大家可能已經發(fā)現(xiàn),上例的畫面有些閃動。閃爍有兩個原因:一是繪制每一幀花費的時間太長(因為重繪時要求的計算量大),二是在每次調用pait()前整個背景被去除,當在進行下一幀的計算時,用戶看到的是背景。去除背景和繪制圖形間的短暫時間被用戶看見,就是閃爍。在有些平臺,如PC機上,閃爍比在XWindow上明顯,這是因為XWindow的圖像被緩存過,使得閃爍的時間比較短。有兩種方法可以明顯地減弱閃爍:重載update()或使用雙緩沖。這里我們先討論重載update()的方法。當AWT接收到一個重繪(repaint)請求時,它就先調用update()去除背景,而update()方法又會調用paint()。重載update(),手動調用paint()方法,防止每次重繪時將整個區(qū)域去除,即背景不再自動去除。這需要我們自己在update()中編寫代碼來完成。在繪制新的圖像之前手動將原來的舊圖擦除,這樣可以有效地防止閃爍。我們來看修改以后的例子。例9.13Animation1.javaimportjava.awt.*;publicclassAnimation1extendsFrameimplementsRunnable{ inttotalImages=19; intcurrentImage=0; intdelay=50; intx,x1; Image[]spin; Threadanimator;publicstaticvoidmain(String[]args) { Animation1frame=newAnimation1(); frame.setSize(500,150); frame.setBackground(Color.yellow); frame.setVisible(true); }

publicAnimation1() { spin=newImage[totalImages]; Toolkit

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論