Giao diện Observer

Một phần của tài liệu Đồ án xử lý ảnh trong Java (Trang 83 - 89)

5. 1 DFt

6.2Giao diện Observer

Mặc dù giao diện Observer không đợc đa ra ở đây nhng nó là lớp trọng tâm để tìm hiểu xem các hoạt động của lớp Image nh thế nào. Giao diện đặt trong gói java.util (đây là gói th viện có sẵn của java) đợc sử dụng để thực thi các phơng thức cần thiết và liên kết các thao tác trong môi trờng hớng đối tợng. Mối quan hệ giữa lớp thi hành giao diện và lớp mở rộng là mối quan hệ kiểu modul-view. Chúng ta hãy tởng tợng mối quan hệ modul-view tơng tự nh mối quan hệ giữa bình ga ô tô và bộ phận đo nhiên liệu của nó. Khi lợng nhiên liệu trong bình ga thay đổi thì bộ phận đo lợng nhiên liệu cho thấy sự thay đổi đó.

Sau đây ta xét hớng chảy thông tin giữa hai biến lớp, một biến là lớp mở rộng của Observable biến còn lại là lớp thi hành giao diện Observer. Biến lớp Obserable giữ một vector liệt kê tất cả các biến kiểu Observer, trong đó mỗi biến kiểu Observerr thì lu trạng thái hoạt động của biến Observable. Mỗi khi biến Observable có thay đổi nó gửi một bản cập nhật về các thông tin mới tới tất cả các biến kiểu Observer đã đợc lu. Mối quan hệ này có dạng nh trên hình 6.2.

Hình 6.2

Nội dung của giao diện

package java.util;

public interface Observer {

void update(Observable o, Object arg); }

Lớp Observable (the Observer Class)

Lớp Observer đặt trong gói java.util. Nh ta đã biết gói java.util là một th viện chuẩn do java cung cấp, mỗi biến có kiểu Observable sử dụng một

instance của danh sách các biến Observer. Danh sách này gọi là ObserverList và đặt trong gói java.util.

Tóm tắt nội dung của lớp

package java.util;

public class Observable {

public synchronized void addObserver(Observer o) public synchronized void deleteObserver(Observer o) public void notifyObserver()

public synchronized void notifyObservers(Object arg) public synchronized void deleteObservers()

public synchronized boolean hasChanged() public synchronized int countObservers() }

Lớp NamedObservable

Lớp NamedObservable cung cấp một kĩ thuật liên kết một biến kiểu String với một biến kiểu Observable.

package observers; import java.util.*;

public abstract class NamedObservable extends Observable { private String name;

public synchronized void setName(String nm) { name = nm;

}

public synchronized String getName() { return name;

} }

Ví dụ về Observable Double và Observer-Observable

Chơng trình DiffCAD do ta viết cũng dựa trên dạng thức model-view và có một gói tên là observers. Một trong các lớp thuộc gói Observers là lớp ObservableDouble.

Khi phơng thức setValue đợc thực hiện với một biến thuộc kiểu ObservableDouble thì phơng thức notifyObservers gọi tới phơng thức update để gửi tới các biến có kiểu Observer những thay đổi đó.

package observers; import java.util.*;

public class ObservableDouble extends NamedObservable { private double value; (adsbygoogle = window.adsbygoogle || []).push({});

public ObservableDouble(double newValue, String nm) { value = newValue;

setName(nm); }

public synchronized void setValue(double newValue) { if (newValue != value) { value = newValue; super.setChanged(); super.notifyObservers(); } }

public synchronized double getValue() { return value;

}

}

Lớp Image

Trong java, một ảnh đợc lu trong một instance của lớp Image, lớp này nằm trong gói th viện chuẩn java.awt. Lớp Image đợc thiết lập với mục đích hình ảnh sẽ đợc tạo ra bởi hệ thống có hạn chế I/O. Lớp Image cung cấp các phơng thức thao tác với ImageObserver. Các biến có kiểu ImageObserver đợc lu giữ để thông báo cho ngời dùng mỗi khi một hình ảnh mới đợc tạo ra.

Nội dung của lớp

package java.awt;

import java.awt.image.ImageProducer; import java.awt.image.ImageObserver; public abstract class Image {

public abstract int getWidth(ImageObserver observer); public abstract int getHeight(ImageObserver observer); public absteact ImageProducer getSource();

public abstract Graphics getGraphics();

public abstract Object getProperty(String name, ImageObserver observer);

public static final Observer UndefinedProperty = new Observer(); public abstract abstract void flush();

}

Cách sử dụng

Lớp Image sử dụng mô hình observer-observable và có thuộc tính abstract do đó không thể khởi tạo nó trực tiếp. Giả sử ta khai báo các biến nh dới đây:

Image image;

ImageObserver imageObserver; ImageProducer imageProducer; int height, width;

Graphics graphics; String name;

Khi đó muốn nhận đợc bề rộng của ảnh, bề cao của ảnh ta sử dụng các câu lệnh sau:

width = image.getWidth(imageObserver); height = image.getHeight(imageObserver);

Giá trị trả về sẽ là -1 nếu hình ảnh không tồn tại và thông báo Observer khi hình ảnh đã hiện hữu.

Muốn nhận đợc biến mà biến này tạo ra các điểm ảnh:

imageProducer = image.getSource();

Để nhận đợc một biến đồ hoạ đối với hình ảnh off-screen :

graphics = image.getGraphics(); (adsbygoogle = window.adsbygoogle || []).push({});

