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

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第9章Java在多媒體中的應(yīng)用9.1利用AWT繪圖9.2Graphics類的使用9.3Font類的使用9.4圖像處理9.5動(dòng)畫圖像處理9.1利用AWT繪圖這一節(jié)中我們主要介紹如何使用Java語(yǔ)言提供的AWT包繪圖。java.awt包中提供了用于繪圖的API,我們通常稱之為2DAPI。不要以為只有設(shè)計(jì)繪圖程序或游戲軟件才會(huì)用到Java2D,其實(shí)Java2D的用途可能遠(yuǎn)比你想象的更廣泛。其實(shí),只要你的程序有GUI,就很可能會(huì)用到Java2D。因?yàn)锳WT和Swing的組件常常無(wú)法完全適合我們,這個(gè)時(shí)候自己繪制一局部的GUI就有絕對(duì)的必要。甚至,我們還可以用Java2D來(lái)繪制自己的組件。實(shí)際上,AWT和Swing組件都是透過(guò)Java2D來(lái)進(jìn)行繪制的。Java2DAPI增強(qiáng)了AWT的圖形、文本和圖像功能,可以開發(fā)更為強(qiáng)大的用戶接口和新型的Java應(yīng)用程序。除了更為強(qiáng)大的圖形、字體和圖像API外,Java2DAPI還改進(jìn)了顏色的定義與復(fù)合及對(duì)任意幾何形狀和文本的選中檢測(cè),并為打印機(jī)和顯示設(shè)備提供了統(tǒng)一的繪制模式。Java2DAPI還可以創(chuàng)立高級(jí)圖形庫(kù),并可創(chuàng)立圖像和圖形文件讀/寫過(guò)濾器。當(dāng)與Java媒體框架(JMF)和其他Java媒體應(yīng)用程序配合使用時(shí),Java2DAPI還可用來(lái)創(chuàng)立和顯示動(dòng)畫和其他多媒體演示稿。到底Java2DAPI有多強(qiáng)大?這一點(diǎn)我們可以通過(guò)SUNJDK包中提供的例程來(lái)了解。在命令行窗口下輸入: c:\>cd\jdk1.2\demo\jfc\Java2Dc:\jdk1.2\demo\jfc\Java2D>java-classpathJava2Demo.jarJava2Demo或c:\jdk1.2\demo\jfc\Java2D>appletviewerjava2demo.html看到了嗎?Java2D神奇的威力!下面我們來(lái)學(xué)習(xí)如何使用Java2D繪圖。上面看到的例子雖然功能十分強(qiáng)大,但是它的實(shí)現(xiàn)非常復(fù)雜。下面,我們先從簡(jiǎn)單一點(diǎn)的入手。從java.awt.Component類(所有窗口對(duì)象的基類)繼承的類提供了一個(gè)名為paint()的方法,在需要重新繪制組件時(shí),可調(diào)用該方法。paint()方法只有一個(gè)參數(shù),該參數(shù)是Graphics類的實(shí)例。如果在某個(gè)繼承了Component的類中覆蓋了該方法,那么就可以使用該方法來(lái)控制在控制區(qū)域著何種顏色。例如,下面的類創(chuàng)立了一個(gè)帶有藍(lán)背景的面板。例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);}}程序運(yùn)行結(jié)果如圖9.1所示。

