Do you drink java?



      像写情书一样coding

 

[Image] AWT使用ImageProducer/ImagConsumer模式加载和显示图像的原理

以前写过2篇关于AWT中图像加载显示方法的文章,最近又多了一些对于 ImageProducer / ImagConsumer 模式的一些理解,尝试着用文字总结了一下,接着还想再写一篇介绍 AWT 中图像过滤的原理和方法。你可能认为现在学习 AWT 中的成像方法对于开发中已经没有太大的意义,因为已经有了 Java 2D 和 JAI ,但是我在实际工作中感到还是无法完全离开 AWT,特别是在一些基本的应用上。而且我觉得理解 AWT 的 Producer / Consumer (push) model 对于理解 Java 2D 的 Immediate mode model 和 JAI 的 Pipeline (pull) model 的都是有好处的。

因为水平有限,这方面学习资料相对也不丰富,我也不知道我的理解或想法是否完全正确或者表述清楚,感兴趣的朋友可以当作学习参考,希望能够和我联系进行进一步的讨论。



AWT 使用 ImageProducer / ImagConsumer 模式,支持加载和显示 GIF 图像文件格式和 JPEG 图像文件格式。因为图像的加载和显示是异步方式进行的,所以有大量加载和显示的技术。

在 AWT 中,提供了一个 java.awt.Image 类。java.awt.Image 类代表一个图像对象被作为参数传递给其他用来显示和处理图像的其他 AWT 对象使用。例如,通过调用 Graphics.drawImage(java.awt.Image, int, int, ImageObserver) 方法,可以在组件中画出图像。

java.awt.Image 是一个定义方法的抽象类,它定义的方法提供的对图像信息的访问。而创建和处理图像的基本结构则在 java.awt.image 包中。注意,这里不要和 java.awt.Image 发生混淆。

AWT  加载和显示图像使用的是 ImageProducer / ImagConsumer 模式,我们必须了解3个术语,ImageProducer(图像生产者),ImageConsumer(图像消费者)和ImageObserver(图像观察者)。

ImageProducer 负责生产图像的位,ImagConsumer 接受图像的位,ImageObserver 监视 ImageProducer 的图像生产过程。ImageProducer 生产传递给 ImagConsumer 与图像相关的位。因为图像生产过程是异步进行的,并不是一次性生产所有图像位,所以当 ImageProducer 加载图像时,ImageObserver 用来监视它的进展情况。因为 java.awt.Component 实现了 ImageObserver 接口,所以 AWT 中的每个组件都可以是ImageObserver,当一个给定的 ImageProducer 进行异步操作时,这个 ImageObserver 可以选择是否被更新。java.awt.image 包为 ImageProducer,ImagConsumer 和 ImageObserver 都定义了接口。

ImageProducer
和图像相关的位并不存储在 java.awt.Image 中,每个图像都维护一个和一个 ImageProducer 的关联。这个 ImageProducer 的责任是生产图像的位并将它们传送给 ImagConsumer,用于过滤该图像。

java.awt.image软件包中,FilteredImageSource(被过滤的图像源)和 MemoryImageSource(内存的图像源)实现了 ImageProducer  接口,是 ImageProducer 。


ImagConsumer
java.awt.image软件包中,ImageFilter(图像过滤器)和 PixelGrabber(像素抓取器)实现了 ImagConsumer 接口,是 ImagConsumer。


ImageProducer 和 ImagConsumer 的详细介绍请阅读 使用 ImageProducer  / ImagConsumer 进行图像过滤


ImageObserver
ImageObserver接口中,定义了一个常数集合和一个方法:

public boolean imageUpdate(image img, int flags, int x, int y, int width, int height);

ImageObserver的常数
标志 含义
ABORT 图像加载被中断
ALLBITS 所有的位都已加载给图像
ERROR 在加载过程中发生错误
FRAMEBITS 多帧图像的一个帧被传送,一般用于GIF
HEIGHT 图像的高度已经可用
PROPERTIES 图像的属性已经可用
SOMEBITS 图像的缩放变体的多个位已经可用
WIDTH 图像的宽度已经可用

参数 flags 的作用是通知图像观察者图像生产的进展情况。这些常数代表传递给 ImageObserver.imageUpdate() 的 flags 参数中的位。

当 Component 作为 ImageObserver 时,一旦图像有新的部分被加载,就会调用 Component.imageUpdate() 方法,imageUpdate() 再调用 repaint() 重新绘制图像。repaint() 将先调用 update() 方法清除组件背景,再由 update() 方法调用 paint() 方法绘制图像。我们可以通过重载 imageUpdate() 方法控制组件何时被更新,重载 update() 方法控制是否每次重绘都要清除背景图像(每次重绘都清除背景图像会造成画面闪烁)。


为了更好的理解,下面我们来看几个样例程序:

例1,图像位在需要之前不被生产

import java.net.URL;
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Image;

public class ImageTestAppletSimple extends Applet{
    
private Image im;
    
    
public void init(){
        URL codebase 
= getCodeBase();
        System.out.println(codebase);
        
        im 
= getImage(codebase,"flower.jpg");
        
        System.out.print(
"Image width = " + im.getWidth(this));
        System.out.println(
" hight = " + im.getHeight(this));
    }

    
    
public void paint(Graphics g){
        g.drawImage(im,
0,0,this);
    }

}

输出结果:
image width = -1 height = -1

图像的高度和宽度只有在图像被完全加载后才是有效的,输出结果说明 java.awt.image 相关的图像位在需要之前不被生产。


