小菜樂園

          生活就是一杯茶

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            8 Posts :: 0 Stories :: 3 Comments :: 0 Trackbacks
          筆者在這里將畫線,畫或填充多邊形等理解為"圖形"技術,將圖片的變換,顯示理解為"圖像"技術.

          相對而言,圖形技術較簡單,圖像技術較復雜.下面筆者從實用的角度出發,講解幾個圖像編程問題.首先,我們看下面這個程序.

          import java.applet.*;

          import java.awt.*;

          public class easy extends Applet

          {

          int i=1;

          Image img;

          public void init()

          {

          img=getImage(getCodeBase(),"mama.gif");

          }

          public void paint(Graphics g)

          {

          g.drawImage(img,0,0,this);

          showStatus(String.valueOf(i++));

          }

          }

          HTML 文件如下:

          <APPLET CODE="easy.class"WIDTH=300 HEIGHT=300></APPLET>

          程序非常簡單. 但你注意到沒有,在瀏覽器的狀態欄,顯示出的數值并不一定是1: 你要顯示的圖片幅面越大,這個數值越大.這說明 paint() 方法被調用了不止一次.那么,是誰,在什么時候調用的?

          事實上,每當有新的圖片數據到達或生成時,Java小程序都會自動去調用paint()方法重繪屏幕.這個工作由ImageObserver接口的imageUpdate()方法實現.你可以超越這個imageUpdate()方法,自己重新編程.考慮到本地的機器從Web服務器上獲取圖片的速度一般比較慢,很多時候你必須要知道已經有多少圖片數據已經被下載.下面給出一個示范程序,程序可以一邊下載,一邊顯示,同時通知用戶已經獲得多少圖片數據.

          import java.awt.*;

          import java.applet.*;

          import java.awt.image.*;

          public class image_download extends Applet

          {

          Image img;

          int step=0;//step 用來表述已被下載的那部分圖片的高度

          int percent=0;//percent 用來表述已下載的圖片的高度占圖片總高度的百分比

          public void init()

          {

          img=getImage(getCodeBase(),"mama.gif");

          }

          public void paint(Graphics g)

          {

          g.drawImage(img,0,0,this);

          }

           

          //下面我們超越本來的imageUpdate()方法.每當有新的圖片數據到達(或產生)時此方法會被自動調用

          public boolean imageUpdate(Image img_ob,int flags,int x,int y,int width,int height)

          {

          if(((flags & SOMEBITS)!=0) & (img_ob==img))//判斷是否又有新的圖像數據都被下載

          {

          step=step+height;//計算已被下載的圖片的高度

          percent=step*100/img.getHeight(this);//計算這個高度占圖片高度的的百分比

          showStatus(percent+"%");//在狀態欄顯示

          repaint(x,y,width,height);//重繪屏幕.但只畫新數據表達的部分.簡單使用repaint()重繪

          //整個屏幕會使畫面閃爍

          }

          if((flags & ERROR)!=0)//假如下載出錯

          showStatus("image loading error");

          if((flags & ALLBITS)!=0)//假如全部圖片數據都已下載完

          showStatus("Done");

          return true;

          }

          }

          HTML文件如下:

          <APPLET CODE="image_download.class"WIDTH=300 HEIGHT=300></APPLET>

          imageUpdate()參數說明如下:

          img_ob: 被監視的圖像.

          flags: 被監視圖像的狀態.

          ABORT: 圖像生成被異常中斷

          ALLBITS: 全部圖像都已生成

          ERROR: 發生錯誤

          FRAMEBITS: 完成一幅

          HEIGHT: 本次生成的高度

          SOMEBITS: 已將生成了一部分圖像

          WIDTH: 本次生成的寬度

          x: x軸坐標

          y: y軸坐標

          width: 本次下載的圖像的寬度

          height: 本次下載的圖像的高度

           

          下面用兩個例子說明怎樣獲取大幅圖像的局部.第一個例子使用CropImageFilter類去獲得圖像的局部.你可以這樣使用這種技術:

          首先根據圖像裁剪過濾器產生圖像過濾器.

          ImageFilter filter=new CropImageFilter (int x, int y, int width, int height).

          x: 裁剪起始點 X 軸坐標

          y: 裁剪起始點Y 軸坐標

          width: 裁剪寬度

          height: 裁剪高度

          然后根據根據過濾器產生圖像生產者. ImageProducer procuder=new FilteredImageSource(baseImage.getSource(),filter).

          baseImage: 將要被裁剪的圖片

          然后根據圖像生產者產生新的圖像. Image img=createImage(procuder).

          下面的程序使用上述技術裁剪圖片.程序運行后,你用"拖拽"鼠標的方式(按住鼠標鍵并移動鼠標)在圖片上選定一片區域,然后再在運行區上點擊鼠標,剛才你選定的區域的圖片將被復制到這個位置.要注意的是,程序并未對選擇區域的起始點和終止點的相對位置作出判斷,因此,你一定要使終止點在起始點的右下方.

          import java.awt.*;

          import java.applet.*;

          import java.awt.image.*;

          public class CropFilterImage extends Applet

          {

          Image baseImage,cropImage;//baseImage是原始圖片,cropImage是根據選定區域產生的新圖片

          int sx,sy;//選定區域起始點坐標

          int dx=0,dy=0;//要顯示新圖片的位置

          int width,height;//選定區域的寬和高

          boolean selected=false;//用來判定現在用戶在干什么

          public void init()
          {

          baseImage=getImage(getCodeBase(),"mama.gif");

          cropImage=baseImage;

          }

          public void paint(Graphics g)

          {

          g.drawImage(baseImage,0,0,this);

          g.drawImage(cropImage,dx,dy,this);

          }

          public boolean mouseDown(Event evt,int x,int y)

          {

          if(!selected)//假如用戶開始選擇

          {

          sx=x;//記下起始點

          sy=y;

          selected=true;

          return true;

          }

          else//假如用戶已經設定了選擇區

          {

          dx=x;

          dy=y;

          cropImage=cropImage();//裁剪圖像

          repaint();//重畫屏幕

          selected=false;

          }

          return true;

          }

          public boolean mouseUp(Event evt,int x,int y)

          {

          if(selected)//用戶松開鼠標健表示已確定選擇區

          {

          width=Math.abs(x-sx);

          height=Math.abs(y-sy);

          getGraphics().drawRect(sx,sy,width,height);

          }

          return true;

          }

          public boolean mouseDrag(Event evt,int x,int y)

          {

          showStatus("from("+sx+","+sy+") to ("+x+","+y+")");

          return true;

          }

          Image cropImage()

          {

          ImageFilter filter=new CropImageFilter(sx,sy,width,height);//根據圖像裁剪過濾器產生過濾器

          //下面根據過濾器產生圖像生產者

          ImageProducer producer=new FilteredImageSource(baseImage.getSource(),filter);

          Image img=createImage(producer);//根據圖像生產者產生新圖像

          return img;

          }

          }

          HTML文件如下:

          <APPLET CODE="CropFilterImage.class"WIDTH=600 HEIGHT=300></APPLET>

           

          很多情況下上面的方法不實用.比如你想對圖片作出某種變換,上面的方法就無能為力了.下面的程序給出更強大的算法:將圖像數據取到數組中,再在數組中將需要的數據提取出來,依據這些數據再生成新的圖像去顯示.設想你有一個幅面大于窗口尺寸的圖像要顯示,你必須要讓用戶可以控制窗口的位置,通過移動窗口,瀏覽

          整個圖像.程序運行后,你可以用四個光標鍵移動窗口瀏覽全部圖像.

          程序中的關鍵技術有三個,第一個是PixelGrabber類用于獲取圖像數據.你可以這樣使用:

          首先生成一個PixelGrabber實例:

          PixelGrabber pg=new PixelGrabber(Image img,int x,int y,int width,int height,int pix[ ],int offset,int scansize)

          img: 被取數據的圖像

          x: 起始點 x 軸坐標

          y: 起始點 y 軸坐標

          width: 圖像寬度

          height: 圖像高度

          pix[ ]: 目標數組

          offset: 目標數組的起始地址

          scansize: 圖像每行點數

          然后使用grabPixels( ) 方法取數據:

          try { pg.grabPixels( ) ; }

          catch ( InterruptedException e) { }

          第二個關鍵技術是使用媒體追蹤器MediaTracker監視圖像的生成情況.你可以這樣使用:

          首先生成一個媒體追蹤器的實例:

          MediaTracker mt=new MediaTracker(this);

           

          然后向其中加入要追蹤的圖像:

          mt.addImage(Image image,int ID)

          image是你要追蹤的圖像, ID是你設定的一個表示這個圖像的序號.

          然后使用waitForID ( int ID ) 或 waitForAll( ) 等待圖像全部生成

          try { mt.waitForID(1);}

          catch(InterruptedException e){ }

          第三個關鍵技術是使用內存數據(數組)產生圖像.你可以這樣使用:

          createImage(new MemoryImageSource(int width, int height, int pix[ ], int offset, int scanwidth)

          width: 欲生成的圖像的寬度

          heidth: 欲生成的圖像的高度

          pix[ ]: 數據源

          offset: 叢數組的哪里開始使用數據

          scanwidth: 圖像每行的象素數

          程序如下:

          import java.applet.*;

          import java.awt.*;

          import java.awt.image.*;

          public class picture_window extends Applet

          {

          Image img_full,img_window;//img_full是原圖像, img_window是從原圖像中裁剪的要在窗口中顯示的圖像

          int img_width,img_height;//原始圖像的寬和高

          int window_width=150,window_height=150;//窗口的寬和高

          int window_x=30,window_y=30;//窗口的左上角坐標

          int point_img_full,point_img_window;//原始圖像數據數組的操作地址和窗口圖像數據數組的操作地址

          int img_full_data[];//原始圖像數據數組.沒有初始化是因為現在不知道原始圖像的大小

          int img_window_data[]=new int[window_width * window_height];//窗口圖像數據數組

          MediaTracker mt=new MediaTracker(this);//媒體追蹤器

          PixelGrabber img_full_grabber;//用來獲取原始圖像的數據

          public void init()

          {

          img_window=createImage(window_width,window_height);//創建窗口圖像

          img_full=getImage(getCodeBase()," mama.gif");

          //下面要等待直到全部的原始圖像數據都被正確載入.否則無法知道原始圖像的大小

          mt.addImage(img_full,1);//向媒體追蹤其中加入要追蹤的圖像

          try{mt.waitForID(1);} // 等待全部數據被正確載入

          catch(InterruptedException e){ }

          img_width=img_full.getWidth(this);//現在可以獲取原始圖像的正確信息了.取它的寬和高

          img_height=img_full.getHeight(this);

          img_full_data=new int[img_width * img_height];//初始化原始圖像數據數組

          img_full_grabber=new PixelGrabber(img_full,0,0,img_width,img_height,img_full_data,0,img_width);//準備獲取圖像數據

          try{img_full_grabber.grabPixels();}//采集數據

          catch(InterruptedException e){ }

          get_img_window_data();//生成窗口圖像

          }

          public void paint(Graphics g)

          {

          g.drawImage(img_window,0,0,this);

          }

          public void get_img_window_data()

          {

          point_img_full=window_y * img_width+window_x;//從這個位置開始獲取原始圖像數據

          point_img_window=0;//從這個位置開始向窗口圖像數據數組放數據

          for(int i=0;i<window_height;i++)//逐行處理

          {

          for(int j=0;j<window_width;j++)//逐列處理

          img_window_data[point_img_window++]=img_full_data[point_img_full++];//取和存

           

          point_img_full=point_img_full+img_width-window_width;//開始處理下一行

          }

          img_window=createImage(new MemoryImageSource(window_width,window_height,img_window_data,0,window_width));//根據內存數據(數組)生成圖像

          //等待圖像完全生成.否則一邊生成一邊繪制窗口圖像會閃爍.

          mt.addImage(img_window,1);

          try{mt.waitForID(1);}

          catch(InterruptedException e){}

          }

          //下面的鍵盤事件方法根據用戶的按鍵重置窗口坐標,再生成圖像,再顯示

          public boolean keyDown(Event e,int key)

          {

          switch(key)

          {

          case(Event.UP):

          if(window_y>0)

          window_y-=1;

          break;

          case(Event.DOWN):

          if(window_y<(img_height-window_height))

          window_y+=1;

          break;

          case(Event.RIGHT):

          if(window_x<(img_width-window_width))

          window_x+=1;

          break;

          case(Event.LEFT):

          if(window_x>0)

          window_x-=1;

          break;

          default:

          break;

          }

          showStatus(String.valueOf(window_x)+" , "+String.valueOf(window_y));

          get_img_window_data();

          getGraphics().drawImage(img_window,0,0,this);

          return true;

          }

          }

          HTML文件如下:

          <APPLET CODE="picture_window.class"WIDTH=150 HEIGHT=150></APPLET>

           

          下面的程序對兩個圖像進行合成并顯示來模擬圖像的淡入淡出.程序運行后,每按一次向上鍵,前景圖像就增強一點,每按一次向下鍵,前景圖像就減弱一點.

          首先你要了解圖像數據.

          每個象素點的信息由一個整數表達.整數共32個二進制位,從左向右,分成四個部分,每部分都是8位.

          第一部分: Alpha 信息.控制圖像顯示的強度.下面的程序就是通過調整這個數值控制圖像的淡入淡出.

          第二部分:紅色數據.

          第三部分:綠色數據.

          第四部分:藍色數據.

          程序使用的方法是:先畫背景圖像,再在上面畫帶Alpha數據的前景圖像,通過調整Alpha值使前景圖像淡入 淡出.

          import java.applet.*;

          import java.awt.*;

          import java.awt.image.*;

          public class alpha extends Applet

          {

          Image background, foreground;//背景圖像和前景圖像

          Image foreground_new;//依據前景圖像生成的帶Alpha通道的新圖像

          MediaTracker mt;

          int foreground_alpha=175;//前景圖像的起始Alpha值

          int foreground_data[];//用來生成新圖像的內存數據

          PixelGrabber pg;

          int transparancy;//前景圖像的全透明點的像素值.只要前景圖像的某個點是這個值,它就全透明

          public void init()

          {

          background=getImage(getCodeBase(),"mama.gif");

          foreground=getImage(getCodeBase(),"baba.gif");

          mt=new MediaTracker(this);

          mt.addImage(background,1);

          mt.addImage(foreground,2);

          try{mt.waitForAll();} // 等待所有圖片的數據都被正確載入

          catch(InterruptedException e){ }

          foreground_data=new int[foreground.getWidth(this) * foreground.getHeight(this)];//初始化

          //下面把前景圖片的數據載入數組

          pg=new PixelGrabber(foreground,0,0,foreground.getWidth(this),foreground.getHeight(this),foreground_data,0,foreground.getWidth(this));

          try{pg.grabPixels();}

          catch(InterruptedException e){ }

          for (int i=0;i<(foreground.getWidth(this) * foreground.getHeight(this));i++)

          foreground_data[i]=foreground_data[i]&0x00ffffff;//把所有的象素的Alpha值置為0

          //下面我把圖像左上角的點的值作為透明值.假如圖像中哪個點的值和左上角的點的值一樣,

          //這個點就全透明--背景100%出現.我用這個比較簡單的辦法把前景圖像中我不想要的部分去掉

          transparancy=foreground_data[0];

          }

          public void paint(Graphics g)

          {

          g.drawImage(background,0,0,this);

          }

          public boolean keyDown(Event e, int key)

          {

          if (key==Event.UP && foreground_alpha<255)//依據按鍵改變Alpha值

          foreground_alpha++;

          if (key==Event.DOWN && foreground_alpha>0)

          foreground_alpha--;

          showStatus(String.valueOf(foreground_alpha));//在狀態欄顯示Alpha值

          for (int i=0;i<(foreground.getWidth(this) * foreground.getHeight(this));i++)//逐點處理

          {

          foreground_data[i]=foreground_data[i] & 0x00ffffff;//置此點為全透明

          if (foreground_data[i]!=transparancy)//假如這個點的值和全透明點不同

          foreground_data[i]=foreground_data[i] | (foreground_alpha<<24);//給它Alpha值

          }

          foreground_new=createImage(new MemoryImageSource(foreground.getWidth(this),foreground.getHeight(this),foreground_data,0,foreground.getWidth(this)));//生成前景圖象

          mt.addImage(foreground_new,3);

          try{mt.waitForID(3);}

          catch(InterruptedException e2){ }

          getGraphics().drawImage(background,0,0,this);//先畫背景

          getGraphics().drawImage(foreground_new,100,100,this);//再畫前景

          return true;

          }

          }

          下面是HTML文件:

          <APPLET CODE="alpha.class"WIDTH=300 HEIGHT=300></APPLET>  
          posted on 2007-08-17 07:48 小菜 閱讀(734) 評論(0)  編輯  收藏 所屬分類: Java圖形圖像
          主站蜘蛛池模板: 鲜城| 会泽县| 镇江市| 蛟河市| 中江县| 宁德市| 广汉市| 陆良县| 太谷县| 岱山县| 和龙市| 湖南省| 潜江市| 陆河县| 湖北省| 奉新县| 海盐县| 武威市| 张家界市| 千阳县| 海丰县| 平阳县| 同心县| 靖江市| 昆明市| 定襄县| 达州市| 井陉县| 平江县| 马关县| 古交市| 吉安县| 新和县| 彰化市| 磐石市| 育儿| 轮台县| 高邑县| 台北市| 平利县| 当雄县|