Để nhận đợc đặc tính của ảnh thông qua tên của ảnh.

object = image.getProperty(name, imageObserver);

nếu hình ảnh là không tồn tại, getproperty trả về giá trị null và thông báo cho imageObserver ngay sau đó. Image.UndefinedProperty là một biến đối tợng có thuộc tính static final đợc trả về khi đặc tính không đợc định nghĩa.

Cuối cùng để loại bỏ tất cả các nguồn sử dụng bởi hình ảnh mà hiện không còn dùng tới ta sử dụng câu lệnh:

image.flush();

Giao diện ImageObserver

Giao diện ImageObserver nằm trong gói java.awt.image. Một instance của lớp có bổ xung giao diện Imageobserver thì đợc xem nh trọng tâm trong nội dung của một biến Imageproducer. Khi nội dung đợc thay đổi, biến ImageObserver đợc thông báo cho biết có sự thay đổi đó nhờ vào lời gọi tới ph- ơng thức inmageUpdate của Imagerproducer.

Nội dung của lớp

package java.awt.image; import java.awt.Image;

public interface ImageObserver {

public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height);

public static final int WIDTH = 1; public static final int HEIGHT = 2; public static final int PROPERTIES = 4;

public static final int SOMEBITS = 8; public static final int FRAMEBITS = 16; public static final int ALLBITS = 32; public static final int ERROR = 64; public static final int ABORT = 128;

Ví dụ về ảnh trong ImageFrame

Lớp ImageFrame có phơng thức getImage tạo ra hộp hội thoại cho phép ngời sử dụng nhập vào tên fie ảnh muốn xem, chờ quá trình đọc ảnh kết thúc và sau đó tạo nguồn cần thiết để lu các biến ảnh này. Chúng ta cần nắm bắt cách thiết kế này để phục vụ cho tác vụ đọc các file ảnh của ta. Dễ nhận thấy là các mã lệnh rất khó cho việc hiểu, viết, và dạy hơn là một API đơn giản. Để tránh đ ợc thì cách thông thờng là tạo ra một Imageproducer tạm trong đó có sử dụng ph- ơng thức getImage. Phơng thức getImage khá thuận lợi cho ngời dùng, nhng tổng quan mà nói ảnh đợc lu trên một thiết bị lu trữ ngầm và là nhỏ. Các biến filename, image là các biến lớp thuộc lớp ImageFrame, phơng thức getImage có dạng nh sau:

pulic void getImage() {

// Open the image by file name and wait for it! Filename = Futil.getFileName();

System.out.println(“Get image:” +filename); try{

image = getToolkit().getImage(filename); waitForImage(this, name);

}

catch (Eception e) {

System.out.println(“Get image could not open:” + e); }

//more the image, change its dimanetions reshape(100,100,

image.getWidth(this), image.getHeight(this)); //set image title

setTitle(filename); Show();

}

Hộp hội thoại có dạng nh sau:

Phơng thức waitForImage tránh lời gọi trở về và dừng các công việc trớc khi phơng thức getImage đợc trả lại. Phơng thức paint của ImageFrame gọi tới phơng thức drawImage có trong biến Graphics, g: (adsbygoogle = window.adsbygoogle || []).push({});

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

Trong phần trên chúng ta đã tìm hiểu sơ lợc các phơng thức có sẵn của java để thao tác với các file ảnh, sau đây là một số lớp do ta viết có sử dụng các tiện ích sẵn có đó để thực hiện một số phép xử lý ảnh cơ bản.

Lớp ProcessPlane

Trong lớp ProcessPlane có ba phơng thức shadow, negate, edge nh sau:

Ph

ơng thức negate

public void negate() { int r,g,b,a; for(int y =0; y<getHeight();y++) for(int x=0; x<getWidth();x++ ) { r=getRed(x,y); g=getGreen(x,y); b=getBlue(x,y); a=getAlpha(x, y); setPixel(x,y,255-r,255-g,255-b,a); } } ph ơng thức shadow

public void shadow() { int r,g,b,a; for(int y =0; y<getHeight()-2;y++) for(int x=0; x<getWidth()-2;x++ ) { r=getRed(x,y); g=getGreen(x,y); b=getBlue(x,y); a=getAlpha(x, y); 88

r=r + (127-getRed(x+2,y+2)); g=g + (127-getGreen(x+2,y+2)); b=b + (127-getBlue(x+2,y+2)); setPixel(x,y,r,g,b,a); } } ph ơng thức edge :

public ProcessPlane edge() {

ProcessPlane pp = new ProcessPlane(getWidth(), getHeight());

int r,a;

int average; // average intensity for (int y = 0; y < getHeight(); y++) new_line: {

average = 0;

for (int x =0 ; x < getWidth(); x++) average = average + getRed (x,y); average = average / getWidth();

for (int x =0 ; x < getWidth(); x++) { r = getRed (x,y);

a = getAlpha(x,y); if (r > average) { int start=x;

for (int i=x;i < getWidth(); i++) { r = getRed (i,y);

if (r < average) { pp.setPixel(

start + (i - start) / 2,y,255,255,255,a); break new_line; } } } } } return pp; }

Sau đây là hiệu quả của ba phép xử lý trên:

Hiệu quả của phơng thức edge

Hiệu quả phơng thức shadow Hiệu quả phơng thức negate

Một phần của tài liệu Đồ án xử lý ảnh trong Java (Trang 83 - 89)