圖9.19.2Graphics類的使用java.awt中提供了一系列的類用于繪制圖形。其中,Color類包含了編輯顏色的方法和常量;Font類包含了編輯字體的方法和常量;FontMetrics類包含了獲取字體信息的方法;Polygon類包含了創(chuàng)立多邊形的方法;Toolkit類提供了從系統(tǒng)獲得圖形信息的方法,例如可顯示的字體集和屏幕分辨率等等;Graphics類包含了繪制字符串、線條以及各種幾何圖形的方法。Graphics是一個(gè)抽象類,其作用是定義一個(gè)真正的工具,用來(lái)接受圖形操作。在該類中,有47個(gè)公用方法,可以用作顯示圖像和文本、繪制和填充形狀、剪貼圖像操作等等。9.2.1繪制字符串、字符和字節(jié)用于繪制字符串、字符和字節(jié)的方法分別為●publicabstractvoiddrawString(Stringstring,intx,inty)在坐標(biāo)(x,y)處以當(dāng)前字體和顏色繪制指定的字符串string?!駊ublicvoiddrawChars(char[]chars,intoffset,intnumber,intx,inty)在坐標(biāo)(x,y)處以當(dāng)前字體和顏色繪制指定的一系列字符。chars為要繪制的字符組,offset為位置的坐標(biāo),number為要繪制的元素個(gè)數(shù)?!駊ublicvoiddrawBytes(byte[]bytes,intoffset,intnumber,intx,inty)在坐標(biāo)(x,y)處以當(dāng)前字體和顏色繪制指定的一系列字節(jié)。bytes為要繪制的字節(jié)數(shù)組,offset為位置的坐標(biāo),number為要繪制的元素個(gè)數(shù)。下面的例子展示了如何使用了drawString(),drawChars()和drawBytes()三個(gè)方法:例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); }}程序運(yùn)行結(jié)果如圖9.2所示。圖顏色控制Color類定義了顏色常量和方法。每種顏色都是從RGB(紅/綠/藍(lán))值創(chuàng)立出來(lái)的。一個(gè)RGB值有三局部,都是從0~255的整數(shù)值,分別代表著三種顏色的含量。因此,實(shí)際上我們可以使用256×256×256種顏色,即224種顏色。這就是我們常說(shuō)的24位真彩色。但不是任何計(jì)算機(jī)都可以顯示所有的顏色,就目前來(lái)說(shuō),大局部計(jì)算機(jī)都可以顯示24位甚至超過(guò)24位的彩色。顯然,我們很難記住一種顏色的RGB值,因而,Color類將一些最常用的顏色預(yù)定義為常量以方便我們使用。表9.1列出了預(yù)定義的顏色常量。表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藍(lán)色0,0,255Color類中常用的一些方法如下:●publicColor(intr,intg,intb):創(chuàng)立指定RGB值的顏色?!駊ublicintgetRed():返回紅色含量的值?!駊ublicintgetBlue():返回藍(lán)色含量的值?!駊ublicintgetGreen():返回綠色含量的值。Graphics類與Color類相關(guān)的常用方法有:●publicabstactColorgetColor():返回圖形上下文的當(dāng)前顏色?!駊ublicabstractvoidsetColor(Colorc):設(shè)置圖形上下文的當(dāng)前顏色。下面來(lái)看一個(gè)顏色控制的實(shí)例。例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); }}程序運(yùn)行結(jié)果如圖9.3所示。圖繪制幾何圖形Graphics類中用于繪制幾何圖形的方法如下:●publicabstractvoiddrawLine(intx1,inty1,intx2,inty2)在點(diǎn)(x1,y1)和(x2,y2)之間用當(dāng)前顏色繪制線段。●publicvoiddrawRect(intx,inty,intwidth,intheight)以點(diǎn)(x,y)為左上角坐標(biāo),width和height為寬度和高度,用當(dāng)前顏色畫矩形?!駊ublicabstactvoidfillRect(intx,inty,intwidth,intheight)以點(diǎn)(x,y)為左上角坐標(biāo),width和height為寬度和高度,用當(dāng)前顏色畫一個(gè)實(shí)心的矩形?!駊ublicabstactvoidclearRect(intx,inty,intwidth,intheight)以點(diǎn)(x,y)為左上角坐標(biāo),width和height為寬度和高度,用當(dāng)前背景顏色畫一個(gè)實(shí)心的矩形。此方法用于去除某個(gè)矩形顯示區(qū)域?!駊ublicabstactvoiddrawRoundRect(intx,inty,intwidth,intheight,intarcWidth,intarcHeight)以點(diǎn)(x,y)為左上角坐標(biāo),width和height為寬度和高度,用當(dāng)前顏色畫圓角矩形?!駊ublicabstactvoidfillRoundRect(intx,inty,intwidth,intheight,intarcWidth,intarcHeight)以點(diǎn)(x,y)為左上角坐標(biāo),width和height為寬度和高度,用當(dāng)前顏色畫一個(gè)實(shí)心的圓角矩形?!駊ublicvoiddraw3Drect(intx,inty,intwidth,intheight,booleanb)用指定的width和height,以當(dāng)前顏色畫一個(gè)三維矩形。矩形的左上角坐標(biāo)為(x,y)。當(dāng)b為true時(shí),矩形為凸的;b為false時(shí),矩形為凹的?!駊ublicvoidfill3Drect(intx,inty,intwidth,intheight,booleanb)用指定的width和height,以當(dāng)前顏色畫一個(gè)填充的三維矩形。矩形的左上角坐標(biāo)為(x,y)。當(dāng)b為true時(shí),矩形為凸的;b為false時(shí),矩形為凹的?!駊ublicabstractvoiddrawOval(intx,inty,intwidth,intheight)用指定的width和height,以當(dāng)前顏色畫橢圓。外切矩形的左上角坐標(biāo)為(x,y)?!駊ublicabstractvoidfillOval(intx,inty,intwidth,intheight)用指定的width和height,以當(dāng)前顏色畫實(shí)心橢圓。外切矩形的左上角坐標(biāo)為(x,y)?!駊ublicabstractvoiddrawArc(intx,inty,intwidth,intheight,intstartAngle,intarcAngle)參考外切矩形的左上角坐標(biāo)(x,y),用指定的width和height,以當(dāng)前顏色繪制一段弧。弧段從起始角startAngle開始一直到張角arcAngle?!駊ublicabstractvoidfillArc(intx,inty,intwidth,intheight,intstartAngle,intarcAngle)參考外切矩形的左上角坐標(biāo)(x,y),用指定的width和height,以當(dāng)前顏色繪制一段實(shí)心的弧?;《螐钠鹗冀莝tartAngle開始一直到張角arcAngle?!駊ublicabstractvoiddrawPolygon(int[]xPoints,int[]yPoints,intpoints)以當(dāng)前顏色畫一個(gè)具有points個(gè)頂點(diǎn)的多邊形。xPoint和yPoint數(shù)組分別指定了每個(gè)頂點(diǎn)的x和y坐標(biāo)?!駊ublicvoiddrawPolygon(Polygonp)以當(dāng)前顏色畫指定的多邊形?!駊ublicabstractvoidfillPolygon(int[]xPoints,int[],yPoints,intpoints)以當(dāng)前顏色畫一個(gè)具有points個(gè)頂點(diǎn)的填充多邊形。xPoint和yPoint數(shù)組分別指定了每個(gè)頂點(diǎn)的x和y坐標(biāo)。下面我們通過(guò)一個(gè)例子來(lái)學(xué)習(xí)這些方法。例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); }}