例2,图像异步生产

import java.net.URL;
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Image;

public class ImageTestAppletSimple2 extends Applet{
    
private Image im;
    
    
public void init(){
        im 
= getImage(getCodeBase(),"flower.jpg");
    }

    
    
public void paint(Graphics g){
        System.out.println(
"drawing image...");
        System.out.println(g.drawImage(im,
0,0,this));
    }

}

输出结果:
drawing image...
false
drawing image...
false
drawing image...
false
drawing image...
true

输出结果说明组件作为 ImageObserver ,监视 ImageProducer 异步生产图像,一旦有新的图像位被生产时就重绘图像,图像完全加载后 drawImage() 方法返回 true。


例3,重载 ImageObserver 的 imageUpdate() 方法,在图像完全加载前不调用 repaint()

import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Image;

public class ImageTestAppletWithUpdate extends Applet{
    
private Image im;
    
    
public void init(){
        im 
= getImage(getCodeBase(),"flower.jpg");
        
        System.out.print(
"Image width = " + im.getWidth(this));
        System.out.println(
"hight = " + im.getHeight(this));
    }

    
    
public void paint(Graphics g){
        g.drawImage(im,
0,0,this);
    }

    
    
public boolean imageUpdate(Image image,int flags,int x,int y,int w,int h){
        System.out.println(
"imageUpdate():x=" + x + ",y=" + y + ",w=" + w + ",h=" + h);
        
        
if((flags & ALLBITS) == 0)
            
return true;
        
else
        
{
            repaint();
            
return false;
        }

    }

}



例4,重载  Component.update() 方法,被调用时不清除背景图像,直接调用 paint() 方法绘制图像,消除闪烁

import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Image;

public class ImageTestAppletWithSmoothDynamicUpdate extends Applet{
    
private Image im;
    
    
public void init(){
        im 
= getImage(getCodeBase(),"hl.jpg");
        
        System.out.print(
"Image width = " + im.getWidth(this));
        System.out.println(
"hight = " + im.getHeight(this));
    }

    
    
public void paint(Graphics g){
        g.drawImage(im,
0,0,this);
    }

    
    
public boolean imageUpdate(Image image,int flags,int x,int y,int w,int h){
        System.out.println(
"imageUpdate():x=" + x + ",y=" + y + ",w=" + w + ",h=" + h);
        
        repaint();
        
        
if((flags & ALLBITS) == 0)
            
return true;
        
else
            
return false;
    }

    
    
public void update(Graphics g){
        paint(g);
    }

}

 

posted on 2005-10-11 10:35 leon 阅读(2611) 评论(3)  编辑  收藏 所属分类: JFC

评论

# re: [Image] AWT使用ImageProducer/ImagConsumer模式加载和显示图像的原理 2005-12-31 08:58 kris zhang

看到你的文章很受启发,希望能与你成为朋友。 我的msn: zqs77713@hotmail.com  回复  更多评论   

# re: [Image] AWT使用ImageProducer/ImagConsumer模式加载和显示图像的原理 2006-12-01 11:08 lattimore[匿名]

今天竟然搜到你的BLOG上来拉..太神奇拉..  回复  更多评论   

# re: [Image] AWT使用ImageProducer/ImagConsumer模式加载和显示图像的原理 2007-05-21 11:13 youke

大哥 你能不能把getImage()给出来啊!  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航:
 

导航

统计

公告

DSC_0106.jpg
本博客已经搬家到CSDN
http://blog.csdn.net/chenweionline




常用链接

留言簿(5)

随笔分类

随笔档案

About Technology

My Favorite Website

搜索

积分与排名

最新评论

  • 1. re: 胃痉挛
  • 兄弟们你们都做胃镜了吗开的啥药?有什么养胃秘方啊?请赐教啊!
  • --我也进来了
  • 2. re: 胃痉挛
  • @痛啊
    我感觉比生孩子还疼,生孩子还能有意识呢!这种疼还叫不出来连说话的力气都没了
  • --我也进来了
  • 3. re: 胃痉挛
  • 评论内容较长,点击标题查看
  • --我也进来了
  • 4. re: 胃痉挛
  • 我都周期性的发作,算来有4年了 。每年最少一次,一次最少2天。吃了好多药就差没去做胃镜了。 刚刚发作就随便煮了点姜汤喝下就好了些,不知道还会不会发作了。
  • --许家洛
  • 5. re: 胃痉挛
  • 我昨晚也疼的要死。。上次疼的直接120送医院了,一上120我竟然就不疼了,医院里掉了瓶盐水就放回家了。这次正好国外旅游中,几乎疼了一整晚,整个在床上翻滚状态了。今天不疼了,就是整个人难受。。。求助阿
  • --胃疼
  • 6. re: [Swing]在 JFileChooser 中进行文件验证的小技巧
  • 输入*还是会有问题
  • --ngh
  • 7. re: 胃痉挛[未登录]
  • 昨晚一夜的身不如死的感觉,胃痉挛兄不要来了吧 ,求你了
  • --李飞
  • 8. re: 胃痉挛
  • 评论内容较长,点击标题查看
  • --daidai
  • 9. re: 胃痉挛
  • 评论内容较长,点击标题查看
  • --痛啊
  • 10. re: 胃痉挛
  • 妈啊 痛的快死了~!第一次感觉过这样的痛啊~!和女的生孩子有的一比了吧~!哭哭哭~!
  • --痛啊

阅读排行榜