筆者在這里將畫線,畫或填充多邊形等理解為"圖形"技術(shù),將圖片的變換,顯示理解為"圖像"技術(shù).
相對而言,圖形技術(shù)較簡單,圖像技術(shù)較復(fù)雜.下面筆者從實用的角度出發(fā),講解幾個圖像編程問題.首先,我們看下面這個程序.
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
文件如下:
程序非常簡單. 但你注意到?jīng)]有,在瀏覽器的狀態(tài)欄,顯示出的數(shù)值并不一定是1:
你要顯示的圖片幅面越大,這個數(shù)值越大.這說明 paint()
方法被調(diào)用了不止一次.那么,是誰,在什么時候調(diào)用的?
事實上,每當(dāng)有新的圖片數(shù)據(jù)到達或生成時,Java小程序都會自動去調(diào)用paint()方法重繪屏幕.這個工作由ImageObserver接口的imageUpdate()方法實現(xiàn).你可以超越這個imageUpdate()方法,自己重新編程.考慮到本地的機器從Web
服務(wù)器上獲取圖片的速度一般比較慢,很多時候你必須要知道已經(jīng)有多少圖片數(shù)據(jù)已經(jīng)被下載.下面給出一個示范程序,程序可以一邊下載,一邊顯示,同時通知用戶已經(jīng)獲得多少圖片數(shù)據(jù).
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()方法.每當(dāng)有新的圖片數(shù)據(jù)到達(或產(chǎn)生)時此方法會被自動調(diào)用
public
boolean imageUpdate(Image img_ob,int flags,int x,int y,int width,int
height)
{
if(((flags & SOMEBITS)!=0) &
(img_ob==img))//判斷是否又有新的圖像數(shù)據(jù)都被下載
{
step=step+height;//計算已被下載的圖片的高度
percent=step*100/img.getHeight(this);//計算這個高度占圖片高度的的百分比
showStatus(percent+"%");//在狀態(tài)欄顯示
repaint(x,y,width,height);//重繪屏幕.但只畫新數(shù)據(jù)表達的部分.簡單使用repaint()重繪
//整個屏幕會使畫面閃爍
}
if((flags
& ERROR)!=0)//假如下載出錯
showStatus("image loading
error");
if((flags &
ALLBITS)!=0)//假如全部圖片數(shù)據(jù)都已下載完
showStatus("Done");
return
true;
}
}
HTML文件如下:
imageUpdate()參數(shù)說明如下:
img_ob:
被監(jiān)視的圖像.
flags: 被監(jiān)視圖像的狀態(tài).
ABORT: 圖像生成被異常中斷
ALLBITS:
全部圖像都已生成
ERROR: 發(fā)生錯誤
FRAMEBITS: 完成一幅
HEIGHT:
本次生成的高度
SOMEBITS: 已將生成了一部分圖像
WIDTH: 本次生成的寬度
x:
x軸坐標(biāo)
y: y軸坐標(biāo)
width: 本次下載的圖像的寬度
height:
本次下載的圖像的高度
下面用兩個例子說明怎樣獲取大幅圖像的局部.第一個例子使用CropImageFilter類去獲得圖像的局部.你可以這樣使用這種技術(shù):
首先根據(jù)圖像裁剪過濾器產(chǎn)生圖像過濾器.
ImageFilter filter=new CropImageFilter (int x, int y, int width, int
height).
x: 裁剪起始點 X 軸坐標(biāo)
y: 裁剪起始點Y 軸坐標(biāo)
width:
裁剪寬度
height: 裁剪高度
然后根據(jù)根據(jù)過濾器產(chǎn)生圖像生產(chǎn)者. ImageProducer procuder=new
FilteredImageSource(baseImage.getSource(),filter).
baseImage:
將要被裁剪的圖片
然后根據(jù)圖像生產(chǎn)者產(chǎn)生新的圖像. Image
img=createImage(procuder).
下面的程序使用上述技術(shù)裁剪圖片.程序運行后,你用"拖拽"鼠標(biāo)的方式(按住鼠標(biāo)鍵并移動鼠標(biāo))在圖片上選定一片區(qū)域,然后再在運行區(qū)上點擊鼠標(biāo),剛才你選定的區(qū)域的圖片將被復(fù)制到這個位置.要注意的是,程序并未對選擇區(qū)域的起始點和終止點的相對位置作出判斷,因此,你一定要使終止點在起始點的右下方.
import
java.awt.*;
import java.applet.*;
import
java.awt.image.*;
public class CropFilterImage extends
Applet
{
Image
baseImage,cropImage;//baseImage是原始圖片,cropImage是根據(jù)選定區(qū)域產(chǎn)生的新圖片
int
sx,sy;//選定區(qū)域起始點坐標(biāo)
int dx=0,dy=0;//要顯示新圖片的位置
int
width,height;//選定區(qū)域的寬和高
boolean
selected=false;//用來判定現(xiàn)在用戶在干什么
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//假如用戶已經(jīng)設(shè)定了選擇區(qū)
{
dx=x;
dy=y;
cropImage=cropImage();//裁剪圖像
repaint();//重畫屏幕
selected=false;
}
return
true;
}
public boolean mouseUp(Event evt,int x,int
y)
{
if(selected)//用戶松開鼠標(biāo)健表示已確定選擇區(qū)
{
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);//根據(jù)圖像裁剪過濾器產(chǎn)生過濾器
//下面根據(jù)過濾器產(chǎn)生圖像生產(chǎn)者
ImageProducer
producer=new FilteredImageSource(baseImage.getSource(),filter);
Image
img=createImage(producer);//根據(jù)圖像生產(chǎn)者產(chǎn)生新圖像
return
img;
}
}
HTML文件如下:
很多情況下上面的方法不實用.比如你想對圖片作出某種變換,上面的方法就無能為力了.下面的程序給出更強大的算法:將圖像數(shù)據(jù)取到數(shù)組中,再在數(shù)組中將需要的數(shù)據(jù)提取出來,依據(jù)這些數(shù)據(jù)再生成新的圖像去顯示.設(shè)想你有一個幅面大于窗口尺寸的圖像要顯示,你必須要讓用戶可以控制窗口的位置,通過移動窗口,瀏覽
整個圖像.程序運行后,你可以用四個光標(biāo)鍵移動窗口瀏覽全部圖像.
程序中的關(guān)鍵技術(shù)有三個,第一個是PixelGrabber類用于獲取圖像數(shù)據(jù).你可以這樣使用:
首先生成一個PixelGrabber實例:
PixelGrabber pg=new PixelGrabber(Image img,int x,int y,int width,int
height,int pix[ ],int offset,int scansize)
img: 被取數(shù)據(jù)的圖像
x: 起始點 x
軸坐標(biāo)
y: 起始點 y 軸坐標(biāo)
width: 圖像寬度
height: 圖像高度
pix[ ]:
目標(biāo)數(shù)組
offset: 目標(biāo)數(shù)組的起始地址
scansize: 圖像每行點數(shù)
然后使用grabPixels( )
方法取數(shù)據(jù):
try { pg.grabPixels( ) ; }
catch ( InterruptedException e)
{
}
第二個關(guān)鍵技術(shù)是使用媒體追蹤器MediaTracker監(jiān)視圖像的生成情況.你可以這樣使用:
首先生成一個媒體追蹤器的實例:
MediaTracker
mt=new
MediaTracker(this);
然后向其中加入要追蹤的圖像:
mt.addImage(Image
image,int ID)
image是你要追蹤的圖像, ID是你設(shè)定的一個表示這個圖像的序號.
然后使用waitForID (
int ID ) 或 waitForAll( ) 等待圖像全部生成
try { mt.waitForID(1);}
catch(InterruptedException e){
}
第三個關(guān)鍵技術(shù)是使用內(nèi)存數(shù)據(jù)(數(shù)組)產(chǎn)生圖像.你可以這樣使用:
createImage(new
MemoryImageSource(int width, int height, int pix[ ], int offset, int
scanwidth)
width: 欲生成的圖像的寬度
heidth: 欲生成的圖像的高度
pix[ ]:
數(shù)據(jù)源
offset: 叢數(shù)組的哪里開始使用數(shù)據(jù)
scanwidth:
圖像每行的象素數(shù)
程序如下:
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;//窗口的左上角坐標(biāo)
int
point_img_full,point_img_window;//原始圖像數(shù)據(jù)數(shù)組的操作地址和窗口圖像數(shù)據(jù)數(shù)組的操作地址
int
img_full_data[];//原始圖像數(shù)據(jù)數(shù)組.沒有初始化是因為現(xiàn)在不知道原始圖像的大小
int img_window_data[]=new
int[window_width * window_height];//窗口圖像數(shù)據(jù)數(shù)組
MediaTracker mt=new
MediaTracker(this);//媒體追蹤器
PixelGrabber
img_full_grabber;//用來獲取原始圖像的數(shù)據(jù)
public void
init()
{
img_window=createImage(window_width,window_height);//創(chuàng)建窗口圖像
img_full=getImage(getCodeBase(),"mama.gif");
//下面要等待直到全部的原始圖像數(shù)據(jù)都被正確載入.否則無法知道原始圖像的大小
mt.addImage(img_full,1);//向媒體追蹤其中加入要追蹤的圖像
try{mt.waitForID(1);}
// 等待全部數(shù)據(jù)被正確載入
catch(InterruptedException e){
}
img_width=img_full.getWidth(this);//現(xiàn)在可以獲取原始圖像的正確信息了.取它的寬和高
img_height=img_full.getHeight(this);
img_full_data=new
int[img_width * img_height];//初始化原始圖像數(shù)據(jù)數(shù)組
img_full_grabber=new
PixelGrabber(img_full,0,0,img_width,img_height,img_full_data,0,img_width);//準備獲取圖像數(shù)據(jù)
try{img_full_grabber.grabPixels();}//采集數(shù)據(jù)
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;//從這個位置開始獲取原始圖像數(shù)據(jù)
point_img_window=0;//從這個位置開始向窗口圖像數(shù)據(jù)數(shù)組放數(shù)據(jù)
for(int
i=0;i
{
for(int
j=0;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));//根據(jù)內(nèi)存數(shù)據(jù)(數(shù)組)生成圖像
//等待圖像完全生成.否則一邊生成一邊繪制窗口圖像會閃爍.
mt.addImage(img_window,1);
try{mt.waitForID(1);}
catch(InterruptedException
e){}
}
//下面的鍵盤事件方法根據(jù)用戶的按鍵重置窗口坐標(biāo),再生成圖像,再顯示
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文件如下:
下面的程序?qū)蓚€圖像進行合成并顯示來模擬圖像的淡入淡出.程序運行后,每按一次向上鍵,前景圖像就增強一點,每按一次向下鍵,前景圖像就減弱一點.
首先你要了解圖像數(shù)據(jù).
每個象素點的信息由一個整數(shù)表達.整數(shù)共32個二進制位,從左向右,分成四個部分,每部分都是8位.
第一部分:
Alpha
信息.控制圖像顯示的強度.下面的程序就是通過調(diào)整這個數(shù)值控制圖像的淡入淡出.
第二部分:紅色數(shù)據(jù).
第三部分:綠色數(shù)據(jù).
第四部分:藍色數(shù)據(jù).
程序使用的方法是:先畫背景圖像,再在上面畫帶Alpha數(shù)據(jù)的前景圖像,通過調(diào)整Alpha值使前景圖像淡入
淡出.
import java.applet.*;
import java.awt.*;
import
java.awt.image.*;
public class alpha extends Applet
{
Image
background, foreground;//背景圖像和前景圖像
Image
foreground_new;//依據(jù)前景圖像生成的帶Alpha通道的新圖像
MediaTracker mt;
int
foreground_alpha=175;//前景圖像的起始Alpha值
int
foreground_data[];//用來生成新圖像的內(nèi)存數(shù)據(jù)
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();}
// 等待所有圖片的數(shù)據(jù)都被正確載入
catch(InterruptedException e){
}
foreground_data=new int[foreground.getWidth(this) *
foreground.getHeight(this)];//初始化
//下面把前景圖片的數(shù)據(jù)載入數(shù)組
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%出現(xiàn).我用這個比較簡單的辦法把前景圖像中我不想要的部分去掉
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)//依據(jù)按鍵改變Alpha值
foreground_alpha++;
if
(key==Event.DOWN &&
foreground_alpha>0)
foreground_alpha--;
showStatus(String.valueOf(foreground_alpha));//在狀態(tài)欄顯示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文件:
[@more@]
分享名稱:Java圖像技術(shù)(轉(zhuǎn))
網(wǎng)頁地址:
http://weahome.cn/article/iiccoc.html