程序運(yùn)行結(jié)果如圖9.4所示。圖屏幕操作本節(jié)介紹一種實(shí)現(xiàn)屏幕操作的Graphics方法copyArea()。copyArea()方法用于復(fù)制屏幕的一個(gè)區(qū)域,并將它放置在屏幕的另一個(gè)位置上。copyArea方法的定義如下:publicabstractvoidcopyArea(intx,inty,intwidth,intheight,intdx,intdy)其中,參數(shù)x和y指定了復(fù)制區(qū)域的左上角坐標(biāo);width和height為區(qū)域的寬和高;dx和dy指定了與點(diǎn)(x,y)的水平和垂直偏移量,復(fù)制的區(qū)域放置在該偏移量相對(duì)于(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);}}程序運(yùn)行結(jié)果如圖9.5所示。圖繪圖模式繪圖模式(paintmode)用于描述如何繪圖。默認(rèn)的繪圖模式是覆蓋模式(overwrite),當(dāng)一個(gè)圖形畫在另一個(gè)圖形上面時(shí),舊的圖形將被覆蓋,看到的將只是新的圖形。另外,還有一種異或繪圖模式(XOR),使用這種模式可以看到互相重疊的所有圖形。使用異或繪圖模式可以通過(guò)調(diào)用Graphics的方法:publicabstractvoidsetXORMode(Colorc)來(lái)實(shí)現(xiàn)。該方法的參數(shù)為一個(gè)Color對(duì)象。這個(gè)顏色稱作XORMode顏色。由于XOR繪圖模式實(shí)際上是對(duì)新舊兩種顏色的二進(jìn)制值做異或操作,所以當(dāng)重疊的局部顏色相同時(shí),將恢復(fù)為背景顏色。這時(shí)候可以通過(guò)設(shè)置XORMode顏色,指定用某顏色來(lái)替代。例如:例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);}}程序繪制了六種不同的形狀,前三種為覆蓋模式,后三種為異或模式。大家可以通過(guò)運(yùn)行結(jié)果中圖形重疊局部看出兩種不同繪圖模式的效果。程序運(yùn)行結(jié)果如圖9.6所示。圖9.69.3Font類的使用Java2D具有復(fù)雜文本的輸出能力。Java2D和一個(gè)重新設(shè)計(jì)的字體引擎支持使用屬性集對(duì)字符串的單個(gè)字符進(jìn)行操作。9.3.1字體字體是一套具有一個(gè)點(diǎn)尺寸和外觀的字符類型集合,例如,所有10點(diǎn)Helvetica英文字符和符號(hào)組成一個(gè)字體。文本所使用的字體定義特定的外觀、大小和式樣(黑體、斜體或者普通體)。字體如何定義特定外觀呢?字體是從字形(glyphs)創(chuàng)立的,一個(gè)字形是一個(gè)位映像圖像,它定義字體中的字符和符號(hào)的外觀。同一字體家族的字體都有相似的外觀,因?yàn)樗麄兪褂猛粋€(gè)字形創(chuàng)立。同樣的,不同的字體家族使用不同的字形得到相互區(qū)分的外觀。一個(gè)字體家族不但由具有相似外觀的字體組成,還包括不同的大小和式樣。Helvetica10point黑體和Helvetica12point斜體是同一家族中的兩個(gè)不同字體,而TimesRoman8point黑體和TimesRoman10point普通體是另一個(gè)家族的兩個(gè)不同字體。為了使用一個(gè)字體,需要?jiǎng)?chuàng)立一個(gè)Font對(duì)象,而為了做到這個(gè),那么需要知道系統(tǒng)中有什么字體可用以及它們的名字。字體有邏輯名、家族名和字體名。邏輯名是被映射到平臺(tái)上,可用的特定字體的名字。調(diào)用java.awt.Font.getName類可以得到一個(gè)Font對(duì)象的邏輯名。家族名是字體家族的名字,它通過(guò)不同的外觀決定排幅員案,例如,Helvetica或者TimesNewRoman。要得到一個(gè)Font對(duì)象的家族名,須調(diào)用java.awt.Font.getFamily類。字體名代表家族中的特定字體,例如HelveticaBold。要得到一個(gè)Font對(duì)象的字體名,須調(diào)用java.awt.Font.getFontName類。要決定系統(tǒng)上哪些字體可用,須調(diào)用java.awt.GraphicsEnvironment.getAllFonts類。9.3.2創(chuàng)立和派生字體創(chuàng)立一個(gè)字體的最簡(jiǎn)單的方法是指定字體名、大小和式樣。一旦你有一個(gè)Font對(duì)象,你就可以通過(guò)調(diào)用Font.deriveFont方法在存在的字體上派生任意個(gè)新Font對(duì)象,并指定新的大小、樣式、變換(位置、傾斜、縮放或者旋轉(zhuǎn))或者屬性映射。例如 FontboldFont=newFont("Helvetica",Font.BOLD,12); FontitalicDerived=boldFont.deriveFont(Font.ITALIC,12); FontplainDerived=boldFont.deriveFont(Font.PLAIN,14);一旦你有一個(gè)字體,你就可以用它創(chuàng)立一個(gè)TextLayout對(duì)象并繪制藝術(shù)字。java.awt.Font.TextLayout類可以讓你使用字符、字體和屬性集創(chuàng)立藝術(shù)字。一旦被創(chuàng)立,TextLayout對(duì)象就不可編輯,但是它的方法可以讓你訪問(wèn)布局、字體、脫字符,選擇和點(diǎn)擊測(cè)試信息。下面的代碼使用Font,TextLayout和FontRenderContext對(duì)象繪制了一個(gè)簡(jiǎn)單的文本,使用的是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();}}程序運(yùn)行結(jié)果如圖9.7所示。圖9.7程序中,java.awt.Font代表系統(tǒng)中可用字體的一個(gè)實(shí)例;java.awt.TextLayout代表不可變的藝術(shù)字?jǐn)?shù)據(jù);java.awt.Font.FontRenderContext包含繪制文本時(shí)需要的正確測(cè)量和定位的信息。9.4圖像處理正如上一節(jié)所介紹的,Graphics類中確實(shí)提供了不少繪制圖形的方法,但如果用它們?cè)贏pplet運(yùn)行過(guò)程中實(shí)時(shí)地繪制一幅較復(fù)雜的圖形,就好比是在用斧頭和木塊去制造航天飛機(jī)。因此,對(duì)于復(fù)雜圖形,一般都事先用專用的繪圖軟件將其繪制好,或者是用其他截取圖像的工具(如掃描儀、視效卡等)獲取圖像的數(shù)據(jù)信息,再將它們按一定的格式存入圖像文件中。程序運(yùn)行時(shí),只要找到圖像文件存貯的位置,將它裝載到內(nèi)存里,然后在適當(dāng)?shù)臅r(shí)機(jī)將它顯示在屏幕上就可以了。9.4.1加載和顯示圖像在AWT中,java.awt.image類用于描述圖像,它通過(guò)傳遞一個(gè)Image類對(duì)象的引用給Graphics.drawImage(Image,int,int,ImageObserver)方法,就可以將圖像在畫布(Canvas)或是其他可視組件中顯示出來(lái)。Java目前所支持的圖像文件格式只有兩種,分別是GIF和JPEG格式(帶有.GIF、.JPG、.JPEG后綴名的文件)。因此,假設(shè)圖像文件是其他格式,就須先將它們轉(zhuǎn)換為這兩種格式。java.awt.image是一個(gè)抽象類,它定義的方法提供對(duì)圖像信息的訪問(wèn)。下面通過(guò)一個(gè)例子來(lái)看看如何利用Image類來(lái)顯示一幅圖像。例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)); }}在應(yīng)用程序中加載圖像必須調(diào)用Toolkit類的靜態(tài)方法getImage(),該方法返回一個(gè)指定圖像文件的Image對(duì)象描述,然后在paint()方法中調(diào)用Graphics類的drawImage()方法,就可以將圖片顯示在當(dāng)前容器中。需要注意的是addNotify()方法,覆蓋這個(gè)方法是為了得到框架窗口空白區(qū)域的引用,并用它來(lái)設(shè)置框架窗口的大小。這樣做是因?yàn)榭蚣艽翱诘淖笊辖?0,0)坐標(biāo)是從標(biāo)題欄開始計(jì)算的,如果將圖從(0,0)開始畫,空白區(qū)域以外(即標(biāo)題欄覆蓋的局部)將會(huì)被裁減,所以必須從坐標(biāo)(insets.left,insets.top)的位置開始畫圖。程序的運(yùn)行結(jié)果如圖9.8所示。圖9.8在上面的例子中,查看控制臺(tái)會(huì)發(fā)現(xiàn),paint()方法被調(diào)用了很屢次,這是因?yàn)間etImage()方法是啟動(dòng)一個(gè)線程來(lái)加載圖像的,所以paint()方法被調(diào)用的時(shí)候不一定已經(jīng)載入了整張圖片,每次只繪出已經(jīng)加載的局部。Java這樣采用線程的做法雖然會(huì)提高性能,但是也為編程帶來(lái)了一些問(wèn)題。例如,上例中的setBounds()方法中的尺寸是硬編碼(直接寫入數(shù)值)的,這種方法缺乏通用性,是明確不被推薦的做法。較好的方法是直接取圖像的尺寸,通過(guò)調(diào)用Image.getWidth()和Image.getHeight()方法可以做到。因?yàn)樵趫D像被完全加載以前,它們的返回值都是-1,所以要等到圖像加載完才能調(diào)用它們。如何知道圖像有沒(méi)有被加載完呢?AWT包為此提供了MediaTracker類用于監(jiān)控圖像的加載過(guò)程。使用MediaTracker類分為三步:(1)創(chuàng)立MediaTracker對(duì)象。(2)使用MediaTracker.addImage()指明要監(jiān)控的圖像對(duì)象。(3)創(chuàng)立try/catch塊,等待和指定與ID相關(guān)的圖像被完全加載。現(xiàn)在采用MediaTracker類來(lái)改寫上面的例子。

例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)); }}再來(lái)看看控制臺(tái),可以看到paint()方法只被執(zhí)行了一次。這說(shuō)明圖像是被完全加載以后才調(diào)用paint()方法顯示的。9.4.2圖像生成AWT除了提供用于描述圖像的java.awt.image類外,還提供了用于圖像處理的java.awt.image包,這個(gè)包的所有類幾乎都和生產(chǎn)和消費(fèi)圖像有關(guān)。圖像生產(chǎn)者負(fù)責(zé)產(chǎn)生圖像的位,而圖像消費(fèi)者用于接收?qǐng)D像的位。注:用于描述圖像的是java.awt包中的Image類,它為圖像提供引用,而java.awt.image包中的類那么用于圖像處理,不要將它們混淆。在java.awt.image包中,提供了圖像源生產(chǎn)者接口ImageProducer,以及用于像素抓取和圖像過(guò)濾器的消費(fèi)者接口ImageConsumer。實(shí)際上,和圖像相關(guān)聯(lián)的位并不存在java.awt.image中,而是每個(gè)圖像都和一個(gè)ImageProducer接口相關(guān)聯(lián),這個(gè)ImageProducer真正負(fù)責(zé)生產(chǎn)圖像的位。AWT組件除了可以顯示圖像,還可以創(chuàng)立圖像。要生成一幅圖像就必須調(diào)用AWT組件類提供的方法createImage(ImageProducer)或CreateImage(intwidth,intheight)。第一個(gè)方法通過(guò)給定一個(gè)提供圖像位的ImageProducer參數(shù)來(lái)創(chuàng)立圖像;第二個(gè)方法那么通過(guò)指定圖像大小來(lái)生成圖像。此外,java.awt.Toolkit類也擁有創(chuàng)立圖像的能力。它提供了三種創(chuàng)立圖像的方法:①createImage(ImageProducer)②createImage(byte[]bits)③createImage(byte[]bits,intoffset,intlength)和AWT一樣,Toolkit類在創(chuàng)立圖像時(shí),也可以通過(guò)給定一個(gè)ImageProducer參數(shù)來(lái)實(shí)現(xiàn)。另外,它還提供了兩種方法,從一個(gè)byte數(shù)組創(chuàng)立圖像,該方法是使用位數(shù)組創(chuàng)立圖像,即我們常用的內(nèi)存圖像。9.4.3圖像處理在AWT中,提供了大量的方法支持圖像處理,特別是在java.awt.image包中,為我們提供了一些十分有用的圖像過(guò)濾器。這一節(jié)將向大家介紹如何使用這些奇妙的圖像過(guò)濾器。前面已經(jīng)提到,生產(chǎn)者接口ImageProducer用于產(chǎn)生圖像位并把它們傳遞給圖像消費(fèi)者。對(duì)于每個(gè)Image對(duì)象,都有一個(gè)和它對(duì)應(yīng)的圖像生產(chǎn)者,其作用是用來(lái)重構(gòu)圖像和生產(chǎn)隨時(shí)需要的圖像位。圖像生產(chǎn)者保持一個(gè)圖像消費(fèi)者列表,他們得到的圖像數(shù)據(jù)都來(lái)自圖像生產(chǎn)者。ImageProducer接口提供用來(lái)在列表中增加或刪除圖像消費(fèi)者的方法,而且同時(shí)還用于判斷一個(gè)消費(fèi)者是否已經(jīng)向生產(chǎn)者注冊(cè)。在java.awt.image軟件包中,有兩個(gè)類實(shí)現(xiàn)ImageProducer接口,它們是:FilteredImageSource類和MemoryImageSource類。圖像消費(fèi)者ImageConsumer接口用于從圖像生產(chǎn)者接收?qǐng)D像數(shù)據(jù),java.awt.image包中也提供了兩個(gè)類實(shí)現(xiàn)ImageConsumer接口,它們是:ImageFilter類和PixelGrabber類。下面我們來(lái)介紹如何使用java.awt.image包中的圖像處理工具——圖像過(guò)濾器。java.awt.image包提供了下面幾種圖像過(guò)濾器:●CorpImageFilter:從一副圖像中裁剪出一個(gè)特殊的矩形,要裁剪的矩形形狀由過(guò)濾器的構(gòu)造器來(lái)決定?!馬eplicateScaleFilter:使用一個(gè)簡(jiǎn)單的算法縮放圖像,例如復(fù)制圖像數(shù)據(jù)的行或列進(jìn)行放大;刪除圖像數(shù)據(jù)的行或列進(jìn)行縮小?!馎reaAveragingScaleFilter:是ReplicateScaleFilter的一個(gè)擴(kuò)展,它在縮放時(shí)采用了一個(gè)比較高級(jí)的算法。兩者的使用方式相同,但AreaAveragingSealeFilter縮放圖像的質(zhì)量要好些。●RGBImageFilter:是一類抽象過(guò)濾器,其作用是傳輸專用像素到它在RGB顏色模式中的擴(kuò)展,用于實(shí)現(xiàn)自定義圖像過(guò)濾器。這里我們主要討論CorpImageFilter和RGBImageFilter的使用。我們先來(lái)看一個(gè)使用CropImageFilter實(shí)現(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);}}上面的程序中,通過(guò)創(chuàng)立一個(gè)CropImageFilter的對(duì)象來(lái)指定要裁減的區(qū)域?yàn)樽笊辖鞘?100,5),寬和高都是100的一個(gè)矩形區(qū)域。接下來(lái)構(gòu)造一個(gè)FilteredImageSource對(duì)象,并通過(guò)Image.getSource()方法得到原圖的圖像生產(chǎn)者的引用,傳遞給FilteredImageSource的對(duì)象。最后,調(diào)用Component.createImage()方法生成裁減后的圖像,并將FilteredImageSource對(duì)象作為參數(shù)傳遞給該方法。這是因?yàn)镕ilteredImageSource實(shí)現(xiàn)了ImageProducer接口,所以它可以作為createImage()方法的合法參數(shù)。程序的運(yùn)行結(jié)果如圖9.9所示。圖9.9RGBImageFilter是一個(gè)抽象類,它定義了如下一個(gè)抽象方法:intfilterRGB(intx,inty,intrgb)改方法在缺省的RGB顏色模式中,向filterRGB()方法傳遞像素的位置和RGB顏色的一個(gè)整數(shù)表示,用于檢驗(yàn)像素的RGB表示,返回相同的RGB整數(shù)表示或被修改的像素顏色表示。下面是一個(gè)使用RGBImageFilter實(shí)現(xiàn)自定義的溶解過(guò)濾器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;}}這個(gè)程序?qū)崿F(xiàn)了一個(gè)溶解過(guò)濾器DissolveFilter,它是通過(guò)擴(kuò)展RGBImageFilter得到的。在DissolveFilter構(gòu)造器中,接收被過(guò)濾圖像中每個(gè)顏色的直接顏色模式中的alpha值(直接顏色模式即直接指明顏色值比特位)。alpha值的取值范圍是0~255。alpha值為0表示該圖像是完全透明的,而值255那么表示圖像完全不透明(即原圖)。將載入的圖像中的每個(gè)點(diǎn)通過(guò)DissolveFilter.filterRGB()處理后,重構(gòu)圖像,就得到了如圖9.10所示的運(yùn)行結(jié)果。圖9.109.5動(dòng)畫圖像處理9.5.1使用線程設(shè)計(jì)動(dòng)畫在Java中,實(shí)現(xiàn)動(dòng)畫有很多種方法,但它們實(shí)現(xiàn)的根本原理是一樣的,即在屏幕上畫出一系列的幀來(lái)造成運(yùn)動(dòng)的視覺效果。在此,我們先構(gòu)造一個(gè)程序的框架,再慢慢擴(kuò)展,使之功能比較齊備。為了每秒鐘屢次更新屏幕,必須創(chuàng)立一個(gè)線程來(lái)實(shí)現(xiàn)動(dòng)畫的循環(huán),這個(gè)循環(huán)要跟蹤當(dāng)前幀并響應(yīng)周期性的屏幕更新要求。實(shí)現(xiàn)線程的方法有兩種:創(chuàng)立一個(gè)類Thread的派生類,或在當(dāng)前類上實(shí)現(xiàn)一個(gè)Runnable接口。一個(gè)較容易犯的錯(cuò)誤是將動(dòng)畫循環(huán)放在paint()中,這樣就會(huì)占據(jù)主AWT線程,而主線程是用于負(fù)責(zé)所有的繪圖和事件處理的,這將導(dǎo)致界面對(duì)事件響應(yīng)遲鈍。下面我們來(lái)看一個(gè)使用線程實(shí)現(xiàn)動(dòng)畫的例子。例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;}}此程序的原理是利用一系列的圖片的更替來(lái)實(shí)現(xiàn)動(dòng)畫,run()方法中不斷的調(diào)用repaint()方法,repaint()方法又會(huì)導(dǎo)致paint()方法被調(diào)用,每次調(diào)用paint()方法都會(huì)繪制一副圖片,并且將currentImage指針移動(dòng)到下一幅圖片的位置,橫坐標(biāo)也隨之平移。這樣的效果就是出現(xiàn)一個(gè)不斷移動(dòng)的小人,如圖9.11所示。圖防止閃爍大家可能已經(jīng)發(fā)現(xiàn),上例的畫面有些閃動(dòng)。閃爍有兩個(gè)原因:一是繪制每一幀花費(fèi)的時(shí)間太長(zhǎng)(因?yàn)橹乩L時(shí)要求的計(jì)算量大),二是在每次調(diào)用pait()前整個(gè)背景被去除,當(dāng)在進(jìn)行下一幀的計(jì)算時(shí),用戶看到的是背景。去除背景和繪制圖形間的短暫時(shí)間被用戶看見,就是閃爍。在有些平臺(tái),如PC機(jī)上,閃爍比在XWindow上明顯,這是因?yàn)閄Window的圖像被緩存過(guò),使得閃爍的時(shí)間比較短。有兩種方法可以明顯地減弱閃爍:重載update()或使用雙緩沖。這里我們先討論重載update()的方法。當(dāng)AWT接收到一個(gè)重繪(repaint)請(qǐng)求時(shí),它就先調(diào)用update()去除背景,而update()方法又會(huì)調(diào)用paint()。重載update(),手動(dòng)調(diào)用paint()方法,防止每次重繪時(shí)將整個(gè)區(qū)域去除,即背景不再自動(dòng)去除。這需要我們自己在update()中編寫代碼來(lái)完成。在繪制新的圖像之前手動(dòng)將原來(lái)的舊圖擦除,這樣可以有效地防止閃爍。我們來(lái)看修改以后的例子。例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. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論